diff options
517 files changed, 19342 insertions, 5052 deletions
@@ -76,7 +76,8 @@ LOCAL_SRC_FILES += \ 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 @@ LOCAL_SRC_FILES += \ 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 \ 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/framew $(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 1c8698a..67c9276 100644 --- a/api/current.txt +++ b/api/current.txt @@ -491,7 +491,7 @@ package android { 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,7 +501,9 @@ package android { 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 = 16843855; // 0x101044f field public static final int excludeFromRecents = 16842775; // 0x1010017 + 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 @@ -596,6 +598,7 @@ package android { 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 @@ -1049,6 +1052,7 @@ package android { 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 @@ -1106,7 +1110,7 @@ package android { 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 @@ -1630,6 +1634,7 @@ package android { field public static final int selectAll = 16908319; // 0x102001f field public static final int selectTextMode = 16908333; // 0x102002d field public static final int selectedIcon = 16908302; // 0x102000e + field public static final int shared_element = 16908355; // 0x1020043 field public static final int shared_element_name = 16908353; // 0x1020041 field public static final int startSelectingText = 16908328; // 0x1020028 field public static final int stopSelectingText = 16908329; // 0x1020029 @@ -1852,52 +1857,52 @@ package android { 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 = 16974542; // 0x10302ce + field public static final int TextAppearance_Quantum_Body2 = 16974541; // 0x10302cd + field public static final int TextAppearance_Quantum_Button = 16974545; // 0x10302d1 + field public static final int TextAppearance_Quantum_Caption = 16974543; // 0x10302cf + field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974353; // 0x1030211 + field public static final int TextAppearance_Quantum_Display1 = 16974537; // 0x10302c9 + field public static final int TextAppearance_Quantum_Display2 = 16974536; // 0x10302c8 + field public static final int TextAppearance_Quantum_Display3 = 16974535; // 0x10302c7 + field public static final int TextAppearance_Quantum_Display4 = 16974534; // 0x10302c6 + field public static final int TextAppearance_Quantum_Headline = 16974538; // 0x10302ca + 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 = 16974544; // 0x10302d0 + 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 = 16974540; // 0x10302cc + field public static final int TextAppearance_Quantum_Title = 16974539; // 0x10302cb + 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 @@ -1992,34 +1997,34 @@ package android { 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 @@ -2076,8 +2081,8 @@ package android { 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 @@ -2111,8 +2116,8 @@ package android { 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 @@ -2136,6 +2141,7 @@ package android { 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 @@ -2159,6 +2165,7 @@ package android { 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 @@ -2169,7 +2176,7 @@ package android { 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 @@ -2201,8 +2208,8 @@ package android { 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 @@ -2223,7 +2230,7 @@ package android { 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 @@ -2238,7 +2245,7 @@ package android { 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 @@ -2262,6 +2269,7 @@ package android { 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 @@ -2285,6 +2293,7 @@ package android { 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 @@ -2308,133 +2317,132 @@ package android { 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 = 16974473; // 0x1030289 + field public static final int Widget_Quantum_Light_ActionBar = 16974474; // 0x103028a + field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974475; // 0x103028b + field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974476; // 0x103028c + field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974477; // 0x103028d + field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974478; // 0x103028e + field public static final int Widget_Quantum_Light_ActionButton = 16974479; // 0x103028f + field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974480; // 0x1030290 + field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974481; // 0x1030291 + field public static final int Widget_Quantum_Light_ActionMode = 16974482; // 0x1030292 + field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974483; // 0x1030293 + field public static final int Widget_Quantum_Light_Button = 16974484; // 0x1030294 + field public static final int Widget_Quantum_Light_ButtonBar = 16974490; // 0x103029a + field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974491; // 0x103029b + field public static final int Widget_Quantum_Light_Button_Borderless = 16974485; // 0x1030295 + field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974486; // 0x1030296 + field public static final int Widget_Quantum_Light_Button_Inset = 16974487; // 0x1030297 + field public static final int Widget_Quantum_Light_Button_Small = 16974488; // 0x1030298 + field public static final int Widget_Quantum_Light_Button_Toggle = 16974489; // 0x1030299 + field public static final int Widget_Quantum_Light_CalendarView = 16974492; // 0x103029c + field public static final int Widget_Quantum_Light_CheckedTextView = 16974493; // 0x103029d + field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974494; // 0x103029e + field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974495; // 0x103029f + field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974496; // 0x10302a0 + field public static final int Widget_Quantum_Light_DropDownItem = 16974497; // 0x10302a1 + field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974498; // 0x10302a2 + field public static final int Widget_Quantum_Light_EditText = 16974499; // 0x10302a3 + field public static final int Widget_Quantum_Light_ExpandableListView = 16974500; // 0x10302a4 + field public static final int Widget_Quantum_Light_FastScroll = 16974501; // 0x10302a5 + field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974502; // 0x10302a6 + field public static final int Widget_Quantum_Light_GridView = 16974503; // 0x10302a7 + field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974504; // 0x10302a8 + field public static final int Widget_Quantum_Light_ImageButton = 16974505; // 0x10302a9 + field public static final int Widget_Quantum_Light_ListPopupWindow = 16974506; // 0x10302aa + field public static final int Widget_Quantum_Light_ListView = 16974507; // 0x10302ab + field public static final int Widget_Quantum_Light_ListView_DropDown = 16974508; // 0x10302ac + field public static final int Widget_Quantum_Light_MediaRouteButton = 16974509; // 0x10302ad + field public static final int Widget_Quantum_Light_PopupMenu = 16974510; // 0x10302ae + field public static final int Widget_Quantum_Light_PopupWindow = 16974511; // 0x10302af + field public static final int Widget_Quantum_Light_ProgressBar = 16974512; // 0x10302b0 + field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974513; // 0x10302b1 + field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974514; // 0x10302b2 + field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974515; // 0x10302b3 + field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974516; // 0x10302b4 + field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974517; // 0x10302b5 + field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974518; // 0x10302b6 + field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974519; // 0x10302b7 + field public static final int Widget_Quantum_Light_RatingBar = 16974520; // 0x10302b8 + field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974521; // 0x10302b9 + field public static final int Widget_Quantum_Light_RatingBar_Small = 16974522; // 0x10302ba + field public static final int Widget_Quantum_Light_ScrollView = 16974523; // 0x10302bb + field public static final int Widget_Quantum_Light_SeekBar = 16974524; // 0x10302bc + field public static final int Widget_Quantum_Light_SegmentedButton = 16974525; // 0x10302bd + field public static final int Widget_Quantum_Light_Spinner = 16974527; // 0x10302bf + field public static final int Widget_Quantum_Light_StackView = 16974526; // 0x10302be + field public static final int Widget_Quantum_Light_Tab = 16974528; // 0x10302c0 + field public static final int Widget_Quantum_Light_TabWidget = 16974529; // 0x10302c1 + field public static final int Widget_Quantum_Light_TextView = 16974530; // 0x10302c2 + field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974531; // 0x10302c3 + field public static final int Widget_Quantum_Light_WebTextView = 16974532; // 0x10302c4 + field public static final int Widget_Quantum_Light_WebView = 16974533; // 0x10302c5 + 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_PopupWindow = 16974453; // 0x1030275 + field public static final int Widget_Quantum_ProgressBar = 16974454; // 0x1030276 + field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974455; // 0x1030277 + field public static final int Widget_Quantum_ProgressBar_Large = 16974456; // 0x1030278 + field public static final int Widget_Quantum_ProgressBar_Small = 16974457; // 0x1030279 + field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974458; // 0x103027a + field public static final int Widget_Quantum_RatingBar = 16974459; // 0x103027b + field public static final int Widget_Quantum_RatingBar_Indicator = 16974460; // 0x103027c + field public static final int Widget_Quantum_RatingBar_Small = 16974461; // 0x103027d + field public static final int Widget_Quantum_ScrollView = 16974462; // 0x103027e + field public static final int Widget_Quantum_SeekBar = 16974463; // 0x103027f + field public static final int Widget_Quantum_SegmentedButton = 16974464; // 0x1030280 + field public static final int Widget_Quantum_Spinner = 16974466; // 0x1030282 + field public static final int Widget_Quantum_StackView = 16974465; // 0x1030281 + field public static final int Widget_Quantum_Tab = 16974467; // 0x1030283 + field public static final int Widget_Quantum_TabWidget = 16974468; // 0x1030284 + field public static final int Widget_Quantum_TextView = 16974469; // 0x1030285 + field public static final int Widget_Quantum_TextView_SpinnerItem = 16974470; // 0x1030286 + field public static final int Widget_Quantum_WebTextView = 16974471; // 0x1030287 + field public static final int Widget_Quantum_WebView = 16974472; // 0x1030288 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 @@ -3061,6 +3069,7 @@ package android.app { 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(); @@ -3071,6 +3080,7 @@ package android.app { 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(); @@ -3089,6 +3099,8 @@ package android.app { 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); @@ -3304,7 +3316,6 @@ package android.app { 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); @@ -3322,6 +3333,7 @@ package android.app { 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); @@ -3442,8 +3454,7 @@ package android.app { 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; @@ -3451,6 +3462,21 @@ package android.app { 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[]); @@ -3533,8 +3559,9 @@ package android.app { public static class ActivityOptions.ActivityTransitionListener { ctor public ActivityOptions.ActivityTransitionListener(); method public android.util.Pair<android.view.View, java.lang.String>[] getSharedElementsMapping(); - method public void onCaptureSharedElementEnd(); - method public void onCaptureSharedElementStart(); + method public boolean handleRejectedSharedElements(java.util.List<android.view.View>); + method public void onCaptureSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>); + method public void onCaptureSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>); method public void onEnterReady(); method public void onExitTransitionComplete(); method public void onRemoteExitComplete(); @@ -4981,8 +5008,10 @@ package android.app.admin { public class DevicePolicyManager { 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 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); @@ -5042,6 +5071,8 @@ package android.app.admin { field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN"; field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "defaultManagedProfileName"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "deviceAdminPackageName"; + field public static int FLAG_TO_MANAGED_PROFILE; + field public static int FLAG_TO_PRIMARY_USER; field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff field public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; // 0x0 field public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 2; // 0x2 @@ -5158,6 +5189,27 @@ package android.app.maintenance { } +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 { @@ -7520,6 +7572,55 @@ package android.content { 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); @@ -7758,6 +7859,8 @@ package android.content.pm { public class LauncherApps { method public synchronized void addOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener); method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle); + method public boolean isActivityEnabledForProfile(android.content.ComponentName, android.os.UserHandle); + method public boolean isPackageEnabledForProfile(java.lang.String, android.os.UserHandle); method public synchronized void removeOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener); method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle); method public void startActivityForProfile(android.content.ComponentName, android.graphics.Rect, android.os.Bundle, android.os.UserHandle); @@ -12128,6 +12231,14 @@ package android.hardware.camera2 { 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(); @@ -12140,18 +12251,83 @@ package android.hardware.camera2 { 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 { @@ -12194,7 +12370,6 @@ package android.hardware.hdmi { 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 @@ -12204,6 +12379,7 @@ package android.hardware.hdmi { 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 @@ -12284,6 +12460,7 @@ package android.hardware.hdmi { 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 { @@ -12301,6 +12478,17 @@ package android.hardware.hdmi { 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); } @@ -12314,6 +12502,7 @@ package android.hardware.hdmi { 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; } } @@ -15093,11 +15282,13 @@ package android.media.routeprovider { 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"; @@ -15108,6 +15299,7 @@ package android.media.session { 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"; @@ -15140,25 +15332,25 @@ package android.media.session { 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 @@ -15167,6 +15359,8 @@ package android.media.session { 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 } @@ -23671,7 +23865,11 @@ package android.provider { public final class TvContract { method public static final android.net.Uri buildChannelUri(long); + method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName); + method public static final android.net.Uri buildChannelsUriForInput(android.content.ComponentName, boolean); method public static final android.net.Uri buildProgramUri(long); + method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri); + method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long); field public static final java.lang.String AUTHORITY = "com.android.tv"; } @@ -27950,6 +28148,18 @@ package android.transition { method public void setResizeClip(boolean); } + public class ChangeClipBounds extends android.transition.Transition { + ctor public ChangeClipBounds(); + method public void captureEndValues(android.transition.TransitionValues); + method public void captureStartValues(android.transition.TransitionValues); + } + + public class ChangeTransform extends android.transition.Transition { + ctor public ChangeTransform(); + method public void captureEndValues(android.transition.TransitionValues); + method public void captureStartValues(android.transition.TransitionValues); + } + public class CircularPropagation extends android.transition.VisibilityPropagation { ctor public CircularPropagation(); method public long getStartDelay(android.view.ViewGroup, android.transition.Transition, android.transition.TransitionValues, android.transition.TransitionValues); @@ -28010,6 +28220,7 @@ package android.transition { ctor public Transition(); method public android.transition.Transition addListener(android.transition.Transition.TransitionListener); method public android.transition.Transition addTarget(int); + method public android.transition.Transition addTarget(java.lang.Class); method public android.transition.Transition addTarget(android.view.View); method public boolean canRemoveViews(); method public abstract void captureEndValues(android.transition.TransitionValues); @@ -28587,6 +28798,25 @@ package android.util { 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); @@ -30084,7 +30314,7 @@ package android.view { 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); @@ -30622,6 +30852,7 @@ package android.view { field protected static final int[] WINDOW_FOCUSED_STATE_SET; field public static final android.util.Property X; field public static final android.util.Property Y; + field public static final android.util.Property Z; } public static class View.AccessibilityDelegate { @@ -30718,10 +30949,11 @@ package android.view { public class ViewConfiguration { ctor public deprecated ViewConfiguration(); method public static android.view.ViewConfiguration get(android.content.Context); + method public long getDeviceGlobalActionKeyTimeout(); 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(); @@ -30876,7 +31108,7 @@ package android.view { 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); @@ -31014,7 +31246,7 @@ package android.view { 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); @@ -32569,6 +32801,16 @@ package android.view.textservice { 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(); @@ -32797,6 +33039,7 @@ package android.webkit { 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(); @@ -32841,6 +33084,7 @@ package android.webkit { 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); @@ -32862,6 +33106,9 @@ package android.webkit { 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 { @@ -32954,6 +33201,7 @@ package android.webkit { 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(); @@ -33070,13 +33318,15 @@ package android.webkit { 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); diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index 3481437..74ccbc2 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -15,10 +15,12 @@ #include <cutils/properties.h> #include <cutils/trace.h> #include <android_runtime/AndroidRuntime.h> +#include <private/android_filesystem_config.h> // for AID_SYSTEM #include <stdlib.h> #include <stdio.h> #include <unistd.h> +#include <sys/prctl.h> namespace android { @@ -136,6 +138,44 @@ static size_t computeArgBlockSize(int argc, char* const argv[]) { return (end - start); } +static void maybeCreateDalvikCache() { +#if defined(__aarch64__) + static const char kInstructionSet[] = "arm64"; +#elif defined(__x86_64__) + static const char kInstructionSet[] = "x86_64"; +#elif defined(__arm__) + static const char kInstructionSet[] = "arm"; +#elif defined(__i386__) + static const char kInstructionSet[] = "x86"; +#elif defined (__mips__) + static const char kInstructionSet[] = "mips"; +#else +#error "Unknown instruction set" +#endif + const char* androidRoot = getenv("ANDROID_DATA"); + LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset"); + + char dalvikCacheDir[PATH_MAX]; + const int numChars = snprintf(dalvikCacheDir, PATH_MAX, + "%s/dalvik-cache/%s", androidRoot, kInstructionSet); + LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0), + "Error constructing dalvik cache : %s", strerror(errno)); + + int result = mkdir(dalvikCacheDir, 0771); + LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST), + "Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno)); + + // We always perform these steps because the directory might + // already exist, with wider permissions and a different owner + // than we'd like. + result = chown(dalvikCacheDir, AID_SYSTEM, AID_SYSTEM); + LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno)); + + result = chmod(dalvikCacheDir, 0771); + LOG_ALWAYS_FATAL_IF((result < 0), + "Error changing dalvik-cache permissions : %s", strerror(errno)); +} + #if defined(__LP64__) static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64"; static const char ZYGOTE_NICE_NAME[] = "zygote64"; @@ -146,6 +186,15 @@ static const char ZYGOTE_NICE_NAME[] = "zygote"; int main(int argc, char* const argv[]) { + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { + // Older kernels don't understand PR_SET_NO_NEW_PRIVS and return + // EINVAL. Don't die on such kernels. + if (errno != EINVAL) { + LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno)); + return 12; + } + } + AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Process command line arguments // ignore argv[0] @@ -213,6 +262,9 @@ int main(int argc, char* const argv[]) args.add(application ? String8("application") : String8("tool")); runtime.setClassNameAndArgs(className, argc - i, argv + i); } else { + // We're in zygote mode. + maybeCreateDalvikCache(); + if (startSystemServer) { args.add(String8("start-system-server")); } diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 1780e03..3dc024e 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -156,12 +156,12 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, return NO_ERROR; } -status_t BootAnimation::initTexture(void* buffer, size_t len) +status_t BootAnimation::initTexture(const Animation::Frame& frame) { //StopWatch watch("blah"); SkBitmap bitmap; - SkMemoryStream stream(buffer, len); + SkMemoryStream stream(frame.map->getDataPtr(), frame.map->getDataLength()); SkImageDecoder* codec = SkImageDecoder::Factory(&stream); if (codec) { codec->setDitherImage(false); @@ -171,6 +171,11 @@ status_t BootAnimation::initTexture(void* buffer, size_t len) delete codec; } + // FileMap memory is never released until application exit. + // Release it now as the texture is already loaded and the memory used for + // the packed resource can be released. + frame.map->release(); + // ensure we can call getPixels(). No need to call unlock, since the // bitmap will go out of scope when we return from this method. bitmap.lockPixels(); @@ -409,6 +414,7 @@ bool BootAnimation::movie() String8 desString((char const*)descMap->getDataPtr(), descMap->getDataLength()); + descMap->release(); char const* s = desString.string(); Animation animation; @@ -533,9 +539,7 @@ bool BootAnimation::movie() glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } - initTexture( - frame.map->getDataPtr(), - frame.map->getDataLength()); + initTexture(frame); } if (!clearReg.isEmpty()) { diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 22963c2..ba1c507 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -79,7 +79,7 @@ private: }; status_t initTexture(Texture* texture, AssetManager& asset, const char* name); - status_t initTexture(void* buffer, size_t len); + status_t initTexture(const Animation::Frame& frame); bool android(); bool movie(); 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 abstract class ActionBar { */ 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..5ec3117 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -3493,6 +3493,16 @@ public class Activity extends ContextThemeWrapper } 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 +4789,26 @@ public class Activity extends ContextThemeWrapper } /** - * 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) { } } diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 018e949..5d809d8 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -475,6 +475,111 @@ public class ActivityManager { } /** + * 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 class ActivityManager { 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)}. - */ - 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)}. + * The recent activity values for the highest activity in the stack to have set the values. + * {@link Activity#setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues)}. */ - public Bitmap activityIcon; + public RecentsActivityValues activityValues; public RecentTaskInfo() { } @@ -555,13 +654,11 @@ public class ActivityManager { 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 @@ public class ActivityManager { 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 @@ public class ActivityManager { * 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 class ActivityManager { */ 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; + } } /** @@ -1627,13 +1693,6 @@ public class ActivityManager { public int lastTrimLevel; /** - * Constant for {@link #importance}: this is a persistent process. - * Only used when reporting to process observers. - * @hide - */ - public static final int IMPORTANCE_PERSISTENT = 50; - - /** * Constant for {@link #importance}: this process is running the * foreground UI. */ @@ -1748,9 +1807,16 @@ public class ActivityManager { */ public int importanceReasonImportance; + /** + * Current process state, as per PROCESS_STATE_* constants. + * @hide + */ + public int processState; + public RunningAppProcessInfo() { importance = IMPORTANCE_FOREGROUND; importanceReasonCode = REASON_UNKNOWN; + processState = PROCESS_STATE_IMPORTANT_FOREGROUND; } public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) { @@ -1776,6 +1842,7 @@ public class ActivityManager { dest.writeInt(importanceReasonPid); ComponentName.writeToParcel(importanceReasonComponent, dest); dest.writeInt(importanceReasonImportance); + dest.writeInt(processState); } public void readFromParcel(Parcel source) { @@ -1791,6 +1858,7 @@ public class ActivityManager { importanceReasonPid = source.readInt(); importanceReasonComponent = ComponentName.readFromParcel(source); importanceReasonImportance = source.readInt(); + processState = source.readInt(); } public static final Creator<RunningAppProcessInfo> CREATOR = 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 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM 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 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM 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 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM 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 @@ class ActivityManagerProxy implements IActivityManager 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 @@ class ActivityManagerProxy implements IActivityManager 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 @@ class ActivityManagerProxy implements IActivityManager } @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/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 85464c47..a49359f 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -649,13 +649,31 @@ public class ActivityOptions { /** * Called when the start state for shared elements is captured on enter. + * + * @param sharedElementNames The names of the shared elements that were accepted into + * the View hierarchy. + * @param sharedElements The shared elements that are part of the View hierarchy. + * @param sharedElementSnapshots The Views containing snap shots of the shared element + * from the launching Window. These elements will not + * be part of the scene, but will be positioned relative + * to the Window decor View. */ - public void onCaptureSharedElementStart() {} + public void onCaptureSharedElementStart(List<String> sharedElementNames, + List<View> sharedElements, List<View> sharedElementSnapshots) {} /** * Called when the end state for shared elements is captured on enter. + * + * @param sharedElementNames The names of the shared elements that were accepted into + * the View hierarchy. + * @param sharedElements The shared elements that are part of the View hierarchy. + * @param sharedElementSnapshots The Views containing snap shots of the shared element + * from the launching Window. These elements will not + * be part of the scene, but will be positioned relative + * to the Window decor View. */ - public void onCaptureSharedElementEnd() {} + public void onCaptureSharedElementEnd(List<String> sharedElementNames, + List<View> sharedElements, List<View> sharedElementSnapshots) {} /** * Called when the enter Transition has been started. @@ -700,6 +718,22 @@ public class ActivityOptions { * call. */ public Pair<View, String>[] getSharedElementsMapping() { return null; } + + /** + * Returns <code>true</code> if the ActivityTransitionListener will handle removing + * rejected shared elements from the scene. If <code>false</code> is returned, a default + * animation will be used to remove the rejected shared elements from the scene. + * + * @param rejectedSharedElements Views containing visual information of shared elements + * that are not part of the entering scene. These Views + * are positioned relative to the Window decor View. + * @return <code>false</code> if the default animation should be used to remove the + * rejected shared elements from the scene or <code>true</code> if the listener provides + * custom handling. + */ + public boolean handleRejectedSharedElements(List<View> rejectedSharedElements) { + return false; + } } private static class SharedElementMappingListener extends ActivityTransitionListener { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7dc21b4..3b2ff7f 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -821,10 +821,6 @@ public final class ActivityThread { 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 final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 @@ public final class ActivityThread { 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 diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index d8a356f..3c1455b 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -15,6 +15,12 @@ */ package android.app; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; @@ -26,8 +32,10 @@ import android.util.ArrayMap; import android.util.Pair; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroupOverlay; import android.view.ViewTreeObserver; import android.view.Window; +import android.widget.ImageView; import java.util.ArrayList; import java.util.Collection; @@ -129,6 +137,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { private static final String KEY_WIDTH = "shared_element:width"; private static final String KEY_HEIGHT = "shared_element:height"; private static final String KEY_NAME = "shared_element:name"; + private static final String KEY_BITMAP = "shared_element:bitmap"; /** * Sent by the exiting coordinator (either EnterTransitionCoordinator @@ -197,6 +206,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { private ResultReceiver mRemoteResultReceiver; private boolean mNotifiedSharedElementTransitionComplete; private boolean mNotifiedExitTransitionComplete; + private boolean mSharedElementTransitionStarted; private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback(); @@ -241,7 +251,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { onPrepareRestore(); break; case MSG_EXIT_TRANSITION_COMPLETE: - onRemoteSceneExitComplete(); + if (!mSharedElementTransitionStarted) { + send(resultCode, resultData); + } else { + onRemoteSceneExitComplete(); + } break; case MSG_TAKE_SHARED_ELEMENTS: ArrayList<String> sharedElementNames @@ -305,16 +319,23 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { setSharedElements(); reconcileSharedElements(sharedElementNames); mEnteringViews.removeAll(mSharedElements); - setSharedElementState(state); + final ArrayList<View> accepted = new ArrayList<View>(); + final ArrayList<View> rejected = new ArrayList<View>(); + createSharedElementImages(accepted, rejected, sharedElementNames, state); + setSharedElementState(state, accepted); + handleRejected(rejected); + if (getViewsTransition() != null) { setViewVisibility(mEnteringViews, View.INVISIBLE); } setViewVisibility(mSharedElements, View.VISIBLE); Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(), true); + if (allowOverlappingTransitions()) { onStartEnterTransition(transition, mEnteringViews); } + mRemoteResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null); } @@ -440,9 +461,13 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { mTargetSharedNames.clear(); if (sharedElements == null) { ArrayMap<String, View> map = new ArrayMap<String, View>(); - setViewVisibility(mEnteringViews, View.VISIBLE); + if (getViewsTransition() != null) { + setViewVisibility(mEnteringViews, View.VISIBLE); + } getDecor().findSharedElements(map); - setViewVisibility(mEnteringViews, View.INVISIBLE); + if (getViewsTransition() != null) { + setViewVisibility(mEnteringViews, View.INVISIBLE); + } for (int i = 0; i < map.size(); i++) { View view = map.valueAt(i); String name = map.keyAt(i); @@ -513,35 +538,60 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } private void reconcileSharedElements(ArrayList<String> sharedElementNames) { - Rect epicenter = null; - for (int i = mTargetSharedNames.size() - 1; i >= 0; i--) { - if (!sharedElementNames.contains(mTargetSharedNames.get(i))) { - mTargetSharedNames.remove(i); - mSharedElements.remove(i); + // keep only those that are in sharedElementNames. + int numSharedElements = sharedElementNames.size(); + int targetIndex = 0; + for (int i = 0; i < numSharedElements; i++) { + String name = sharedElementNames.get(i); + int index = mTargetSharedNames.indexOf(name); + if (index >= 0) { + // Swap the items at the indexes if necessary. + if (index != targetIndex) { + View temp = mSharedElements.get(index); + mSharedElements.set(index, mSharedElements.get(targetIndex)); + mSharedElements.set(targetIndex, temp); + mTargetSharedNames.set(index, mTargetSharedNames.get(targetIndex)); + mTargetSharedNames.set(targetIndex, name); + } + targetIndex++; } } - if (!mSharedElements.isEmpty()) { + for (int i = mSharedElements.size() - 1; i >= targetIndex; i--) { + mSharedElements.remove(i); + mTargetSharedNames.remove(i); + } + Rect epicenter = null; + if (!mTargetSharedNames.isEmpty() + && mTargetSharedNames.get(0).equals(sharedElementNames.get(0))) { epicenter = calcEpicenter(mSharedElements.get(0)); } mEpicenterCallback.setEpicenter(epicenter); } - private void setSharedElementState(Bundle sharedElementState) { + private void setSharedElementState(Bundle sharedElementState, + final ArrayList<View> acceptedOverlayViews) { + final int[] tempLoc = new int[2]; if (sharedElementState != null) { - int[] tempLoc = new int[2]; for (int i = 0; i < mSharedElements.size(); i++) { View sharedElement = mSharedElements.get(i); + View parent = (View) sharedElement.getParent(); + parent.getLocationOnScreen(tempLoc); String name = mTargetSharedNames.get(i); setSharedElementState(sharedElement, name, sharedElementState, tempLoc); + sharedElement.requestLayout(); } } - mListener.onCaptureSharedElementStart(); + mListener.onCaptureSharedElementStart(mTargetSharedNames, mSharedElements, + acceptedOverlayViews); + getDecor().getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { getDecor().getViewTreeObserver().removeOnPreDrawListener(this); - mListener.onCaptureSharedElementEnd(); + mListener.onCaptureSharedElementEnd(mTargetSharedNames, mSharedElements, + acceptedOverlayViews); + mSharedElementTransitionStarted = true; return true; } } @@ -555,10 +605,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { * @param name The shared element name given from the source Activity. * @param transitionArgs A <code>Bundle</code> containing all placementinformation for named * shared elements in the scene. - * @param tempLoc A temporary int[2] for capturing the current location of views. + * @param parentLoc The x and y coordinates of the parent's screen position. */ private static void setSharedElementState(View view, String name, Bundle transitionArgs, - int[] tempLoc) { + int[] parentLoc) { Bundle sharedElementBundle = transitionArgs.getBundle(name); if (sharedElementBundle == null) { return; @@ -576,15 +626,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); view.measure(widthSpec, heightSpec); - ViewGroup parent = (ViewGroup) view.getParent(); - parent.getLocationOnScreen(tempLoc); - int left = x - tempLoc[0]; - int top = y - tempLoc[1]; + int left = x - parentLoc[0]; + int top = y - parentLoc[1]; int right = left + width; int bottom = top + height; view.layout(left, top, right, bottom); - - view.requestLayout(); } /** @@ -615,6 +661,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { sharedElementBundle.putString(KEY_NAME, view.getSharedElementName()); + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + view.draw(canvas); + sharedElementBundle.putParcelable(KEY_BITMAP, bitmap); + transitionArgs.putBundle(name, sharedElementBundle); } @@ -723,6 +774,61 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { return transition; } + private void handleRejected(final ArrayList<View> rejected) { + int numRejected = rejected.size(); + if (numRejected == 0) { + return; + } + boolean rejectionHandled = mListener.handleRejectedSharedElements(rejected); + if (rejectionHandled) { + return; + } + + ViewGroupOverlay overlay = getDecor().getOverlay(); + ObjectAnimator animator = null; + for (int i = 0; i < numRejected; i++) { + View view = rejected.get(i); + overlay.add(view); + animator = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0); + animator.start(); + } + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + ViewGroupOverlay overlay = getDecor().getOverlay(); + for (int i = rejected.size() - 1; i >= 0; i--) { + overlay.remove(rejected.get(i)); + } + } + }); + } + + private void createSharedElementImages(ArrayList<View> accepted, ArrayList<View> rejected, + ArrayList<String> sharedElementNames, Bundle state) { + int numSharedElements = sharedElementNames.size(); + Context context = getWindow().getContext(); + int[] parentLoc = new int[2]; + getDecor().getLocationOnScreen(parentLoc); + for (int i = 0; i < numSharedElements; i++) { + String name = sharedElementNames.get(i); + Bundle sharedElementBundle = state.getBundle(name); + if (sharedElementBundle != null) { + Bitmap bitmap = sharedElementBundle.getParcelable(KEY_BITMAP); + ImageView imageView = new ImageView(context); + imageView.setId(com.android.internal.R.id.shared_element); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setImageBitmap(bitmap); + imageView.setSharedElementName(name); + setSharedElementState(imageView, name, state, parentLoc); + if (mTargetSharedNames.contains(name)) { + accepted.add(imageView); + } else { + rejected.add(imageView); + } + } + } + } + private static class FixedEpicenterCallback extends Transition.EpicenterCallback { private Rect mEpicenter; 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 @@ public abstract class ApplicationThreadNative extends Binder 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 @@ class ApplicationThreadProxy implements IApplicationThread { 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..a4b2651 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -473,14 +473,14 @@ class ContextImpl extends Context { registerService(NOTIFICATION_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { final Context outerContext = ctx.getOuterContext(); + // TODO: Why are we not just using the theme attribute + // that defines the dialog theme? return new NotificationManager( new ContextThemeWrapper(outerContext, - Resources.selectSystemTheme(0, + outerContext.getResources().selectSystemTheme(0, outerContext.getApplicationInfo().targetSdkVersion, - com.android.internal.R.style.Theme_Dialog, - com.android.internal.R.style.Theme_Holo_Dialog, - com.android.internal.R.style.Theme_DeviceDefault_Dialog, - com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)), + com.android.internal.R.array.system_theme_sdks, + com.android.internal.R.array.system_theme_dialog_styles)), ctx.mMainThread.getHandler()); }}); @@ -731,7 +731,7 @@ class ContextImpl extends Context { @Override public Resources.Theme getTheme() { if (mTheme == null) { - mThemeResource = Resources.selectDefaultTheme(mThemeResource, + mThemeResource = mResources.selectDefaultTheme(mThemeResource, getOuterContext().getApplicationInfo().targetSdkVersion); mTheme = mResources.newTheme(); mTheme.applyStyle(mThemeResource, true); diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index aa097e0..cbb8359 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -23,8 +23,6 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.ResultReceiver; import android.transition.Transition; -import android.util.ArrayMap; -import android.util.Pair; import android.view.View; import android.view.ViewTreeObserver; import android.view.Window; @@ -135,11 +133,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator } @Override - protected void onRemoteSceneExitComplete() { - super.onRemoteSceneExitComplete(); - } - - @Override protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) { mEnteringSharedElementNames = new ArrayList<String>(); mEnteringSharedElementNames.addAll(sharedElementNames); @@ -149,6 +142,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator @Override protected void sharedElementTransitionComplete(Bundle bundle) { notifySharedElementTransitionComplete(bundle); + exitAfterSharedElementTransition(); } @Override @@ -223,6 +217,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator @Override protected void startExitTransition(ArrayList<String> sharedElements) { + mMakeOpaque = false; notifyPrepareRestore(); if (getDecor().getBackground() == null) { @@ -264,7 +259,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator mExitTransitionComplete = true; exitAfterSharedElementTransition(); super.onExitTransitionEnd(); - clearConnections(); } @Override @@ -281,12 +275,13 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator } private void exitAfterSharedElementTransition() { - if (mSharedElementTransitionComplete && mExitTransitionComplete) { + if (mSharedElementTransitionComplete && mExitTransitionComplete && mBackgroundFadedOut) { mActivity.finish(); if (mSupportsTransition) { mActivity.overridePendingTransition(0, 0); } notifyExitTransitionComplete(); + clearConnections(); } } } 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 interface IActivityManager extends IInterface { 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 interface IActivityManager extends IInterface { 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 interface IActivityManager extends IInterface { 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 @@ public interface IActivityManager extends IInterface { 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 @@ public interface IActivityManager extends IInterface { 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 @@ public interface IApplicationThread extends IInterface { 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 @@ public interface IApplicationThread extends IInterface { 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 @@ interface INotificationManager 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/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl index e587912..ecf2c73 100644 --- a/core/java/android/app/IProcessObserver.aidl +++ b/core/java/android/app/IProcessObserver.aidl @@ -20,7 +20,7 @@ package android.app; oneway interface IProcessObserver { void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities); - void onImportanceChanged(int pid, int uid, int importance); + void onProcessStateChanged(int pid, int uid, int procState); void onProcessDied(int pid, int uid); } 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/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 5f8ebbe..58d707c 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -651,6 +651,10 @@ public class WallpaperManager { * not "image/*" */ public Intent getCropAndSetWallpaperIntent(Uri imageUri) { + if (imageUri == null) { + throw new IllegalArgumentException("Image URI must not be null"); + } + if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())) { throw new IllegalArgumentException("Image URI must be of the " + ContentResolver.SCHEME_CONTENT + " scheme type"); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 68ab611..6f68dfb 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -172,6 +172,16 @@ public class DevicePolicyManager { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 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. + */ + public static int FLAG_TO_PRIMARY_USER = 0x0001; + + /** + * Flag for {@link #forwardMatchingIntents}: the intents will be forwarded to the managed + * profile. + */ + public static int FLAG_TO_MANAGED_PROFILE = 0x0002; /** * Return true if the given administrator component is currently @@ -1778,7 +1788,7 @@ public class DevicePolicyManager { * Sets the enabled state of the profile. A profile should be enabled only once it is ready to * be used. Only the profile owner can call this. * - * @see #isPRofileOwnerApp + * @see #isProfileOwnerApp * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. */ @@ -1834,27 +1844,6 @@ public class DevicePolicyManager { /** * @hide - * @param userId the userId of a managed profile profile. - * - * @return whether or not the managed profile is enabled. - * @throws IllegalArgumentException if the userId is invalid. - */ - public boolean isProfileEnabled(int userId) throws IllegalArgumentException { - if (mService != null) { - try { - return mService.isProfileEnabled(userId); - } catch (RemoteException re) { - Log.w(TAG, "Failed to get status for owner profile."); - throw new IllegalArgumentException( - "Failed to get status for owner profile.", re); - } - } - return true; - } - - - /** - * @hide * @return the human readable name of the organisation associated with this DPM or null if * one is not set. * @throws IllegalArgumentException if the userId is invalid. @@ -1953,6 +1942,39 @@ public class DevicePolicyManager { } /** + * Called by a profile owner to forward intents sent from the managed profile to the owner, or + * from the owner to the managed profile. + * If an intent matches this intent filter, then activities belonging to the other user can + * respond to this intent. + * @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) { + if (mService != null) { + try { + mService.forwardMatchingIntents(admin, filter, flags); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * Called by a profile owner to remove all the forwarding intent filters from the current user + * and from the owner. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + */ + public void clearForwardingIntentFilters(ComponentName admin) { + if (mService != null) { + try { + mService.clearForwardingIntentFilters(admin); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** * Called by a profile or device owner to get the application restrictions for a given target * application running in the managed profile. * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 72b3c20..495a5f9 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -109,7 +109,6 @@ interface IDevicePolicyManager { String getProfileOwner(int userHandle); String getProfileOwnerName(int userHandle); void setProfileEnabled(in ComponentName who); - boolean isProfileEnabled(int userHandle); boolean installCaCert(in byte[] certBuffer); void uninstallCaCert(in byte[] certBuffer); @@ -121,4 +120,6 @@ interface IDevicePolicyManager { 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 clearForwardingIntentFilters(in ComponentName admin); } 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/java/android/app/task/TaskParams.aidl b/core/java/android/app/task/TaskParams.aidl new file mode 100644 index 0000000..9b25855 --- /dev/null +++ b/core/java/android/app/task/TaskParams.aidl @@ -0,0 +1,19 @@ +/** + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.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/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 4b33799..8670da7 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -54,6 +54,12 @@ public class AppWidgetProviderInfo implements Parcelable { public static final int WIDGET_CATEGORY_KEYGUARD = 2; /** + * Indicates that the widget can be displayed within recents. + * @hide + */ + 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/content/Task.java b/core/java/android/content/Task.java new file mode 100644 index 0000000..ed5ed88 --- /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/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index 796b113..0acf043 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -35,4 +35,6 @@ interface ILauncherApps { ResolveInfo resolveActivity(in Intent intent, in UserHandle user); void startActivityAsUser(in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); + boolean isPackageEnabled(String packageName, in UserHandle user); + boolean isActivityEnabled(in ComponentName component, in UserHandle user); } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 488e25f..cf9a296 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -111,6 +111,8 @@ interface IPackageManager { ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId); + boolean canForwardTo(in Intent intent, String resolvedType, int userIdFrom, int userIdDest); + List<ResolveInfo> queryIntentActivities(in Intent intent, String resolvedType, int flags, int userId); @@ -245,6 +247,10 @@ interface IPackageManager { void clearPackagePersistentPreferredActivities(String packageName, int userId); + void addForwardingIntentFilter(in IntentFilter filter, int userIdOrig, int userIdDest); + + void clearForwardingIntentFilters(int userIdOrig); + /** * Report the set of 'Home' activity candidates, plus (if any) which of them * is the current "always use this one" setting. diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 5187181..8025b60 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -187,6 +187,39 @@ public class LauncherApps { } /** + * Checks if the package is installed and enabled for a profile. + * + * @param packageName The package to check. + * @param user The UserHandle of the profile. + * + * @return true if the package exists and is enabled. + */ + public boolean isPackageEnabledForProfile(String packageName, UserHandle user) { + try { + return mService.isPackageEnabled(packageName, user); + } catch (RemoteException re) { + return false; + } + } + + /** + * Checks if the activity exists and it enabled for a profile. + * + * @param component The activity to check. + * @param user The UserHandle of the profile. + * + * @return true if the activity exists and is enabled. + */ + public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) { + try { + return mService.isActivityEnabled(component, user); + } catch (RemoteException re) { + return false; + } + } + + + /** * Adds a listener for changes to packages in current and managed profiles. * * @param listener The listener to add. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 8f19f01..080b37b 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -459,7 +459,7 @@ public class PackageParser { return pi; } - private Certificate[] loadCertificates(StrictJarFile jarFile, ZipEntry je, + private Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry je, byte[] readBuffer) { try { // We must read the stream for the JarEntry to retrieve @@ -469,7 +469,7 @@ public class PackageParser { // not using } is.close(); - return je != null ? jarFile.getCertificates(je) : null; + return je != null ? jarFile.getCertificateChains(je) : null; } catch (IOException e) { Slog.w(TAG, "Exception reading " + je.getName() + " in " + jarFile, e); } catch (RuntimeException e) { @@ -632,7 +632,7 @@ public class PackageParser { try { StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath); - Certificate[] certs = null; + Certificate[][] certs = null; if ((flags&PARSE_IS_SYSTEM) != 0) { // If this package comes from the system image, then we @@ -656,8 +656,8 @@ public class PackageParser { final int N = certs.length; for (int i=0; i<N; i++) { Slog.i(TAG, " Public key: " - + certs[i].getPublicKey().getEncoded() - + " " + certs[i].getPublicKey()); + + certs[i][0].getPublicKey().getEncoded() + + " " + certs[i][0].getPublicKey()); } } } @@ -677,7 +677,7 @@ public class PackageParser { ManifestDigest.fromInputStream(jarFile.getInputStream(je)); } - final Certificate[] localCerts = loadCertificates(jarFile, je, readBuffer); + final Certificate[][] localCerts = loadCertificates(jarFile, je, readBuffer); if (DEBUG_JAR) { Slog.i(TAG, "File " + mArchiveSourcePath + " entry " + je.getName() + ": certs=" + certs + " (" @@ -726,8 +726,7 @@ public class PackageParser { final int N = certs.length; pkg.mSignatures = new Signature[certs.length]; for (int i=0; i<N; i++) { - pkg.mSignatures[i] = new Signature( - certs[i].getEncoded()); + pkg.mSignatures[i] = new Signature(certs[i]); } } else { Slog.e(TAG, "Package " + pkg.packageName @@ -739,7 +738,7 @@ public class PackageParser { // Add the signing KeySet to the system pkg.mSigningKeys = new HashSet<PublicKey>(); for (int i=0; i < certs.length; i++) { - pkg.mSigningKeys.add(certs[i].getPublicKey()); + pkg.mSigningKeys.add(certs[i][0].getPublicKey()); } } catch (CertificateEncodingException e) { diff --git a/core/java/android/content/pm/Signature.java b/core/java/android/content/pm/Signature.java index 752bf8b..f4e7dc3 100644 --- a/core/java/android/content/pm/Signature.java +++ b/core/java/android/content/pm/Signature.java @@ -25,6 +25,7 @@ import java.io.ByteArrayInputStream; import java.lang.ref.SoftReference; import java.security.PublicKey; import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.util.Arrays; @@ -38,12 +39,28 @@ public class Signature implements Parcelable { private int mHashCode; private boolean mHaveHashCode; private SoftReference<String> mStringRef; + private Certificate[] mCertificateChain; /** * Create Signature from an existing raw byte array. */ public Signature(byte[] signature) { mSignature = signature.clone(); + mCertificateChain = null; + } + + /** + * Create signature from a certificate chain. Used for backward + * compatibility. + * + * @throws CertificateEncodingException + * @hide + */ + public Signature(Certificate[] certificateChain) throws CertificateEncodingException { + mSignature = certificateChain[0].getEncoded(); + if (certificateChain.length > 1) { + mCertificateChain = Arrays.copyOfRange(certificateChain, 1, certificateChain.length); + } } private static final int parseHexDigit(int nibble) { @@ -156,6 +173,29 @@ public class Signature implements Parcelable { return cert.getPublicKey(); } + /** + * Used for compatibility code that needs to check the certificate chain + * during upgrades. + * + * @throws CertificateEncodingException + * @hide + */ + public Signature[] getChainSignatures() throws CertificateEncodingException { + if (mCertificateChain == null) { + return new Signature[] { this }; + } + + Signature[] chain = new Signature[1 + mCertificateChain.length]; + chain[0] = this; + + int i = 1; + for (Certificate c : mCertificateChain) { + chain[i++] = new Signature(c.getEncoded()); + } + + return chain; + } + @Override public boolean equals(Object obj) { try { diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index f53aa4c..c0383a3 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -27,8 +27,8 @@ import android.os.UserHandle; */ public class UserInfo implements Parcelable { - /** 6 bits for user type */ - public static final int FLAG_MASK_USER_TYPE = 0x0000003F; + /** 8 bits for user type */ + public static final int FLAG_MASK_USER_TYPE = 0x000000FF; /** * *************************** NOTE *************************** @@ -70,6 +70,11 @@ public class UserInfo implements Parcelable { */ public static final int FLAG_MANAGED_PROFILE = 0x00000020; + /** + * Indicates that this user is disabled. + */ + public static final int FLAG_DISABLED = 0x00000040; + public static final int NO_PROFILE_GROUP_ID = -1; @@ -117,6 +122,10 @@ public class UserInfo implements Parcelable { return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE; } + public boolean isEnabled() { + return (flags & FLAG_DISABLED) != FLAG_DISABLED; + } + /** * @return true if this user can be switched to. **/ diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 4879c23..1331777 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -137,42 +137,45 @@ public class Resources { /** * Returns the most appropriate default theme for the specified target SDK version. - * <ul> - * <li>Below API 11: Gingerbread - * <li>APIs 11 thru 14: Holo - * <li>APIs 14 thru XX: Device default dark - * <li>API XX and above: Device default light with dark action bar - * </ul> * * @param curTheme The current theme, or 0 if not specified. * @param targetSdkVersion The target SDK version. * @return A theme resource identifier * @hide */ - public static int selectDefaultTheme(int curTheme, int targetSdkVersion) { + public int selectDefaultTheme(int curTheme, int targetSdkVersion) { return selectSystemTheme(curTheme, targetSdkVersion, - com.android.internal.R.style.Theme, - com.android.internal.R.style.Theme_Holo, - com.android.internal.R.style.Theme_DeviceDefault, - com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar); + com.android.internal.R.array.system_theme_sdks, + com.android.internal.R.array.system_theme_styles); } - /** @hide */ - public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo, - int dark, int deviceDefault) { + /** + * Returns the most appropriate default theme for the specified target SDK version. + * + * @param curTheme The current theme, or 0 if not specified. + * @param targetSdkVersion The target SDK version. + * @param sdkArrayId Identifier for integer array resource containing + * sorted minimum SDK versions. First entry must be 0. + * @param themeArrayId Identifier for array resource containing the + * default themes that map to SDK versions. + * @return A theme resource identifier + * @hide + */ + public int selectSystemTheme( + int curTheme, int targetSdkVersion, int sdkArrayId, int themeArrayId) { if (curTheme != 0) { return curTheme; } - if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) { - return orig; - } - if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - return holo; - } - if (targetSdkVersion < Build.VERSION_CODES.CUR_DEVELOPMENT) { - return dark; + + final int[] targetSdks = getIntArray(sdkArrayId); + final TypedArray defaultThemes = obtainTypedArray(themeArrayId); + for (int i = targetSdks.length - 1; i > 0; i--) { + if (targetSdkVersion >= targetSdks[i]) { + return defaultThemes.getResourceId(i, 0); + } } - return deviceDefault; + + return defaultThemes.getResourceId(0, 0); } /** @@ -2308,8 +2311,8 @@ public class Resources { */ 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 528e119..28309d7 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -372,7 +372,6 @@ public final class CameraCharacteristics extends CameraMetadata { /** * <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> @@ -455,22 +454,25 @@ public final class CameraCharacteristics extends CameraMetadata { * <p>The maximum numbers of different types of output streams * that can be configured and used simultaneously by a camera device.</p> * <p>This is a 3 element tuple that contains the max number of output simultaneous - * streams for raw sensor, processed (and uncompressed), and JPEG formats respectively. - * For example, if max raw sensor format output stream number is 1, max YUV streams + * streams for raw sensor, processed (but not stalling), and processed (and stalling) + * formats respectively. For example, assuming that JPEG is typically a processed and + * stalling stream, if max raw sensor format output stream number is 1, max YUV streams * number is 3, and max JPEG stream number is 2, then this tuple should be <code>(1, 3, 2)</code>.</p> * <p>This lists the upper bound of the number of output streams supported by * the camera device. Using more streams simultaneously may require more hardware and * CPU resources that will consume more power. The image format for a output stream can - * be any supported format provided by {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS android.scaler.availableFormats}. The formats - * defined in {@link CameraCharacteristics#SCALER_AVAILABLE_FORMATS android.scaler.availableFormats} can be catergorized into the 3 stream types - * as below:</p> + * be any supported format provided by {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations}. + * The formats defined in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS android.scaler.availableStreamConfigurations} can be catergorized + * into the 3 stream types as below:</p> * <ul> - * <li>JPEG-compressed format: BLOB.</li> - * <li>Raw formats: RAW_SENSOR and RAW_OPAQUE.</li> - * <li>processed, uncompressed formats: YCbCr_420_888, YCrCb_420_SP, YV12.</li> + * <li>Processed (but stalling): any non-RAW format with a stallDurations > 0. + * Typically JPEG format (ImageFormat#JPEG).</li> + * <li>Raw formats: ImageFormat#RAW_SENSOR and ImageFormat#RAW_OPAQUE.</li> + * <li>Processed (but not-stalling): any non-RAW format without a stall duration. + * Typically ImageFormat#YUV_420_888, ImageFormat#NV21, ImageFormat#YV12.</li> * </ul> * - * @see CameraCharacteristics#SCALER_AVAILABLE_FORMATS + * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS */ public static final Key<int[]> REQUEST_MAX_NUM_OUTPUT_STREAMS = new Key<int[]>("android.request.maxNumOutputStreams", int[].class); 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 @@ public interface CameraDevice extends AutoCloseable { * * <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 @@ public interface CameraDevice extends AutoCloseable { * @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/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..2c224f6 --- /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 @@ public final class Size { 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 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { * 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 final class HdmiCec { 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 final class HdmiCec { 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 @@ public final class HdmiCec { 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 @@ public final class HdmiCec { "Recorder_3", "Tuner_4", "Playback_3", + "Secondary_TV", }; private HdmiCec() { } // Prevents instantiation. @@ -221,9 +225,7 @@ public final class HdmiCec { * @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 @@ package android.hardware.hdmi; import android.os.Parcel; import android.os.Parcelable; +import libcore.util.EmptyArray; + import java.util.Arrays; /** @@ -28,6 +30,8 @@ import java.util.Arrays; */ 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..e6dbcd0 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -654,13 +654,11 @@ public class InputMethodService extends AbstractInputMethodService { return false; } - @Override public void onCreate() { - mTheme = Resources.selectSystemTheme(mTheme, - getApplicationInfo().targetSdkVersion, - android.R.style.Theme_InputMethod, - android.R.style.Theme_Holo_InputMethod, - android.R.style.Theme_DeviceDefault_InputMethod, - android.R.style.Theme_DeviceDefault_InputMethod); + @Override + public void onCreate() { + mTheme = getResources().selectSystemTheme(mTheme, getApplicationInfo().targetSdkVersion, + com.android.internal.R.array.system_theme_sdks, + com.android.internal.R.array.system_theme_ime_styles); super.setTheme(mTheme); super.onCreate(); mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); 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 @@ interface INetworkScoreService /** * 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 @@ interface INetworkScoreService * 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/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index a470e88..30b61c5 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -54,7 +54,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class MobileDataStateTracker extends BaseNetworkStateTracker { private static final String TAG = "MobileDataStateTracker"; - private static final boolean DBG = true; + private static final boolean DBG = false; private static final boolean VDBG = false; private PhoneConstants.DataState mMobileDataState; 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 @@ package android.net; 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 @@ public class NetworkScoreManager { * 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 @@ public class NetworkScoreManager { * * @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 @@ public class NetworkScoreManager { 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..bea8d1c 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -274,48 +274,6 @@ public final class Proxy { 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) { String host = null; 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 @@ public class RssiCurve implements Parcelable { } /** + * 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 f05ddde..f1ad1f8 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -173,6 +173,10 @@ public abstract class BatteryStats implements Parcelable { private static final String BLUETOOTH_STATE_COUNT_DATA = "bsc"; private static final String POWER_USE_SUMMARY_DATA = "pws"; 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); @@ -1340,6 +1344,18 @@ public abstract class BatteryStats implements Parcelable { public abstract long computeBatteryTimeRemaining(long curTime); /** + * Return the historical number of discharge steps we currently have. + */ + public abstract int getNumDischargeStepDurations(); + + /** + * Return the array of discharge step durations; the number of valid + * items in it is returned by {@link #getNumDischargeStepDurations()}. + * These values are in milliseconds. + */ + public abstract long[] getDischargeStepDurationsArray(); + + /** * Compute an approximation for how much time (in microseconds) remains until the battery * is fully charged. Returns -1 if no time can be computed: either there is not * enough current data to make a decision, or the battery is currently @@ -1349,6 +1365,18 @@ public abstract class BatteryStats implements Parcelable { */ public abstract long computeChargeTimeRemaining(long curTime); + /** + * Return the historical number of charge steps we currently have. + */ + public abstract int getNumChargeStepDurations(); + + /** + * Return the array of charge step durations; the number of valid + * items in it is returned by {@link #getNumChargeStepDurations()}. + * These values are in milliseconds. + */ + public abstract long[] getChargeStepDurationsArray(); + public abstract Map<String, ? extends LongCounter> getWakeupReasonStats(); public abstract Map<String, ? extends Timer> getKernelWakelockStats(); @@ -3050,7 +3078,7 @@ public abstract class BatteryStats implements Parcelable { 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="); @@ -3120,6 +3148,28 @@ public abstract class BatteryStats implements Parcelable { pw.print(suffix); } + private static boolean dumpDurationSteps(PrintWriter pw, String header, long[] steps, + int count, boolean checkin) { + if (count <= 0) { + return false; + } + if (!checkin) { + pw.println(header); + } + String[] lineArgs = new String[1]; + for (int i=0; i<count; i++) { + if (checkin) { + lineArgs[0] = Long.toString(steps[i]); + dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs); + } else { + pw.print(" #"); pw.print(i); pw.print(": "); + TimeUtils.formatDuration(steps[i], pw); + pw.println(); + } + } + return true; + } + public static final int DUMP_UNPLUGGED_ONLY = 1<<0; public static final int DUMP_CHARGED_ONLY = 1<<1; public static final int DUMP_HISTORY_ONLY = 1<<2; @@ -3239,7 +3289,27 @@ public abstract class BatteryStats implements Parcelable { } } if (didPid) { - pw.println(""); + pw.println(); + } + if (dumpDurationSteps(pw, "Discharge step durations:", getDischargeStepDurationsArray(), + getNumDischargeStepDurations(), false)) { + long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime()); + if (timeRemaining >= 0) { + pw.print(" Estimated discharge time remaining: "); + TimeUtils.formatDuration(timeRemaining / 1000, pw); + pw.println(); + } + pw.println(); + } + if (dumpDurationSteps(pw, "Charge step durations:", getChargeStepDurationsArray(), + getNumChargeStepDurations(), false)) { + long timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime()); + if (timeRemaining >= 0) { + pw.print(" Estimated charge time remaining: "); + TimeUtils.formatDuration(timeRemaining / 1000, pw); + pw.println(); + } + pw.println(); } } @@ -3248,7 +3318,7 @@ public abstract class BatteryStats implements Parcelable { pw.println(" System starts: " + getStartCount() + ", currently on battery: " + getIsOnBattery()); dumpLocked(context, pw, "", STATS_SINCE_CHARGED, reqUid); - pw.println(""); + pw.println(); } if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) { pw.println("Statistics since last unplugged:"); @@ -3352,6 +3422,25 @@ public abstract class BatteryStats implements Parcelable { } } } + 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/Build.java b/core/java/android/os/Build.java index 0336dd6..1ca6b90 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -81,12 +81,38 @@ public class Build { public static final String SERIAL = getString("ro.serialno"); /** - * A list of ABIs (in priority) order supported by this device. + * An ordered list of ABIs supported by this device. The most preferred ABI is the first + * element in the list. + * + * See {@link #SUPPORTED_32_BIT_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}. * * @hide */ public static final String[] SUPPORTED_ABIS = getString("ro.product.cpu.abilist").split(","); + /** + * An ordered list of <b>32 bit</b> ABIs supported by this device. The most preferred ABI + * is the first element in the list. + * + * See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}. + * + * @hide + */ + public static final String[] SUPPORTED_32_BIT_ABIS = getString("ro.product.cpu.abilist32") + .split(","); + + /** + * An ordered list of <b>64 bit</b> ABIs supported by this device. The most preferred ABI + * is the first element in the list. + * + * See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_32_BIT_ABIS}. + * + * @hide + */ + public static final String[] SUPPORTED_64_BIT_ABIS = getString("ro.product.cpu.abilist64") + .split(","); + + /** Various version strings. */ public static class VERSION { /** diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index c3f7370..899a958 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -29,6 +29,7 @@ import android.graphics.Bitmap; interface IUserManager { UserInfo createUser(in String name, int flags); UserInfo createProfileForUser(in String name, int flags, int userHandle); + void setUserEnabled(int userHandle); boolean removeUser(int userHandle); void setUserName(int userHandle, String name); void setUserIcon(int userHandle, in Bitmap icon); diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index b4ed68c..1b3aa0a 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -707,16 +707,6 @@ public class Process { return primaryZygoteState; } - // TODO: Get rid of this. This is a temporary workaround until all the - // compilation related pieces for the dual zygote stack are ready. - // b/3647418. - if (System.getenv("ANDROID_SOCKET_" + SECONDARY_ZYGOTE_SOCKET) == null) { - Log.e(LOG_TAG, "Forcing app to primary zygote, secondary unavailable (ABI= " + abi + ")"); - // Should be : - // throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); - return primaryZygoteState; - } - // The primary zygote didn't match. Try the secondary. if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET, diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1fe9337..1b2b798 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -437,6 +437,22 @@ public class UserManager { } /** + * Sets the user as enabled, if such an user exists. + * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. + * Note that the default is true, it's only that managed profiles might not be enabled. + * + * @param userHandle the id of the profile to enable + * @hide + */ + public void setUserEnabled(int userHandle) { + try { + mService.setUserEnabled(userHandle); + } catch (RemoteException e) { + Log.w(TAG, "Could not enable the profile", e); + } + } + + /** * Return the number of users currently created on the device. */ public int getUserCount() { @@ -488,8 +504,7 @@ public class UserManager { 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/TvContract.java b/core/java/android/provider/TvContract.java index 233e0ca..62252be 100644 --- a/core/java/android/provider/TvContract.java +++ b/core/java/android/provider/TvContract.java @@ -16,9 +16,13 @@ package android.provider; +import android.content.ComponentName; +import android.content.ContentResolver; import android.content.ContentUris; import android.net.Uri; +import java.util.List; + /** * <p> * The contract between the TV provider and applications. Contains definitions for the supported @@ -42,6 +46,35 @@ public final class TvContract { /** The authority for the TV provider. */ public static final String AUTHORITY = "com.android.tv"; + private static final String PATH_CHANNEL = "channel"; + private static final String PATH_PROGRAM = "program"; + private static final String PATH_INPUT = "input"; + + /** + * An optional query, update or delete URI parameter that allows the caller to specify start + * time (in milliseconds since the epoch) to filter programs. + * + * @hide + */ + public static final String PARAM_START_TIME = "start_time"; + + /** + * An optional query, update or delete URI parameter that allows the caller to specify end time + * (in milliseconds since the epoch) to filter programs. + * + * @hide + */ + public static final String PARAM_END_TIME = "end_time"; + + /** + * A query, update or delete URI parameter that allows the caller to operate on all or + * browsable-only channels. If set to "true", the rows that contain non-browsable channels are + * not affected. + * + * @hide + */ + public static final String PARAM_BROWSABLE_ONLY = "browable_only"; + /** * Builds a URI that points to a specific channel. * @@ -52,6 +85,32 @@ public final class TvContract { } /** + * Builds a URI that points to all browsable channels from a given TV input. + * + * @param name {@link ComponentName} of the {@link android.tv.TvInputService} that implements + * the given TV input. + */ + public static final Uri buildChannelsUriForInput(ComponentName name) { + return buildChannelsUriForInput(name, true); + } + + /** + * Builds a URI that points to all or browsable-only channels from a given TV input. + * + * @param name {@link ComponentName} of the {@link android.tv.TvInputService} that implements + * the given TV input. + * @param browsableOnly If set to {@code true} the URI points to only browsable channels. If set + * to {@code false} the URI points to all channels regardless of whether they are + * browsable or not. + */ + public static final Uri buildChannelsUriForInput(ComponentName name, boolean browsableOnly) { + return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY) + .appendPath(PATH_INPUT).appendPath(name.getPackageName()) + .appendPath(name.getClassName()).appendPath(PATH_CHANNEL) + .appendQueryParameter(PARAM_BROWSABLE_ONLY, String.valueOf(browsableOnly)).build(); + } + + /** * Builds a URI that points to a specific program. * * @param programId The ID of the program to point to. @@ -61,6 +120,37 @@ public final class TvContract { } /** + * Builds a URI that points to all programs on a given channel. + * + * @param channelUri The URI of the channel to return programs for. + */ + public static final Uri buildProgramsUriForChannel(Uri channelUri) { + if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) { + throw new IllegalArgumentException("Not a channel: " + channelUri); + } + String channelId = String.valueOf(ContentUris.parseId(channelUri)); + return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY) + .appendPath(PATH_CHANNEL).appendPath(channelId).appendPath(PATH_PROGRAM).build(); + } + + /** + * Builds a URI that points to programs on a specific channel whose schedules overlap with the + * given time frame. + * + * @param channelUri The URI of the channel to return programs for. + * @param startTime The start time used to filter programs. The returned programs should have + * {@link Programs#END_TIME_UTC_MILLIS} that is greater than this time. + * @param endTime The end time used to filter programs. The returned programs should have + * {@link Programs#START_TIME_UTC_MILLIS} that is less than this time. + */ + public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime, + long endTime) { + Uri uri = buildProgramsUriForChannel(channelUri); + return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime)) + .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build(); + } + + /** * Builds a URI that points to a specific program the user watched. * * @param watchedProgramId The ID of the watched program to point to. @@ -70,6 +160,61 @@ public final class TvContract { return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, watchedProgramId); } + /** + * Extracts the {@link Channels#PACKAGE_NAME} from a given URI. + * + * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or + * {@link #buildChannelsUriForInput(ComponentName, boolean)}. + * @hide + */ + public static final String getPackageName(Uri channelsUri) { + final List<String> paths = channelsUri.getPathSegments(); + if (paths.size() < 4) { + throw new IllegalArgumentException("Not channels: " + channelsUri); + } + if (!PATH_INPUT.equals(paths.get(0)) || !PATH_CHANNEL.equals(paths.get(3))) { + throw new IllegalArgumentException("Not channels: " + channelsUri); + } + return paths.get(1); + } + + /** + * Extracts the {@link Channels#SERVICE_NAME} from a given URI. + * + * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or + * {@link #buildChannelsUriForInput(ComponentName, boolean)}. + * @hide + */ + public static final String getServiceName(Uri channelsUri) { + final List<String> paths = channelsUri.getPathSegments(); + if (paths.size() < 4) { + throw new IllegalArgumentException("Not channels: " + channelsUri); + } + if (!PATH_INPUT.equals(paths.get(0)) || !PATH_CHANNEL.equals(paths.get(3))) { + throw new IllegalArgumentException("Not channels: " + channelsUri); + } + return paths.get(2); + } + + /** + * Extracts the {@link Channels#_ID} from a given URI. + * + * @param programsUri A URI constructed by {@link #buildProgramsUriForChannel(Uri)} or + * {@link #buildProgramsUriForChannel(Uri, long, long)}. + * @hide + */ + public static final String getChannelId(Uri programsUri) { + final List<String> paths = programsUri.getPathSegments(); + if (paths.size() < 3) { + throw new IllegalArgumentException("Not programs: " + programsUri); + } + if (!PATH_CHANNEL.equals(paths.get(0)) || !PATH_PROGRAM.equals(paths.get(2))) { + throw new IllegalArgumentException("Not programs: " + programsUri); + } + return paths.get(1); + } + + private TvContract() {} /** @@ -93,7 +238,8 @@ public final class TvContract { public static final class Channels implements BaseTvColumns { /** The content:// style URI for this table. */ - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/channel"); + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + + PATH_CHANNEL); /** The MIME type of a directory of TV channels. */ public static final String CONTENT_TYPE = @@ -276,7 +422,8 @@ public final class TvContract { public static final class Programs implements BaseTvColumns { /** The content:// style URI for this table. */ - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/program"); + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + + PATH_PROGRAM); /** The MIME type of a directory of TV programs. */ public static final String CONTENT_TYPE = 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 class Condition implements Parcelable { public static final int FLAG_RELEVANT_ALWAYS = 1 << 1; public final Uri id; - public String caption; - public int state; - public int flags; - - public Condition(Uri id, String caption, int state, 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 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 @@ public class Condition implements Parcelable { 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 @@ public class Condition implements Parcelable { @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 @@ public class Condition implements Parcelable { 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/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java index d6ef8f5..326412f 100644 --- a/core/java/android/service/notification/ConditionProviderService.java +++ b/core/java/android/service/notification/ConditionProviderService.java @@ -22,7 +22,9 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.os.ServiceManager; import android.util.Log; @@ -46,6 +48,8 @@ public abstract class ConditionProviderService extends Service { private final String TAG = ConditionProviderService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; + private final H mHandler = new H(); + private Provider mProvider; private INotificationManager mNoMan; @@ -100,41 +104,57 @@ public abstract class ConditionProviderService extends Service { } private final class Provider extends IConditionProvider.Stub { - private final ConditionProviderService mService = ConditionProviderService.this; - @Override public void onConnected() { - try { - mService.onConnected(); - } catch (Throwable t) { - Log.w(TAG, "Error running onConnected", t); - } + mHandler.obtainMessage(H.ON_CONNECTED).sendToTarget(); } @Override public void onRequestConditions(int relevance) { - try { - mService.onRequestConditions(relevance); - } catch (Throwable t) { - Log.w(TAG, "Error running onRequestConditions", t); - } + mHandler.obtainMessage(H.ON_REQUEST_CONDITIONS, relevance, 0).sendToTarget(); } @Override public void onSubscribe(Uri conditionId) { - try { - mService.onSubscribe(conditionId); - } catch (Throwable t) { - Log.w(TAG, "Error running onSubscribe", t); - } + mHandler.obtainMessage(H.ON_SUBSCRIBE, conditionId).sendToTarget(); } @Override public void onUnsubscribe(Uri conditionId) { + mHandler.obtainMessage(H.ON_UNSUBSCRIBE, conditionId).sendToTarget(); + } + } + + private final class H extends Handler { + private static final int ON_CONNECTED = 1; + private static final int ON_REQUEST_CONDITIONS = 2; + private static final int ON_SUBSCRIBE = 3; + private static final int ON_UNSUBSCRIBE = 4; + + @Override + public void handleMessage(Message msg) { + String name = null; try { - mService.onUnsubscribe(conditionId); + switch(msg.what) { + case ON_CONNECTED: + name = "onConnected"; + onConnected(); + break; + case ON_REQUEST_CONDITIONS: + name = "onRequestConditions"; + onRequestConditions(msg.arg1); + break; + case ON_SUBSCRIBE: + name = "onSubscribe"; + onSubscribe((Uri)msg.obj); + break; + case ON_UNSUBSCRIBE: + name = "onUnsubscribe"; + onUnsubscribe((Uri)msg.obj); + break; + } } catch (Throwable t) { - Log.w(TAG, "Error running onUnsubscribe", t); + Log.w(TAG, "Error running " + name, t); } } } 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.XmlPullParserException; 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 @@ public class ZenModeConfig implements Parcelable { 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 class ZenModeConfig implements Parcelable { public int sleepStartMinute; public int sleepEndHour; public int sleepEndMinute; + public ComponentName[] conditionComponents; + public Uri[] conditionIds; public ZenModeConfig() { } @@ -72,6 +82,16 @@ public class ZenModeConfig implements Parcelable { 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 @@ public class ZenModeConfig implements Parcelable { 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 @@ public class ZenModeConfig implements Parcelable { .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 @@ public class ZenModeConfig implements Parcelable { && 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 @@ public class ZenModeConfig implements Parcelable { 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 @@ public class ZenModeConfig implements Parcelable { 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 @@ public class ZenModeConfig implements Parcelable { 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 @@ public class ZenModeConfig implements Parcelable { 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/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index 9c98b98..b0cbcd2 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -106,4 +106,69 @@ public final class Formatter { public static String formatIpAddress(int ipv4Address) { return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress(); } + + private static final int SECONDS_PER_MINUTE = 60; + private static final int SECONDS_PER_HOUR = 60 * 60; + private static final int SECONDS_PER_DAY = 24 * 60 * 60; + + /** + * Returns elapsed time for the given millis, in the following format: + * 1 day 5 hrs; will include at most two units, can go down to seconds precision. + * @param context the application context + * @param millis the elapsed time in milli seconds + * @return the formatted elapsed time + * @hide + */ + public static String formatShortElapsedTime(Context context, long millis) { + long secondsLong = millis / 1000; + + int days = 0, hours = 0, minutes = 0; + if (secondsLong >= SECONDS_PER_DAY) { + days = (int)(secondsLong / SECONDS_PER_DAY); + secondsLong -= days * SECONDS_PER_DAY; + } + if (secondsLong >= SECONDS_PER_HOUR) { + hours = (int)(secondsLong / SECONDS_PER_HOUR); + secondsLong -= hours * SECONDS_PER_HOUR; + } + if (secondsLong >= SECONDS_PER_MINUTE) { + minutes = (int)(secondsLong / SECONDS_PER_MINUTE); + secondsLong -= minutes * SECONDS_PER_MINUTE; + } + int seconds = (int)secondsLong; + + if (days >= 2) { + days += (hours+12)/24; + return context.getString(com.android.internal.R.string.durationDays, days); + } else if (days > 0) { + if (hours == 1) { + return context.getString(com.android.internal.R.string.durationDayHour, days, hours); + } + return context.getString(com.android.internal.R.string.durationDayHours, days, hours); + } else if (hours >= 2) { + hours += (minutes+30)/60; + return context.getString(com.android.internal.R.string.durationHours, hours); + } else if (hours > 0) { + if (minutes == 1) { + return context.getString(com.android.internal.R.string.durationHourMinute, hours, + minutes); + } + return context.getString(com.android.internal.R.string.durationHourMinutes, hours, + minutes); + } else if (minutes >= 2) { + minutes += (seconds+30)/60; + return context.getString(com.android.internal.R.string.durationMinutes, minutes); + } else if (minutes > 0) { + if (seconds == 1) { + return context.getString(com.android.internal.R.string.durationMinuteSecond, minutes, + seconds); + } + return context.getString(com.android.internal.R.string.durationMinuteSeconds, minutes, + seconds); + } else if (seconds == 1) { + return context.getString(com.android.internal.R.string.durationSecond, seconds); + } else { + return context.getString(com.android.internal.R.string.durationSeconds, seconds); + } + } } diff --git a/core/java/android/transition/ChangeClipBounds.java b/core/java/android/transition/ChangeClipBounds.java new file mode 100644 index 0000000..a61b29d --- /dev/null +++ b/core/java/android/transition/ChangeClipBounds.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 android.transition; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.animation.RectEvaluator; +import android.graphics.Rect; +import android.view.View; +import android.view.ViewGroup; + +/** + * ChangeClipBounds captures the {@link android.view.View#getClipBounds()} before and after the + * scene change and animates those changes during the transition. + */ +public class ChangeClipBounds extends Transition { + + private static final String TAG = "ChangeTransform"; + + private static final String PROPNAME_CLIP = "android:clipBounds:clip"; + private static final String PROPNAME_BOUNDS = "android:clipBounds:bounds"; + + private static final String[] sTransitionProperties = { + PROPNAME_CLIP, + }; + + @Override + public String[] getTransitionProperties() { + return sTransitionProperties; + } + + private void captureValues(TransitionValues values) { + View view = values.view; + if (view.getVisibility() == View.GONE) { + return; + } + + Rect clip = view.getClipBounds(); + values.values.put(PROPNAME_CLIP, clip); + if (clip == null) { + Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight()); + values.values.put(PROPNAME_BOUNDS, bounds); + } + } + + @Override + public void captureStartValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + @Override + public void captureEndValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + @Override + public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues, + TransitionValues endValues) { + if (startValues == null || endValues == null + || !startValues.values.containsKey(PROPNAME_CLIP) + || !endValues.values.containsKey(PROPNAME_CLIP)) { + return null; + } + Rect start = (Rect) startValues.values.get(PROPNAME_CLIP); + Rect end = (Rect) endValues.values.get(PROPNAME_CLIP); + if (start == null && end == null) { + return null; // No animation required since there is no clip. + } + + if (start == null) { + start = (Rect) startValues.values.get(PROPNAME_BOUNDS); + } else if (end == null) { + end = (Rect) endValues.values.get(PROPNAME_BOUNDS); + } + if (start.equals(end)) { + return null; + } + + endValues.view.setClipBounds(start); + RectEvaluator evaluator = new RectEvaluator(new Rect()); + return ObjectAnimator.ofObject(endValues.view, "clipBounds", evaluator, start, end); + } +} diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java new file mode 100644 index 0000000..85cb2c7 --- /dev/null +++ b/core/java/android/transition/ChangeTransform.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.transition; + +import android.animation.Animator; +import android.animation.FloatArrayEvaluator; +import android.animation.ObjectAnimator; +import android.util.FloatProperty; +import android.util.Property; +import android.view.View; +import android.view.ViewGroup; + +/** + * This Transition captures scale and rotation for Views before and after the + * scene change and animates those changes during the transition. + * + * <p>ChangeTransform does not work when the pivot changes between scenes, so either the + * pivot must be set to prevent automatic pivot adjustment or the View's size must be unchanged.</p> + */ +public class ChangeTransform extends Transition { + + private static final String TAG = "ChangeTransform"; + + private static final String PROPNAME_SCALE_X = "android:changeTransform:scaleX"; + private static final String PROPNAME_SCALE_Y = "android:changeTransform:scaleY"; + private static final String PROPNAME_ROTATION_X = "android:changeTransform:rotationX"; + private static final String PROPNAME_ROTATION_Y = "android:changeTransform:rotationY"; + private static final String PROPNAME_ROTATION_Z = "android:changeTransform:rotationZ"; + private static final String PROPNAME_PIVOT_X = "android:changeTransform:pivotX"; + private static final String PROPNAME_PIVOT_Y = "android:changeTransform:pivotY"; + + private static final String[] sTransitionProperties = { + PROPNAME_SCALE_X, + PROPNAME_SCALE_Y, + PROPNAME_ROTATION_X, + PROPNAME_ROTATION_Y, + PROPNAME_ROTATION_Z, + }; + + private static final FloatProperty<View>[] sChangedProperties = new FloatProperty[] { + (FloatProperty) View.SCALE_X, + (FloatProperty) View.SCALE_Y, + (FloatProperty) View.ROTATION_X, + (FloatProperty) View.ROTATION_Y, + (FloatProperty) View.ROTATION, + }; + + private static Property<View, float[]> TRANSFORMS = new Property<View, float[]>(float[].class, + "transforms") { + @Override + public float[] get(View object) { + return null; + } + + @Override + public void set(View view, float[] values) { + for (int i = 0; i < values.length; i++) { + float value = values[i]; + if (value != Float.NaN) { + sChangedProperties[i].setValue(view, value); + } + } + } + }; + + @Override + public String[] getTransitionProperties() { + return sTransitionProperties; + } + + private void captureValues(TransitionValues values) { + View view = values.view; + if (view.getVisibility() == View.GONE) { + return; + } + + values.values.put(PROPNAME_SCALE_X, view.getScaleX()); + values.values.put(PROPNAME_SCALE_Y, view.getScaleY()); + values.values.put(PROPNAME_PIVOT_X, view.getPivotX()); + values.values.put(PROPNAME_PIVOT_Y, view.getPivotY()); + values.values.put(PROPNAME_ROTATION_X, view.getRotationX()); + values.values.put(PROPNAME_ROTATION_Y, view.getRotationY()); + values.values.put(PROPNAME_ROTATION_Z, view.getRotation()); + } + + @Override + public void captureStartValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + @Override + public void captureEndValues(TransitionValues transitionValues) { + captureValues(transitionValues); + } + + @Override + public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues, + TransitionValues endValues) { + if (startValues == null || endValues == null + || !startValues.values.containsKey(PROPNAME_SCALE_X) + || !endValues.values.containsKey(PROPNAME_SCALE_X) + || !isPivotSame(startValues, endValues) + || !isChanged(startValues, endValues)) { + return null; + } + + float[] start = createValues(startValues); + float[] end = createValues(endValues); + for (int i = 0; i < start.length; i++) { + if (start[i] == end[i]) { + start[i] = Float.NaN; + end[i] = Float.NaN; + } else { + sChangedProperties[i].setValue(endValues.view, start[i]); + } + } + FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[start.length]); + return ObjectAnimator.ofObject(endValues.view, TRANSFORMS, evaluator, start, end); + } + + private static float[] createValues(TransitionValues transitionValues) { + float[] values = new float[sChangedProperties.length]; + for (int i = 0; i < values.length; i++) { + values[i] = (Float) transitionValues.values.get(sTransitionProperties[i]); + } + return values; + } + + private static boolean isPivotSame(TransitionValues startValues, TransitionValues endValues) { + float startPivotX = (Float) startValues.values.get(PROPNAME_PIVOT_X); + float startPivotY = (Float) startValues.values.get(PROPNAME_PIVOT_Y); + float endPivotX = (Float) endValues.values.get(PROPNAME_PIVOT_X); + float endPivotY = (Float) endValues.values.get(PROPNAME_PIVOT_Y); + + // We don't support pivot changes, because they could be automatically set + // and we can't end the state in an automatic state. + return startPivotX == endPivotX && startPivotY == endPivotY; + } + + private static boolean isChanged(TransitionValues startValues, TransitionValues endValues) { + for (int i = 0; i < sChangedProperties.length; i++) { + Object start = startValues.values.get(sTransitionProperties[i]); + Object end = endValues.values.get(sTransitionProperties[i]); + if (!start.equals(end)) { + return true; + } + } + return false; + } +} diff --git a/core/java/android/transition/CircularPropagation.java b/core/java/android/transition/CircularPropagation.java index 18a3d22..51beb51 100644 --- a/core/java/android/transition/CircularPropagation.java +++ b/core/java/android/transition/CircularPropagation.java @@ -34,7 +34,7 @@ import android.view.ViewGroup; public class CircularPropagation extends VisibilityPropagation { private static final String TAG = "CircularPropagation"; - private float mPropagationSpeed = 4.0f; + private float mPropagationSpeed = 3.0f; /** * Sets the speed at which transition propagation happens, relative to the duration of the @@ -91,8 +91,12 @@ public class CircularPropagation extends VisibilityPropagation { float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight()); float distanceFraction = distance/maxDistance; - return Math.round(transition.getDuration() * directionMultiplier / mPropagationSpeed - * distanceFraction); + long duration = transition.getDuration(); + if (duration < 0) { + duration = 300; + } + + return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction); } private static float distance(float x1, float y1, float x2, float y2) { diff --git a/core/java/android/transition/MoveImage.java b/core/java/android/transition/MoveImage.java index d68e971..e4c3939 100644 --- a/core/java/android/transition/MoveImage.java +++ b/core/java/android/transition/MoveImage.java @@ -170,13 +170,20 @@ public class MoveImage extends Transition { drawable = drawable.getConstantState().newDrawable(); final MatrixClippedDrawable matrixClippedDrawable = new MatrixClippedDrawable(drawable); + final ImageView overlayImage = new ImageView(imageView.getContext()); + final ViewGroupOverlay overlay = sceneRoot.getOverlay(); + overlay.add(overlayImage); + overlayImage.setLeft(0); + overlayImage.setTop(0); + overlayImage.setRight(sceneRoot.getWidth()); + overlayImage.setBottom(sceneRoot.getBottom()); + overlayImage.setScaleType(ImageView.ScaleType.MATRIX); + overlayImage.setImageDrawable(matrixClippedDrawable); matrixClippedDrawable.setMatrix(startMatrix); matrixClippedDrawable.setBounds(startBounds); matrixClippedDrawable.setClipRect(startClip); imageView.setVisibility(View.INVISIBLE); - final ViewGroupOverlay overlay = sceneRoot.getOverlay(); - overlay.add(matrixClippedDrawable); ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(matrixClippedDrawable, changes.toArray(new PropertyValuesHolder[changes.size()])); @@ -184,19 +191,24 @@ public class MoveImage extends Transition { @Override public void onAnimationEnd(Animator animation) { imageView.setVisibility(View.VISIBLE); - overlay.remove(matrixClippedDrawable); + overlay.remove(overlayImage); } @Override public void onAnimationPause(Animator animation) { imageView.setVisibility(View.VISIBLE); - overlay.remove(matrixClippedDrawable); + overlayImage.setVisibility(View.INVISIBLE); } @Override public void onAnimationResume(Animator animation) { imageView.setVisibility(View.INVISIBLE); - overlay.add(matrixClippedDrawable); + overlayImage.setVisibility(View.VISIBLE); + } + + @Override + public void onAnimationCancel(Animator animation) { + onAnimationEnd(animation); } }; diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java index c331945..5d38ac8 100644 --- a/core/java/android/transition/SidePropagation.java +++ b/core/java/android/transition/SidePropagation.java @@ -52,7 +52,7 @@ public class SidePropagation extends VisibilityPropagation { */ public static final int BOTTOM = Slide.BOTTOM; - private float mPropagationSpeed = 4.0f; + private float mPropagationSpeed = 3.0f; private int mSide = BOTTOM; /** @@ -129,8 +129,12 @@ public class SidePropagation extends VisibilityPropagation { float maxDistance = getMaxDistance(sceneRoot); float distanceFraction = distance/maxDistance; - return Math.round(transition.getDuration() * directionMultiplier / mPropagationSpeed - * distanceFraction); + long duration = transition.getDuration(); + if (duration < 0) { + duration = 300; + } + + return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction); } private int distance(int viewX, int viewY, int epicenterX, int epicenterY, diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index c67d6fa..2549fde 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -66,13 +66,12 @@ import java.util.List; * * {@sample development/samples/ApiDemos/res/transition/changebounds.xml ChangeBounds} * - * <p>{@link android.transition.Explode} transition:</p> + * <p>This TransitionSet contains {@link android.transition.Explode} for visibility, + * {@link android.transition.ChangeBounds}, {@link android.transition.ChangeTransform}, + * and {@link android.transition.ChangeClipBounds} for non-<code>ImageView</code>s and + * {@link android.transition.MoveImage} for <code>ImageView</code>s:</p> * - * {@sample development/samples/ApiDemos/res/transition/explode.xml Explode} - * - * <p>{@link android.transition.MoveImage} transition:</p> - * - * {@sample development/samples/ApiDemos/res/transition/move_image.xml MoveImage} + * {@sample development/samples/ApiDemos/res/transition/explode_move_together.xml MultipleTransform} * * <p>Note that attributes for the transition are not required, just as they are * optional when declared in code; Transitions created from XML resources will use @@ -89,7 +88,8 @@ import java.util.List; * transition uses a fadingMode of {@link Fade#OUT} instead of the default * out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which * takes a set of {@link android.R.styleable#TransitionTarget target} tags, each - * of which lists a specific <code>targetId</code> which this transition acts upon. + * of which lists a specific <code>targetId</code>, <code>targetClass</code>, + * <code>excludeId</code>, or <code>excludeClass</code>, which this transition acts upon. * Use of targets is optional, but can be used to either limit the time spent checking * attributes on unchanging views, or limiting the types of animations run on specific views. * In this case, we know that only the <code>grayscaleContainer</code> will be @@ -116,6 +116,7 @@ public abstract class Transition implements Cloneable { ArrayList<Integer> mTargetIdExcludes = null; ArrayList<View> mTargetExcludes = null; ArrayList<Class> mTargetTypeExcludes = null; + ArrayList<Class> mTargetTypes = null; ArrayList<Integer> mTargetIdChildExcludes = null; ArrayList<View> mTargetChildExcludes = null; ArrayList<Class> mTargetTypeChildExcludes = null; @@ -569,19 +570,15 @@ public abstract class Transition implements Cloneable { } } } - if (mTargetIds.size() == 0 && mTargets.size() == 0) { + if (mTargetIds.size() == 0 && mTargets.size() == 0 && mTargetTypes == null) { return true; } - if (mTargetIds.size() > 0) { - for (int i = 0; i < mTargetIds.size(); ++i) { - if (mTargetIds.get(i) == targetId) { - return true; - } - } + if (mTargetIds.contains((int) targetId) || mTargets.contains(target)) { + return true; } - if (target != null && mTargets.size() > 0) { - for (int i = 0; i < mTargets.size(); ++i) { - if (mTargets.get(i) == target) { + if (mTargetTypes != null) { + for (int i = 0; i < mTargetTypes.size(); ++i) { + if (mTargetTypes.get(i).isInstance(target)) { return true; } } @@ -727,6 +724,36 @@ public abstract class Transition implements Cloneable { } /** + * Adds the Class of a target view that this Transition is interested in + * animating. By default, there are no targetTypes, and a Transition will + * listen for changes on every view in the hierarchy below the sceneRoot + * of the Scene being transitioned into. Setting targetTypes constrains + * the Transition to only listen for, and act on, views with these classes. + * Views with different classes will be ignored. + * + * <p>Note that any View that can be cast to targetType will be included, so + * if targetType is <code>View.class</code>, all Views will be included.</p> + * + * @see #addTarget(int) + * @see #addTarget(android.view.View) + * @see #excludeTarget(Class, boolean) + * @see #excludeChildren(Class, boolean) + * + * @param targetType The type to include when running this transition. + * @return The Transition to which the target class was added. + * Returning the same object makes it easier to chain calls during + * construction, such as + * <code>transitionSet.addTransitions(new Fade()).addTarget(ImageView.class);</code> + */ + public Transition addTarget(Class targetType) { + if (mTargetTypes == null) { + mTargetTypes = new ArrayList<Class>(); + } + mTargetTypes.add(targetType); + return this; + } + + /** * Removes the given targetId from the list of ids that this Transition * is interested in animating. * @@ -1116,9 +1143,6 @@ public abstract class Transition implements Cloneable { if (view == null) { return; } - if (!isValidTarget(view, view.getId())) { - return; - } boolean isListViewItem = false; if (view.getParent() instanceof ListView) { isListViewItem = true; diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java index 14ecc15..a5e960a 100644 --- a/core/java/android/transition/TransitionInflater.java +++ b/core/java/android/transition/TransitionInflater.java @@ -153,6 +153,12 @@ public class TransitionInflater { } else if ("moveImage".equals(name)) { transition = new MoveImage(); newTransition = true; + } else if ("changeTransform".equals(name)) { + transition = new ChangeTransform(); + newTransition = true; + } else if ("changeClipBounds".equals(name)) { + transition = new ChangeClipBounds(); + newTransition = true; } else if ("autoTransition".equals(name)) { transition = new AutoTransition(); newTransition = true; @@ -210,7 +216,6 @@ public class TransitionInflater { int type; int depth = parser.getDepth(); - ArrayList<Integer> targetIds = new ArrayList<Integer>(); while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { @@ -225,18 +230,31 @@ public class TransitionInflater { int id = a.getResourceId( com.android.internal.R.styleable.TransitionTarget_targetId, -1); if (id >= 0) { - targetIds.add(id); + transition.addTarget(id); + } else if ((id = a.getResourceId( + com.android.internal.R.styleable.TransitionTarget_excludeId, -1)) >= 0) { + transition.excludeTarget(id, true); + } else { + String className = a.getString( + com.android.internal.R.styleable.TransitionTarget_excludeClass); + try { + if (className != null) { + Class clazz = Class.forName(className); + transition.excludeTarget(clazz, true); + } else if ((className = a.getString( + com.android.internal.R.styleable.TransitionTarget_targetClass)) + != null) { + Class clazz = Class.forName(className); + transition.addTarget(clazz); + } + } catch (ClassNotFoundException e) { + throw new RuntimeException("Could not create " + className, e); + } } } else { throw new RuntimeException("Unknown scene name: " + parser.getName()); } } - int numTargets = targetIds.size(); - if (numTargets > 0) { - for (int i = 0; i < numTargets; ++i) { - transition.addTarget(targetIds.get(i)); - } - } } private Transition loadTransition(Transition transition, AttributeSet attrs) diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java index 636e3b4..70e7f95 100644 --- a/core/java/android/tv/TvInputService.java +++ b/core/java/android/tv/TvInputService.java @@ -150,6 +150,7 @@ public abstract class TvInputService extends Service { private final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState(); private final WindowManager mWindowManager; private WindowManager.LayoutParams mWindowParams; + private Surface mSurface; private View mOverlayView; private boolean mOverlayViewEnabled; private IBinder mWindowToken; @@ -346,6 +347,10 @@ public abstract class TvInputService extends Service { */ void release() { onRelease(); + if (mSurface != null) { + mSurface.release(); + mSurface = null; + } removeOverlayView(true); } @@ -354,6 +359,10 @@ public abstract class TvInputService extends Service { */ void setSurface(Surface surface) { onSetSurface(surface); + if (mSurface != null) { + mSurface.release(); + } + mSurface = surface; // TODO: Handle failure. } 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/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java index 0afbde9..ba1c4b6 100644 --- a/core/java/android/view/ContextThemeWrapper.java +++ b/core/java/android/view/ContextThemeWrapper.java @@ -96,7 +96,7 @@ public class ContextThemeWrapper extends ContextWrapper { return mTheme; } - mThemeResource = Resources.selectDefaultTheme(mThemeResource, + mThemeResource = getResources().selectDefaultTheme(mThemeResource, getApplicationInfo().targetSdkVersion); initializeTheme(); diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 34b85d9..11948b2 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -18,6 +18,7 @@ package android.view; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.CanvasProperty; import android.graphics.DrawFilter; import android.graphics.Matrix; import android.graphics.NinePatch; @@ -889,6 +890,16 @@ class GLES20Canvas extends HardwareCanvas { 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 @@ class GLES20RecordingCanvas extends GLES20Canvas { 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/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 233f846..7ec2cc6 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -18,6 +18,7 @@ package android.view; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.CanvasProperty; import android.graphics.Paint; import android.graphics.Rect; @@ -189,4 +190,7 @@ public abstract class HardwareCanvas extends Canvas { * @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/KeyEvent.java b/core/java/android/view/KeyEvent.java index c3f429c..05e202b 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -645,12 +645,11 @@ public class KeyEvent extends InputEvent implements Parcelable { // NOTE: If you add a new keycode here you must also add it to: // isSystem() // frameworks/native/include/android/keycodes.h - // frameworks/base/include/androidfw/KeycodeLabels.h + // frameworks/base/include/androidfw/InputEventAttributes.h // external/webkit/WebKit/android/plugins/ANPKeyCodes.h // frameworks/base/core/res/res/values/attrs.xml // emulator? // LAST_KEYCODE - // KEYCODE_SYMBOLIC_NAMES // // Also Android currently does not reserve code ranges for vendor- // specific key codes. If you have new key codes to have, you @@ -658,237 +657,6 @@ public class KeyEvent extends InputEvent implements Parcelable { // those new codes. This is intended to maintain a consistent // set of key code definitions across all Android devices. - // Symbolic names of all key codes. - private static final SparseArray<String> KEYCODE_SYMBOLIC_NAMES = new SparseArray<String>(); - private static void populateKeycodeSymbolicNames() { - SparseArray<String> names = KEYCODE_SYMBOLIC_NAMES; - names.append(KEYCODE_UNKNOWN, "KEYCODE_UNKNOWN"); - names.append(KEYCODE_SOFT_LEFT, "KEYCODE_SOFT_LEFT"); - names.append(KEYCODE_SOFT_RIGHT, "KEYCODE_SOFT_RIGHT"); - names.append(KEYCODE_HOME, "KEYCODE_HOME"); - names.append(KEYCODE_BACK, "KEYCODE_BACK"); - names.append(KEYCODE_CALL, "KEYCODE_CALL"); - names.append(KEYCODE_ENDCALL, "KEYCODE_ENDCALL"); - names.append(KEYCODE_0, "KEYCODE_0"); - names.append(KEYCODE_1, "KEYCODE_1"); - names.append(KEYCODE_2, "KEYCODE_2"); - names.append(KEYCODE_3, "KEYCODE_3"); - names.append(KEYCODE_4, "KEYCODE_4"); - names.append(KEYCODE_5, "KEYCODE_5"); - names.append(KEYCODE_6, "KEYCODE_6"); - names.append(KEYCODE_7, "KEYCODE_7"); - names.append(KEYCODE_8, "KEYCODE_8"); - names.append(KEYCODE_9, "KEYCODE_9"); - names.append(KEYCODE_STAR, "KEYCODE_STAR"); - names.append(KEYCODE_POUND, "KEYCODE_POUND"); - names.append(KEYCODE_DPAD_UP, "KEYCODE_DPAD_UP"); - names.append(KEYCODE_DPAD_DOWN, "KEYCODE_DPAD_DOWN"); - names.append(KEYCODE_DPAD_LEFT, "KEYCODE_DPAD_LEFT"); - names.append(KEYCODE_DPAD_RIGHT, "KEYCODE_DPAD_RIGHT"); - names.append(KEYCODE_DPAD_CENTER, "KEYCODE_DPAD_CENTER"); - names.append(KEYCODE_VOLUME_UP, "KEYCODE_VOLUME_UP"); - names.append(KEYCODE_VOLUME_DOWN, "KEYCODE_VOLUME_DOWN"); - names.append(KEYCODE_POWER, "KEYCODE_POWER"); - names.append(KEYCODE_CAMERA, "KEYCODE_CAMERA"); - names.append(KEYCODE_CLEAR, "KEYCODE_CLEAR"); - names.append(KEYCODE_A, "KEYCODE_A"); - names.append(KEYCODE_B, "KEYCODE_B"); - names.append(KEYCODE_C, "KEYCODE_C"); - names.append(KEYCODE_D, "KEYCODE_D"); - names.append(KEYCODE_E, "KEYCODE_E"); - names.append(KEYCODE_F, "KEYCODE_F"); - names.append(KEYCODE_G, "KEYCODE_G"); - names.append(KEYCODE_H, "KEYCODE_H"); - names.append(KEYCODE_I, "KEYCODE_I"); - names.append(KEYCODE_J, "KEYCODE_J"); - names.append(KEYCODE_K, "KEYCODE_K"); - names.append(KEYCODE_L, "KEYCODE_L"); - names.append(KEYCODE_M, "KEYCODE_M"); - names.append(KEYCODE_N, "KEYCODE_N"); - names.append(KEYCODE_O, "KEYCODE_O"); - names.append(KEYCODE_P, "KEYCODE_P"); - names.append(KEYCODE_Q, "KEYCODE_Q"); - names.append(KEYCODE_R, "KEYCODE_R"); - names.append(KEYCODE_S, "KEYCODE_S"); - names.append(KEYCODE_T, "KEYCODE_T"); - names.append(KEYCODE_U, "KEYCODE_U"); - names.append(KEYCODE_V, "KEYCODE_V"); - names.append(KEYCODE_W, "KEYCODE_W"); - names.append(KEYCODE_X, "KEYCODE_X"); - names.append(KEYCODE_Y, "KEYCODE_Y"); - names.append(KEYCODE_Z, "KEYCODE_Z"); - names.append(KEYCODE_COMMA, "KEYCODE_COMMA"); - names.append(KEYCODE_PERIOD, "KEYCODE_PERIOD"); - names.append(KEYCODE_ALT_LEFT, "KEYCODE_ALT_LEFT"); - names.append(KEYCODE_ALT_RIGHT, "KEYCODE_ALT_RIGHT"); - names.append(KEYCODE_SHIFT_LEFT, "KEYCODE_SHIFT_LEFT"); - names.append(KEYCODE_SHIFT_RIGHT, "KEYCODE_SHIFT_RIGHT"); - names.append(KEYCODE_TAB, "KEYCODE_TAB"); - names.append(KEYCODE_SPACE, "KEYCODE_SPACE"); - names.append(KEYCODE_SYM, "KEYCODE_SYM"); - names.append(KEYCODE_EXPLORER, "KEYCODE_EXPLORER"); - names.append(KEYCODE_ENVELOPE, "KEYCODE_ENVELOPE"); - names.append(KEYCODE_ENTER, "KEYCODE_ENTER"); - names.append(KEYCODE_DEL, "KEYCODE_DEL"); - names.append(KEYCODE_GRAVE, "KEYCODE_GRAVE"); - names.append(KEYCODE_MINUS, "KEYCODE_MINUS"); - names.append(KEYCODE_EQUALS, "KEYCODE_EQUALS"); - names.append(KEYCODE_LEFT_BRACKET, "KEYCODE_LEFT_BRACKET"); - names.append(KEYCODE_RIGHT_BRACKET, "KEYCODE_RIGHT_BRACKET"); - names.append(KEYCODE_BACKSLASH, "KEYCODE_BACKSLASH"); - names.append(KEYCODE_SEMICOLON, "KEYCODE_SEMICOLON"); - names.append(KEYCODE_APOSTROPHE, "KEYCODE_APOSTROPHE"); - names.append(KEYCODE_SLASH, "KEYCODE_SLASH"); - names.append(KEYCODE_AT, "KEYCODE_AT"); - names.append(KEYCODE_NUM, "KEYCODE_NUM"); - names.append(KEYCODE_HEADSETHOOK, "KEYCODE_HEADSETHOOK"); - names.append(KEYCODE_FOCUS, "KEYCODE_FOCUS"); - names.append(KEYCODE_PLUS, "KEYCODE_PLUS"); - names.append(KEYCODE_MENU, "KEYCODE_MENU"); - names.append(KEYCODE_NOTIFICATION, "KEYCODE_NOTIFICATION"); - names.append(KEYCODE_SEARCH, "KEYCODE_SEARCH"); - names.append(KEYCODE_MEDIA_PLAY_PAUSE, "KEYCODE_MEDIA_PLAY_PAUSE"); - names.append(KEYCODE_MEDIA_STOP, "KEYCODE_MEDIA_STOP"); - names.append(KEYCODE_MEDIA_NEXT, "KEYCODE_MEDIA_NEXT"); - names.append(KEYCODE_MEDIA_PREVIOUS, "KEYCODE_MEDIA_PREVIOUS"); - names.append(KEYCODE_MEDIA_REWIND, "KEYCODE_MEDIA_REWIND"); - names.append(KEYCODE_MEDIA_FAST_FORWARD, "KEYCODE_MEDIA_FAST_FORWARD"); - names.append(KEYCODE_MUTE, "KEYCODE_MUTE"); - names.append(KEYCODE_PAGE_UP, "KEYCODE_PAGE_UP"); - names.append(KEYCODE_PAGE_DOWN, "KEYCODE_PAGE_DOWN"); - names.append(KEYCODE_PICTSYMBOLS, "KEYCODE_PICTSYMBOLS"); - names.append(KEYCODE_SWITCH_CHARSET, "KEYCODE_SWITCH_CHARSET"); - names.append(KEYCODE_BUTTON_A, "KEYCODE_BUTTON_A"); - names.append(KEYCODE_BUTTON_B, "KEYCODE_BUTTON_B"); - names.append(KEYCODE_BUTTON_C, "KEYCODE_BUTTON_C"); - names.append(KEYCODE_BUTTON_X, "KEYCODE_BUTTON_X"); - names.append(KEYCODE_BUTTON_Y, "KEYCODE_BUTTON_Y"); - names.append(KEYCODE_BUTTON_Z, "KEYCODE_BUTTON_Z"); - names.append(KEYCODE_BUTTON_L1, "KEYCODE_BUTTON_L1"); - names.append(KEYCODE_BUTTON_R1, "KEYCODE_BUTTON_R1"); - names.append(KEYCODE_BUTTON_L2, "KEYCODE_BUTTON_L2"); - names.append(KEYCODE_BUTTON_R2, "KEYCODE_BUTTON_R2"); - names.append(KEYCODE_BUTTON_THUMBL, "KEYCODE_BUTTON_THUMBL"); - names.append(KEYCODE_BUTTON_THUMBR, "KEYCODE_BUTTON_THUMBR"); - names.append(KEYCODE_BUTTON_START, "KEYCODE_BUTTON_START"); - names.append(KEYCODE_BUTTON_SELECT, "KEYCODE_BUTTON_SELECT"); - names.append(KEYCODE_BUTTON_MODE, "KEYCODE_BUTTON_MODE"); - names.append(KEYCODE_ESCAPE, "KEYCODE_ESCAPE"); - names.append(KEYCODE_FORWARD_DEL, "KEYCODE_FORWARD_DEL"); - names.append(KEYCODE_CTRL_LEFT, "KEYCODE_CTRL_LEFT"); - names.append(KEYCODE_CTRL_RIGHT, "KEYCODE_CTRL_RIGHT"); - names.append(KEYCODE_CAPS_LOCK, "KEYCODE_CAPS_LOCK"); - names.append(KEYCODE_SCROLL_LOCK, "KEYCODE_SCROLL_LOCK"); - names.append(KEYCODE_META_LEFT, "KEYCODE_META_LEFT"); - names.append(KEYCODE_META_RIGHT, "KEYCODE_META_RIGHT"); - names.append(KEYCODE_FUNCTION, "KEYCODE_FUNCTION"); - names.append(KEYCODE_SYSRQ, "KEYCODE_SYSRQ"); - names.append(KEYCODE_BREAK, "KEYCODE_BREAK"); - names.append(KEYCODE_MOVE_HOME, "KEYCODE_MOVE_HOME"); - names.append(KEYCODE_MOVE_END, "KEYCODE_MOVE_END"); - names.append(KEYCODE_INSERT, "KEYCODE_INSERT"); - names.append(KEYCODE_FORWARD, "KEYCODE_FORWARD"); - names.append(KEYCODE_MEDIA_PLAY, "KEYCODE_MEDIA_PLAY"); - names.append(KEYCODE_MEDIA_PAUSE, "KEYCODE_MEDIA_PAUSE"); - names.append(KEYCODE_MEDIA_CLOSE, "KEYCODE_MEDIA_CLOSE"); - names.append(KEYCODE_MEDIA_EJECT, "KEYCODE_MEDIA_EJECT"); - names.append(KEYCODE_MEDIA_RECORD, "KEYCODE_MEDIA_RECORD"); - names.append(KEYCODE_F1, "KEYCODE_F1"); - names.append(KEYCODE_F2, "KEYCODE_F2"); - names.append(KEYCODE_F3, "KEYCODE_F3"); - names.append(KEYCODE_F4, "KEYCODE_F4"); - names.append(KEYCODE_F5, "KEYCODE_F5"); - names.append(KEYCODE_F6, "KEYCODE_F6"); - names.append(KEYCODE_F7, "KEYCODE_F7"); - names.append(KEYCODE_F8, "KEYCODE_F8"); - names.append(KEYCODE_F9, "KEYCODE_F9"); - names.append(KEYCODE_F10, "KEYCODE_F10"); - names.append(KEYCODE_F11, "KEYCODE_F11"); - names.append(KEYCODE_F12, "KEYCODE_F12"); - names.append(KEYCODE_NUM_LOCK, "KEYCODE_NUM_LOCK"); - names.append(KEYCODE_NUMPAD_0, "KEYCODE_NUMPAD_0"); - names.append(KEYCODE_NUMPAD_1, "KEYCODE_NUMPAD_1"); - names.append(KEYCODE_NUMPAD_2, "KEYCODE_NUMPAD_2"); - names.append(KEYCODE_NUMPAD_3, "KEYCODE_NUMPAD_3"); - names.append(KEYCODE_NUMPAD_4, "KEYCODE_NUMPAD_4"); - names.append(KEYCODE_NUMPAD_5, "KEYCODE_NUMPAD_5"); - names.append(KEYCODE_NUMPAD_6, "KEYCODE_NUMPAD_6"); - names.append(KEYCODE_NUMPAD_7, "KEYCODE_NUMPAD_7"); - names.append(KEYCODE_NUMPAD_8, "KEYCODE_NUMPAD_8"); - names.append(KEYCODE_NUMPAD_9, "KEYCODE_NUMPAD_9"); - names.append(KEYCODE_NUMPAD_DIVIDE, "KEYCODE_NUMPAD_DIVIDE"); - names.append(KEYCODE_NUMPAD_MULTIPLY, "KEYCODE_NUMPAD_MULTIPLY"); - names.append(KEYCODE_NUMPAD_SUBTRACT, "KEYCODE_NUMPAD_SUBTRACT"); - names.append(KEYCODE_NUMPAD_ADD, "KEYCODE_NUMPAD_ADD"); - names.append(KEYCODE_NUMPAD_DOT, "KEYCODE_NUMPAD_DOT"); - names.append(KEYCODE_NUMPAD_COMMA, "KEYCODE_NUMPAD_COMMA"); - names.append(KEYCODE_NUMPAD_ENTER, "KEYCODE_NUMPAD_ENTER"); - names.append(KEYCODE_NUMPAD_EQUALS, "KEYCODE_NUMPAD_EQUALS"); - names.append(KEYCODE_NUMPAD_LEFT_PAREN, "KEYCODE_NUMPAD_LEFT_PAREN"); - names.append(KEYCODE_NUMPAD_RIGHT_PAREN, "KEYCODE_NUMPAD_RIGHT_PAREN"); - names.append(KEYCODE_VOLUME_MUTE, "KEYCODE_VOLUME_MUTE"); - names.append(KEYCODE_INFO, "KEYCODE_INFO"); - names.append(KEYCODE_CHANNEL_UP, "KEYCODE_CHANNEL_UP"); - names.append(KEYCODE_CHANNEL_DOWN, "KEYCODE_CHANNEL_DOWN"); - names.append(KEYCODE_ZOOM_IN, "KEYCODE_ZOOM_IN"); - names.append(KEYCODE_ZOOM_OUT, "KEYCODE_ZOOM_OUT"); - names.append(KEYCODE_TV, "KEYCODE_TV"); - names.append(KEYCODE_WINDOW, "KEYCODE_WINDOW"); - names.append(KEYCODE_GUIDE, "KEYCODE_GUIDE"); - names.append(KEYCODE_DVR, "KEYCODE_DVR"); - names.append(KEYCODE_BOOKMARK, "KEYCODE_BOOKMARK"); - names.append(KEYCODE_CAPTIONS, "KEYCODE_CAPTIONS"); - names.append(KEYCODE_SETTINGS, "KEYCODE_SETTINGS"); - names.append(KEYCODE_TV_POWER, "KEYCODE_TV_POWER"); - names.append(KEYCODE_TV_INPUT, "KEYCODE_TV_INPUT"); - names.append(KEYCODE_STB_INPUT, "KEYCODE_STB_INPUT"); - names.append(KEYCODE_STB_POWER, "KEYCODE_STB_POWER"); - names.append(KEYCODE_AVR_POWER, "KEYCODE_AVR_POWER"); - names.append(KEYCODE_AVR_INPUT, "KEYCODE_AVR_INPUT"); - names.append(KEYCODE_PROG_RED, "KEYCODE_PROG_RED"); - names.append(KEYCODE_PROG_GREEN, "KEYCODE_PROG_GREEN"); - names.append(KEYCODE_PROG_YELLOW, "KEYCODE_PROG_YELLOW"); - names.append(KEYCODE_PROG_BLUE, "KEYCODE_PROG_BLUE"); - names.append(KEYCODE_APP_SWITCH, "KEYCODE_APP_SWITCH"); - names.append(KEYCODE_BUTTON_1, "KEYCODE_BUTTON_1"); - names.append(KEYCODE_BUTTON_2, "KEYCODE_BUTTON_2"); - names.append(KEYCODE_BUTTON_3, "KEYCODE_BUTTON_3"); - names.append(KEYCODE_BUTTON_4, "KEYCODE_BUTTON_4"); - names.append(KEYCODE_BUTTON_5, "KEYCODE_BUTTON_5"); - names.append(KEYCODE_BUTTON_6, "KEYCODE_BUTTON_6"); - names.append(KEYCODE_BUTTON_7, "KEYCODE_BUTTON_7"); - names.append(KEYCODE_BUTTON_8, "KEYCODE_BUTTON_8"); - names.append(KEYCODE_BUTTON_9, "KEYCODE_BUTTON_9"); - names.append(KEYCODE_BUTTON_10, "KEYCODE_BUTTON_10"); - names.append(KEYCODE_BUTTON_11, "KEYCODE_BUTTON_11"); - names.append(KEYCODE_BUTTON_12, "KEYCODE_BUTTON_12"); - names.append(KEYCODE_BUTTON_13, "KEYCODE_BUTTON_13"); - names.append(KEYCODE_BUTTON_14, "KEYCODE_BUTTON_14"); - names.append(KEYCODE_BUTTON_15, "KEYCODE_BUTTON_15"); - names.append(KEYCODE_BUTTON_16, "KEYCODE_BUTTON_16"); - names.append(KEYCODE_LANGUAGE_SWITCH, "KEYCODE_LANGUAGE_SWITCH"); - names.append(KEYCODE_MANNER_MODE, "KEYCODE_MANNER_MODE"); - names.append(KEYCODE_3D_MODE, "KEYCODE_3D_MODE"); - names.append(KEYCODE_CONTACTS, "KEYCODE_CONTACTS"); - names.append(KEYCODE_CALENDAR, "KEYCODE_CALENDAR"); - names.append(KEYCODE_MUSIC, "KEYCODE_MUSIC"); - names.append(KEYCODE_CALCULATOR, "KEYCODE_CALCULATOR"); - names.append(KEYCODE_ZENKAKU_HANKAKU, "KEYCODE_ZENKAKU_HANKAKU"); - names.append(KEYCODE_EISU, "KEYCODE_EISU"); - names.append(KEYCODE_MUHENKAN, "KEYCODE_MUHENKAN"); - names.append(KEYCODE_HENKAN, "KEYCODE_HENKAN"); - names.append(KEYCODE_KATAKANA_HIRAGANA, "KEYCODE_KATAKANA_HIRAGANA"); - names.append(KEYCODE_YEN, "KEYCODE_YEN"); - names.append(KEYCODE_RO, "KEYCODE_RO"); - names.append(KEYCODE_KANA, "KEYCODE_KANA"); - names.append(KEYCODE_ASSIST, "KEYCODE_ASSIST"); - names.append(KEYCODE_BRIGHTNESS_DOWN, "KEYCODE_BRIGHTNESS_DOWN"); - names.append(KEYCODE_BRIGHTNESS_UP, "KEYCODE_BRIGHTNESS_UP"); - names.append(KEYCODE_MEDIA_AUDIO_TRACK, "KEYCODE_MEDIA_AUDIO_TRACK"); - names.append(KEYCODE_SLEEP, "KEYCODE_SLEEP"); - names.append(KEYCODE_WAKEUP, "KEYCODE_WAKEUP"); - }; - // Symbolic names of all metakeys in bit order from least significant to most significant. // Accordingly there are exactly 32 values in this table. private static final String[] META_SYMBOLIC_NAMES = new String[] { @@ -926,6 +694,8 @@ public class KeyEvent extends InputEvent implements Parcelable { "0x80000000", }; + private static final String LABEL_PREFIX = "KEYCODE_"; + /** * @deprecated There are now more than MAX_KEYCODE keycodes. * Use {@link #getMaxKeyCode()} instead. @@ -1367,9 +1137,8 @@ public class KeyEvent extends InputEvent implements Parcelable { boolean onKeyMultiple(int keyCode, int count, KeyEvent event); } - static { - populateKeycodeSymbolicNames(); - } + private static native String nativeKeyCodeToString(int keyCode); + private static native int nativeKeyCodeFromString(String keyCode); private KeyEvent() { } @@ -1792,19 +1561,15 @@ public class KeyEvent extends InputEvent implements Parcelable { return mAction == ACTION_DOWN; } - /** - * Is this a system key? System keys can not be used for menu shortcuts. - * - * TODO: this information should come from a table somewhere. - * TODO: should the dpad keys be here? arguably, because they also shouldn't be menu shortcuts + /** Is this a system key? System keys can not be used for menu shortcuts. */ public final boolean isSystem() { - return native_isSystemKey(mKeyCode); + return isSystemKey(mKeyCode); } /** @hide */ - public final boolean hasDefaultAction() { - return native_hasDefaultAction(mKeyCode); + public final boolean isWakeKey() { + return isWakeKey(mKeyCode); } /** @@ -1887,6 +1652,62 @@ public class KeyEvent extends InputEvent implements Parcelable { return false; } + + /** Is this a system key? System keys can not be used for menu shortcuts. + * @hide + */ + public static final boolean isSystemKey(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_MENU: + case KeyEvent.KEYCODE_SOFT_RIGHT: + case KeyEvent.KEYCODE_HOME: + case KeyEvent.KEYCODE_BACK: + case KeyEvent.KEYCODE_CALL: + case KeyEvent.KEYCODE_ENDCALL: + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_VOLUME_MUTE: + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_POWER: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_PLAY: + case KeyEvent.KEYCODE_MEDIA_PAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_RECORD: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: + case KeyEvent.KEYCODE_CAMERA: + case KeyEvent.KEYCODE_FOCUS: + case KeyEvent.KEYCODE_SEARCH: + case KeyEvent.KEYCODE_BRIGHTNESS_DOWN: + case KeyEvent.KEYCODE_BRIGHTNESS_UP: + case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: + case KeyEvent.KEYCODE_DPAD_UP: + case KeyEvent.KEYCODE_DPAD_RIGHT: + case KeyEvent.KEYCODE_DPAD_DOWN: + case KeyEvent.KEYCODE_DPAD_LEFT: + return true; + } + + return false; + } + + /** @hide */ + public static final boolean isWakeKey(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_BACK: + case KeyEvent.KEYCODE_POWER: + case KeyEvent.KEYCODE_MENU: + case KeyEvent.KEYCODE_SLEEP: + case KeyEvent.KEYCODE_WAKEUP: + return true; + } + return false; + } + /** {@inheritDoc} */ @Override public final int getDeviceId() { @@ -2866,8 +2687,8 @@ public class KeyEvent extends InputEvent implements Parcelable { * @see KeyCharacterMap#getDisplayLabel */ public static String keyCodeToString(int keyCode) { - String symbolicName = KEYCODE_SYMBOLIC_NAMES.get(keyCode); - return symbolicName != null ? symbolicName : Integer.toString(keyCode); + String symbolicName = nativeKeyCodeToString(keyCode); + return symbolicName != null ? LABEL_PREFIX + symbolicName : Integer.toString(keyCode); } /** @@ -2879,17 +2700,13 @@ public class KeyEvent extends InputEvent implements Parcelable { * @see #keycodeToString(int) */ public static int keyCodeFromString(String symbolicName) { - if (symbolicName == null) { - throw new IllegalArgumentException("symbolicName must not be null"); + if (symbolicName.startsWith(LABEL_PREFIX)) { + symbolicName = symbolicName.substring(LABEL_PREFIX.length()); } - - final int count = KEYCODE_SYMBOLIC_NAMES.size(); - for (int i = 0; i < count; i++) { - if (symbolicName.equals(KEYCODE_SYMBOLIC_NAMES.valueAt(i))) { - return i; - } + int keyCode = nativeKeyCodeFromString(symbolicName); + if (keyCode > 0) { + return keyCode; } - try { return Integer.parseInt(symbolicName, 10); } catch (NumberFormatException ex) { @@ -2977,7 +2794,4 @@ public class KeyEvent extends InputEvent implements Parcelable { out.writeLong(mDownTime); out.writeLong(mEventTime); } - - private native boolean native_isSystemKey(int keyCode); - private native boolean native_hasDefaultAction(int keyCode); } 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.Handler; 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 @@ import java.util.HashMap; * @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 @@ public abstract class LayoutInflater { * 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/MotionEvent.java b/core/java/android/view/MotionEvent.java index 6378ffd..0626ab9 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -167,6 +167,7 @@ import android.util.SparseArray; */ public final class MotionEvent extends InputEvent implements Parcelable { private static final long NS_PER_MS = 1000000; + private static final String LABEL_PREFIX = "AXIS_"; /** * An invalid pointer id. @@ -1369,6 +1370,9 @@ public final class MotionEvent extends InputEvent implements Parcelable { private static native long nativeReadFromParcel(long nativePtr, Parcel parcel); private static native void nativeWriteToParcel(long nativePtr, Parcel parcel); + private static native String nativeAxisToString(int axis); + private static native int nativeAxisFromString(String label); + private MotionEvent() { } @@ -3051,8 +3055,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @return The symbolic name of the specified axis. */ public static String axisToString(int axis) { - String symbolicName = AXIS_SYMBOLIC_NAMES.get(axis); - return symbolicName != null ? symbolicName : Integer.toString(axis); + String symbolicName = nativeAxisToString(axis); + return symbolicName != null ? LABEL_PREFIX + symbolicName : Integer.toString(axis); } /** @@ -3064,17 +3068,13 @@ public final class MotionEvent extends InputEvent implements Parcelable { * @see KeyEvent#keyCodeToString(int) */ public static int axisFromString(String symbolicName) { - if (symbolicName == null) { - throw new IllegalArgumentException("symbolicName must not be null"); + if (symbolicName.startsWith(LABEL_PREFIX)) { + symbolicName = symbolicName.substring(LABEL_PREFIX.length()); } - - final int count = AXIS_SYMBOLIC_NAMES.size(); - for (int i = 0; i < count; i++) { - if (symbolicName.equals(AXIS_SYMBOLIC_NAMES.valueAt(i))) { - return i; - } + int axis = nativeAxisFromString(symbolicName); + if (axis >= 0) { + return axis; } - try { return Integer.parseInt(symbolicName, 10); } catch (NumberFormatException ex) { diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index 3dc09c4..0cfde94 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -20,6 +20,9 @@ import android.annotation.NonNull; import android.graphics.Matrix; import android.graphics.Outline; +import java.util.ArrayList; +import java.util.List; + /** * <p>A display list records a series of graphics related operations and can replay * them later. Display lists are usually built by recording operations on a @@ -176,11 +179,24 @@ public class RenderNode { private boolean mValid; private final long mNativeRenderNode; + // We need to keep a strong reference to all running animators to ensure that + // they can call removeAnimator when they have finished, as the native-side + // object can only hold a WeakReference<> to avoid leaking memory due to + // cyclic references. + private List<RenderNodeAnimator> mActiveAnimators; + private RenderNode(String name) { mNativeRenderNode = nCreate(name); } /** + * @see RenderNode#adopt(long) + */ + private RenderNode(long nativePtr) { + mNativeRenderNode = nativePtr; + } + + /** * Creates a new display list that can be used to record batches of * drawing operations. * @@ -195,6 +211,17 @@ public class RenderNode { } /** + * Adopts an existing native render node. + * + * Note: This will *NOT* incRef() on the native object, however it will + * decRef() when it is destroyed. The caller should have already incRef'd it + */ + public static RenderNode adopt(long nativePtr) { + return new RenderNode(nativePtr); + } + + + /** * Starts recording a display list for the render node. All * operations performed on the returned canvas are recorded and * stored in this display list. @@ -212,7 +239,7 @@ public class RenderNode { * @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); @@ -822,6 +849,23 @@ public class RenderNode { } /////////////////////////////////////////////////////////////////////////// + // Animations + /////////////////////////////////////////////////////////////////////////// + + public void addAnimator(RenderNodeAnimator animator) { + if (mActiveAnimators == null) { + mActiveAnimators = new ArrayList<RenderNodeAnimator>(); + } + mActiveAnimators.add(animator); + nAddAnimator(mNativeRenderNode, animator.getNativeAnimator()); + } + + public void removeAnimator(RenderNodeAnimator animator) { + nRemoveAnimator(mNativeRenderNode, animator.getNativeAnimator()); + mActiveAnimators.remove(animator); + } + + /////////////////////////////////////////////////////////////////////////// // Native methods /////////////////////////////////////////////////////////////////////////// @@ -896,6 +940,13 @@ public class RenderNode { private static native void nOutput(long renderNode); /////////////////////////////////////////////////////////////////////////// + // Animations + /////////////////////////////////////////////////////////////////////////// + + private static native void nAddAnimator(long renderNode, long animatorPtr); + private static native void nRemoveAnimator(long renderNode, long animatorPtr); + + /////////////////////////////////////////////////////////////////////////// // Finalization /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java new file mode 100644 index 0000000..a675821 --- /dev/null +++ b/core/java/android/view/RenderNodeAnimator.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.graphics.Canvas; +import android.graphics.CanvasProperty; +import android.graphics.Paint; +import android.util.SparseIntArray; + +import java.lang.ref.WeakReference; + +/** + * @hide + */ +public final class RenderNodeAnimator { + + // Keep in sync with enum RenderProperty in Animator.h + 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 + // directly as internally it uses a lookup table so it needs the values to + // be sequential starting from 0 + private static final SparseIntArray sViewPropertyAnimatorMap = new SparseIntArray(15) {{ + put(ViewPropertyAnimator.TRANSLATION_X, TRANSLATION_X); + put(ViewPropertyAnimator.TRANSLATION_Y, TRANSLATION_Y); + put(ViewPropertyAnimator.TRANSLATION_Z, TRANSLATION_Z); + put(ViewPropertyAnimator.SCALE_X, SCALE_X); + put(ViewPropertyAnimator.SCALE_Y, SCALE_Y); + put(ViewPropertyAnimator.ROTATION, ROTATION); + put(ViewPropertyAnimator.ROTATION_X, ROTATION_X); + put(ViewPropertyAnimator.ROTATION_Y, ROTATION_Y); + put(ViewPropertyAnimator.X, X); + put(ViewPropertyAnimator.Y, Y); + put(ViewPropertyAnimator.Z, Z); + put(ViewPropertyAnimator.ALPHA, ALPHA); + }}; + + // Keep in sync DeltaValueType in Animator.h + public static final int DELTA_TYPE_ABSOLUTE = 0; + public static final int DELTA_TYPE_DELTA = 1; + + private RenderNode mTarget; + private long mNativePtr; + + public int mapViewPropertyToRenderProperty(int viewProperty) { + return sViewPropertyAnimatorMap.get(viewProperty); + } + + public RenderNodeAnimator(int property, int deltaType, float deltaValue) { + mNativePtr = nCreateAnimator(new WeakReference<RenderNodeAnimator>(this), + property, deltaType, deltaValue); + } + + public RenderNodeAnimator(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); + // Kick off a frame to start the process + 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); + } + + public void setDuration(int duration) { + nSetDuration(mNativePtr, duration); + } + + long getNativeAnimator() { + return mNativePtr; + } + + private void onFinished() { + mTarget.removeAnimator(this); + } + + // Called by native + private static void callOnFinished(WeakReference<RenderNodeAnimator> weakThis) { + RenderNodeAnimator animator = weakThis.get(); + if (animator != null) { + animator.onFinished(); + } + } + + @Override + protected void finalize() throws Throwable { + try { + nUnref(mNativePtr); + mNativePtr = 0; + } finally { + super.finalize(); + } + } + + private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis, + int property, int deltaValueType, float deltaValue); + 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/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index c7a6d41..eaec8ab 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -50,7 +50,7 @@ import java.io.PrintWriter; public class ThreadedRenderer extends HardwareRenderer { private static final String LOGTAG = "ThreadedRenderer"; - private static final Rect NULL_RECT = new Rect(-1, -1, -1, -1); + private static final Rect NULL_RECT = new Rect(); private int mWidth, mHeight; private long mNativeProxy; @@ -58,9 +58,10 @@ public class ThreadedRenderer extends HardwareRenderer { private RenderNode mRootNode; ThreadedRenderer(boolean translucent) { - mNativeProxy = nCreateProxy(translucent); - mRootNode = RenderNode.create("RootNode"); + long rootNodePtr = nCreateRootRenderNode(); + mRootNode = RenderNode.adopt(rootNodePtr); mRootNode.setClipToBounds(false); + mNativeProxy = nCreateProxy(translucent, rootNodePtr); } @Override @@ -202,8 +203,7 @@ public class ThreadedRenderer extends HardwareRenderer { if (dirty == null) { dirty = NULL_RECT; } - nDrawDisplayList(mNativeProxy, mRootNode.getNativeDisplayList(), - dirty.left, dirty.top, dirty.right, dirty.bottom); + nSyncAndDrawFrame(mNativeProxy, dirty.left, dirty.top, dirty.right, dirty.bottom); } @Override @@ -293,7 +293,8 @@ public class ThreadedRenderer extends HardwareRenderer { /** @hide */ public static native void postToRenderThread(Runnable runnable); - private static native long nCreateProxy(boolean translucent); + private static native long nCreateRootRenderNode(); + private static native long nCreateProxy(boolean translucent, long rootRenderNode); private static native void nDeleteProxy(long nativeProxy); private static native boolean nInitialize(long nativeProxy, Surface window); @@ -302,7 +303,7 @@ public class ThreadedRenderer extends HardwareRenderer { private static native void nSetup(long nativeProxy, int width, int height); private static native void nSetDisplayListData(long nativeProxy, long displayList, long newData); - private static native void nDrawDisplayList(long nativeProxy, long displayList, + private static native void nSyncAndDrawFrame(long nativeProxy, 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 463a2f7..6afff4d 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10633,8 +10633,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } else { // always copy the path since caller may reuse if (mOutline == null) { - mOutline = new Outline(outline); + mOutline = new Outline(); } + mOutline.set(outline); } mRenderNode.setOutline(mOutline); } @@ -17988,7 +17989,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * <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 * @@ -17998,6 +18001,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (enabled) { mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; } else { + stopNestedScroll(); mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; } } @@ -18137,23 +18141,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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; } @@ -18179,30 +18189,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ 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; } @@ -18210,18 +18225,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * 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; } @@ -18863,6 +18884,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback, }; /** + * A Property wrapper around the <code>z</code> functionality handled by the + * {@link View#setZ(float)} and {@link View#getZ()} methods. + */ + public static final Property<View, Float> Z = new FloatProperty<View>("z") { + @Override + public void setValue(View object, float value) { + object.setZ(value); + } + + @Override + public Float get(View object) { + return object.getZ(); + } + }; + + /** * A Property wrapper around the <code>rotation</code> functionality handled by the * {@link View#setRotation(float)} and {@link View#getRotation()} methods. */ diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 5112b9a..20ef429 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -234,6 +234,7 @@ public class ViewConfiguration { 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 @@ public class ViewConfiguration { mOverscrollDistance = OVERSCROLL_DISTANCE; mOverflingDistance = OVERFLING_DISTANCE; mFadingMarqueeEnabled = true; + mGlobalActionsKeyTimeout = GLOBAL_ACTIONS_KEY_TIMEOUT; } /** @@ -287,8 +289,6 @@ public class ViewConfiguration { 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 @@ public class ViewConfiguration { 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,24 @@ public class ViewConfiguration { * * @return how long a user needs to press the relevant key to bring up * the global actions dialog. + * @deprecated use getDeviceGlobalActionKeyTimeout */ 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. + */ + 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..43bc0b6 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2342,7 +2342,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (disallowIntercept) { mGroupFlags |= FLAG_DISALLOW_INTERCEPT; - stopNestedScroll(); } else { mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; } @@ -5914,7 +5913,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @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 @@ public interface ViewParent { /** * 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/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java index b1aa7b2..11d2622 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -133,19 +133,19 @@ public class ViewPropertyAnimator { * Constants used to associate a property being requested and the mechanism used to set * the property (this class calls directly into View to set the properties in question). */ - private static final int NONE = 0x0000; - private static final int TRANSLATION_X = 0x0001; - private static final int TRANSLATION_Y = 0x0002; - private static final int TRANSLATION_Z = 0x0004; - private static final int SCALE_X = 0x0008; - private static final int SCALE_Y = 0x0010; - private static final int ROTATION = 0x0020; - private static final int ROTATION_X = 0x0040; - private static final int ROTATION_Y = 0x0080; - private static final int X = 0x0100; - private static final int Y = 0x0200; - private static final int Z = 0x0400; - private static final int ALPHA = 0x0800; + static final int NONE = 0x0000; + static final int TRANSLATION_X = 0x0001; + static final int TRANSLATION_Y = 0x0002; + static final int TRANSLATION_Z = 0x0004; + static final int SCALE_X = 0x0008; + static final int SCALE_Y = 0x0010; + static final int ROTATION = 0x0020; + static final int ROTATION_X = 0x0040; + static final int ROTATION_Y = 0x0080; + static final int X = 0x0100; + static final int Y = 0x0200; + static final int Z = 0x0400; + static final int ALPHA = 0x0800; private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z | SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y | Z; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 14e422c..db87394 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -234,6 +234,7 @@ public final class ViewRootImpl implements ViewParent, InputStage mFirstInputStage; InputStage mFirstPostImeInputStage; + InputStage mSyntheticInputStage; boolean mWindowAttributesChanged = false; int mWindowAttributesChangesFlag = 0; @@ -599,8 +600,8 @@ public final class ViewRootImpl implements ViewParent, // 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); @@ -2587,10 +2588,6 @@ public final class ViewRootImpl implements ViewParent, * @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 +3004,7 @@ public final class ViewRootImpl implements ViewParent, 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 +3054,8 @@ public final class ViewRootImpl implements ViewParent, 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 +3218,10 @@ public final class ViewRootImpl implements ViewParent, 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 +3231,8 @@ public final class ViewRootImpl implements ViewParent, // 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 +4028,7 @@ public final class ViewRootImpl implements ViewParent, private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler(); private final SyntheticTouchNavigationHandler mTouchNavigation = new SyntheticTouchNavigationHandler(); + private final SyntheticKeyboardHandler mKeyboard = new SyntheticKeyboardHandler(); public SyntheticInputStage() { super(null); @@ -4045,7 +4051,11 @@ public final class ViewRootImpl implements ViewParent, 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 +4892,33 @@ public final class ViewRootImpl implements ViewParent, }; } + 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 +5498,7 @@ public final class ViewRootImpl implements ViewParent, 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 +5513,14 @@ public final class ViewRootImpl implements ViewParent, 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 +5624,13 @@ public final class ViewRootImpl implements ViewParent, 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 +5862,29 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendMessage(msg); } - public void dispatchKeyFromIme(KeyEvent event) { - Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event); + public void synthesizeInputEvent(InputEvent event) { + Message msg = mHandler.obtainMessage(MSG_SYNTHESIZE_INPUT_EVENT, 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); - } - } + public void dispatchKeyFromIme(KeyEvent event) { + Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event); + msg.setAsynchronous(true); + mHandler.sendMessage(msg); } + /** + * 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,7 +6169,7 @@ public final class ViewRootImpl implements ViewParent, } @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/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index c9be54d..4fde1e4 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -76,14 +76,7 @@ import java.lang.annotation.RetentionPolicy; public interface WindowManagerPolicy { // Policy flags. These flags are also defined in frameworks/base/include/ui/Input.h. public final static int FLAG_WAKE = 0x00000001; - public final static int FLAG_WAKE_DROPPED = 0x00000002; - public final static int FLAG_SHIFT = 0x00000004; - public final static int FLAG_CAPS_LOCK = 0x00000008; - public final static int FLAG_ALT = 0x00000010; - public final static int FLAG_ALT_GR = 0x00000020; - public final static int FLAG_MENU = 0x00000040; - public final static int FLAG_LAUNCHER = 0x00000080; - public final static int FLAG_VIRTUAL = 0x00000100; + public final static int FLAG_VIRTUAL = 0x00000002; public final static int FLAG_INJECTED = 0x01000000; public final static int FLAG_TRUSTED = 0x02000000; @@ -450,8 +443,6 @@ public interface WindowManagerPolicy { 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}) @@ -907,23 +898,23 @@ public interface WindowManagerPolicy { 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/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index f8160c8..bc2d7ec 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -259,7 +259,7 @@ public final class InputMethodInfo implements Parcelable { public InputMethodInfo(String packageName, String className, CharSequence label, String settingsActivity) { this(buildDummyResolveInfo(packageName, className, label), false, settingsActivity, null, - 0, false); + 0, false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */); } /** @@ -269,6 +269,17 @@ public final class InputMethodInfo implements Parcelable { public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault) { + this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, + forceDefault, true /* supportsSwitchingToNextInputMethod */); + } + + /** + * Temporary API for creating a built-in input method for test. + * @hide + */ + public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, + String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId, + boolean forceDefault, boolean supportsSwitchingToNextInputMethod) { final ServiceInfo si = ri.serviceInfo; mService = ri; mId = new ComponentName(si.packageName, si.name).flattenToShortString(); @@ -277,7 +288,7 @@ public final class InputMethodInfo implements Parcelable { mIsAuxIme = isAuxIme; mSubtypes = new InputMethodSubtypeArray(subtypes); mForceDefault = forceDefault; - mSupportsSwitchingToNextInputMethod = true; + mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod; } private static ResolveInfo buildDummyResolveInfo(String packageName, String className, 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 @@ import java.security.cert.X509Certificate; * 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/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 @@ public abstract class WebSettings { } /** + * 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 abstract class WebSettings { 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 c914e52..d06cd75 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -33,6 +33,7 @@ import android.os.Looper; 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; @@ -701,7 +702,7 @@ public class WebView extends AbsoluteLayout */ @Deprecated public static void enablePlatformNotifications() { - getFactory().getStatics().setPlatformNotificationsEnabled(true); + // noop } /** @@ -713,7 +714,7 @@ public class WebView extends AbsoluteLayout */ @Deprecated public static void disablePlatformNotifications() { - getFactory().getStatics().setPlatformNotificationsEnabled(false); + // noop } /** @@ -1479,18 +1480,16 @@ public class WebView extends AbsoluteLayout * 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); } /** @@ -1610,6 +1609,8 @@ public class WebView extends AbsoluteLayout * @return the address, or if no address is found, null */ public static String findAddress(String addr) { + // TODO: Rewrite this in Java so it is not needed to start up chromium + // Could also be deprecated return getFactory().getStatics().findAddress(addr); } diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java index 688c251..62b80c4 100644 --- a/core/java/android/webkit/WebViewClient.java +++ b/core/java/android/webkit/WebViewClient.java @@ -19,6 +19,7 @@ package android.webkit; 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 @@ public class WebViewClient { * @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 @@ public class WebViewClient { * * @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 @@ public interface WebViewFactoryProvider { * {@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 interface WebViewProvider { 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..3fac883 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -110,6 +110,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @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 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @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 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te 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 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } + /** + * 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 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } - 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 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te 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,46 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te 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]; + 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(); - } - invalidate(mEdgeGlowTop.getBounds(false)); - } else if (rawDeltaY < 0) { - mEdgeGlowBottom.onPull((float) overscroll / getHeight()); - if (!mEdgeGlowTop.isFinished()) { - mEdgeGlowTop.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(mEdgeGlowBottom.getBounds(true)); } } } mMotionY = y; } - mLastY = y; + mLastY = y + lastYCorrection; } } else if (mTouchMode == TOUCH_MODE_OVERSCROLL) { if (y != mLastY) { @@ -3493,6 +3539,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return false; } + startNestedScroll(SCROLL_AXIS_VERTICAL); + if (mFastScroll != null) { boolean intercepted = mFastScroll.onTouchEvent(ev); if (intercepted) { @@ -3501,7 +3549,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } initVelocityTrackerIfNotExists(); - mVelocityTracker.addMovement(ev); + final MotionEvent vtev = MotionEvent.obtain(ev); final int actionMasked = ev.getActionMasked(); switch (actionMasked) { @@ -3511,7 +3559,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } case MotionEvent.ACTION_MOVE: { - onTouchMove(ev); + onTouchMove(ev, vtev); break; } @@ -3562,6 +3610,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } + if (mVelocityTracker != null) { + mVelocityTracker.addMovement(vtev); + } + vtev.recycle(); return true; } @@ -3628,7 +3680,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } - private void onTouchMove(MotionEvent ev) { + private void onTouchMove(MotionEvent ev, MotionEvent vtev) { int pointerIndex = ev.findPointerIndex(mActivePointerId); if (pointerIndex == -1) { pointerIndex = 0; @@ -3649,7 +3701,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te 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 +3721,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te break; case TOUCH_MODE_SCROLL: case TOUCH_MODE_OVERSCROLL: - scrollIfNeeded(y); + scrollIfNeeded(y, vtev); break; } } @@ -3911,6 +3963,49 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } @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 +4141,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mLastY = Integer.MIN_VALUE; initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); + startNestedScroll(SCROLL_AXIS_VERTICAL); if (touchMode == TOUCH_MODE_FLING) { return true; } @@ -4063,7 +4159,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te final int y = (int) ev.getY(pointerIndex); initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); - if (startScrollIfNeeded(y)) { + if (startScrollIfNeeded(y, null)) { return true; } break; @@ -4077,6 +4173,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mActivePointerId = INVALID_POINTER; recycleVelocityTracker(); reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); + stopNestedScroll(); break; } diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index b47177a..10ec105 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -1565,7 +1565,7 @@ public class ListPopupWindow { // 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 @@ public class ListView extends AbsListView { if (needToRedraw) { if (selectedView != null) { - positionSelector(selectedPos, selectedView); + positionSelectorLikeFocus(selectedPos, selectedView); mSelectedTop = selectedView.getTop(); } if (!awakenScrollBars()) { diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index 7e8f6b4..8dfef25a 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -583,7 +583,8 @@ public class ScrollView extends FrameLayout { @Override public boolean onTouchEvent(MotionEvent ev) { initVelocityTrackerIfNotExists(); - mVelocityTracker.addMovement(ev); + + MotionEvent vtev = MotionEvent.obtain(ev); final int action = ev.getAction(); @@ -628,6 +629,7 @@ public class ScrollView extends FrameLayout { int deltaY = mLastMotionY - y; if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) { deltaY -= mScrollConsumed[1] + mScrollOffset[1]; + vtev.offsetLocation(0, mScrollOffset[1]); } if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) { final ViewParent parent = getParent(); @@ -663,6 +665,7 @@ public class ScrollView extends FrameLayout { 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 @@ public class ScrollView extends FrameLayout { mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId)); break; } + + if (mVelocityTracker != null) { + mVelocityTracker.addMovement(vtev); + } + vtev.recycle(); return true; } @@ -1565,10 +1573,10 @@ public class ScrollView extends FrameLayout { } 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 @@ public class ScrollView extends FrameLayout { 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 @@ public class ScrollView extends FrameLayout { @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/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index fc89b31..1bb577b 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -31,6 +31,14 @@ interface IBatteryStats { // Remaining methods are only used in Java. byte[] getStatistics(); + // Return the computed amount of time remaining on battery, in milliseconds. + // Returns -1 if nothing could be computed. + long computeBatteryTimeRemaining(); + + // Return the computed amount of time remaining to fully charge, in milliseconds. + // Returns -1 if nothing could be computed. + long computeChargeTimeRemaining(); + void addIsolatedUid(int isolatedUid, int appUid); void removeIsolatedUid(int isolatedUid, int appUid); diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java new file mode 100644 index 0000000..2f74372 --- /dev/null +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import android.app.Activity; +import android.app.AppGlobals; +import android.os.Bundle; +import android.content.Context; +import android.content.Intent; +import android.content.pm.IPackageManager; +import android.content.pm.UserInfo; +import android.os.UserHandle; +import android.os.UserManager; +import android.app.ActivityManagerNative; +import android.os.RemoteException; +import android.util.Slog; +import java.util.List; +import java.util.Set; + + + + +/* + * This is used in conjunction with DevicePolicyManager.setForwardingIntents to enable intents to be + * passed in and out of a managed profile. + */ + +public class IntentForwarderActivity extends Activity { + + public static String TAG = "IntentForwarderActivity"; + + public static String FORWARD_INTENT_TO_USER_OWNER + = "com.android.internal.app.ForwardIntentToUserOwner"; + + public static String FORWARD_INTENT_TO_MANAGED_PROFILE + = "com.android.internal.app.ForwardIntentToManagedProfile"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Intent intentReceived = getIntent(); + + String className = intentReceived.getComponent().getClassName(); + final UserHandle userDest; + + if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) { + userDest = UserHandle.OWNER; + } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { + userDest = getManagedProfile(); + } else { + Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly"); + userDest = null; + } + if (userDest == null) { // This covers the case where there is no managed profile. + finish(); + return; + } + Intent newIntent = new Intent(intentReceived); + newIntent.setComponent(null); + newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT + |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); + int callingUserId = getUserId(); + IPackageManager ipm = AppGlobals.getPackageManager(); + String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver()); + boolean canForward = false; + try { + canForward = ipm.canForwardTo(newIntent, resolvedType, callingUserId, + userDest.getIdentifier()); + } catch (RemoteException e) { + Slog.e(TAG, "PackageManagerService is dead?"); + } + if (canForward) { + startActivityAsUser(newIntent, userDest); + } else { + Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user " + + callingUserId + " to user " + userDest.getIdentifier()); + } + finish(); + } + + /** + * Returns the managed profile for this device or null if there is no managed + * profile. + * + * TODO: Remove the assumption that there is only one managed profile + * on the device. + */ + private UserHandle getManagedProfile() { + UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); + List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER); + for (UserInfo userInfo : relatedUsers) { + if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id); + } + Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE + + " has been called, but there is no managed profile"); + return null; + } +} diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java index 131f828..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.Context; 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 android.widget.SpinnerAdapter; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Map; /** * WindowDecorActionBar is the ActionBar implementation used @@ -66,7 +66,8 @@ import java.util.Map; * 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 @@ public class WindowDecorActionBar extends ActionBar { private Animator mCurrentShowAnim; private boolean mShowHideAnimationEnabled; + boolean mHideOnContentScroll; final AnimatorListener mHideListener = new AnimatorListenerAdapter() { @Override @@ -132,7 +134,7 @@ public class WindowDecorActionBar extends ActionBar { mCurrentShowAnim = null; completeDeferredDestroyActionMode(); if (mOverlayLayout != null) { - mOverlayLayout.requestFitSystemWindows(); + mOverlayLayout.requestApplyInsets(); } } }; @@ -183,7 +185,7 @@ public class WindowDecorActionBar extends ActionBar { 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 @@ public class WindowDecorActionBar extends ActionBar { 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 @@ public class WindowDecorActionBar extends ActionBar { 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 class WindowDecorActionBar extends ActionBar { } } - public void setWindowVisibility(int visibility) { + public void onWindowVisibilityChanged(int visibility) { mCurWindowVisibility = visibility; } @@ -453,6 +460,7 @@ public class WindowDecorActionBar extends ActionBar { mActionMode.finish(); } + mOverlayLayout.setHideOnContentScrollEnabled(false); mContextView.killMode(); ActionModeImpl mode = new ActionModeImpl(callback); if (mode.dispatchOnCreate()) { @@ -464,7 +472,7 @@ public class WindowDecorActionBar extends ActionBar { if (mSplitView.getVisibility() != View.VISIBLE) { mSplitView.setVisibility(View.VISIBLE); if (mOverlayLayout != null) { - mOverlayLayout.requestFitSystemWindows(); + mOverlayLayout.requestApplyInsets(); } } } @@ -652,6 +660,35 @@ public class WindowDecorActionBar extends ActionBar { } } + @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 @@ public class WindowDecorActionBar extends ActionBar { mShowListener.onAnimationEnd(null); } if (mOverlayLayout != null) { - mOverlayLayout.requestFitSystemWindows(); + mOverlayLayout.requestApplyInsets(); } } @@ -781,11 +818,7 @@ public class WindowDecorActionBar extends ActionBar { } public boolean isShowing() { - return mNowShowing; - } - - public boolean isSystemShowing() { - return !mHiddenBySystem; + return mNowShowing && getHideOffset() < getHeight(); } void animateToMode(boolean toActionMode) { @@ -844,6 +877,18 @@ public class WindowDecorActionBar extends ActionBar { mActionView.setHomeActionContentDescription(resId); } + @Override + public void onContentScrollStarted() { + if (mCurrentShowAnim != null) { + mCurrentShowAnim.cancel(); + mCurrentShowAnim = null; + } + } + + @Override + public void onContentScrollStopped() { + } + /** * @hide */ @@ -894,6 +939,7 @@ public class WindowDecorActionBar extends ActionBar { // 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 @@ public class WindowDecorActionBar extends ActionBar { 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 dcc0a4c..cba09d1 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java +++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java @@ -16,6 +16,7 @@ package com.android.internal.inputmethod; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings; import android.content.Context; @@ -119,14 +120,14 @@ public class InputMethodSubtypeSwitchingController { } } - private static class InputMethodAndSubtypeCircularList { + private static class InputMethodAndSubtypeList { private final Context mContext; // Used to load label private final PackageManager mPm; private final String mSystemLocaleStr; private final InputMethodSettings mSettings; - public InputMethodAndSubtypeCircularList(Context context, InputMethodSettings settings) { + public InputMethodAndSubtypeList(Context context, InputMethodSettings settings) { mContext = context; mSettings = settings; mPm = context.getPackageManager(); @@ -152,38 +153,6 @@ public class InputMethodSubtypeSwitchingController { } }); - public ImeSubtypeListItem getNextInputMethod( - boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) { - if (imi == null) { - return null; - } - final List<ImeSubtypeListItem> imList = - getSortedInputMethodAndSubtypeList(); - if (imList.size() <= 1) { - return null; - } - 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; - } - } - return null; - } - public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() { return getSortedInputMethodAndSubtypeList(true, false, false); } @@ -247,7 +216,38 @@ public class InputMethodSubtypeSwitchingController { private final ArrayDeque<SubtypeParams> mTypedSubtypeHistory = new ArrayDeque<SubtypeParams>(); private final Object mLock = new Object(); private final InputMethodSettings mSettings; - private InputMethodAndSubtypeCircularList mSubtypeList; + private InputMethodAndSubtypeList mSubtypeList; + + @VisibleForTesting + public static ImeSubtypeListItem getNextInputMethodImpl(List<ImeSubtypeListItem> imList, + boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) { + if (imi == null) { + return null; + } + if (imList.size() <= 1) { + return null; + } + 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; + } + } + return null; + } public InputMethodSubtypeSwitchingController(InputMethodSettings settings) { mSettings = settings; @@ -278,14 +278,15 @@ public class InputMethodSubtypeSwitchingController { public void resetCircularListLocked(Context context) { synchronized(mLock) { - mSubtypeList = new InputMethodAndSubtypeCircularList(context, mSettings); + mSubtypeList = new InputMethodAndSubtypeList(context, mSettings); } } public ImeSubtypeListItem getNextInputMethod( boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) { synchronized(mLock) { - return mSubtypeList.getNextInputMethod(onlyCurrentIme, imi, subtype); + return getNextInputMethodImpl(mSubtypeList.getSortedInputMethodAndSubtypeList(), + onlyCurrentIme, imi, subtype); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 343c507..f63fa8a 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -88,7 +88,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 103 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 104 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -319,6 +319,18 @@ public final class BatteryStatsImpl extends BatteryStats { int mDischargeAmountScreenOff; int mDischargeAmountScreenOffSinceCharge; + static final int MAX_LEVEL_STEPS = 100; + + int mLastDischargeStepLevel; + long mLastDischargeStepTime; + int mNumDischargeStepDurations; + final long[] mDischargeStepDurations = new long[MAX_LEVEL_STEPS]; + + int mLastChargeStepLevel; + long mLastChargeStepTime; + int mNumChargeStepDurations; + final long[] mChargeStepDurations = new long[MAX_LEVEL_STEPS]; + long mLastWriteTime = 0; // Milliseconds private int mBluetoothPingCount; @@ -5721,6 +5733,10 @@ public final class BatteryStatsImpl extends BatteryStats { mDischargeAmountScreenOnSinceCharge = 0; mDischargeAmountScreenOff = 0; mDischargeAmountScreenOffSinceCharge = 0; + mLastDischargeStepTime = -1; + mNumDischargeStepDurations = 0; + mLastChargeStepTime = -1; + mNumChargeStepDurations = 0; } public void resetAllStatsCmdLocked() { @@ -5885,7 +5901,10 @@ public final class BatteryStatsImpl extends BatteryStats { resetAllStatsLocked(); mDischargeStartLevel = level; reset = true; + mNumDischargeStepDurations = 0; } + mLastDischargeStepLevel = level; + mLastDischargeStepTime = -1; pullPendingStateUpdatesLocked(); mHistoryCur.batteryLevel = (byte)level; mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; @@ -5921,6 +5940,9 @@ public final class BatteryStatsImpl extends BatteryStats { } updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn); updateTimeBasesLocked(false, !mScreenOn, uptime, realtime); + mNumChargeStepDurations = 0; + mLastChargeStepLevel = level; + mLastChargeStepTime = -1; } if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) { if (mFile != null) { @@ -5944,6 +5966,24 @@ public final class BatteryStatsImpl extends BatteryStats { // This should probably be exposed in the API, though it's not critical private static final int BATTERY_PLUGGED_NONE = 0; + private static int addLevelSteps(long[] steps, int stepCount, long lastStepTime, + int numStepLevels, long elapsedRealtime) { + if (lastStepTime >= 0 && numStepLevels > 0) { + long duration = elapsedRealtime - lastStepTime; + for (int i=0; i<numStepLevels; i++) { + System.arraycopy(steps, 0, steps, 1, steps.length-1); + long thisDuration = duration / (numStepLevels-i); + duration -= thisDuration; + steps[0] = thisDuration; + } + stepCount += numStepLevels; + if (stepCount > steps.length) { + stepCount = steps.length; + } + } + return stepCount; + } + public void setBatteryState(int status, int health, int plugType, int level, int temp, int volt) { synchronized(this) { @@ -6021,6 +6061,23 @@ public final class BatteryStatsImpl extends BatteryStats { if (changed) { addHistoryRecordLocked(elapsedRealtime, uptime); } + if (onBattery) { + if (mLastDischargeStepLevel != level) { + mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations, + mNumDischargeStepDurations, mLastDischargeStepTime, + mLastDischargeStepLevel - level, elapsedRealtime); + mLastDischargeStepLevel = level; + mLastDischargeStepTime = elapsedRealtime; + } + } else { + if (mLastChargeStepLevel != level) { + mNumChargeStepDurations = addLevelSteps(mChargeStepDurations, + mNumChargeStepDurations, mLastChargeStepTime, + level - mLastChargeStepLevel, elapsedRealtime); + mLastChargeStepLevel = level; + mLastChargeStepTime = elapsedRealtime; + } + } } if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) { // We don't record history while we are plugged in and fully charged. @@ -6235,11 +6292,51 @@ public final class BatteryStatsImpl extends BatteryStats { return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which); } + private long computeTimePerLevel(long[] steps, int numSteps) { + // For now we'll do a simple average across all steps. + if (numSteps <= 0) { + return -1; + } + long total = 0; + for (int i=0; i<numSteps; i++) { + total += steps[i]; + } + return total / numSteps; + /* + long[] buckets = new long[numSteps]; + int numBuckets = 0; + int numToAverage = 4; + int i = 0; + while (i < numSteps) { + long totalTime = 0; + int num = 0; + for (int j=0; j<numToAverage && (i+j)<numSteps; j++) { + totalTime += steps[i+j]; + num++; + } + buckets[numBuckets] = totalTime / num; + numBuckets++; + numToAverage *= 2; + i += num; + } + if (numBuckets < 1) { + return -1; + } + long averageTime = buckets[numBuckets-1]; + for (i=numBuckets-2; i>=0; i--) { + averageTime = (averageTime + buckets[i]) / 2; + } + return averageTime; + */ + } + @Override public long computeBatteryTimeRemaining(long curTime) { if (!mOnBattery) { return -1; } + /* Simple implementation just looks at the average discharge per level across the + entire sample period. int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2; if (discharge < 2) { return -1; @@ -6250,14 +6347,32 @@ public final class BatteryStatsImpl extends BatteryStats { } long usPerLevel = duration/discharge; return usPerLevel * mCurrentBatteryLevel; + */ + if (mNumDischargeStepDurations < 1) { + return -1; + } + long msPerLevel = computeTimePerLevel(mDischargeStepDurations, mNumDischargeStepDurations); + if (msPerLevel <= 0) { + return -1; + } + return (msPerLevel * mCurrentBatteryLevel) * 1000; + } + + public int getNumDischargeStepDurations() { + return mNumDischargeStepDurations; + } + + public long[] getDischargeStepDurationsArray() { + return mDischargeStepDurations; } @Override public long computeChargeTimeRemaining(long curTime) { - if (true || mOnBattery) { + if (mOnBattery) { // Not yet working. return -1; } + /* Broken int curLevel = mCurrentBatteryLevel; int plugLevel = mDischargePlugLevel; if (plugLevel < 0 || curLevel < (plugLevel+1)) { @@ -6269,6 +6384,23 @@ public final class BatteryStatsImpl extends BatteryStats { } long usPerLevel = duration/(curLevel-plugLevel); return usPerLevel * (100-curLevel); + */ + if (mNumChargeStepDurations < 1) { + return -1; + } + long msPerLevel = computeTimePerLevel(mChargeStepDurations, mNumChargeStepDurations); + if (msPerLevel <= 0) { + return -1; + } + return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000; + } + + public int getNumChargeStepDurations() { + return mNumChargeStepDurations; + } + + public long[] getChargeStepDurationsArray() { + return mChargeStepDurations; } long getBatteryUptimeLocked() { @@ -6776,6 +6908,10 @@ public final class BatteryStatsImpl extends BatteryStats { mHighDischargeAmountSinceCharge = in.readInt(); mDischargeAmountScreenOnSinceCharge = in.readInt(); mDischargeAmountScreenOffSinceCharge = in.readInt(); + mNumDischargeStepDurations = in.readInt(); + in.readLongArray(mDischargeStepDurations); + mNumChargeStepDurations = in.readInt(); + in.readLongArray(mChargeStepDurations); mStartCount++; @@ -7030,6 +7166,10 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(getHighDischargeAmountSinceCharge()); out.writeInt(getDischargeAmountScreenOnSinceCharge()); out.writeInt(getDischargeAmountScreenOffSinceCharge()); + out.writeInt(mNumDischargeStepDurations); + out.writeLongArray(mDischargeStepDurations); + out.writeInt(mNumChargeStepDurations); + out.writeLongArray(mChargeStepDurations); mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS); for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) { @@ -7344,6 +7484,10 @@ public final class BatteryStatsImpl extends BatteryStats { mDischargeAmountScreenOnSinceCharge = in.readInt(); mDischargeAmountScreenOff = in.readInt(); mDischargeAmountScreenOffSinceCharge = in.readInt(); + mNumDischargeStepDurations = in.readInt(); + in.readLongArray(mDischargeStepDurations); + mNumChargeStepDurations = in.readInt(); + in.readLongArray(mChargeStepDurations); mLastWriteTime = in.readLong(); mBluetoothPingCount = in.readInt(); @@ -7464,6 +7608,10 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(mDischargeAmountScreenOnSinceCharge); out.writeInt(mDischargeAmountScreenOff); out.writeInt(mDischargeAmountScreenOffSinceCharge); + out.writeInt(mNumDischargeStepDurations); + out.writeLongArray(mDischargeStepDurations); + out.writeInt(mNumChargeStepDurations); + out.writeLongArray(mChargeStepDurations); out.writeLong(mLastWriteTime); out.writeInt(getBluetoothPingCount()); 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 @@ public class Preconditions { * @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 @@ public class Preconditions { * @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 @@ public class Preconditions { * @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 @@ public class Preconditions { * 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/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 @@ public class ActionBarOverlayLayout extends ViewGroup { 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 @@ public class ActionBarOverlayLayout extends ViewGroup { 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 @@ public class ActionBarOverlayLayout extends ViewGroup { 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 @@ public class ActionBarOverlayLayout extends ViewGroup { mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.KITKAT; + + mFlingEstimator = new OverScroller(context); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + haltActionBarHideOffsetAnimations(); } - public void setActionBar(WindowDecorActionBar impl) { - mActionBar = impl; + 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 @@ public class ActionBarOverlayLayout extends ViewGroup { 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 @@ public class ActionBarOverlayLayout extends ViewGroup { 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 @@ public class ActionBarOverlayLayout extends ViewGroup { 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 @@ public class ActionBarOverlayLayout extends ViewGroup { // 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 @@ public class ActionBarOverlayLayout extends ViewGroup { 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 @@ public class ActionBarOverlayLayout extends ViewGroup { 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 @@ import android.widget.FrameLayout; 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 @@ public class SwipeDismissLayout extends FrameLayout { private OnDismissedListener mDismissedListener; private OnSwipeProgressChangedListener mProgressListener; + private float mLastX; + public SwipeDismissLayout(Context context) { super(context); init(context); @@ -95,7 +97,7 @@ public class SwipeDismissLayout extends FrameLayout { 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 @@ public class SwipeDismissLayout extends FrameLayout { 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 @@ public class SwipeDismissLayout extends FrameLayout { 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 711f28a..667bf6c 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -61,6 +61,7 @@ LOCAL_SRC_FILES:= \ android_view_MotionEvent.cpp \ android_view_PointerIcon.cpp \ android_view_RenderNode.cpp \ + android_view_RenderNodeAnimator.cpp \ android_view_VelocityTracker.cpp \ android_text_AndroidCharacter.cpp \ android_text_AndroidBidi.cpp \ @@ -91,6 +92,7 @@ LOCAL_SRC_FILES:= \ 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 \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index aa635c6..66fbb8e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -105,6 +105,7 @@ extern int register_android_content_StringBlock(JNIEnv* env); 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); @@ -120,6 +121,7 @@ extern int register_android_graphics_Xfermode(JNIEnv* env); extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env); extern int register_android_view_DisplayEventReceiver(JNIEnv* env); extern int register_android_view_RenderNode(JNIEnv* env); +extern int register_android_view_RenderNodeAnimator(JNIEnv* env); extern int register_android_view_GraphicBuffer(JNIEnv* env); extern int register_android_view_GLES20Canvas(JNIEnv* env); extern int register_android_view_GLRenderer(JNIEnv* env); @@ -1193,6 +1195,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_graphics_Graphics), REG_JNI(register_android_view_DisplayEventReceiver), REG_JNI(register_android_view_RenderNode), + REG_JNI(register_android_view_RenderNodeAnimator), REG_JNI(register_android_view_GraphicBuffer), REG_JNI(register_android_view_GLES20Canvas), REG_JNI(register_android_view_GLRenderer), @@ -1219,6 +1222,7 @@ static const RegJNIRec gRegJNI[] = { 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/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp index 799782d..6591d60 100644 --- a/core/jni/android/graphics/YuvToJpegEncoder.cpp +++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp @@ -226,16 +226,17 @@ static jboolean YuvImage_compressToJpeg(JNIEnv* env, jobject, jbyteArray inYuv, jint* imgOffsets = env->GetIntArrayElements(offsets, NULL); jint* imgStrides = env->GetIntArrayElements(strides, NULL); YuvToJpegEncoder* encoder = YuvToJpegEncoder::create(format, imgStrides); - if (encoder == NULL) { - return JNI_FALSE; + jboolean result = JNI_FALSE; + if (encoder != NULL) { + encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality); + delete encoder; + result = JNI_TRUE; } - encoder->encode(strm, yuv, width, height, imgOffsets, jpegQuality); - delete encoder; env->ReleaseByteArrayElements(inYuv, yuv, 0); env->ReleaseIntArrayElements(offsets, imgOffsets, 0); env->ReleaseIntArrayElements(strides, imgStrides, 0); - return JNI_TRUE; + return result; } /////////////////////////////////////////////////////////////////////////////// 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 @@ static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyN 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 @@ static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyN 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 @@ static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyN 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; - 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; + 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]; + + 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 (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_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 @@ static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thi 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 @@ static jint android_media_AudioTrack_write_short(JNIEnv *env, jobject thiz, 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*/); + + //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 /= 2; + 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_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index ef5ebd0..3aa179d 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> @@ -544,6 +545,16 @@ static void android_view_GLES20Canvas_drawCircle(JNIEnv* env, jobject clazz, 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) { @@ -1041,6 +1052,7 @@ static JNINativeMethod gMethods[] = { { "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_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp index c83541d..7ae21a7 100644 --- a/core/jni/android_view_KeyEvent.cpp +++ b/core/jni/android_view_KeyEvent.cpp @@ -22,6 +22,7 @@ #include <android_runtime/Log.h> #include <utils/Log.h> #include <input/Input.h> +#include <ScopedUtfChars.h> #include "android_view_KeyEvent.h" namespace android { @@ -102,20 +103,25 @@ status_t android_view_KeyEvent_recycle(JNIEnv* env, jobject eventObj) { return OK; } -static jboolean native_isSystemKey(JNIEnv* env, jobject clazz, jint keyCode) { - return KeyEvent::isSystemKey(keyCode); +static jstring android_view_KeyEvent_nativeKeyCodeToString(JNIEnv* env, jobject clazz, + jint keyCode) { + return env->NewStringUTF(KeyEvent::getLabel(keyCode)); } -static jboolean native_hasDefaultAction(JNIEnv* env, jobject clazz, jint keyCode) { - return KeyEvent::hasDefaultAction(keyCode); +static jint android_view_KeyEvent_nativeKeyCodeFromString(JNIEnv* env, jobject clazz, + jstring label) { + ScopedUtfChars keyLabel(env, label); + return KeyEvent::getKeyCodeFromLabel(keyLabel.c_str()); } // ---------------------------------------------------------------------------- static const JNINativeMethod g_methods[] = { - { "native_isSystemKey", "(I)Z", (void*)native_isSystemKey }, - { "native_hasDefaultAction", "(I)Z", (void*)native_hasDefaultAction }, + { "nativeKeyCodeToString", "(I)Ljava/lang/String;", + (void*)android_view_KeyEvent_nativeKeyCodeToString}, + { "nativeKeyCodeFromString", "(Ljava/lang/String;)I", + (void*)android_view_KeyEvent_nativeKeyCodeFromString}, }; #define FIND_CLASS(var, className) \ diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 76e145b..6ae02e0 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -23,6 +23,7 @@ #include <android_runtime/Log.h> #include <utils/Log.h> #include <input/Input.h> +#include <ScopedUtfChars.h> #include "android_os_Parcel.h" #include "android_view_MotionEvent.h" #include "android_util_Binder.h" @@ -724,6 +725,17 @@ static void android_view_MotionEvent_nativeWriteToParcel(JNIEnv* env, jclass cla } } +static jstring android_view_MotionEvent_nativeAxisToString(JNIEnv* env, jclass clazz, + jint axis) { + return env->NewStringUTF(MotionEvent::getLabel(static_cast<int32_t>(axis))); +} + +static jint android_view_MotionEvent_nativeAxisFromString(JNIEnv* env, jclass clazz, + jstring label) { + ScopedUtfChars axisLabel(env, label); + return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str())); +} + // ---------------------------------------------------------------------------- static JNINativeMethod gMotionEventMethods[] = { @@ -840,6 +852,10 @@ static JNINativeMethod gMotionEventMethods[] = { { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)android_view_MotionEvent_nativeWriteToParcel }, + { "nativeAxisToString", "(I)Ljava/lang/String;", + (void*)android_view_MotionEvent_nativeAxisToString }, + { "nativeAxisFromString", "(Ljava/lang/String;)I", + (void*)android_view_MotionEvent_nativeAxisFromString }, }; #define FIND_CLASS(var, className) \ diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 3ad2ae5..4715c26 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -23,6 +23,7 @@ #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> +#include <Animator.h> #include <DisplayListRenderer.h> #include <RenderNode.h> @@ -438,6 +439,25 @@ static jfloat android_view_RenderNode_getPivotY(JNIEnv* env, return renderNode->stagingProperties().getPivotY(); } +// ---------------------------------------------------------------------------- +// RenderProperties - Animations +// ---------------------------------------------------------------------------- + +static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz, + jlong renderNodePtr, jlong animatorPtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr); + renderNode->addAnimator(animator); +} + +static void android_view_RenderNode_removeAnimator(JNIEnv* env, jobject clazz, + jlong renderNodePtr, jlong animatorPtr) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr); + renderNode->removeAnimator(animator); +} + + #endif // USE_OPENGL_RENDERER // ---------------------------------------------------------------------------- @@ -513,6 +533,9 @@ static JNINativeMethod gMethods[] = { { "nGetPivotX", "(J)F", (void*) android_view_RenderNode_getPivotX }, { "nGetPivotY", "(J)F", (void*) android_view_RenderNode_getPivotY }, + + { "nAddAnimator", "(JJ)V", (void*) android_view_RenderNode_addAnimator }, + { "nRemoveAnimator", "(JJ)V", (void*) android_view_RenderNode_removeAnimator }, #endif }; diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp new file mode 100644 index 0000000..3be013b --- /dev/null +++ b/core/jni/android_view_RenderNodeAnimator.cpp @@ -0,0 +1,180 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include "jni.h" +#include "GraphicsJNI.h" +#include <nativehelper/JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> + +#include <Animator.h> +#include <Interpolator.h> +#include <RenderProperties.h> + +namespace android { + +using namespace uirenderer; + +static struct { + jclass clazz; + + jmethodID callOnFinished; +} gRenderNodeAnimatorClassInfo; + +#ifdef USE_OPENGL_RENDERER + +static JNIEnv* getEnv(JavaVM* vm) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + return 0; + } + return env; +} + +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); + } + + virtual ~AnimationListenerBridge() { + JNIEnv* env = getEnv(mJvm); + env->DeleteGlobalRef(mWeakThis); + mWeakThis = NULL; + } + + virtual void onAnimationFinished(BaseAnimator*) { + JNIEnv* env = getEnv(mJvm); + env->CallStaticVoidMethod( + gRenderNodeAnimatorClassInfo.clazz, + gRenderNodeAnimatorClassInfo.callOnFinished, + mWeakThis); + } + +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); +} + +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"); + BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr); + animator->setDuration(duration); +} + +static void unref(JNIEnv* env, jobject clazz, jlong objPtr) { + VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr); + obj->decStrong(0); +} + +#endif + +// ---------------------------------------------------------------------------- +// JNI Glue +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "android/view/RenderNodeAnimator"; + +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 +}; + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); + +#define GET_STATIC_METHOD_ID(var, clazz, methodName, methodDescriptor) \ + var = env->GetStaticMethodID(clazz, methodName, methodDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find method " methodName); + +int register_android_view_RenderNodeAnimator(JNIEnv* env) { + FIND_CLASS(gRenderNodeAnimatorClassInfo.clazz, kClassPathName); + gRenderNodeAnimatorClassInfo.clazz = jclass(env->NewGlobalRef(gRenderNodeAnimatorClassInfo.clazz)); + + GET_STATIC_METHOD_ID(gRenderNodeAnimatorClassInfo.callOnFinished, gRenderNodeAnimatorClassInfo.clazz, + "callOnFinished", "(Ljava/lang/ref/WeakReference;)V"); + + return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); +} + + +} // namespace android diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index b5f489d..564c9a6 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "ThreadedRenderer" +#include <algorithm> + #include "jni.h" #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> @@ -24,6 +26,8 @@ #include <android_runtime/android_view_Surface.h> #include <system/window.h> +#include <Animator.h> +#include <RenderNode.h> #include <renderthread/RenderProxy.h> #include <renderthread/RenderTask.h> #include <renderthread/RenderThread.h> @@ -63,15 +67,83 @@ private: 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<OnFinishedEvent>& events) { + mOnFinishedEvents.swap(events); + } + + static void callOnFinished(OnFinishedEvent& event) { + event.listener->onAnimationFinished(event.animator.get()); + } + + virtual void handleMessage(const Message& message) { + std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished); + mOnFinishedEvents.clear(); + } + +private: + std::vector<OnFinishedEvent> mOnFinishedEvents; +}; + +class RootRenderNode : public RenderNode, public AnimationHook { +public: + RootRenderNode() : RenderNode() { + mLooper = Looper::getForThread(); + LOG_ALWAYS_FATAL_IF(!mLooper.get(), + "Must create RootRenderNode on a thread with a looper!"); + } + + virtual ~RootRenderNode() {} + + virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) { + OnFinishedEvent event(animator, listener); + mOnFinishedEvents.push_back(event); + } + + virtual void prepareTree(TreeInfo& info) { + info.animationHook = this; + RenderNode::prepareTree(info); + info.animationHook = NULL; + + // post all the finished stuff + if (mOnFinishedEvents.size()) { + sp<InvokeAnimationListeners> message + = new InvokeAnimationListeners(mOnFinishedEvents); + mLooper->sendMessage(message, 0); + } + } + +private: + sp<Looper> mLooper; + std::vector<OnFinishedEvent> mOnFinishedEvents; +}; + static void android_view_ThreadedRenderer_postToRenderThread(JNIEnv* env, jobject clazz, jobject jrunnable) { RenderTask* task = new JavaTask(env, jrunnable); RenderThread::getInstance().queue(task); } +static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) { + RootRenderNode* node = new RootRenderNode(); + node->incStrong(0); + node->setName("RootRenderNode"); + return reinterpret_cast<jlong>(node); +} + static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz, - jboolean translucent) { - return (jlong) new RenderProxy(translucent); + jboolean translucent, jlong rootRenderNodePtr) { + RenderNode* rootRenderNode = reinterpret_cast<RenderNode*>(rootRenderNodePtr); + return (jlong) new RenderProxy(translucent, rootRenderNode); } static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz, @@ -113,12 +185,11 @@ static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, proxy->setup(width, height); } -static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz, - jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop, +static void android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz, + jlong proxyPtr, jint dirtyLeft, jint dirtyTop, jint dirtyRight, jint dirtyBottom) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); - proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); + proxy->syncAndDrawFrame(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); } static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz, @@ -187,13 +258,14 @@ const char* const kClassPathName = "android/view/ThreadedRenderer"; static JNINativeMethod gMethods[] = { #ifdef USE_OPENGL_RENDERER { "postToRenderThread", "(Ljava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_postToRenderThread }, - { "nCreateProxy", "(Z)J", (void*) android_view_ThreadedRenderer_createProxy }, + { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode }, + { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy }, { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, { "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 }, - { "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList }, + { "nSyncAndDrawFrame", "(JIIII)V", (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/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index a61fa87..c58bf04 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -92,14 +92,10 @@ static void SigChldHandler(int /*signal_number*/) { if (WIFEXITED(status)) { if (WEXITSTATUS(status)) { ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status)); - } else if (false) { - ALOGI("Process %d exited cleanly (%d)", pid, WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { if (WTERMSIG(status) != SIGKILL) { - ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status)); - } else if (false) { - ALOGI("Process %d exited cleanly (%d)", pid, WTERMSIG(status)); + ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status)); } #ifdef WCOREDUMP if (WCOREDUMP(status)) { @@ -117,8 +113,10 @@ static void SigChldHandler(int /*signal_number*/) { } } - if (pid < 0) { - ALOGW("Zygote SIGCHLD error in waitpid: %d", errno); + // Note that we shouldn't consider ECHILD an error because + // the secondary zygote might have no children left to wait for. + if (pid < 0 && errno != ECHILD) { + ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno)); } } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4f093a8..241500a 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 @@ -2681,6 +2681,26 @@ <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> + <activity android:name="com.android.internal.app.IntentForwarderActivity" + android:finishOnCloseSystemDialogs="true" + android:theme="@style/Theme.NoDisplay" + android:excludeFromRecents="true" + android:label="@string/user_owner_label" + android:exported="true" + > + </activity> + <activity-alias android:name="com.android.internal.app.ForwardIntentToUserOwner" + android:targetActivity="com.android.internal.app.IntentForwarderActivity" + android:icon="@drawable/personal_icon" + android:exported="true" + android:label="@string/user_owner_label"> + </activity-alias> + <activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile" + android:targetActivity="com.android.internal.app.IntentForwarderActivity" + android:icon="@drawable/work_icon" + android:exported="true" + android:label="@string/managed_profile_label"> + </activity-alias> <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity" android:theme="@style/Theme.Holo.Dialog" android:label="@string/heavy_weight_switcher_title" @@ -2773,7 +2793,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/drawable-hdpi/personal_icon.png b/core/res/res/drawable-hdpi/personal_icon.png Binary files differnew file mode 100644 index 0000000..8d96b5e --- /dev/null +++ b/core/res/res/drawable-hdpi/personal_icon.png diff --git a/core/res/res/drawable-hdpi/work_icon.png b/core/res/res/drawable-hdpi/work_icon.png Binary files differnew file mode 100644 index 0000000..e90866b --- /dev/null +++ b/core/res/res/drawable-hdpi/work_icon.png 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/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index db4092e..20d306d 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Titelloos>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 de89ec6..04bfee5 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<ርዕስ አልባ>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"የአውሮፕላን ሁነታ"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"የአውሮፕላንሁነታ በርቷል"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"የአውሮፕላንሁነታ ጠፍቷል"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"ቅንብሮች"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string> <string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string> @@ -388,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"የVPN ግልጋሎትን ወደ ከፍተኛ-ደረጃ በየነ ገጽ ለማሳር ለመያዣው ይፈቅዳሉ፡፡ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"በልጣፍ ጠርዝ"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ያዡ ግቤት ስልቱን ወደ ከፍተኛ-ደረጃ ልጣፍ ለመጠረዝ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ከአንድ የድምጽ በይነተገናኝ ጋር ይሰሩ"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"ያዢው የአንድ የድምጽ በይነግንኙነት አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ከአንድ የርቀት ማሳያ ጋር ይጠርዛል"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ያዢው ከአንድ የርቀት ማሳያ ከፍተኛ-ደረጃ በይነገጽ ጋር እንዲጠርዝ ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ወደ ፍርግም አገልግሎት አያይዝ"</string> @@ -700,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"መተግበሪያው ማሳወቂያዎችን እንዲያስመጣ፣ እንዲመረምር እና እንዲያጸዳ ያስችለዋል፣ በሌሎች መተግበሪያዎች የተለጠፉትንም ጨምሮ።"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ከአንድ የማሳወቂያ አዳማጭ አገልግሎት ጋር ይሰሩ"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ያዢው የማሳወቂያ አዳማጭ አገልግሎቱን ከከፍተኛ-ደረጃ በይነገጹ ጋር እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ከአንድ የሁኔታ አቅራቢ አገልግሎት ጋር ይሰሩ"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"ያዢው የአንድ የሁኔታ አቅራቢ አገልግሎት የከፍተኛ ደረጃ በይነገጽ እንዲያስር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን መጥራት"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን ያዳምጣል"</string> @@ -1370,6 +1395,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> + <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 2ee49bd..83168e4 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<بلا عنوان>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"للسماح للمالك بالالتزام بواجهة المستوى العلوي لخدمة الشبكة الظاهرية الخاصة (VPN). لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"الالتزام بخلفية ما"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للخلفية. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"الربط بخدمة التفاعل الصوتي"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة التفاعل الصوتي. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"الربط بالشاشة عن بُعد"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"للسماح للمالك بالالتزام بواجهة المستوى العلوي للعرض عن بُعد. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"الالتزام بخدمة أداة"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"يتيح للتطبيق استرجاع الإشعارات وفحصها ومسحها، بما في ذلك تلك التي نشرتها تطبيقات أخرى."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"الربط بخدمة تلقّي الإشعارات الصوتية"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"يتيح للمالك الربط بواجهة المستوى العلوي لخدمة تلقّي الإشعارات الصوتية. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"الربط بخدمة موفر الحالة"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"للسماح للمالك بالربط بواجهة المستوى العلوي لخدمة موفر الحالة. لن تكون هناك حاجة إلى هذا الإعداد مطلقًا مع التطبيقات العادية."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"استدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"الاستماع إلى ملاحظات حول أحوال الشبكة"</string> @@ -1369,6 +1395,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> + <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 3f00f1f..2d22cdc 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Без заглавие>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Самолетен режим"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Самолетният режим е ВКЛЮЧЕН"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Самолетният режим е ИЗКЛЮЧЕН"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string> <string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string> @@ -388,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на услуга за VPN. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"обвързване с тапет"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Разрешава на притежателя да се обвърже с интерфейса от най-високото ниво на тапет. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"свързване с услуга за гласово взаимодействие"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за гласово взаимодействие. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"свързване с отдалечен екран"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Разрешава на притежателя да се свърже с интерфейса от първо ниво на отдалечен екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обвързване с услуга за приспособления"</string> @@ -700,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Разрешава на приложението да извлича, преглежда и изчиства известия, включително публикуваните от други приложения."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"обвързване с услуга за слушател на известия"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Разрешава на притежателя да се обвърже с интерфейса от първо ниво на услуга за слушател на известия. Нормалните приложения не би трябвало никога да се нуждаят от това."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"свързване с услуга за предоставяне на условия"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Разрешава на притежателя да се свърже с интерфейса от най-високото ниво на услуга за предоставяне на условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"извикване на предоставеното от оператора приложение за конфигуриране"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Разрешава на притежателя да извиква предоставеното от оператора приложение за конфигуриране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"слушане за наблюдения на мрежовите условия"</string> @@ -1370,6 +1395,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> + <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 afb0852..cfb77d3 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Sense títol>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"vinculació amb una eina d\'interacció de veu"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Permet que el titular es vinculi 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> @@ -699,6 +723,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> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"vinculació amb el servei d\'un proveïdor de condicions"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Permet que el titular es vinculi amb la interfície de nivell superior del servei d\'un 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> @@ -709,14 +735,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> @@ -726,7 +752,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"> @@ -1369,6 +1395,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> + <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 39c6c08..868f899 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Bez názvu>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V letadle"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V letadle je ZAPNUTÝ"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V letadle je VYPNUTÝ"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Nastavení"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string> <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string> @@ -388,6 +409,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> + <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> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 c06ecbb..206db12 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Uden titel>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 e1ee025..87d4aa0 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Unbenannt>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"An einen Bedingungsanbieterdienst binden"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Ermöglicht dem Inhaber, sich an die Oberfläche eines Bedingungsanbieterdienstes 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> @@ -1369,6 +1395,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> + <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Bedingungsanbieter"</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 5af0277..9105cb2 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Χωρίς τίτλο>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας Vpn. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"δέσμευση σε ταπετσαρία"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας ταπετσαρίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"σύνδεση σε παράγοντα φωνητικής αλληλεπίδρασης"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας φωνητικής αλληλεπίδρασης. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"μεταφορά σε μια απομακρυσμένη οθόνη"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας απομακρυσμένης οθόνης. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"δέσμευση σε υπηρεσία γραφικών στοιχείων"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Επιτρέπει στην εφαρμογή να ανακτά, να εξετάζει και να απαλείφει ειδοποιήσεις, συμπεριλαμβανομένων εκείνων που δημοσιεύονται από άλλες εφαρμογές."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"δέσμευση σε υπηρεσία ακρόασης ειδοποίησης"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ακρόασης ειδοποιήσεων. Δεν απαιτείται σε κανονικές εφαρμογές."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"σύνδεση σε μια υπηρεσία παρόχου συνθηκών"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Επιτρέπει στον κάτοχο τη σύνδεση στη διεπαφή ανωτάτου επιπέδου ενός παρόχου συνθηκών. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"λήψη παρατηρήσεων σχετικά με την κατάσταση δικτύου"</string> @@ -1369,6 +1395,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> + <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 ad45887..51a85e3 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Untitled>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Settings"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string> <string name="android_system_label" msgid="6577375335728551336">"Android System"</string> @@ -388,6 +409,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> + <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> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 ad45887..51a85e3 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Untitled>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Aeroplane mode"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Aeroplane mode is ON"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Aeroplane mode is OFF"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Settings"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string> <string name="android_system_label" msgid="6577375335728551336">"Android System"</string> @@ -388,6 +409,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> + <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> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 6d032ca..2a4f7e9 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Sin título>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 63bed24..2e0d68b 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Sin título>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"..."</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 00e4a20..32abeb8 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Pealkirjata>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥."</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lennurežiim"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lennurežiim on SEES"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lennurežiim on VÄLJAS"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Seaded"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string> <string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string> @@ -388,6 +409,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> + <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> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 42d654e..c5abcbd 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<بدون عنوان>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"حالت هواپیما"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"حالت هواپیما روشن است"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"حالت هواپیما خاموش است"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"تنظیمات"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string> <string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string> <string name="android_system_label" msgid="6577375335728551336">"سیستم Android"</string> @@ -388,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"به دارنده اجازه میدهد که به رابط سطح بالای سرویس Vpn متصل شود. هرگز برای برنامههای معمولی مورد نیاز نیست."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"پیوند شده به تصویر زمینه"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"به دارنده اجازه میدهد تا به رابط سطح بالای تصویر زمینه متصل شود. برنامههای معمولی هرگز به این ویژگی نیاز ندارند."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"مقید بودن به سرویس تعامل صوتی"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"به دارنده امکان میدهد به واسط سطح بالای سرویس تعامل صوتی مقید باشد. برای برنامههای عادی هرگز نباید لازم باشد."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"اتصال به نمایشگر راه دور"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"به دارنده امکان میدهد تا به رابط سطح بالای نمایشگر راه دور وصل شود. نباید هرگز برای برنامههای عادی لازم باشد."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"اتصال به یک سرویس ابزارک"</string> @@ -700,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"به برنامه اجازه میدهد به بازیابی، بررسی و پاک کردن اعلانها از جمله موارد پست شده توسط سایر برنامهها بپردازد."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"اتصال به یک سرویس شنونده اعلان"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"به دارنده اجازه میدهد به یک رابط سطح بالای سرویس شنونده اعلان متصل شود. هرگز نباید برای برنامههای عادی لازم شود."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"مقید بودن به سرویس ارائهدهنده وضعیت"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"به دارنده امکان میدهد تا به واسط سطح بالای سرویس ارائهدهنده وضعیت مقید باشد. برای برنامههای عادی هرگز نباید لازم باشد."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"لغو برنامه پیکربندی ارائه شده توسط شرکت مخابراتی"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"به دارنده اجازه میدهد که تنظیمات برنامه شرکت مخابراتی را لغو کند. هرگز برای برنامههای معمولی مورد نیاز نیست."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"گوش دادن برای بررسی شرایط شبکه"</string> @@ -1370,6 +1395,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> + <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 7698dda..945c7ab 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Nimetön>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Lentokonetila"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Lentokonetila on KÄYTÖSSÄ"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Lentokonetila on POIS KÄYTÖSTÄ"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Asetukset"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string> <string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string> @@ -388,6 +409,10 @@ <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_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> @@ -700,6 +725,10 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Antaa sovelluksen noutaa, tutkia ja tyhjentää ilmoituksia (myös muiden sovelluksien lähettämiä)."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sido ilmoituskuuntelijapalveluun"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Antaa sovelluksen sitoutua ilmoituskuuntelijan ylimmän tason käyttöliittymään. Ei tavallisten sovelluksien käyttöön."</string> + <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) --> + <skip /> + <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) --> + <skip /> <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> @@ -1370,6 +1399,8 @@ <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="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 cc3bcd2..c917749 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Sans_titre>"</string> <string name="ellipsis" msgid="7899829516048813237">"..."</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1284,11 +1310,11 @@ <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Si vous activez la mémoire de stockage USB, certaines applications en cours d\'utilisation vont être fermées et risquent de rester indisponibles jusqu\'à ce que la mémoire de stockage USB soit désactivée."</string> <string name="dlg_error_title" msgid="7323658469626514207">"Échec du fonctionnement de la mémoire de stockage USB."</string> <string name="dlg_ok" msgid="7376953167039865701">"OK"</string> - <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connecté en tant qu\'appareil multimédia"</string> + <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connecté en tant qu\'app. multimédia"</string> <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connecté en tant qu\'appareil photo"</string> <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connecté en tant que programme d\'installation"</string> <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connecté à un accessoire USB"</string> - <string name="usb_notification_message" msgid="2290859399983720271">"Appuyez ici pour accéder aux autres options USB."</string> + <string name="usb_notification_message" msgid="2290859399983720271">"Appuyez pour accéder aux autres options USB."</string> <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Formater mémoire?"</string> <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Formater la carte SD?"</string> <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Tous les fichiers stockés sur la mémoire de stockage USB vont être effacés. Cette action est irréversible."</string> @@ -1369,6 +1395,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> + <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 30c7767..9359606 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Sans nom>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mode Avion"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Le mode Avion est activé."</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Le mode Avion est désactivé."</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Paramètres"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string> <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string> <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string> @@ -388,6 +409,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> + <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> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 852215f..3d5f4df 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<शीर्षक-रहित>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"धारक को किसी Vpn सेवा के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"वॉलपेपर से आबद्ध करें"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"धारक को किसी वॉलपेपर के शीर्ष-स्तर इंटरफ़ेस से आबद्ध होने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"किसी ध्वनि सहभागिताकर्ता से आबद्ध हों"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"धारक को किसी ध्वनि सहभागिता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"रिमोट डिस्प्ले से आबद्ध करें"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"धारक को किसी रिमोट डिस्प्ले के शीर्ष-स्तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"किसी विजेट सेवा से आबद्ध करें"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप्स को सूचनाओं को प्राप्त करने, जांच करने, और साफ़ करने देता है, जिनमें अन्य ऐप्स के द्वारा पोस्ट की गई सूचनाएं भी शामिल हैं."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को सूचना श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"किसी स्थिति प्रदाता सेवा से आबद्ध हों"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"धारक को किसी स्थिति प्रदाता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन ऐप्स प्रारंभ करें"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन ऐप्स प्रारंभ करने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"नेटवर्क स्थितियों के अवलोकनों को सुनें"</string> @@ -1369,6 +1395,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> + <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 4ab25af..a195512 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Bez naslova>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Način rada u zrakoplovu"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uključen je način rada u zrakoplovu"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Isključen je način rada u zrakoplovu"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Postavke"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string> <string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string> @@ -388,6 +409,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> + <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> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 cc47d26..6e82bb8 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Névtelen>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 34bebb2..12e5fdb 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Անանուն>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռային ռեժիմ"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռային ռեժիմը միացված է"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռային ռեժիմը անջատված է"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Կարգավորումներ"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string> <string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string> @@ -388,6 +409,10 @@ <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_bindRemoteDisplay" msgid="1782923938029941960">"միանալ հեռակա էկրանին"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Թույլ է տալիս սեփականատիրոջը միանալ հեռակա էկրանի վերին մակարդակի ինտերֆեյսին: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"միանալ վիջեթ ծառայությանը"</string> @@ -700,6 +725,10 @@ <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_invokeCarrierSetup" msgid="3699600833975117478">"գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Թույլ է տալիս սեփականատիրոջը գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"լսել դիտարկումներ ցանցային պայմանների վերաբերյալ"</string> @@ -1370,6 +1399,8 @@ <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="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 1100bd0..2fb00bb 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Tanpa judul>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 243dd15..af8ed3f 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Senza nome>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 537aac6..0157f74 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">">ללא כותרת<"</string> <string name="ellipsis" msgid="7899829516048813237">"..."</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"מאפשר למשתמש לבצע איגוד לממשק ברמה עליונה של שירות VPN. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"קשור לטפט"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"מאפשר למשתמש לבצע איגוד לממשק הרמה העליונה של טפט. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"איגוד לשירות אינטראקציה קולית"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות אינטראקציה קולית. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"איגוד לצג מרוחק"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של צג רחוק. לעולם אינה אמורה להיות נחוצה לאפליקציות רגילות."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"הכפפה לשירות Widget"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"מאפשר לאפליקציה לאחזר, לבדוק ולמחוק התראות, כולל כאלה שפורסמו על ידי אפליקציות אחרות."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"איגוד לשירות של מאזין להתראות"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"הרשאה זו מאפשרת למשתמש לבצע איגוד לממשק הרמה העליונה של שירות מאזין להתראות. הרשאה זו אף פעם אינה נחוצה לאפליקציות רגילים."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"איגוד לשירות ספק תנאי"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות ספק תנאי. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"הפעלה של אפליקציית תצורה שסופקה על ידי ספק"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"קליטת מעקב אחר תנאי רשת"</string> @@ -1369,6 +1395,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> + <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 e334773..a9c5cfb 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<新規>"</string> <string name="ellipsis" msgid="7899829516048813237">"..."</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"機内モード"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"機内モードON"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"機内モードOFF"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"設定"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string> <string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string> @@ -388,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"VPNサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"壁紙にバインド"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"壁紙のトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"音声対話サービスへのバインド"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"音声対話サービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"リモートディスプレイへのバインド"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"リモートディスプレイのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ウィジェットサービスにバインド"</string> @@ -700,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"通知(他のアプリから投稿されたものも含む)を取得、調査、クリアすることをアプリに許可します。"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"通知リスナーサービスにバインド"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"通知リスナーサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"コンディションプロバイダサービスへのバインド"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"コンディションプロバイダサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"携帯通信会社が提供する設定アプリの呼び出し"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"携帯通信会社が提供する設定アプリを呼び出すことを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ネットワーク状況監視のためのリッスン"</string> @@ -1370,6 +1395,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> + <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 b6856c6..e5ec81b 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"უსათაურო"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"თვითმფრინავის რეჟიმი"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"თვითმფრინავის რეჟიმი ჩართულია."</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"თვითმფრინავის რეჟიმი გამორთულია."</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"პარამეტრები"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string> <string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string> @@ -388,6 +409,10 @@ <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_bindRemoteDisplay" msgid="1782923938029941960">"დისტანციურ მონიტორზე მიბმა"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"მფლობელს შეეძლება მიებას დისტანციურ მონიტორის ზედა დონის ინტერფეისს. ჩვეულებრივ აპს ეს წესით არასოდეს უნდა დაჭირდეს."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ვიჯეტ სერვისთან დაკავშირება"</string> @@ -700,6 +725,10 @@ <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_invokeCarrierSetup" msgid="3699600833975117478">"ოპერატორის მიერ მოწოდებული კოფიგურაციის აპის გამოხმობა"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"საშუალებას აძლევს მფლობელს გამოიწვიოს ოპერატორის მიერ მოწოდებული კონფიგურაციის აპი. ჩვეულებრივ აპს ეს წესით არასოდეს არ უნდა დაჭირდეს."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"განხორციელდეს ქსელის მდგომარეობის მონიტორინგი"</string> @@ -1370,6 +1399,8 @@ <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="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 bac95d5..e9a021c 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<គ្មានចំណងជើង>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្ម Vpn ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ចងទៅផ្ទាំងរូបភាព"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃផ្ទាំងរូបភាព។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"ភ្ជាប់ទៅអ្នកសហការសំឡេង"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលរបស់សេវាកម្មអន្តរកម្មសំឡេង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ភ្ជាប់ទៅការបង្ហាញពីចម្ងាយ"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលនៃការបង្ហាញពីចម្ងាយ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ចងសេវាកម្មធាតុក្រាហ្វិក"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ឲ្យកម្មវិធីទៅយក ពិនិត្យ និងសម្អាតការជូនដំណឹង រួមមានប្រកាសដោយកម្មវិធីផ្សេងៗ។"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ចងទៅសេវាកម្មស្ដាប់ការជូនដំណឹង"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"ឲ្យម្ចាស់ចងចំណុចប្រទាក់កម្រិតកំពូលនៃសេវាកម្មកម្មវិធីស្ដាប់ការជូនដំណឹង។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"ភ្ជាប់ទៅសេវាកម្មក្រុមហ៊ុនផ្ដល់លក្ខខណ្ឌ"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"អនុញ្ញាតឲ្យម្ចាស់ភ្ជាប់ទៅចំណុចប្រទាក់កម្រិតកំពូលរបស់សេវាកម្មក្រុមហ៊ុនផ្ដល់លក្ខខណ្ឌ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"ដកហូតកម្មវិធីកំណត់រចនាសម្ព័ន្ធដែលបានផ្ដល់ដោយក្រុមហ៊ុនបញ្ជូន"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"អនុញ្ញាតឲ្យម្ចាស់ដកហូតកម្មវិធីកំណត់រចនាសម្ព័ន្ធដែលបានផ្ដល់ដោយក្រុមហ៊ុនបញ្ជូន។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"សង្កេតមើលលើលក្ខខណ្ឌបណ្ដាញ"</string> @@ -1369,6 +1395,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> + <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 7b064a3..7c6feba 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<제목 없음>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"비행기 모드"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"비행기 모드 사용중"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"비행기 모드 사용중이 아님"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"설정"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string> <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string> @@ -388,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"권한을 가진 프로그램이 VPN 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"배경화면 연결"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"권한을 가진 프로그램이 배경화면에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"음성 상호작용 서비스 사용"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"권한을 가진 프로그램이 음성 상호작용 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"원격 디스플레이에 연결"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"권한을 가진 프로그램이 원격 디스플레이에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"위젯 서비스와 연결"</string> @@ -700,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"앱이 다른 앱에서 게시한 알림을 비롯하여 알림을 검색하고 살펴보며 삭제할 수 있도록 허용합니다."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"알림 수신기 서비스 사용"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"권한을 가진 프로그램이 알림 수신기 서비스에 대한 최상위 인터페이스를 사용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"조건 제공자 서비스 사용"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"권한을 가진 프로그램이 조건 제공자 서비스의 최상위 인터페이스를 사용하도록 합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"이동통신사에서 제공한 구성 앱 호출"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"권한을 가진 프로그램이 이동통신사에서 제공한 구성 앱을 호출하도록 합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"네트워크 상태에 대한 관측 보고 수신"</string> @@ -1370,6 +1395,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> + <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 d486092..b31fbff 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<ບໍ່ມີຊື່>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"ໂໝດໃນຍົນ"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"ເປີດໂໝດຢູ່ໃນຍົນແລ້ວ"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"ປິດໂໝດໃນຍົນແລ້ວ"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"ການຕັ້ງຄ່າ"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string> <string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string> @@ -388,6 +409,10 @@ <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_bindRemoteDisplay" msgid="1782923938029941960">"ຜູກກັນເພື່ອສະແດງຜົນທາງໄກ."</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"ອະນຸຍາດໃຫ້ຜູ່ຖືຜູກກັບສ່ວນຕິດຕໍ່ລະດັບສູງສຸດ ຂອງການສະແດງຜົນທາງໄກ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"ເຊື່ອມໂຍງໄປຫາບໍລິການວິດເຈັດ"</string> @@ -700,6 +725,10 @@ <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_invokeCarrierSetup" msgid="3699600833975117478">"ຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ. ບໍ່ໜ້າຈະຕ້ອງການສຳລັບແອັບຯທົ່ວໄປ."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ"</string> @@ -1370,6 +1399,8 @@ <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="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 c8724a3..62b6c7a 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Be pavadinimo>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 f2aec67..b803e61 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Bez nosaukuma>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 1006907..cc0fa7f 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Гарчиггүй>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Эзэмшигч нь VPN үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"ханын зурагтай холбох"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Эзэмшигч нь ханын зурагны дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-уудад шаардлагагүй."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"дуугаар харьцагчтай холбох"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Эзэмшигчид дуугаар харьцах үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"алсын дэлгэцтэй холбогдох"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Эзэмшигчид алсын дэлгэц дэх дээд давхаргын интерфэйстэй холбогдох боломж олгоно. Энгийн апп-д шаардагдахгүй."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"виджет үйлчилгээтэй холбох"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Апп нь бусад апп-уудын илгээсэн мэдэгдлүүдийг дуудах, шалгах, болон цэвэрлэх боломжтой."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"мэдэгдэл сонсогч үйлчилгээтэй холбох"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Эзэмшигч нь мэдэгдэл сонсох үйлчилгээний дээд-төвшиний интерфейстэй холбох боломжтой. Энгийн апп-д шаардлагагүй."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"нөхцөл нийлүүлэгч үйлчилгээнд холбох"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Эзэмшигчид нөхцөл нийлүүлэгч үйлчилгээний дээд-түвшний интерфейстэй холбох боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"үүрэн компанийн нийлүүлсэн тохируулгын апп-г өдөөх"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Эзэмшигчид үүрэн компанийн нийлүүлсэн тохируулах апп-г өдөөх боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Сүлжээний байдлын талаар ажиглалтуудыг хүлээн авах"</string> @@ -1369,6 +1395,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> + <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 d3b5987..53c9b94 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Tidak bertajuk>"</string> <string name="ellipsis" msgid="7899829516048813237">"..."</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod pesawat"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Mod Pesawat DIHIDUPKAN"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Mod Pesawat DIMATIKAN"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Tetapan"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string> <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string> @@ -388,6 +409,10 @@ <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_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> @@ -700,6 +725,10 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Membenarkan apl untuk mendapatkan semula, memeriksa dan memadam bersih pemberitahuan, termasuk yang disiarkan oleh apl lain."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"ikat kepada perkhidmatan pendengar pemberitahuan"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi bagi perkhidmatan pendengar pemberitahuan. Tidak sekali-kali diperlukan untuk apl biasa."</string> + <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) --> + <skip /> + <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) --> + <skip /> <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> @@ -1370,6 +1399,8 @@ <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="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 d95d6f1..a67cb28 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Uten navn>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flymodus"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flymodus er på"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flymodus er av"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Innstillinger"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string> <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string> @@ -388,6 +409,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> + <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> @@ -396,7 +419,7 @@ <string name="permdesc_bindRouteProvider" msgid="4703804520859960329">"Innehaveren av tillatelsen kan binde seg til ruteleverandører. Dette er ikke nødvendig for vanlige apper."</string> <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"kommunisere med enhetsadministrator"</string> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Lar innehaveren sende hensikter til en enhetsadministrator. Skal aldri være nødvendig for normale apper."</string> - <string name="permlab_bindTvInput" msgid="5601264742478168987">"binde applikasjonen til en TV-inngang"</string> + <string name="permlab_bindTvInput" msgid="5601264742478168987">"binde appen til en TV-inngang"</string> <string name="permdesc_bindTvInput" msgid="2371008331852001924">"Lar innehaveren binde appen til det øverste grensesnittnivået for en TV-inngang. Dette skal aldri være nødvendig for vanlige apper."</string> <string name="permlab_manageDeviceAdmins" msgid="4248828900045808722">"legge til eller fjerne en enhetsadministrator"</string> <string name="permdesc_manageDeviceAdmins" msgid="5025608167709942485">"Tillater innehaveren å legge til eller fjerne aktive enhetsadministratorer. Dette skal aldri være nødvendig for vanlige apper."</string> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 c629254..3b2391f 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Zonder titel>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 34d43de..b80c1fd 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Bez nazwy>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 6996d13..668f9ef 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Sem nome>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1123,7 +1149,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> @@ -1369,6 +1395,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> + <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 a0124ca..db493e0 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Sem título>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avião"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modo avião ATIVADO"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modo avião DESATIVADO"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Configurações"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string> <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string> <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string> @@ -388,6 +409,10 @@ <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_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> @@ -700,6 +725,10 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite que o aplicativo recupere, examine e limpe notificações, inclusive as postadas por outros aplicativos."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"sujeitar a um serviço ouvinte de notificações"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite que o proprietário sujeite a interface de nível superior a um serviço ouvinte de notificações. Não deve ser necessário para aplicativos comuns."</string> + <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) --> + <skip /> + <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) --> + <skip /> <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> @@ -1370,6 +1399,8 @@ <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="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 dc710d4..3103b1f 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> @@ -608,6 +630,10 @@ <string name="permlab_bindWallpaper" msgid="8716400279937856462">"sa fixar vid in fund davos"</string> <!-- no translation found for permdesc_bindWallpaper (7108428692595491668) --> <skip /> + <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) --> + <skip /> + <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) --> + <skip /> <!-- no translation found for permlab_bindRemoteDisplay (1782923938029941960) --> <skip /> <!-- no translation found for permdesc_bindRemoteDisplay (1261242718727295981) --> @@ -1190,6 +1216,10 @@ <skip /> <!-- no translation found for permdesc_bindNotificationListenerService (985697918576902986) --> <skip /> + <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) --> + <skip /> + <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) --> + <skip /> <!-- no translation found for permlab_invokeCarrierSetup (3699600833975117478) --> <skip /> <!-- no translation found for permdesc_invokeCarrierSetup (4159549152529111920) --> @@ -2188,6 +2218,8 @@ <string name="chooser_wallpaper" msgid="7873476199295190279">"Midar il fund davos"</string> <!-- no translation found for notification_listener_binding_label (2014162835481906429) --> <skip /> + <!-- no translation found for condition_provider_service_binding_label (1321343352906524564) --> + <skip /> <!-- no translation found for vpn_title (19615213552042827) --> <skip /> <!-- no translation found for vpn_title_long (6400714798049252294) --> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 0757578..3ee0b8a 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Fără titlu>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Mod Avion"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Modul Avion este ACTIVAT"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Modul avion este DEZACTIVAT"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Setări"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string> <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string> <string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string> @@ -388,6 +409,10 @@ <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_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> @@ -700,6 +725,10 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"conectare la un serviciu de citire a notificărilor"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Permite proprietarului să se conecteze la interfața de nivel superior a unui serviciu de citire a notificărilor. În mod normal aplicațiile nu ar trebui să aibă nevoie de această permisiune."</string> + <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) --> + <skip /> + <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) --> + <skip /> <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> @@ -1370,6 +1399,8 @@ <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="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 f826f1a..8c7a566 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Без названия>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"..."</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим полета"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Выключить"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Включить"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Настройки"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string> <string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string> <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string> @@ -388,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Приложение сможет подключаться к базовому интерфейсу службы VPN. Это разрешение не используется обычными приложениями."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"Привязка к фоновому рисунку"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Приложение сможет подключаться к базовому интерфейсу службы обоев. Это разрешение не используется обычными приложениями."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"Подключение к службам голосового взаимодействия"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Приложение сможет подключаться к базовому интерфейсу служб голосового взаимодействия. Это разрешение обычно используется только специальными приложениями."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"Подключение к удаленному дисплею"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Приложение сможет подключаться к базовому интерфейсу удаленного дисплея. Это разрешение обычно используется только специальными приложениями."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"Подключение к службе виджетов"</string> @@ -700,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Приложение сможет получать, проверять и удалять уведомления, включая те, что опубликованы другими приложениями."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"Подключение к службе просмотра уведомлений"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Приложение сможет подключаться к базовому интерфейсу службы просмотра уведомлений. Это разрешение не используется обычными приложениями."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"Подключение к серверам поставщиков условий"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Приложение сможет подключаться к базовому интерфейсу поставщиков условий. Это разрешение обычно используется только специальными приложениями."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"Запуск приложения настроек, предоставленного оператором"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Владелец сможет запускать приложение настроек, предоставленное оператором. Это разрешение не используется обычными приложениями."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Использование данных о состоянии сети"</string> @@ -1370,6 +1395,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> + <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 09cf7f6..c96c661 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Bez mena>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim V lietadle"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim V lietadle je ZAPNUTÝ"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim V lietadle je VYPNUTÝ"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Nastavenia"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string> <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string> @@ -388,6 +409,10 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby VPN. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"väzba na tapetu"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania tapety. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string> + <!-- no translation found for permlab_bindVoiceInteraction (5334852580713715068) --> + <skip /> + <!-- no translation found for permdesc_bindVoiceInteraction (2345721766501778101) --> + <skip /> <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> @@ -700,6 +725,10 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Umožňuje aplikácii načítať, zobrazovať a mazať upozornenia vrátane tých, ktoré boli uverejnené inými aplikáciami."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"naviazanie sa na službu na počúvanie upozornení"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Umožňuje držiteľovi naviazať sa na najvyššiu úroveň služby na počúvanie upozornení. Bežné aplikácie by toto nastavenie nemali nikdy požadovať."</string> + <!-- no translation found for permlab_bindConditionProviderService (1180107672332704641) --> + <skip /> + <!-- no translation found for permdesc_bindConditionProviderService (1680513931165058425) --> + <skip /> <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> @@ -1370,6 +1399,8 @@ <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="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 00649f4..ef5d872 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Brez naslova>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 d363771..b87bd89 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Без наслова>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Режим рада у авиону"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Режим рада у авиону је УКЉУЧЕН"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Режим рада у авиону је ИСКЉУЧЕН"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Подешавања"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string> <string name="android_system_label" msgid="6577375335728551336">"Android систем"</string> @@ -388,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозвољава власнику да се повеже са интерфејсом VPN услуге највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"обавезивање на позадину"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозвољава власнику да се повеже са интерфејсом позадине највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"повежи са гласовним интерактором"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге гласовне интеракције. Не би требало никада да буде потребно за уобичајене апликације."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"повезивање са удаљеним екраном"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозвољава власнику да се повеже са интерфејсом удаљеног екрана највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"обавезивање на услугу виџета"</string> @@ -700,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозвољава апликацији да преузима, испитује и брише обавештења, укључујући она која постављају друге апликације."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"повезивање са услугом монитора обавештења"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозвољава власнику да се повеже са интерфејсом услуге монитора обавештења највишег нивоа. Уобичајене апликације никада не би требало да је користе."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"повежи са услугом добављача услова"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа услуге добављача услова. Не би требало никада да буде потребно за уобичајене апликације."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"позивање апликације са конфигурацијом коју одређује оператер"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"праћење података о условима на мрежи"</string> @@ -1370,6 +1395,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> + <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 7ec4f41..9b4dae3 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Okänd>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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 40adc3e..558cae2 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Haina jina>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Hali ya ndege"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Hali ya ndege IMEWASHWA"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Hali ya ndege IMEZIMWA"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Mipangilio"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string> <string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string> @@ -255,7 +276,7 @@ <string name="permdesc_statusBarService" msgid="716113660795976060">"Inaruhusu programu kuwa upau wa hali."</string> <string name="permlab_expandStatusBar" msgid="1148198785937489264">"panua/kunja mwambaa hali"</string> <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Inaruhusu programu kupanua au kukunja upau wa hali."</string> - <string name="permlab_install_shortcut" msgid="4279070216371564234">"sakinisha njia za mkato"</string> + <string name="permlab_install_shortcut" msgid="4279070216371564234">"kuweka njia za mkato"</string> <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Huruhusu programu kuongeza njia za mkato za Skrini ya kwanza bila mtumiaji kuingilia."</string> <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ondoa njia za mikato"</string> <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Huruhusu programu kuondoa njia za mkato za Skrini ya kwanza bila mtumiaji kuingilia."</string> @@ -283,7 +304,7 @@ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Inaruhusu programu kupokea na kuchakata ujumbe wa WAP. Idhini hii inajumuisha uwezo wa kuchunguza na kufuta ujumbe uliotumwa kwako bila ya kukuonyesha."</string> <string name="permlab_getTasks" msgid="6466095396623933906">"rudisha programu zinazoendeshwa"</string> <string name="permdesc_getTasks" msgid="7454215995847658102">"Inaruhusu programu kurudisha taarifa kuhusu kazi zinazoendeshwa sasa na hivi karibuni. Hii inaweza kuruhusu programu kugundua taarifa kuhusu ni programu zipi zinazotumika kwenye kifaa."</string> - <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"Tagusana na watumiaji"</string> + <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"kuwasiliana na watumiaji wengine"</string> <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Inaruhusu programu kutenda vitendo kwa watumiaji tofauti kwenye kifaa. Programu hasidi huenda zikatumia hii ili kukiuka ulinzi kati ya watumiaji."</string> <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"leseni kamili ili kushirikiana na watumiaji"</string> <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Inaruhusu miingialiano yote inayowezekana kwa watumiaji."</string> @@ -388,6 +409,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> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"shurutisha kwa muingiliano wa sauti"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Humruhusu mmiliki kushurutisha kwa kiolesura cha hali ya juu cha huduma ya muingiliano wa sauti. Kamwe isihitajike 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> @@ -415,15 +438,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">"Futa data yote kwenye kache ya programu"</string> - <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"Inaruhusu programu kutoa nafasi ya hifadhi ya kompyuta ndogo kwa kufuta faili katika saraka za kache za programu nyingine. Huenda hii ikasababisha programu nyingine kuanza polepole zaidi kwa sababu zinahitaji kuepua data zazo."</string> - <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Inaruhusu programu kutoa nafasi ya hifadhi ya simu kwa kufuta faili katika saraka za kache za programu nyingine. Huenda hii ikasababisha programu nyingine kuanza polepole zaidi kwa sababu zinahitaji kuepua data zazo."</string> + <string name="permlab_clearAppCache" msgid="7487279391723526815">"kufuta data yote kwenye akiba ya programu"</string> + <string name="permdesc_clearAppCache" product="tablet" msgid="8974640871945434565">"Huruhusu programu kuongeza nafasi katika hifadhi ya kompyuta kibao kwa kufuta faili katika saraka za akiba za programu zingine. Huenda hii ikafanya baadhi ya programu zianze kufanya kazi polepole kwa sababu zinahitaji kupakua tena data iliyokuwemo."</string> + <string name="permdesc_clearAppCache" product="default" msgid="2459441021956436779">"Huruhusu programu kuongeza nafasi ya hifadhi ya simu kwa kufuta faili katika saraka za akiba za programu zingine. Huenda hii ikafanya baadhi ya programu zianze kufanya kazi polepole kwa sababu zinahitaji kupakua tena data iliyokuwemo."</string> <string name="permlab_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> @@ -574,7 +597,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> @@ -614,13 +637,13 @@ <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Inaruhusu programu kutekeleza shughuli kama vile kuongeza na kutoa akaunti, na kufuta manenosiri yazo."</string> <string name="permlab_useCredentials" msgid="235481396163877642">"kutumia akaunti zilizo kwenye kifaa"</string> <string name="permdesc_useCredentials" msgid="7984227147403346422">"Inaruhusu programu kuomba shuhuda za uthibitisho."</string> - <string name="permlab_accessNetworkState" msgid="4951027964348974773">"Kuangalia mitandao"</string> + <string name="permlab_accessNetworkState" msgid="4951027964348974773">"kuona mitandao"</string> <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Inaruhusu programu kuona taarifa kuhusu miunganisho ya mtandao kama vile mitandao ipi iliyopo na imeunganishwa."</string> <string name="permlab_createNetworkSockets" msgid="8018758136404323658">"ufikiaji kamili wa mtandao"</string> <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Inaruhusu programu kuunda soketi za mtandao na kutumia itifaki za mtandao maalum. Kivinajri na programu nyingine zilizotolewa zinamaanisha kutuma data kwenye mtandao, kwa hivyo kibali hiki hakihitajiki kutuma data kwenye mtandao."</string> <string name="permlab_writeApnSettings" msgid="505660159675751896">"mabadiliko / kuingilia mipangilio ya mtandao/msonmgamano"</string> <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Inaruhusu programu kubadilisha mipangilio ya mtandao na kukatiza na kukagua uendaji wa mtandao, kwa mfano kubadilisha kituo tarishi na mbadala cha APN yoyote. Programu hasidi zinaweza kuangalia, kuelekeza kwingine, au kurekebisha furushi za mtandao bila ya wewe kujua."</string> - <string name="permlab_changeNetworkState" msgid="958884291454327309">"badilisha muunganisho wa mtandao"</string> + <string name="permlab_changeNetworkState" msgid="958884291454327309">"kubadilisha muunganisho wa mtandao"</string> <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Inaruhusu programu kubadilisha hali ya muunganisho wa mtandao."</string> <string name="permlab_changeTetherState" msgid="5952584964373017960">"Badilisha muunganisho uliofunganishwa"</string> <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Inaruhusu programu kubadilisha hali ya muunganisho wa mtandao uliofungwa."</string> @@ -650,25 +673,25 @@ <string name="permlab_bluetooth" msgid="6127769336339276828">"oanisha na vifaa vya Bluetooth"</string> <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Inaruhusu programu kuona usanidi wa Bluetooth kwenye kompyuta kibao, na kuunda na kukubali miunganisho kwa vifaa vilivyooanishwa."</string> <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Inaruhusu programu kuona usanidi wa Bluetooth kwenye simu, na kuunda na kukubali miunganisho kwa vifaa vilivyooanishwa."</string> - <string name="permlab_nfc" msgid="4423351274757876953">"dhibiti Mawasiliano ya vifaa vilivyo Karibu"</string> + <string name="permlab_nfc" msgid="4423351274757876953">"kudhibiti Mawasiliano ya Vifaa Vilivyokaribu (NFC)"</string> <string name="permdesc_nfc" msgid="7120611819401789907">"Inaruhusu programu kuwasiliana na lebo, kadi na wasomaji wa Near Field Communication (NFC)."</string> <string name="permlab_disableKeyguard" msgid="3598496301486439258">"zima kufuli la skrini yako"</string> <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Inaruhusu programu kulemaza ufunguo wa vitufe na usalama mwingine ambata wa nenosiri. Kwa mfano, simu inalemaza ufunguo wa viitufe inapopokea simu inayoingia, kisha inawezesha upya ufunguo wa vitufe wakati simu inapokamilika."</string> - <string name="permlab_readSyncSettings" msgid="6201810008230503052">"soma mipangilio ya usawazishaji"</string> + <string name="permlab_readSyncSettings" msgid="6201810008230503052">"kusoma mipangilio ya usawazishaji"</string> <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Inaruhusu programu kusoma mipangilio ya upatanishi wa akaunti. Kwa mfano, huku kunaweza kuamua kama programu ya Watu imepatanishwa na akaunti."</string> - <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"washa na uzime usawazishaji"</string> + <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"kuwasha na kuzima usawazishaji"</string> <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Inaruhusu programu kurekebisha mipangalio ya upatanishi wa akaunti. Kwa mfano, hii inaweza kuwezesha programu ya upatanishi wa Watu na akaunti."</string> - <string name="permlab_readSyncStats" msgid="7396577451360202448">"soma takwimu za usawazishaji"</string> + <string name="permlab_readSyncStats" msgid="7396577451360202448">"kusoma takwimu za usawazishaji"</string> <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Inaruhusu programu kusoma takwimu za upatanishi za akaunti, ikiwa ni pamoja na historia ya matukio ya upatanishi na kiasi cha data kimepatanishwa."</string> - <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"soma milisho ya kujiunga"</string> + <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"kusoma mipasho kutoka vyanzo unavyofuatilia"</string> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Inaruhusu programu kupata maelezo kuhusu mlisho iliyolandanishwa kwa sasa."</string> - <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"andika milisho ya kujiunga"</string> + <string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"kuandika mipasho kutoka vyanzo unavyofuatilia"</string> <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Inaruhusu programu kurekebisha milisho yako iliyolandanishwa kwa sasa. Programu hasidi zinaweza kubadilisha milisho yako iliyolandanishwa."</string> <string name="permlab_readDictionary" msgid="4107101525746035718">"soma maneno uliyoongeza kwenye kamusi"</string> <string name="permdesc_readDictionary" msgid="659614600338904243">"Inaruhusu programu kusoma maneno, majina na misemo yote ambayo mtumiaji alihifadhi katika kamusi ya mtumiaji."</string> <string name="permlab_writeDictionary" msgid="2183110402314441106">"ongeza maneno katika kamusi ya mtumiaji iliyofafanuliwa"</string> <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Inaruhusu programu kuandika maneno mapya katika kamusi ya mtumiaji."</string> - <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"soma maudhui ya hifadhi yako ya USB"</string> + <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"kusoma maudhui yaliyo kwenye hifadhi yako ya USB"</string> <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"soma maudhui ya kadi yako ya SD"</string> <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Huruhusu programu kusoma maudhui ya hifadhi ya USB."</string> <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Huruhusu programu kusoma maudhui ya kadi yako ya SD."</string> @@ -682,12 +705,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> @@ -700,6 +723,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> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"shurutisha kwa huduma ya mtoa masharti"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Humruhusu mmiliki kushurutisha kwa kiolesura cha kiwango cha juu cha huduma ya mtoa masharti. Kamwe isihitajike 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> @@ -710,9 +735,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> @@ -1289,14 +1314,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> @@ -1370,6 +1395,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> + <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Mtoa hali"</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 c211018..826fa64 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<ไม่มีชื่อ>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"อนุญาตให้เจ้าของเชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของบริการ VPN ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"เชื่อมโยงกับวอลเปเปอร์"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"อนุญาตให้ผู้ใช้เชื่อมโยงกับส่วนติดต่อผู้ใช้ระดับสูงสุดของวอลเปเปอร์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"เชื่อมโยงกับโปรแกรมโต้ตอบด้วยเสียง"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการโต้ตอบด้วยเสียง ไม่จำเป็นสำหรับแอปทั่วไป"</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"ผูกกับจอแสดงผลระยะไกล"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"อนุญาตให้ผู้ใช้ผูกกับอินเทอร์เฟซระดับสูงสุดของจอแสดงผลระยะไกล ซึ่งแอปพลิเคชันทั่วไปไม่จำเป็นต้องใช้"</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"เชื่อมโยงกับบริการวิดเจ็ต"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ทำให้แอปสามารถเรียกดู ตรวจสอบ และล้างการแจ้งเตือนได้ ซึ่งรวมถึงการแจ้งเตือนที่โพสต์โดยแอปอื่นๆ ด้วย"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"เชื่อมโยงกับบริการตัวฟังการแจ้งเตือน"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"อนุญาตให้เจ้าของเชื่อมโยงกับอินเตอร์เฟซระดับสูงสุดของบริการตัวฟังการแจ้งเตือน ซึ่งไม่มีความจำเป็นสำหรับแอปธรรมดา"</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"เชื่อมโยงกับบริการของผู้เสนอเงื่อนไข"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"อนุญาตให้ผู้ใช้อุปกรณ์เชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการของผู้เสนอเงื่อนไข ไม่จำเป็นสำหรับแอปทั่วไป"</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"เรียกใช้แอปการกำหนดค่าของผู้ให้บริการ"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"อนุญาตให้ผู้ใช้สามารถเรียกใช้แอปการกำหนดค่าของผู้ให้บริการ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย"</string> @@ -1369,6 +1395,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> + <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 a7b7b8f..6e50517 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Walang pamagat>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Airplane mode"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Naka-ON ang airplane mode"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Naka-OFF ang airplane mode"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Mga Setting"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string> <string name="android_system_label" msgid="6577375335728551336">"Android System"</string> @@ -388,6 +409,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> + <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> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 bc73a93..bd2f926 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Adsız>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Uçak modu"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Uçak modu AÇIK"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Uçak modu KAPALI"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Ayarlar"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string> <string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string> @@ -388,6 +409,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> + <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> @@ -700,6 +723,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> + <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> @@ -1370,6 +1395,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> + <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 75d77c8..d01c577 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Без назви>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня служби VPN. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"прив’язати до фонового малюнка"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня фонового малюнка. Ніколи не застосовується для звичайних програм."</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"підключитися до служби голосової взаємодії"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби голосової взаємодії. Звичайні додатки ніколи не використовують цей дозвіл."</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"прив’язуватися до віддаленого екрана"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"Дозволяє власникові прив’язуватися до інтерфейсу верхнього рівня віддаленого екрана. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прив\'язувати до служби віджетів"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Дозволяє програмі отримувати, перевіряти й очищати сповіщення, зокрема опубліковані іншими програмами."</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"прив’язуватися до служби читання сповіщень"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Дозволяє власнику прив’язуватися до інтерфейсу верхнього рівня служби читання сповіщень. Ніколи не застосовується для звичайних програм."</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"підключитися до служби постачання умов"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби постачання умов. Звичайні додатки ніколи не використовують цей дозвіл."</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"викликати надану оператором програму конфігурації"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"прослуховувати дані спостережень за станом мережі"</string> @@ -1369,6 +1395,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> + <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 a1c03ad..24b2db5 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <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> @@ -135,8 +157,7 @@ <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Đồng bộ hóa"</string> <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Quá nhiều lần xóa <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string> <string name="low_memory" product="tablet" msgid="6494019234102154896">"Bộ nhớ máy tính bảng đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string> - <!-- no translation found for low_memory (4415914910770005166) --> - <skip /> + <string name="low_memory" product="watch" msgid="4415914910770005166">"Bộ nhớ đồng hồ đã đầy. Hãy xóa một số tệp để giải phóng dung lượng."</string> <string name="low_memory" product="default" msgid="3475999286680000541">"Bộ nhớ điện thoại đã đầy. Hãy xóa một số tệp để tạo thêm dung lượng."</string> <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mạng có thể được giám sát"</string> <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Bởi một bên thứ ba không xác định"</string> @@ -154,8 +175,7 @@ <string name="silent_mode_ring" msgid="8592241816194074353">"Bật chuông"</string> <string name="shutdown_progress" msgid="2281079257329981203">"Đang tắt…"</string> <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Máy tính bảng của bạn sẽ tắt."</string> - <!-- no translation found for shutdown_confirm (3490275567476369184) --> - <skip /> + <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Đồng hồ của bạn sẽ tắt."</string> <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Điện thoại của bạn sẽ tắt."</string> <string name="shutdown_confirm_question" msgid="2906544768881136183">"Bạn có muốn tắt không?"</string> <string name="reboot_safemode_title" msgid="7054509914500140361">"Khởi động lại ở chế độ an toàn"</string> @@ -175,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Chế độ trên máy bay"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Chế độ trên máy bay BẬT"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Chế độ trên máy bay TẮT"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"Cài đặt"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string> <string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string> @@ -390,6 +409,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> + <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> @@ -702,6 +723,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> + <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> @@ -1372,6 +1395,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> + <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 4c4d0ce..44e258d 100644 --- a/core/res/res/values-watch/config.xml +++ b/core/res/res/values-watch/config.xml @@ -27,4 +27,14 @@ <item>settings</item> </string-array> -</resources>
\ No newline at end of file + <!-- 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/packages/SystemUI/res/layout/notification_adaptive_wrapper.xml b/core/res/res/values-watch/themes.xml index 15d0890..9447d9c 100644 --- a/packages/SystemUI/res/layout/notification_adaptive_wrapper.xml +++ b/core/res/res/values-watch/themes.xml @@ -1,5 +1,5 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 The Android Open Source Project +<?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. @@ -13,8 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. --> -<SizeAdaptiveLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:background="@android:color/background_dark" - android:id="@+id/notification_adaptive_wrapper" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> +<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 134cf9a..9297e3a 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<未命名>"</string> <string name="ellipsis" msgid="7899829516048813237">"..."</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -77,14 +99,14 @@ <string name="serviceNotProvisioned" msgid="8614830180508686666">"未提供服务。"</string> <string name="CLIRPermanent" msgid="3377371145926835671">"您无法更改来电显示设置。"</string> <string name="RestrictedChangedTitle" msgid="5592189398956187498">"网络可用情况发生变化"</string> - <string name="RestrictedOnData" msgid="8653794784690065540">"数据服务已禁用。"</string> - <string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已禁用。"</string> - <string name="RestrictedOnNormal" msgid="4953867011389750673">"已禁用语音服务。"</string> - <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"已停用所有语音服务。"</string> - <string name="RestrictedOnSms" msgid="8314352327461638897">"已禁用短信服务。"</string> - <string name="RestrictedOnVoiceData" msgid="996636487106171320">"已停用语音/数据服务。"</string> - <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"已禁用语音/短信服务。"</string> - <string name="RestrictedOnAll" msgid="5643028264466092821">"已停用所有语音/数据/短信服务。"</string> + <string name="RestrictedOnData" msgid="8653794784690065540">"数据网络服务已停用。"</string> + <string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已停用。"</string> + <string name="RestrictedOnNormal" msgid="4953867011389750673">"语音服务已停用。"</string> + <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"所有语音服务都已停用。"</string> + <string name="RestrictedOnSms" msgid="8314352327461638897">"短信服务已停用。"</string> + <string name="RestrictedOnVoiceData" msgid="996636487106171320">"语音/数据服务已停用。"</string> + <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"语音/短信服务已停用。"</string> + <string name="RestrictedOnAll" msgid="5643028264466092821">"所有语音/数据/短信服务都已停用。"</string> <string name="serviceClassVoice" msgid="1258393812335258019">"语音"</string> <string name="serviceClassData" msgid="872456782077937893">"数据"</string> <string name="serviceClassFAX" msgid="5566624998840486475">"传真"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飞行模式"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"已开启飞行模式"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"未开启飞行模式"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"设置"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string> <string name="safeMode" msgid="2788228061547930246">"安全模式"</string> <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string> @@ -388,6 +409,10 @@ <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_bindRemoteDisplay" msgid="1782923938029941960">"绑定至远程显示屏"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允许应用绑定至远程显示屏的顶级接口。普通应用绝不需要此权限。"</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"绑定到小部件服务"</string> @@ -610,8 +635,8 @@ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"允许该应用获取手机已知的帐户列表,其中可能包括由已安装的应用创建的所有帐户。"</string> <string name="permlab_authenticateAccounts" msgid="5265908481172736933">"创建帐户并设置密码"</string> <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"允许应用使用 AccountManager 的帐户身份验证程序功能,包括创建帐户以及获取和设置其密码。"</string> - <string name="permlab_manageAccounts" msgid="4983126304757177305">"添加或删除帐户"</string> - <string name="permdesc_manageAccounts" msgid="8698295625488292506">"允许应用执行添加帐户、删除帐户、删除帐户密码等操作。"</string> + <string name="permlab_manageAccounts" msgid="4983126304757177305">"添加或移除帐户"</string> + <string name="permdesc_manageAccounts" msgid="8698295625488292506">"允许应用执行添加帐户、移除帐户、删除帐户密码等操作。"</string> <string name="permlab_useCredentials" msgid="235481396163877642">"使用设备上的帐户"</string> <string name="permdesc_useCredentials" msgid="7984227147403346422">"允许应用请求身份验证令牌。"</string> <string name="permlab_accessNetworkState" msgid="4951027964348974773">"查看网络连接"</string> @@ -700,6 +725,10 @@ <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_invokeCarrierSetup" msgid="3699600833975117478">"调用运营商提供的配置应用"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"监听网络状况的观测信息"</string> @@ -1370,6 +1399,8 @@ <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="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 2d3c418..1c8cfe8 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<未命名>"</string> <string name="ellipsis" msgid="7899829516048813237">"..."</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式繫結至 VPN 服務的頂層介面 (不建議一般應用程式使用)。"</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"繫結至桌布"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (不建議一般應用程式使用)。"</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"繫結至語音互動器"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允許應用程式繫結至語音互動服務的頂層介面,但一般應用程式並不需要使用。"</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端屏螢的頂層介面 (不建議一般應用程式使用)。"</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string> @@ -699,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (不建議一般應用程式使用)。"</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件供應商服務"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件供應商服務的頂層介面,但一般應用程式並不需要使用。"</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"調用流動網絡供應商提供的設定應用程式"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式調用流動網絡供應商提供的設定應用程式 (不建議一般應用程式使用)。"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽對網絡狀況的觀察"</string> @@ -981,7 +1007,7 @@ <string name="permlab_setAlarm" msgid="1379294556362091814">"設定鬧鐘"</string> <string name="permdesc_setAlarm" msgid="316392039157473848">"允許應用程式在安裝的鬧鐘應用程式中設定鬧鐘,某些鬧鐘應用程式可能沒有這項功能。"</string> <string name="permlab_addVoicemail" msgid="5525660026090959044">"新增留言"</string> - <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允許應用程式將訊息加到您的留言信箱收件匣。"</string> + <string name="permdesc_addVoicemail" msgid="6604508651428252437">"允許應用程式將訊息加到您的留言信箱收件箱。"</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"修改瀏覽器地理資訊的權限"</string> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"允許應用程式修改瀏覽器的地理資訊權限。惡意應用程式可能會藉此允許將您的位置資訊任意傳送給某些網站。"</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"驗證套件"</string> @@ -1369,6 +1395,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> + <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 e309acc..05e0894 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<未命名>"</string> <string name="ellipsis" msgid="7899829516048813237">"…"</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -173,8 +195,7 @@ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"飛航模式"</string> <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"飛航模式為 [開啟]"</string> <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"飛航模式為 [關閉]"</string> - <!-- no translation found for global_action_settings (1756531602592545966) --> - <skip /> + <string name="global_action_settings" msgid="1756531602592545966">"設定"</string> <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string> <string name="safeMode" msgid="2788228061547930246">"安全模式"</string> <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string> @@ -388,6 +409,8 @@ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"允許應用程式聯繫至 VPN 服務的頂層介面 (一般應用程式不需使用)。"</string> <string name="permlab_bindWallpaper" msgid="8716400279937856462">"連結至桌布"</string> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"允許應用程式繫結至桌布的頂層介面 (一般應用程式不需使用)。"</string> + <string name="permlab_bindVoiceInteraction" msgid="5334852580713715068">"繫結至語音互動器"</string> + <string name="permdesc_bindVoiceInteraction" msgid="2345721766501778101">"允許應用程式繫結至語音互動服務的頂層介面 (一般應用程式並不需要)。"</string> <string name="permlab_bindRemoteDisplay" msgid="1782923938029941960">"繫結至遠端螢幕"</string> <string name="permdesc_bindRemoteDisplay" msgid="1261242718727295981">"允許應用程式繫結至遠端螢幕的頂層介面 (一般應用程式不需使用)。"</string> <string name="permlab_bindRemoteViews" msgid="5697987759897367099">"繫結至小工具服務"</string> @@ -700,6 +723,8 @@ <string name="permdesc_accessNotifications" msgid="458457742683431387">"允許應用程式擷取、檢查及清除通知 (包括由其他應用程式發佈的通知)。"</string> <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"繫結至通知接聽器服務"</string> <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允許應用程式繫結至通知接聽器服務的頂層介面 (一般應用程式不需使用)。"</string> + <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"繫結至條件提供者服務"</string> + <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允許應用程式繫結至條件提供者服務的頂層介面 (一般應用程式並不需要)。"</string> <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"叫用行動通訊業者提供的設定應用程式"</string> <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式叫用行動通訊業者提供的設定應用程式 (一般應用程式並不需要)。"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽網路狀況觀察資訊"</string> @@ -1370,6 +1395,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> + <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 4e36a1b..9c8542e 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -27,6 +27,28 @@ <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> + <!-- 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 /> <string name="untitled" msgid="4638956954852782576">"<Akunasihloko>"</string> <string name="ellipsis" msgid="7899829516048813237">"..."</string> <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string> @@ -387,6 +409,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> + <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> @@ -699,6 +723,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> + <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> @@ -1369,6 +1395,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> + <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/arrays.xml b/core/res/res/values/arrays.xml index f01f10e..305ba28 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -348,4 +348,43 @@ <item>中文 (繁體)</item> </string-array> + <!-- Used by callers to Resources.selectSystemTheme(). Defines the minimum + targetSdkVersion required for the theme style at a given index. + NOTE: Must be sorted in ascending order. --> + <integer-array name="system_theme_sdks"> + <item>0</item> + <item>11</item> + <item>14</item> + <item>21</item> + </integer-array> + + <!-- Used by Resources.selectDefaultTheme(). Defines the default theme style + for the targetSdkVersion at a given index (see system_theme_sdks). + NOTE: Must match number of entries in system_theme_sdks. --> + <array name="system_theme_styles"> + <item>@style/Theme</item> + <item>@style/Theme.Holo</item> + <item>@style/Theme.DeviceDefault</item> + <item>@style/Theme.DeviceDefault.Light.DarkActionBar</item> + </array> + + <!-- Used by ContextImpl for notifications. Defines the default dialog theme + style for the targetSdkVersion at a given index (see system_theme_sdks). + NOTE: Must match number of entries in system_theme_sdks. --> + <array name="system_theme_dialog_styles"> + <item>@style/Theme</item> + <item>@style/Theme.Holo.Dialog</item> + <item>@style/Theme.DeviceDefault.Dialog</item> + <item>@style/Theme.DeviceDefault.Light.Dialog</item> + </array> + + <!-- Used by InputMethodService.onCreate(). Defines the default IME theme + style for the targetSdkVersion at a given index (see system_theme_sdks). + NOTE: Must match number of entries in system_theme_sdks. --> + <array name="system_theme_ime_styles"> + <item>@style/Theme.InputMethod</item> + <item>@style/Theme.Holo.InputMethod</item> + <item>@style/Theme.DeviceDefault.InputMethod</item> + <item>@style/Theme.DeviceDefault.InputMethod</item> + </array> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index abac60e..e07ebd4 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -462,24 +462,24 @@ transitions between different window content. --> <attr name="windowContentTransitionManager" format="reference" /> - <!-- Reference to a TransitionManager XML resource defining the desired Transition + <!-- Reference to a Transition XML resource defining the desired Transition used to move Views into the initial Window's content Scene. Corresponds to {@link android.view.Window#setEnterTransition(android.transition.Transition)}. --> <attr name="windowEnterTransition" format="reference"/> - <!-- Reference to a TransitionManager XML resource defining the desired Transition + <!-- Reference to a Transition XML resource defining the desired Transition used to move Views out of the Window's content Scene when launching a new Activity. Corresponds to {@link android.view.Window#setExitTransition(android.transition.Transition)}. --> <attr name="windowExitTransition" format="reference"/> - <!-- Reference to a TransitionManager XML resource defining the desired Transition + <!-- Reference to a Transition XML resource defining the desired Transition used to move shared elements transferred into the Window's initial content Scene. Corresponds to {@link android.view.Window#setSharedElementEnterTransition( android.transition.Transition)}. --> <attr name="windowSharedElementEnterTransition" format="reference"/> - <!-- Reference to a TransitionManager XML resource defining the desired Transition + <!-- Reference to a Transition XML resource defining the desired Transition used when starting a new Activity to move shared elements prior to transferring to the called Activity. Corresponds to {@link android.view.Window#setSharedElementExitTransition( @@ -966,7 +966,6 @@ <attr name="colorButtonPressed" format="color" /> <attr name="colorButtonNormalColored" format="color" /> <attr name="colorButtonPressedColored" format="color" /> - </declare-styleable> <!-- **************************************************************** --> @@ -5025,6 +5024,12 @@ <declare-styleable name="TransitionTarget"> <!-- The id of a target on which this transition will animate changes. --> <attr name="targetId" format="reference" /> + <!-- The id of a target to exclude from this transition. --> + <attr name="excludeId" format="reference" /> + <!-- The fully-qualified name of the Class to exclude from this transition. --> + <attr name="excludeClass" format="string" /> + <!-- The fully-qualified name of the Class to include in this transition. --> + <attr name="targetClass" /> </declare-styleable> <!-- Use <code>set</code> as the root tag of the XML resource that @@ -6342,6 +6347,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/colors.xml b/core/res/res/values/colors.xml index d0c455b..761170d 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,73 +118,7 @@ <!-- 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> @@ -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/ids.xml b/core/res/res/values/ids.xml index a79e1fe..889c368 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -84,4 +84,5 @@ <item type="id" name="scene_layoutid_cache" /> <item type="id" name="shared_element_name" /> <item type="id" name="mask" /> + <item type="id" name="shared_element" /> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 85ef004..ec73b9f 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2162,8 +2162,12 @@ <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-padding type="dimen" name="l_resource_pad" end="0x01050010" /> @@ -2174,18 +2178,29 @@ <public type="id" name="shared_element_name" /> <public type="id" name="mask" /> + <public type="id" name="shared_element" /> <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" /> @@ -2262,7 +2277,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" /> @@ -2305,6 +2319,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" /> @@ -2325,6 +2340,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" /> @@ -2365,6 +2381,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" /> @@ -2373,12 +2390,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" /> @@ -2392,8 +2403,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/strings.xml b/core/res/res/values/strings.xml index cb52db2..97400b2 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -36,6 +36,45 @@ the placeholders. --> <string name="fileSizeSuffix"><xliff:g id="number" example="123">%1$s</xliff:g><xliff:g id="unit" example="KB">%2$s</xliff:g></string> + <!-- [CHAR_LIMIT=10] Suffix added to signify duration in days --> + <string name="durationDays"><xliff:g id="days">%1$d</xliff:g> days</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one day with hours --> + <string name="durationDayHours"><xliff:g id="days">%1$d</xliff:g> day + <xliff:g id="hours">%2$d</xliff:g> hrs</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one day with one hours --> + <string name="durationDayHour"><xliff:g id="days">%1$d</xliff:g> day + <xliff:g id="hours">%2$d</xliff:g> hr</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration in hours --> + <string name="durationHours"><xliff:g id="hours">%1$d</xliff:g> hrs</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one hour with minutes --> + <string name="durationHourMinutes"><xliff:g id="hours">%1$d</xliff:g> hr + <xliff:g id="minutes">%2$d</xliff:g> mins</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one hour with one minute --> + <string name="durationHourMinute"><xliff:g id="hours">%1$d</xliff:g> hr + <xliff:g id="minutes">%2$d</xliff:g> min</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration in minutes --> + <string name="durationMinutes"><xliff:g id="minutes">%1$d</xliff:g> mins</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one minute with seconds --> + <string name="durationMinuteSeconds"><xliff:g id="minutes">%1$d</xliff:g> min + <xliff:g id="seconds">%2$d</xliff:g> secs</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one minute with one second --> + <string name="durationMinuteSecond"><xliff:g id="minutes">%1$d</xliff:g> min + <xliff:g id="seconds">%2$d</xliff:g> sec</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration in seconds --> + <string name="durationSeconds"><xliff:g id="seconds">%1$d</xliff:g> secs</string> + + <!-- [CHAR_LIMIT=10] Suffix added to signify duration of one second --> + <string name="durationSecond"><xliff:g id="seconds">%1$d</xliff:g> sec</string> + <!-- Used in Contacts for a field that has no label and in Note Pad for a note with no name. --> <string name="untitled"><Untitled></string> @@ -415,6 +454,12 @@ <!-- Label for the Android system components when they are shown to the user. --> <string name="android_system_label">Android System</string> + <!-- Label for the user owner in the intent forwarding app. --> + <string name="user_owner_label">Personal</string> + + <!-- Label for a corporate profile in the intent forwarding app. --> + <string name="managed_profile_label">Work</string> + <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. --> <string name="permgrouplab_costMoney">Services that cost you money</string> <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index fc0fccc..37716f7 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -397,6 +397,11 @@ please see styles_device_defaults.xml. <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 +1614,6 @@ please see styles_device_defaults.xml. <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 +1645,11 @@ please see styles_device_defaults.xml. <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 +2104,11 @@ please see styles_device_defaults.xml. <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 @@ easier. <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 @@ easier. <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 @@ easier. <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 @@ easier. <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 @@ easier. <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 @@ easier. <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 @@ easier. <!-- @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 @@ easier. <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 @@ easier. <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..7679420 100644 --- a/core/res/res/values/styles_quantum.xml +++ b/core/res/res/values/styles_quantum.xml @@ -351,40 +351,6 @@ please see styles_device_defaults.xml. <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"/> @@ -406,16 +372,6 @@ please see styles_device_defaults.xml. <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> @@ -427,11 +383,6 @@ please see styles_device_defaults.xml. <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> @@ -743,8 +694,6 @@ please see styles_device_defaults.xml. <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 +769,8 @@ please see styles_device_defaults.xml. <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 +788,7 @@ please see styles_device_defaults.xml. <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 +808,7 @@ please see styles_device_defaults.xml. <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 +827,7 @@ please see styles_device_defaults.xml. <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"/> @@ -1058,7 +1005,7 @@ please see styles_device_defaults.xml. </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 6e33bed..7c6a91a 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" /> @@ -505,6 +506,17 @@ <java-symbol type="string" name="display_manager_overlay_display_secure_suffix" /> <java-symbol type="string" name="display_manager_overlay_display_title" /> <java-symbol type="string" name="double_tap_toast" /> + <java-symbol type="string" name="durationDays" /> + <java-symbol type="string" name="durationDayHours" /> + <java-symbol type="string" name="durationDayHour" /> + <java-symbol type="string" name="durationHours" /> + <java-symbol type="string" name="durationHourMinutes" /> + <java-symbol type="string" name="durationHourMinute" /> + <java-symbol type="string" name="durationMinutes" /> + <java-symbol type="string" name="durationMinuteSeconds" /> + <java-symbol type="string" name="durationMinuteSecond" /> + <java-symbol type="string" name="durationSeconds" /> + <java-symbol type="string" name="durationSecond" /> <java-symbol type="string" name="elapsed_time_short_format_h_mm_ss" /> <java-symbol type="string" name="elapsed_time_short_format_mm_ss" /> <java-symbol type="string" name="emailTypeCustom" /> @@ -1613,6 +1625,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" /> @@ -1636,6 +1649,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" /> @@ -1848,5 +1862,9 @@ <java-symbol type="id" name="icon_frame" /> <java-symbol type="style" name="Animation.VolumePanel" /> <java-symbol type="transition" name="no_transition" /> + <java-symbol type="array" name="system_theme_sdks" /> + <java-symbol type="array" name="system_theme_styles" /> + <java-symbol type="array" name="system_theme_dialog_styles" /> + <java-symbol type="array" name="system_theme_ime_styles" /> </resources> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 7b3d5e3..6f4e7d0 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -53,6 +53,14 @@ please see themes_device_defaults.xml. <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> @@ -437,6 +445,14 @@ please see themes_device_defaults.xml. <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> @@ -937,6 +953,14 @@ please see themes_device_defaults.xml. <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> @@ -1268,6 +1292,14 @@ please see themes_device_defaults.xml. <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..80c10dd 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -51,139 +51,139 @@ easier. --> <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,240 @@ easier. <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" /> + + <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 +448,117 @@ easier. <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> + <item name="mediaRouteButtonStyle">@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" > + + <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an + inverse color profile. --> + <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Quantum.Light.DarkActionBar" > + <item name="actionBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item> + <item name="actionDropDownStyle">@style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item> + <item name="actionButtonStyle">@style/Widget.DeviceDefault.ActionButton</item> + <item name="actionOverflowButtonStyle">@style/Widget.DeviceDefault.ActionButton.Overflow</item> + <item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView.Inverse</item> + <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse</item> + <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText.Inverse</item> + <item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode.Inverse</item> + <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item> + <item name="actionModePopupWindowStyle">@style/Widget.DeviceDefault.PopupWindow.ActionMode</item> </style> + + <!-- 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" > - </style> + <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" > - </style> + <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" > - </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" > - - </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> + <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="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item> - <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item> + <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item> + <item name="windowAnimationStyle">@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="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item> + <item name="borderlessButtonStyle">@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> + <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" > + <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 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> + <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">@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> + <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">@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> + <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" > - - </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 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> + <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> + <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Quantum.Light.Dialog.Presentation" /> - <!-- 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 name="Theme.DeviceDefault.Light.Dialog.TimePicker" parent="Theme.Quantum.Light.Dialog.TimePicker"/> - </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 name="Theme.DeviceDefault.Light.Panel" parent="Theme.Quantum.Light.Panel" /> - </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="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> - - </style> - - <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Quantum.Dialog.Alert"> - <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item> - </style> <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Quantum.Light.Dialog.Alert"> - <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item> + <item name="windowTitleStyle">@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"> - - </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..c0bd18b 100644 --- a/core/res/res/values/themes_quantum.xml +++ b/core/res/res/values/themes_quantum.xml @@ -391,8 +391,8 @@ please see themes_device_defaults.xml. <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 +411,16 @@ please see themes_device_defaults.xml. <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 +430,8 @@ please see themes_device_defaults.xml. <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> @@ -606,7 +606,7 @@ please see themes_device_defaults.xml. <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> @@ -690,10 +690,10 @@ please see themes_device_defaults.xml. <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 +717,6 @@ please see themes_device_defaults.xml. <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" /> @@ -1031,8 +1028,8 @@ please see themes_device_defaults.xml. <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 34393f9..67203b2 100644 --- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java +++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java @@ -25,6 +25,7 @@ public class BluetoothInstrumentation extends Instrumentation { private BluetoothTestUtils mUtils = null; private BluetoothAdapter mAdapter = null; private Bundle mArgs = null; + private Bundle mSuccessResult = null; private BluetoothTestUtils getBluetoothTestUtils() { if (mUtils == null) { @@ -46,6 +47,9 @@ public class BluetoothInstrumentation extends Instrumentation { public void onCreate(Bundle arguments) { super.onCreate(arguments); mArgs = arguments; + // create the default result response, but only use it in success code path + mSuccessResult = new Bundle(); + mSuccessResult.putString("result", "SUCCESS"); start(); } @@ -60,6 +64,8 @@ public class BluetoothInstrumentation extends Instrumentation { unpairAll(); } else if ("getName".equals(command)) { getName(); + } else if ("getAddress".equals(command)) { + getAddress(); } else { finish(null); } @@ -67,24 +73,29 @@ public class BluetoothInstrumentation extends Instrumentation { public void enable() { getBluetoothTestUtils().enable(getBluetoothAdapter()); - finish(null); + finish(mSuccessResult); } public void disable() { getBluetoothTestUtils().disable(getBluetoothAdapter()); - finish(null); + finish(mSuccessResult); } public void unpairAll() { getBluetoothTestUtils().unpairAll(getBluetoothAdapter()); - finish(null); + finish(mSuccessResult); } public void getName() { String name = getBluetoothAdapter().getName(); - Bundle bundle = new Bundle(); - bundle.putString("name", name); - finish(bundle); + mSuccessResult.putString("name", name); + finish(mSuccessResult); + } + + public void getAddress() { + String name = getBluetoothAdapter().getAddress(); + mSuccessResult.putString("address", name); + finish(mSuccessResult); } public void finish(Bundle result) { 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/run_core_inputmethod_test.sh b/core/tests/inputmethodtests/run_core_inputmethod_test.sh index b0b119b..9029ba5 100755 --- a/core/tests/inputmethodtests/run_core_inputmethod_test.sh +++ b/core/tests/inputmethodtests/run_core_inputmethod_test.sh @@ -21,4 +21,4 @@ if [[ $rebuild == true ]]; then $COMMAND fi -adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner +adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest,android.os.InputMethodSubtypeSwitchingControllerTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java new file mode 100644 index 0000000..6d33529 --- /dev/null +++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.os; + +import android.content.pm.ApplicationInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; +import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; + +import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController; +import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase { + final private static String DUMMY_PACKAGE_NAME = "dymmy package name"; + final private static String DUMMY_SETTING_ACTIVITY_NAME = ""; + final private static boolean DUMMY_IS_AUX_IME = false; + final private static boolean DUMMY_FORCE_DEFAULT = false; + final private static int DUMMY_IS_DEFAULT_RES_ID = 0; + final private static String SYSTEM_LOCALE = "en_US"; + + private static InputMethodSubtype createDummySubtype(final String locale) { + final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder(); + return builder.setSubtypeNameResId(0) + .setSubtypeIconResId(0) + .setSubtypeLocale(locale) + .setIsAsciiCapable(true) + .build(); + } + + private static void addDummyImeSubtypeListItems(List<ImeSubtypeListItem> items, + String imeName, String imeLabel, List<String> subtypeLocales, + boolean supportsSwitchingToNextInputMethod) { + final ResolveInfo ri = new ResolveInfo(); + final ServiceInfo si = new ServiceInfo(); + final ApplicationInfo ai = new ApplicationInfo(); + ai.packageName = DUMMY_PACKAGE_NAME; + ai.enabled = true; + si.applicationInfo = ai; + si.enabled = true; + si.packageName = DUMMY_PACKAGE_NAME; + si.name = imeName; + si.exported = true; + si.nonLocalizedLabel = imeLabel; + ri.serviceInfo = si; + final List<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>(); + for (String subtypeLocale : subtypeLocales) { + subtypes.add(createDummySubtype(subtypeLocale)); + } + final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME, + DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID, + 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)); + } + } + + private static List<ImeSubtypeListItem> createTestData() { + final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>(); + addDummyImeSubtypeListItems(items, "switchAwareLatinIme", "switchAwareLatinIme", + Arrays.asList("en_US", "es_US", "fr"), + true /* supportsSwitchingToNextInputMethod*/); + addDummyImeSubtypeListItems(items, "nonSwitchAwareLatinIme", "nonSwitchAwareLatinIme", + Arrays.asList("en_UK", "hi"), + false /* supportsSwitchingToNextInputMethod*/); + addDummyImeSubtypeListItems(items, "switchAwareJapaneseIme", "switchAwareJapaneseIme", + Arrays.asList("ja_JP"), + true /* supportsSwitchingToNextInputMethod*/); + addDummyImeSubtypeListItems(items, "nonSwitchAwareJapaneseIme", "nonSwitchAwareJapaneseIme", + Arrays.asList("ja_JP"), + false /* supportsSwitchingToNextInputMethod*/); + return items; + } + + @SmallTest + public void testGetNextInputMethodImplWithNotOnlyCurrentIme() throws Exception { + final List<ImeSubtypeListItem> imList = createTestData(); + + final boolean ONLY_CURRENT_IME = false; + ImeSubtypeListItem currentIme; + ImeSubtypeListItem nextIme; + + // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US" + currentIme = imList.get(0); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertEquals(imList.get(1), nextIme); + // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr" + currentIme = imList.get(1); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertEquals(imList.get(2), nextIme); + // "switchAwareLatinIme/fr" -> "nonSwitchAwareLatinIme/en_UK + currentIme = imList.get(2); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertEquals(imList.get(3), 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" + 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" + currentIme = imList.get(6); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertEquals(imList.get(0), nextIme); + } + + @SmallTest + public void testGetNextInputMethodImplWithOnlyCurrentIme() throws Exception { + final List<ImeSubtypeListItem> imList = createTestData(); + + final boolean ONLY_CURRENT_IME = true; + ImeSubtypeListItem currentIme; + ImeSubtypeListItem nextIme; + + // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US" + currentIme = imList.get(0); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertEquals(imList.get(1), nextIme); + // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr" + currentIme = imList.get(1); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertEquals(imList.get(2), nextIme); + // "switchAwareLatinIme/fr" -> "switchAwareLatinIme/en_US" + currentIme = imList.get(2); + 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" -> "switchAwareLatinIme/en_UK" + currentIme = imList.get(4); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertEquals(imList.get(3), nextIme); + + // "switchAwareJapaneseIme/ja_JP" -> null + currentIme = imList.get(5); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertNull(nextIme); + + // "nonSwitchAwareJapaneseIme/ja_JP" -> null + currentIme = imList.get(6); + nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl( + imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype( + currentIme.mSubtypeName.toString())); + assertNull(nextIme); + } + } diff --git a/data/keyboards/AVRCP.kl b/data/keyboards/AVRCP.kl index 736b43c..ccd0209 100644 --- a/data/keyboards/AVRCP.kl +++ b/data/keyboards/AVRCP.kl @@ -14,10 +14,10 @@ # Key layout used for Bluetooth AVRCP support. -key 200 MEDIA_PLAY WAKE -key 201 MEDIA_PAUSE WAKE -key 166 MEDIA_STOP WAKE -key 163 MEDIA_NEXT WAKE -key 165 MEDIA_PREVIOUS WAKE -key 168 MEDIA_REWIND WAKE -key 208 MEDIA_FAST_FORWARD WAKE +key 200 MEDIA_PLAY +key 201 MEDIA_PAUSE +key 166 MEDIA_STOP +key 163 MEDIA_NEXT +key 165 MEDIA_PREVIOUS +key 168 MEDIA_REWIND +key 208 MEDIA_FAST_FORWARD 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_C { } 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 0cdcb1c..cfc1484 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -135,7 +135,7 @@ key 111 FORWARD_DEL key 113 VOLUME_MUTE key 114 VOLUME_DOWN key 115 VOLUME_UP -key 116 POWER WAKE +key 116 POWER key 117 NUMPAD_EQUALS # key 118 "KEY_KPPLUSMINUS" key 119 BREAK @@ -146,7 +146,7 @@ key 123 EISU key 124 YEN key 125 META_LEFT key 126 META_RIGHT -key 127 MENU WAKE_DROPPED +key 127 MENU key 128 MEDIA_STOP # key 129 "KEY_AGAIN" # key 130 "KEY_PROPS" @@ -158,11 +158,11 @@ key 128 MEDIA_STOP # key 136 "KEY_FIND" # key 137 "KEY_CUT" # key 138 "KEY_HELP" -key 139 MENU WAKE_DROPPED +key 139 MENU key 140 CALCULATOR # key 141 "KEY_SETUP" -key 142 SLEEP WAKE -key 143 WAKEUP WAKE +key 142 SLEEP +key 143 WAKEUP # key 144 "KEY_FILE" # key 145 "KEY_SENDFILE" # key 146 "KEY_DELETEFILE" @@ -171,13 +171,13 @@ key 143 WAKEUP WAKE # key 149 "KEY_PROG2" key 150 EXPLORER # key 151 "KEY_MSDOS" -key 152 POWER WAKE +key 152 POWER # key 153 "KEY_DIRECTION" # key 154 "KEY_CYCLEWINDOWS" key 155 ENVELOPE key 156 BOOKMARK # key 157 "KEY_COMPUTER" -key 158 BACK WAKE_DROPPED +key 158 BACK key 159 FORWARD key 160 MEDIA_CLOSE key 161 MEDIA_EJECT @@ -404,6 +404,8 @@ key 484 B FUNCTION # 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/data/keyboards/Vendor_0a5c_Product_8502.kl b/data/keyboards/Vendor_0a5c_Product_8502.kl index f6dbfd4..2f07328 100644 --- a/data/keyboards/Vendor_0a5c_Product_8502.kl +++ b/data/keyboards/Vendor_0a5c_Product_8502.kl @@ -24,7 +24,7 @@ key 316 BUTTON_MODE key 317 BUTTON_THUMBL key 318 BUTTON_THUMBR -key 158 BACK WAKE_DROPPED +key 158 BACK key 172 HOME axis 0x00 X diff --git a/data/keyboards/Vendor_18d1_Product_2c40.kl b/data/keyboards/Vendor_18d1_Product_2c40.kl index 903f13b..6efde4f 100644 --- a/data/keyboards/Vendor_18d1_Product_2c40.kl +++ b/data/keyboards/Vendor_18d1_Product_2c40.kl @@ -24,7 +24,7 @@ key 316 BUTTON_MODE key 317 BUTTON_THUMBL key 318 BUTTON_THUMBR -key 158 BACK WAKE_DROPPED +key 158 BACK key 172 HOME axis 0x00 X diff --git a/data/keyboards/qwerty.kl b/data/keyboards/qwerty.kl index f1caacd..58bf654 100644 --- a/data/keyboards/qwerty.kl +++ b/data/keyboards/qwerty.kl @@ -30,29 +30,29 @@ key 8 7 key 9 8 key 10 9 key 11 0 -key 158 BACK WAKE_DROPPED -key 230 SOFT_RIGHT WAKE -key 60 SOFT_RIGHT WAKE -key 107 ENDCALL WAKE_DROPPED -key 62 ENDCALL WAKE_DROPPED -key 229 MENU WAKE_DROPPED -key 139 MENU WAKE_DROPPED -key 59 MENU WAKE_DROPPED -key 127 SEARCH WAKE_DROPPED -key 217 SEARCH WAKE_DROPPED +key 158 BACK +key 230 SOFT_RIGHT +key 60 SOFT_LEFT +key 107 ENDCALL +key 62 ENDCALL +key 229 MENU +key 139 MENU +key 59 MENU +key 127 SEARCH +key 217 SEARCH key 228 POUND key 227 STAR -key 231 CALL WAKE_DROPPED -key 61 CALL WAKE_DROPPED -key 232 DPAD_CENTER WAKE_DROPPED -key 108 DPAD_DOWN WAKE_DROPPED -key 103 DPAD_UP WAKE_DROPPED -key 102 HOME WAKE -key 105 DPAD_LEFT WAKE_DROPPED -key 106 DPAD_RIGHT WAKE_DROPPED -key 115 VOLUME_UP WAKE -key 114 VOLUME_DOWN WAKE -key 116 POWER WAKE +key 231 CALL +key 61 CALL +key 232 DPAD_CENTER +key 108 DPAD_DOWN +key 103 DPAD_UP +key 102 HOME +key 105 DPAD_LEFT +key 106 DPAD_RIGHT +key 115 VOLUME_UP +key 114 VOLUME_DOWN +key 116 POWER key 212 CAMERA key 16 Q @@ -108,5 +108,5 @@ key 13 EQUALS key 215 AT # On an AT keyboard: ESC, F10 -key 1 BACK WAKE_DROPPED -key 68 MENU WAKE_DROPPED +key 1 BACK +key 68 MENU 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 @@ Platform Versions</a>.</p> </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 @@ Screens</a>.</p> </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 @@ support for any lower version (for example, support for version 2.0 also implies <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 @@ uses.</p> </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 @@ uses.</p> 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 @@ var VERSION_DATA = { "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 @@ var SCREEN_DATA = "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 @@ var SCREEN_DATA = "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/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd index 071492d..8ea5e7e 100644 --- a/docs/html/sdk/installing/studio.jd +++ b/docs/html/sdk/installing/studio.jd @@ -253,36 +253,36 @@ download (or continue to use) the <td>Windows</td> <td> <a onclick="return onDownload(this)" id="win-studio" - href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-windows.exe"> - android-studio-bundle-133.1028713-windows.exe + href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-windows.exe"> + android-studio-bundle-135.1078000-windows.exe </a> </td> - <td>519592042 bytes</td> - <td>9029c18738a75830786326d62c96d557</td> + <td>519082997 bytes</td> + <td>ac69889210c4d02ee3ccc1c0f3c5cf3c</td> </tr> <tr> <td><nobr>Mac OS X</nobr></td> <td> <a onclick="return onDownload(this)" id="mac-studio" - href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-mac.dmg"> - android-studio-bundle-133.1028713-mac.dmg + href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-mac.dmg"> + android-studio-bundle-135.1078000-mac.dmg </a> </td> - <td>497595811 bytes</td> - <td>eb2474e6d17537ddfa535e6fe8adcf0d</td> + <td>495989974 bytes</td> + <td>8c7b1ef376b8ca206c99823d9e8fd54d</td> </tr> <tr> <td>Linux</td> <td> <a onclick="return onDownload(this)" id="linux-studio" - href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-linux.tgz"> - android-studio-bundle-133.1028713-linux.tgz + href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-linux.tgz"> + android-studio-bundle-135.1078000-linux.tgz </a> </td> - <td>522177460 bytes</td> - <td>cc847dd6249b3033737dabe0377c8c66</td> + <td>520523870 bytes</td> + <td>689238d5e632fd236b13f9c6d49f0cb4</td> </tr> </table> @@ -430,6 +430,19 @@ style="vertical-align:bottom;margin:0;height:19px" /> in the toolbar.</p> <div class="toggle-content opened"> <p><a href="#" onclick="return toggleContent(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" + alt=""/>Android Studio v0.5.2</a> <em>(May 2014)</em> + </p> + + <div class="toggle-content-toggleme"> + <ul> + <li>See <a href="http://tools.android.com/recent">tools.android.com</a> for a full list of changes.</li> + </ul> + </div> +</div> + +<div class="toggle-content closed"> + <p><a href="#" onclick="return toggleContent(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""/>Android Studio v0.4.6</a> <em>(March 2014)</em> </p> @@ -650,7 +663,7 @@ for possible resolutions to known issues: <a href="http://tools.android.com/know if (os) { /* set up primary ACE download button */ $('#download-ide-button').show(); - $('#download-ide-button').append("Download Android Studio <span class='small'>v0.4.6</span>" + $('#download-ide-button').append("Download Android Studio <span class='small'>v0.5.2</span>" + "<br/> <span class='small'>for " + os + "</span>"); $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename); 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 @@ above.</p> <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/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 @@ public class ImageFormat { } 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/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 @@ public class PixelFormat info.bytesPerPixel = 1; break; default: - throw new IllegalArgumentException("unkonwon pixel format " + format); + throw new IllegalArgumentException("unknown pixel format " + format); } } @@ -135,4 +135,29 @@ public class PixelFormat 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/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 @@ class Ripple { /** 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 @@ class Ripple { 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; + + /** Configured maximum ripple radius. */ + private final int mMaxInsideRadius; - private int mMinRadius; - private int mOutsideRadius; + 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,272 +104,297 @@ class Ripple { 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; - - /** Exit state. A value in [0...1] or -1 if not set. */ - float mExitState = -1; + private boolean mPulseEnabled; - /** Outside state. A value in [0...1] or -1 if not set. */ - float mOutsideState = -1; + /** Temporary hack since we can't check finished state of animator. */ + private boolean mExitFinished; - /** 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())); + } + + public void setOuterRadius(float r) { + mOuterRadius = r; + invalidateSelf(); + } + + public float getOuterRadius() { + return mOuterRadius; + } - mMinRadius = (int) (density * STARTING_RADIUS_DP + 0.5f); - mOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f); + public void setInnerRadius(float r) { + mInnerRadius = r; + invalidateSelf(); } - - public void setMinRadius(int minRadius) { - mMinRadius = minRadius; + + public float getInnerRadius() { + return mInnerRadius; + } + + public void setAlphaMultiplier(float a) { + mAlphaMultiplier = a; + invalidateSelf(); } - - public void setOutsideRadius(int outsideRadius) { - mOutsideRadius = outsideRadius; + + public float getAlphaMultiplier() { + return mAlphaMultiplier; } /** - * Updates the center coordinates. + * Returns whether this ripple has finished exiting. */ - public void move(float x, float y) { - mX = x; - mY = y; - - final boolean inside = mBounds.contains((int) x, (int) y); - if (mInside != inside) { - if (mAnimator != null) { - mAnimator.outside(); - } - mInside = inside; - } + public boolean isFinished() { + return mExitFinished; } + /** + * Called when the bounds change. + */ public void onBoundsChanged() { - final boolean inside = mBounds.contains((int) mX, (int) mY); - if (mInside != inside) { - if (mAnimator != null) { - mAnimator.outside(); - } - mInside = inside; - } + mMaxRadius = Math.min(mMaxInsideRadius, Math.max(mBounds.width(), mBounds.height())); + + updateInsideBounds(); } - public RippleAnimator animate() { - if (mAnimator == null) { - mAnimator = new RippleAnimator(this); + 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(); + } } - return mAnimator; } + /** + * Draws the ripple using the specified paint. + */ 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 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); + 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 = 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; + final float x; + final float y; + if (mInsideBounds) { + x = mX; + y = mY; } 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); - } + // 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); } - 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; - } - } 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; - } - } - } + 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; } - return 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 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)); + final int maxRadius = mMaxRadius; bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius); } /** - * Constrains a value within a specified asymptotic margin outside a minimum - * and maximum. + * Updates the center coordinates. */ - private static float looseConstrain(float value, float min, float max, float margin, - float factor) { - if (value < min) { - return min - Math.min(margin, (float) Math.pow(min - value, factor)); - } else if (value > max) { - return max + Math.min(margin, (float) Math.pow(value - max, factor)); - } else { - 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; + public void move(float x, float y) { + mX = x; + mY = y; - /** Delay before pulses start. */ - private static final int PULSE_DELAY = 500; + updateInsideBounds(); + invalidateSelf(); + } - /** The target ripple being animated. */ - private final Ripple mTarget; + /** + * 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); + } - /** When the ripple started appearing. */ - private long mEnterTime = -1; + inner.start(); - /** When the ripple started vanishing. */ - private long mExitTime = -1; + final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0); + alpha.setAutoCancel(true); + alpha.setDuration(EXIT_DURATION); + alpha.start(); - /** When the ripple last transitioned between inside and outside touch. */ - private long mOutsideTime = -1; + mInner = inner; + mAlpha = alpha; + } - public RippleAnimator(Ripple target) { - mTarget = target; + /** + * Cancel all animations. + */ + public void cancel() { + if (mInner != null) { + mInner.cancel(); } - /** - * Starts the enter animation. - */ - public void enter() { - mEnterTime = AnimationUtils.currentAnimationTimeMillis(); + if (mOuter != null) { + mOuter.cancel(); } - /** - * 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()); + if (mAlpha != null) { + mAlpha.cancel(); } + } + + private void invalidateSelf() { + mOwner.invalidateSelf(); + } - /** - * Starts the outside transition animation. - */ - public void outside() { - mOutsideTime = AnimationUtils.currentAnimationTimeMillis(); + /** + * 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(); + + 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(); + + mAlpha = pulse; + } + }); } + alpha.setAutoCancel(true); + alpha.setDuration(FADE_DURATION); + alpha.start(); - /** - * 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); + mOuter = outer; + mAlpha = alpha; + } + + /** + * 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; + } + + /** + * Constrains a value within a specified asymptotic margin outside a minimum + * and maximum. + */ + 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) { + return max + Math.min(margin, (float) Math.pow(value - max, factor)); + } else { + return value; } + } - 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.PixelFormat; 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.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; -import java.util.Arrays; /** * Documentation pending. @@ -54,7 +51,6 @@ public class TouchFeedbackDrawable extends LayerDrawable { 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { /** 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { @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 @@ public class TouchFeedbackDrawable extends LayerDrawable { // 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { } 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { } 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { 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 @@ public class TouchFeedbackDrawable extends LayerDrawable { 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/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp index 904ec8c..c1af5f5 100644 --- a/libs/hwui/AmbientShadow.cpp +++ b/libs/hwui/AmbientShadow.cpp @@ -147,6 +147,8 @@ VertexBufferMode AmbientShadow::createAmbientShadow(bool isCasterOpaque, /** * Generate an array of rays' direction vectors. + * To make sure the vertices generated are clockwise, the directions are from PI + * to -PI. * * @param rays The number of rays shooting out from the centroid. * @param vertices Vertices of the polygon. @@ -160,8 +162,8 @@ void AmbientShadow::calculateRayDirections(const int rays, const Vector3* vertic if (vertexCount * 2 > rays) { float deltaAngle = 2 * M_PI / rays; for (int i = 0; i < rays; i++) { - dir[i].x = sinf(deltaAngle * i); - dir[i].y = cosf(deltaAngle * i); + dir[i].x = cosf(M_PI - deltaAngle * i); + dir[i].y = sinf(M_PI - deltaAngle * i); } return; } @@ -178,50 +180,52 @@ void AmbientShadow::calculateRayDirections(const int rays, const Vector3* vertic // Since the incoming polygon is clockwise, we can find the dip to identify // the minimal theta. float polyThetas[vertexCount]; - int minimalPolyThetaIndex = 0; + int maxPolyThetaIndex = 0; for (int i = 0; i < vertexCount; i++) { polyThetas[i] = atan2(vertices[i].y - centroid3d.y, vertices[i].x - centroid3d.x); - if (i > 0 && polyThetas[i] < polyThetas[i - 1]) { - minimalPolyThetaIndex = i; + if (i > 0 && polyThetas[i] > polyThetas[i - 1]) { + maxPolyThetaIndex = i; } } - int polyThetaIndex = minimalPolyThetaIndex; - float polyTheta = polyThetas[minimalPolyThetaIndex]; + // Both poly's thetas and uniform thetas are in decrease order(clockwise) + // from PI to -PI. + int polyThetaIndex = maxPolyThetaIndex; + float polyTheta = polyThetas[maxPolyThetaIndex]; int uniformThetaIndex = 0; - float uniformTheta = - M_PI; + float uniformTheta = M_PI; for (int i = 0; i < rays; i++) { // Compare both thetas and pick the smaller one and move on. bool hasThetaCollision = abs(polyTheta - uniformTheta) < MINIMAL_DELTA_THETA; - if (polyTheta < uniformTheta || hasThetaCollision) { + if (polyTheta > uniformTheta || hasThetaCollision) { if (hasThetaCollision) { // Shift the uniformTheta to middle way between current polyTheta // and next uniform theta. The next uniform theta can wrap around // to exactly PI safely here. // Note that neither polyTheta nor uniformTheta can be FLT_MAX // due to the hasThetaCollision is true. - uniformTheta = (polyTheta + deltaAngle * (uniformThetaIndex + 1) - M_PI) / 2; + uniformTheta = (polyTheta + M_PI - deltaAngle * (uniformThetaIndex + 1)) / 2; #if DEBUG_SHADOW ALOGD("Shifted uniformTheta to %f", uniformTheta); #endif } rayThetas[i] = polyTheta; polyThetaIndex = (polyThetaIndex + 1) % vertexCount; - if (polyThetaIndex != minimalPolyThetaIndex) { + if (polyThetaIndex != maxPolyThetaIndex) { polyTheta = polyThetas[polyThetaIndex]; } else { // out of poly points. - polyTheta = FLT_MAX; + polyTheta = - FLT_MAX; } } else { rayThetas[i] = uniformTheta; uniformThetaIndex++; if (uniformThetaIndex < uniformRayCount) { - uniformTheta = deltaAngle * uniformThetaIndex - M_PI; + uniformTheta = M_PI - deltaAngle * uniformThetaIndex; } else { // out of uniform points. - uniformTheta = FLT_MAX; + uniformTheta = - FLT_MAX; } } } @@ -232,8 +236,8 @@ void AmbientShadow::calculateRayDirections(const int rays, const Vector3* vertic #endif // TODO: Fix the intersection precision problem and remvoe the delta added // here. - dir[i].x = sinf(rayThetas[i] + MINIMAL_DELTA_THETA); - dir[i].y = cosf(rayThetas[i] + MINIMAL_DELTA_THETA); + dir[i].x = cosf(rayThetas[i] + MINIMAL_DELTA_THETA); + dir[i].y = sinf(rayThetas[i] + MINIMAL_DELTA_THETA); } } @@ -308,13 +312,12 @@ void AmbientShadow::calculateNormal(int rays, int currentRayIndex, Vector2 p1 = dir[preIndex] * rayDist[preIndex]; Vector2 p2 = dir[postIndex] * rayDist[postIndex]; - // Now the V (deltaX, deltaY) is the vector going CW around the poly. + // Now the rays are going CW around the poly. Vector2 delta = p2 - p1; if (delta.length() != 0) { delta.normalize(); - // Calculate the normal , which is CCW 90 rotate to the V. - // 90 degrees CCW about z-axis: (x, y, z) -> (-y, x, z) - normal.x = -delta.y; + // Calculate the normal , which is CCW 90 rotate to the delta. + normal.x = - delta.y; normal.y = delta.x; } } diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 52be531..d324439 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -11,6 +11,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) font/CacheTexture.cpp \ font/Font.cpp \ AmbientShadow.cpp \ + Animator.cpp \ AssetAtlas.cpp \ FontRenderer.cpp \ GammaFontRenderer.cpp \ @@ -25,6 +26,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) FboCache.cpp \ GradientCache.cpp \ Image.cpp \ + Interpolator.cpp \ Layer.cpp \ LayerCache.cpp \ LayerRenderer.cpp \ @@ -66,6 +68,8 @@ ifeq ($(USE_OPENGL_RENDERER),true) $(LOCAL_PATH)/../../include/utils \ external/skia/src/core + include external/stlport/libstlport.mk + LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_MODULE_CLASS := SHARED_LIBRARIES diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp new file mode 100644 index 0000000..6a3003e --- /dev/null +++ b/libs/hwui/Animator.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "RT-Animator" + +#include "Animator.h" + +#include <set> + +#include "RenderNode.h" +#include "RenderProperties.h" + +namespace android { +namespace uirenderer { + +/************************************************************ + * Base animator + ************************************************************/ + +BaseAnimator::BaseAnimator() + : mInterpolator(0) + , mPlayState(PENDING) + , mStartTime(0) + , mDuration(300) { + +} + +BaseAnimator::~BaseAnimator() { + setInterpolator(NULL); +} + +void BaseAnimator::setInterpolator(Interpolator* interpolator) { + delete mInterpolator; + mInterpolator = interpolator; +} + +void BaseAnimator::setDuration(nsecs_t duration) { + mDuration = duration; +} + +bool BaseAnimator::animateFrame(TreeInfo& info) { + if (mPlayState == PENDING) { + mPlayState = RUNNING; + mStartTime = info.frameTimeMs; + // No interpolator was set, use the default + if (!mInterpolator) { + setInterpolator(Interpolator::createDefaultInterpolator()); + } + onAnimationStarted(); + } + + float fraction = 1.0f; + if (mPlayState == RUNNING) { + fraction = mDuration > 0 ? (float)(info.frameTimeMs - mStartTime) / mDuration : 1.0f; + if (fraction >= 1.0f) { + fraction = 1.0f; + mPlayState = FINISHED; + } + } + fraction = mInterpolator->interpolate(fraction); + onAnimationUpdated(fraction); + + 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 + ************************************************************/ + +// 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]) { +} + +float RenderPropertyAnimator::getValue() const { + return (target()->animatorProperties().*mPropertyAccess.getter)(); +} + +void RenderPropertyAnimator::setValue(float value) { + (target()->animatorProperties().*mPropertyAccess.setter)(value); +} + +/************************************************************ + * CanvasPropertyPrimitiveAnimator + ************************************************************/ + +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 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 */ +} /* namespace android */ diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h new file mode 100644 index 0000000..0b074cc --- /dev/null +++ b/libs/hwui/Animator.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ANIMATOR_H +#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 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 + // the animator how to lazy-resolve the input value + enum DeltaValueType { + // The delta value represents an absolute value endpoint + // mDeltaValue needs to be recalculated to be mDelta = (mDelta - fromValue) + // in onAnimationStarted() + ABSOLUTE = 0, + // The final value represents an offset from the current value + // No recalculation is needed + DELTA, + }; + + bool animate(RenderNode* target, TreeInfo& info); + +protected: + BaseRenderNodeAnimator(DeltaValueType deltaType, float deltaValue); + + RenderNode* target() const { return mTarget; } + virtual float getValue() const = 0; + virtual void setValue(float value) = 0; + +private: + virtual void onAnimationStarted(); + virtual void onAnimationUpdated(float fraction); + + // mTarget is only valid inside animate() + RenderNode* mTarget; + + BaseRenderNodeAnimator::DeltaValueType mDeltaValueType; + float mDeltaValue; + float mFromValue; +}; + +class RenderPropertyAnimator : public BaseRenderNodeAnimator { +public: + enum RenderProperty { + TRANSLATION_X = 0, + TRANSLATION_Y, + TRANSLATION_Z, + SCALE_X, + SCALE_Y, + ROTATION, + ROTATION_X, + ROTATION_Y, + X, + Y, + Z, + ALPHA, + }; + + ANDROID_API RenderPropertyAnimator(RenderProperty property, + DeltaValueType deltaType, float deltaValue); + +protected: + ANDROID_API virtual float getValue() const; + ANDROID_API virtual void setValue(float value); + +private: + 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 */ +} /* namespace android */ + +#endif /* ANIMATOR_H */ diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index df2123b..43223ec 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -691,9 +691,10 @@ void Caches::initTempProperties() { propertyAmbientShadowStrength = 25; propertySpotShadowStrength = 25; - propertyLightPosXScale = 0.5f; - propertyLightPosYScale = 0.0f; - propertyLightPosZScale = 1.0f; + propertyLightDiameter = -1.0f; + propertyLightPosY = -1.0f; + propertyLightPosZ = -1.0f; + propertyAmbientRatio = -1.0f; } void Caches::setTempProperty(const char* name, const char* value) { @@ -706,17 +707,21 @@ void Caches::setTempProperty(const char* name, const char* value) { propertySpotShadowStrength = atoi(value); ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength); return; - } else if (!strcmp(name, "lightPosXScale")) { - propertyLightPosXScale = fmin(fmax(atof(value), 0.0), 1.0); - ALOGD("lightPos X Scale = %.2f", propertyLightPosXScale); + } else if (!strcmp(name, "ambientRatio")) { + propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0); + ALOGD("ambientRatio = %.2f", propertyAmbientRatio); return; - } else if (!strcmp(name, "lightPosYScale")) { - propertyLightPosYScale = fmin(fmax(atof(value), 0.0), 1.0); - ALOGD("lightPos Y Scale = %.2f", propertyLightPosXScale); + } else if (!strcmp(name, "lightDiameter")) { + propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0); + ALOGD("lightDiameter = %.2f", propertyLightDiameter); return; - } else if (!strcmp(name, "lightPosZScale")) { - propertyLightPosZScale = fmin(fmax(atof(value), 0.0), 1.0); - ALOGD("lightPos Z Scale = %.2f", propertyLightPosXScale); + } else if (!strcmp(name, "lightPosY")) { + propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0); + ALOGD("lightPos Y = %.2f", propertyLightPosY); + return; + } else if (!strcmp(name, "lightPosZ")) { + propertyLightPosZ = fmin(fmax(atof(value), 0.0), 3000.0); + ALOGD("lightPos Z = %.2f", propertyLightPosZ); return; } ALOGD(" failed"); diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index ba3ccaf..2e2ee15 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -352,13 +352,10 @@ public: void initTempProperties(); void setTempProperty(const char* name, const char* value); - // These scaling factors range from 0 to 1, to scale the light position - // within the bound of (screenwidth, screenheight, max(screenwidth, screenheight)); - // The default scale is (0.5, 0, 1) which put the light at - // (screenwidth / 2, 0, max(screenwidth, screenheight)). - float propertyLightPosXScale; - float propertyLightPosYScale; - float propertyLightPosZScale; + float propertyLightDiameter; + float propertyLightPosY; + float propertyLightPosZ; + float propertyAmbientRatio; int propertyAmbientShadowStrength; int propertySpotShadowStrength; 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 @@ public: 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 6dfb918..ce92beb 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1198,6 +1198,27 @@ private: 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 e36d975..8afd106 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -299,6 +299,17 @@ status_t DisplayListRenderer::drawCircle(float x, float y, float radius, const S 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 04c5a73..25e78c1 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -135,6 +135,8 @@ public: 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/Interpolator.cpp b/libs/hwui/Interpolator.cpp new file mode 100644 index 0000000..004ddf5 --- /dev/null +++ b/libs/hwui/Interpolator.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "Interpolator.h" + +#include <math.h> + +namespace android { +namespace uirenderer { + +Interpolator* Interpolator::createDefaultInterpolator() { + return new AccelerateDecelerateInterpolator(); +} + +float AccelerateDecelerateInterpolator::interpolate(float input) { + return (float)(cosf((input + 1) * M_PI) / 2.0f) + 0.5f; +} + +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h new file mode 100644 index 0000000..2cfb60c --- /dev/null +++ b/libs/hwui/Interpolator.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 INTERPOLATOR_H +#define INTERPOLATOR_H + +namespace android { +namespace uirenderer { + +class Interpolator { +public: + virtual ~Interpolator() {} + + virtual float interpolate(float input) = 0; + + static Interpolator* createDefaultInterpolator(); + +protected: + Interpolator() {} +}; + +class AccelerateDecelerateInterpolator : public Interpolator { +public: + AccelerateDecelerateInterpolator() {} + virtual ~AccelerateDecelerateInterpolator() {} + + virtual float interpolate(float input); +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* INTERPOLATOR_H */ diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 1f5389c..95fdb04 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -3230,6 +3230,10 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c const float casterRefinementThresholdSquared = 20.0f; // TODO: experiment with this value PathTessellator::approximatePathOutlineVertices(*casterPerimeter, casterRefinementThresholdSquared, casterVertices2d); + if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) { + ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(), + casterVertices2d.size()); + } if (casterVertices2d.size() == 0) { // empty caster polygon computed from path @@ -3287,10 +3291,8 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& c if (mCaches.propertySpotShadowStrength > 0) { paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0); VertexBuffer spotShadowVertexBuffer; - Vector3 lightPosScale(mCaches.propertyLightPosXScale, - mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale); VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow( - isCasterOpaque, casterPolygon, casterVertexCount, lightPosScale, + isCasterOpaque, casterPolygon, casterVertexCount, *currentTransform(), getWidth(), getHeight(), casterBounds, localClip, spotShadowVertexBuffer); drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index b49d1e1..7794abc 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -49,6 +49,7 @@ #include "UvMapper.h" #include "Vertex.h" #include "Caches.h" +#include "CanvasProperty.h" namespace android { namespace uirenderer { @@ -200,6 +201,12 @@ public: 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, diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 838e5ac..2c29985 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -18,6 +18,8 @@ #include "RenderNode.h" +#include <algorithm> + #include <SkCanvas.h> #include <algorithm> @@ -54,7 +56,8 @@ RenderNode::RenderNode() : mNeedsPropertiesSync(false) , mNeedsDisplayListDataSync(false) , mDisplayListData(0) - , mStagingDisplayListData(0) { + , mStagingDisplayListData(0) + , mNeedsAnimatorsSync(false) { } RenderNode::~RenderNode() { @@ -97,15 +100,32 @@ void RenderNode::prepareTree(TreeInfo& info) { } void RenderNode::prepareTreeImpl(TreeInfo& info) { - pushStagingChanges(info); + if (info.performStagingPush) { + pushStagingChanges(info); + } + if (info.evaluateAnimations) { + evaluateAnimations(info); + } prepareSubTree(info, mDisplayListData); } +static bool is_finished(const sp<BaseRenderNodeAnimator>& animator) { + return animator->isFinished(); +} + void RenderNode::pushStagingChanges(TreeInfo& info) { if (mNeedsPropertiesSync) { mNeedsPropertiesSync = false; mProperties = mStagingProperties; } + if (mNeedsAnimatorsSync) { + mAnimators.resize(mStagingAnimators.size()); + 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); + mAnimators.resize(std::distance(mAnimators.begin(), it)); + } if (mNeedsDisplayListDataSync) { mNeedsDisplayListDataSync = false; // Do a push pass on the old tree to handle freeing DisplayListData @@ -119,6 +139,30 @@ void RenderNode::pushStagingChanges(TreeInfo& info) { } } +class AnimateFunctor { +public: + AnimateFunctor(RenderNode* target, TreeInfo& info) + : mTarget(target), mInfo(info) {} + + bool operator() (sp<BaseRenderNodeAnimator>& animator) { + return animator->animate(mTarget, mInfo); + } +private: + RenderNode* mTarget; + TreeInfo& mInfo; +}; + +void RenderNode::evaluateAnimations(TreeInfo& info) { + if (!mAnimators.size()) return; + + 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(); +} + void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) { if (subtree) { TextureCache& cache = Caches::getInstance().textureCache; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index b9edbe5..159903c 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -20,6 +20,9 @@ #define LOG_TAG "OpenGLRenderer" #endif +#include <set> +#include <vector> + #include <SkCamera.h> #include <SkMatrix.h> @@ -41,6 +44,7 @@ #include "DeferredDisplayList.h" #include "DisplayList.h" #include "RenderProperties.h" +#include "TreeInfo.h" #include "utils/VirtualLightRefBase.h" class SkBitmap; @@ -65,17 +69,6 @@ class SaveOp; class RestoreToCountOp; class DrawDisplayListOp; -struct TreeInfo { - TreeInfo() - : hasFunctors(false) - , prepareTextures(false) - {} - - bool hasFunctors; - bool prepareTextures; - // TODO: Damage calculations? Flag to skip staging pushes for RT animations? -}; - /** * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties. * @@ -91,7 +84,7 @@ struct TreeInfo { class RenderNode : public VirtualLightRefBase { public: ANDROID_API RenderNode(); - ANDROID_API ~RenderNode(); + ANDROID_API virtual ~RenderNode(); // See flags defined in DisplayList.java enum ReplayFlag { @@ -135,6 +128,10 @@ public: return mProperties; } + RenderProperties& animatorProperties() { + return mProperties; + } + const RenderProperties& stagingProperties() { return mStagingProperties; } @@ -152,7 +149,19 @@ public: return properties().getHeight(); } - ANDROID_API void prepareTree(TreeInfo& info); + ANDROID_API virtual void prepareTree(TreeInfo& info); + + // UI thread only! + ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) { + mStagingAnimators.insert(animator); + mNeedsAnimatorsSync = true; + } + + // UI thread only! + ANDROID_API void removeAnimator(const sp<BaseRenderNodeAnimator>& animator) { + mStagingAnimators.erase(animator); + mNeedsAnimatorsSync = true; + } private: typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair; @@ -214,6 +223,7 @@ private: void prepareTreeImpl(TreeInfo& info); void pushStagingChanges(TreeInfo& info); + void evaluateAnimations(TreeInfo& info); void prepareSubTree(TreeInfo& info, DisplayListData* subtree); String8 mName; @@ -226,6 +236,10 @@ private: DisplayListData* mDisplayListData; DisplayListData* mStagingDisplayListData; + bool mNeedsAnimatorsSync; + 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/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp index 9ec7297..99de1fc 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -51,7 +51,8 @@ RenderProperties::PrimitiveFields::PrimitiveFields() RenderProperties::ComputedFields::ComputedFields() : mTransformMatrix(NULL) - , mClipPath(NULL) { + , mClipPath(NULL) + , mClipPathOp(SkRegion::kIntersect_Op) { } RenderProperties::ComputedFields::~ComputedFields() { diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 8fc2dd0..6fc8bce 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -16,7 +16,9 @@ #ifndef RENDERNODEPROPERTIES_H #define RENDERNODEPROPERTIES_H +#include <algorithm> #include <stddef.h> +#include <vector> #include <cutils/compiler.h> #include <androidfw/ResourceTypes.h> @@ -24,6 +26,7 @@ #include <SkMatrix.h> #include <SkRegion.h> +#include "Animator.h" #include "Rect.h" #include "RevealClip.h" #include "Outline.h" @@ -149,6 +152,31 @@ public: return mPrimitiveFields.mTranslationZ; } + // Animation helper + void setX(float value) { + setTranslationX(value - getLeft()); + } + + // Animation helper + float getX() const { + return getLeft() + getTranslationX(); + } + + // Animation helper + void setY(float value) { + setTranslationY(value - getTop()); + } + + // Animation helper + float getY() const { + return getTop() + getTranslationY(); + } + + // Animation helper + void setZ(float value) { + setTranslationZ(value - getElevation()); + } + float getZ() const { return getElevation() + getTranslationZ(); } @@ -457,7 +485,6 @@ private: bool mCaching; } mPrimitiveFields; - // mCameraDistance isn't in mPrimitiveFields as it has a complex setter SkMatrix* mStaticMatrix; SkMatrix* mAnimationMatrix; diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp index 4d0edfb..be49aed 100644 --- a/libs/hwui/ShadowTessellator.cpp +++ b/libs/hwui/ShadowTessellator.cpp @@ -22,6 +22,7 @@ #include <utils/Trace.h> #include "AmbientShadow.h" +#include "Caches.h" #include "ShadowTessellator.h" #include "SpotShadow.h" @@ -41,9 +42,14 @@ VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque, // A bunch of parameters to tweak the shadow. // TODO: Allow some of these changable by debug settings or APIs. - const float heightFactor = 1.0f / 128; + float heightFactor = 1.0f / 128; const float geomFactor = 64; + Caches& caches = Caches::getInstance(); + if (CC_UNLIKELY(caches.propertyAmbientRatio > 0.0f)) { + heightFactor *= caches.propertyAmbientRatio; + } + Rect ambientShadowBounds(casterBounds); ambientShadowBounds.outset(maxZ * geomFactor * heightFactor); @@ -62,16 +68,26 @@ VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque, VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque, const Vector3* casterPolygon, int casterVertexCount, - const Vector3& lightPosScale, const mat4& receiverTransform, + const mat4& receiverTransform, int screenWidth, int screenHeight, const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer) { ATRACE_CALL(); + Caches& caches = Caches::getInstance(); + // A bunch of parameters to tweak the shadow. // TODO: Allow some of these changable by debug settings or APIs. int maximal = max(screenWidth, screenHeight); - Vector3 lightCenter(screenWidth * lightPosScale.x, screenHeight * lightPosScale.y, - maximal * lightPosScale.z); + Vector3 lightCenter(screenWidth * 0.5f, 0, maximal); + + if (CC_UNLIKELY(caches.propertyLightPosY > 0)) { + lightCenter.y = - caches.propertyLightPosY; // negated since this shifts up + } + if (CC_UNLIKELY(caches.propertyLightPosZ > 0)) { + lightCenter.z = caches.propertyLightPosZ; + } + + #if DEBUG_SHADOW ALOGD("light center %f %f %f", lightCenter.x, lightCenter.y, lightCenter.z); #endif @@ -82,9 +98,13 @@ VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque, reverseReceiverTransform.loadInverse(receiverTransform); reverseReceiverTransform.mapPoint3d(lightCenter); - const float lightSize = maximal / 4; + float lightSize = maximal / 4; const int lightVertexCount = 8; + if (CC_UNLIKELY(caches.propertyLightDiameter > 0)) { + lightSize = caches.propertyLightDiameter; + } + // Now light and caster are both in local space, we will check whether // the shadow is within the clip area. Rect lightRect = Rect(lightCenter.x - lightSize, lightCenter.y - lightSize, @@ -169,5 +189,67 @@ Vector2 ShadowTessellator::centroid2d(const Vector2* poly, int polyLength) { return centroid; } +/** + * Test whether the polygon is order in clockwise. + * + * @param polygon the polygon as a Vector2 array + * @param len the number of points of the polygon + */ +bool ShadowTessellator::isClockwise(const Vector2* polygon, int len) { + double sum = 0; + double p1x = polygon[len - 1].x; + double p1y = polygon[len - 1].y; + for (int i = 0; i < len; i++) { + + double p2x = polygon[i].x; + double p2y = polygon[i].y; + sum += p1x * p2y - p2x * p1y; + p1x = p2x; + p1y = p2y; + } + return sum < 0; +} + +bool ShadowTessellator::isClockwisePath(const SkPath& path) { + SkPath::Iter iter(path, false); + SkPoint pts[4]; + SkPath::Verb v; + + Vector<Vector2> arrayForDirection; + while (SkPath::kDone_Verb != (v = iter.next(pts))) { + switch (v) { + case SkPath::kMove_Verb: + arrayForDirection.add(Vector2(pts[0].x(), pts[0].y())); + break; + case SkPath::kLine_Verb: + arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); + break; + case SkPath::kQuad_Verb: + arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); + arrayForDirection.add(Vector2(pts[2].x(), pts[2].y())); + break; + case SkPath::kCubic_Verb: + arrayForDirection.add(Vector2(pts[1].x(), pts[1].y())); + arrayForDirection.add(Vector2(pts[2].x(), pts[2].y())); + arrayForDirection.add(Vector2(pts[3].x(), pts[3].y())); + break; + default: + break; + } + } + + return isClockwise(arrayForDirection.array(), arrayForDirection.size()); +} + +void ShadowTessellator::reverseVertexArray(Vertex* polygon, int len) { + int n = len / 2; + for (int i = 0; i < n; i++) { + Vertex tmp = polygon[i]; + int k = len - 1 - i; + polygon[i] = polygon[k]; + polygon[k] = tmp; + } +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h index 05370dd..e5a3da1 100644 --- a/libs/hwui/ShadowTessellator.h +++ b/libs/hwui/ShadowTessellator.h @@ -73,13 +73,34 @@ public: static VertexBufferMode tessellateSpotShadow(bool isCasterOpaque, const Vector3* casterPolygon, int casterVertexCount, - const Vector3& lightPosScale, const mat4& receiverTransform, + const mat4& receiverTransform, int screenWidth, int screenHeight, const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer); static void generateShadowIndices(uint16_t* shadowIndices); static Vector2 centroid2d(const Vector2* poly, int polyLength); + + static bool isClockwise(const Vector2* polygon, int len); + + /** + * Determine whether the path is clockwise, using the control points. + * + * TODO: Given the skia is using inverted Y coordinate, shadow system needs + * to convert to the same coordinate to avoid the extra reverse. + * + * @param path The path to be examined. + */ + static bool isClockwisePath(const SkPath &path); + + /** + * Reverse the vertex array. + * + * @param polygon The vertex array to be reversed. + * @param len The length of the vertex array. + */ + static void reverseVertexArray(Vertex* polygon, int len); + }; // ShadowTessellator }; // namespace uirenderer diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp index 5fa0ba5..3ebe7b4 100644 --- a/libs/hwui/SpotShadow.cpp +++ b/libs/hwui/SpotShadow.cpp @@ -174,10 +174,10 @@ bool SpotShadow::ccw(double ax, double ay, double bx, double by, int SpotShadow::intersection(const Vector2* poly1, int poly1Length, Vector2* poly2, int poly2Length) { #if DEBUG_SHADOW - if (!isClockwise(poly1, poly1Length)) { + if (!ShadowTessellator::isClockwise(poly1, poly1Length)) { ALOGW("Poly1 is not clockwise! Intersection is wrong!"); } - if (!isClockwise(poly2, poly2Length)) { + if (!ShadowTessellator::isClockwise(poly2, poly2Length)) { ALOGW("Poly2 is not clockwise! Intersection is wrong!"); } #endif @@ -407,33 +407,12 @@ void SpotShadow::makeClockwise(Vector2* polygon, int len) { if (polygon == 0 || len == 0) { return; } - if (!isClockwise(polygon, len)) { + if (!ShadowTessellator::isClockwise(polygon, len)) { reverse(polygon, len); } } /** - * Test whether the polygon is order in clockwise. - * - * @param polygon the polygon as a Vector2 array - * @param len the number of points of the polygon - */ -bool SpotShadow::isClockwise(const Vector2* polygon, int len) { - double sum = 0; - double p1x = polygon[len - 1].x; - double p1y = polygon[len - 1].y; - for (int i = 0; i < len; i++) { - - double p2x = polygon[i].x; - double p2y = polygon[i].y; - sum += p1x * p2y - p2x * p1y; - p1x = p2x; - p1y = p2y; - } - return sum < 0; -} - -/** * Reverse the polygon * * @param polygon the polygon as a Vector2 array diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h index 599d37e..fb3e6d5 100644 --- a/libs/hwui/SpotShadow.h +++ b/libs/hwui/SpotShadow.h @@ -56,7 +56,6 @@ private: static bool testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len); static void makeClockwise(Vector2* polygon, int len); - static bool isClockwise(const Vector2* polygon, int len); static void reverse(Vector2* polygon, int len); static inline bool lineIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, Vector2& ret); diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h new file mode 100644 index 0000000..a383fbf --- /dev/null +++ b/libs/hwui/TreeInfo.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef TREEINFO_H +#define TREEINFO_H + +#include <utils/Timers.h> + +namespace android { +namespace uirenderer { + +class BaseAnimator; +class AnimationListener; + +class AnimationHook { +public: + virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) = 0; +protected: + ~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) + , animationHook(0) + {} + + bool hasFunctors; + bool prepareTextures; + bool performStagingPush; + + // Animations + nsecs_t frameTimeMs; + bool evaluateAnimations; + // This is only updated if evaluateAnimations is true + bool hasAnimations; + AnimationHook* animationHook; + + // TODO: Damage calculations +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* TREEINFO_H */ diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 5ce7ba6..63f4b95 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -308,18 +308,20 @@ bool GlobalContext::enableDirtyRegions(EGLSurface surface) { return value == EGL_BUFFER_PRESERVED; } -CanvasContext::CanvasContext(bool translucent) +CanvasContext::CanvasContext(bool translucent, RenderNode* rootRenderNode) : mRenderThread(RenderThread::getInstance()) , mEglSurface(EGL_NO_SURFACE) , mDirtyRegionsEnabled(false) , mOpaque(!translucent) , mCanvas(0) - , mHaveNewSurface(false) { + , mHaveNewSurface(false) + , mRootRenderNode(rootRenderNode) { mGlobalContext = GlobalContext::get(); } CanvasContext::~CanvasContext() { destroyCanvasAndSurface(); + mRenderThread.removeFrameCallback(this); } void CanvasContext::destroyCanvasAndSurface() { @@ -403,7 +405,16 @@ void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* lay } } -void CanvasContext::drawDisplayList(RenderNode* displayList, Rect* dirty) { +void CanvasContext::prepareTree(TreeInfo& info) { + mRootRenderNode->prepareTree(info); + + if (info.hasAnimations && !info.hasFunctors) { + // TODO: Functors + mRenderThread.postFrameCallback(this); + } +} + +void CanvasContext::draw(Rect* dirty) { LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, "drawDisplayList called on a context with no canvas or surface!"); @@ -417,7 +428,7 @@ void CanvasContext::drawDisplayList(RenderNode* displayList, Rect* dirty) { } status_t status; - if (dirty) { + if (dirty && !dirty->isEmpty()) { status = mCanvas->prepareDirty(dirty->left, dirty->top, dirty->right, dirty->bottom, mOpaque); } else { @@ -425,7 +436,7 @@ void CanvasContext::drawDisplayList(RenderNode* displayList, Rect* dirty) { } Rect outBounds; - status |= mCanvas->drawDisplayList(displayList, outBounds); + status |= mCanvas->drawDisplayList(mRootRenderNode.get(), outBounds); // TODO: Draw debug info // TODO: Performance tracking @@ -437,6 +448,20 @@ void CanvasContext::drawDisplayList(RenderNode* displayList, Rect* dirty) { } } +// Called by choreographer to do an RT-driven animation +void CanvasContext::doFrame(nsecs_t frameTimeNanos) { + ATRACE_CALL(); + + TreeInfo info; + info.evaluateAnimations = true; + info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNanos); + info.performStagingPush = false; + info.prepareTextures = false; + + prepareTree(info); + draw(NULL); +} + void CanvasContext::invokeFunctor(Functor* functor) { ATRACE_CALL(); DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index a3fe591..0873ad4 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -25,6 +25,7 @@ #include "../RenderNode.h" #include "RenderTask.h" +#include "RenderThread.h" #define FUNCTOR_PROCESS_DELAY 4 @@ -39,15 +40,13 @@ class Layer; namespace renderthread { class GlobalContext; -class CanvasContext; -class RenderThread; // This per-renderer class manages the bridge between the global EGL context // and the render surface. -class CanvasContext { +class CanvasContext : public IFrameCallback { public: - CanvasContext(bool translucent); - ~CanvasContext(); + CanvasContext(bool translucent, RenderNode* rootRenderNode); + virtual ~CanvasContext(); bool initialize(EGLNativeWindowType window); void updateSurface(EGLNativeWindowType window); @@ -55,9 +54,13 @@ public: void setup(int width, int height); void makeCurrent(); void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info); - void drawDisplayList(RenderNode* displayList, Rect* dirty); + void prepareTree(TreeInfo& info); + void draw(Rect* dirty); void destroyCanvasAndSurface(); + // IFrameCallback, Chroreographer-driven frame callback entry point + virtual void doFrame(nsecs_t frameTimeNanos); + bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); void invokeFunctor(Functor* functor); @@ -82,6 +85,8 @@ private: bool mOpaque; OpenGLRenderer* mCanvas; bool mHaveNewSurface; + + const sp<RenderNode> mRootRenderNode; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index f542d43..45f5cb0 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -30,7 +30,7 @@ namespace android { namespace uirenderer { namespace renderthread { -DrawFrameTask::DrawFrameTask() : mContext(0), mRenderNode(0) { +DrawFrameTask::DrawFrameTask() : mContext(0) { } DrawFrameTask::~DrawFrameTask() { @@ -55,25 +55,17 @@ void DrawFrameTask::removeLayer(DeferredLayerUpdater* layer) { } } -void DrawFrameTask::setRenderNode(RenderNode* renderNode) { - LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to setRenderNode with!"); - - mRenderNode = renderNode; -} - void DrawFrameTask::setDirty(int left, int top, int right, int bottom) { mDirty.set(left, top, right, bottom); } void DrawFrameTask::drawFrame(RenderThread* renderThread) { - LOG_ALWAYS_FATAL_IF(!mRenderNode.get(), "Cannot drawFrame with no render node!"); LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); postAndWait(renderThread); // Reset the single-frame data mDirty.setEmpty(); - mRenderNode = 0; } void DrawFrameTask::postAndWait(RenderThread* renderThread) { @@ -88,8 +80,7 @@ void DrawFrameTask::run() { bool canUnblockUiThread = syncFrameState(); // Grab a copy of everything we need - Rect dirtyCopy(mDirty); - sp<RenderNode> renderNode = mRenderNode; + Rect dirty(mDirty); CanvasContext* context = mContext; // From this point on anything in "this" is *UNSAFE TO ACCESS* @@ -97,15 +88,20 @@ void DrawFrameTask::run() { unblockUiThread(); } - drawRenderNode(context, renderNode.get(), &dirtyCopy); + context->draw(&dirty); if (!canUnblockUiThread) { unblockUiThread(); } } -static void prepareTreeInfo(TreeInfo& info) { +static void initTreeInfo(TreeInfo& info) { 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() { @@ -113,9 +109,13 @@ bool DrawFrameTask::syncFrameState() { mContext->makeCurrent(); Caches::getInstance().textureCache.resetMarkInUse(); TreeInfo info; - prepareTreeInfo(info); + initTreeInfo(info); mContext->processLayerUpdates(&mLayers, info); - mRenderNode->prepareTree(info); + mContext->prepareTree(info); + if (info.hasAnimations) { + // TODO: dirty calculations, for now just do a full-screen inval + mDirty.setEmpty(); + } // If prepareTextures is false, we ran out of texture cache space return !info.hasFunctors && info.prepareTextures; } @@ -125,16 +125,6 @@ void DrawFrameTask::unblockUiThread() { mSignal.signal(); } -void DrawFrameTask::drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty) { - ATRACE_CALL(); - - if (dirty->bottom == -1 && dirty->left == -1 - && dirty->top == -1 && dirty->right == -1) { - dirty = 0; - } - context->drawDisplayList(renderNode, dirty); -} - } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index 055d4cf..c280868 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -53,7 +53,6 @@ public: void addLayer(DeferredLayerUpdater* layer); void removeLayer(DeferredLayerUpdater* layer); - void setRenderNode(RenderNode* renderNode); void setDirty(int left, int top, int right, int bottom); void drawFrame(RenderThread* renderThread); @@ -63,7 +62,6 @@ private: void postAndWait(RenderThread* renderThread); bool syncFrameState(); void unblockUiThread(); - static void drawRenderNode(CanvasContext* context, RenderNode* renderNode, Rect* dirty); Mutex mLock; Condition mSignal; @@ -73,7 +71,6 @@ private: /********************************************* * Single frame data *********************************************/ - sp<RenderNode> mRenderNode; Rect mDirty; /********************************************* diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index ce490f1..87886e6 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -51,15 +51,16 @@ namespace renderthread { MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \ ARGS(method) *args = (ARGS(method) *) task->payload() -CREATE_BRIDGE1(createContext, bool translucent) { - return new CanvasContext(args->translucent); +CREATE_BRIDGE2(createContext, bool translucent, RenderNode* rootRenderNode) { + return new CanvasContext(args->translucent, args->rootRenderNode); } -RenderProxy::RenderProxy(bool translucent) +RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode) : mRenderThread(RenderThread::getInstance()) , mContext(0) { SETUP_TASK(createContext); args->translucent = translucent; + args->rootRenderNode = rootRenderNode; mContext = (CanvasContext*) postAndWait(task); mDrawFrameTask.setContext(mContext); } @@ -133,9 +134,8 @@ void RenderProxy::setup(int width, int height) { post(task); } -void RenderProxy::drawDisplayList(RenderNode* displayList, +void RenderProxy::syncAndDrawFrame( int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) { - mDrawFrameTask.setRenderNode(displayList); mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); mDrawFrameTask.drawFrame(&mRenderThread); } diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index a112493..eab1395 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -56,14 +56,14 @@ class RenderProxyBridge; */ class ANDROID_API RenderProxy { public: - ANDROID_API RenderProxy(bool translucent); + ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode); ANDROID_API virtual ~RenderProxy(); 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 drawDisplayList(RenderNode* displayList, + ANDROID_API void syncAndDrawFrame( 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 212f475..e95707a 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -18,9 +18,11 @@ #include "RenderThread.h" +#include <gui/DisplayEventReceiver.h> +#include <utils/Log.h> + #include "CanvasContext.h" #include "RenderProxy.h" -#include <utils/Log.h> namespace android { using namespace uirenderer::renderthread; @@ -29,6 +31,14 @@ ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread); namespace uirenderer { namespace renderthread { +// Number of events to read at a time from the DisplayEventReceiver pipe. +// The value should be large enough that we can quickly drain the pipe +// using just a few large reads. +static const size_t EVENT_BUFFER_SIZE = 100; + +// Slight delay to give the UI time to push us a new frame before we replay +static const int DISPATCH_FRAME_CALLBACKS_DELAY = 0; + TaskQueue::TaskQueue() : mHead(0), mTail(0) {} RenderTask* TaskQueue::next() { @@ -103,8 +113,25 @@ void TaskQueue::remove(RenderTask* task) { } } +class DispatchFrameCallbacks : public RenderTask { +private: + RenderThread* mRenderThread; +public: + DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {} + + virtual void run() { + mRenderThread->dispatchFrameCallbacks(); + } +}; + RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>() - , mNextWakeup(LLONG_MAX) { + , mNextWakeup(LLONG_MAX) + , mDisplayEventReceiver(0) + , mVsyncRequested(false) + , mFrameCallbackTaskPending(false) + , mFrameCallbackTask(0) + , mFrameTime(0) { + mFrameCallbackTask = new DispatchFrameCallbacks(this); mLooper = new Looper(false); run("RenderThread"); } @@ -112,10 +139,86 @@ RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>() RenderThread::~RenderThread() { } +void RenderThread::initializeDisplayEventReceiver() { + LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?"); + mDisplayEventReceiver = new DisplayEventReceiver(); + status_t status = mDisplayEventReceiver->initCheck(); + LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver " + "failed with status: %d", status); + + // Register the FD + mLooper->addFd(mDisplayEventReceiver->getFd(), 0, + Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this); +} + +int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) { + if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { + ALOGE("Display event receiver pipe was closed or an error occurred. " + "events=0x%x", events); + return 0; // remove the callback + } + + if (!(events & Looper::EVENT_INPUT)) { + ALOGW("Received spurious callback for unhandled poll event. " + "events=0x%x", events); + return 1; // keep the callback + } + + reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue(); + + return 1; // keep the callback +} + +static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { + DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; + nsecs_t latest = 0; + ssize_t n; + while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { + for (ssize_t i = 0; i < n; i++) { + const DisplayEventReceiver::Event& ev = buf[i]; + switch (ev.header.type) { + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: + latest = ev.header.timestamp; + break; + } + } + } + if (n < 0) { + ALOGW("Failed to get events from display event receiver, status=%d", status_t(n)); + } + return latest; +} + +void RenderThread::drainDisplayEventQueue() { + nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver); + if (vsyncEvent > 0) { + mVsyncRequested = false; + mFrameTime = vsyncEvent; + if (!mFrameCallbackTaskPending) { + mFrameCallbackTaskPending = true; + //queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY); + queue(mFrameCallbackTask); + } + } +} + +void RenderThread::dispatchFrameCallbacks() { + mFrameCallbackTaskPending = false; + + std::set<IFrameCallback*> callbacks; + mFrameCallbacks.swap(callbacks); + + for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) { + (*it)->doFrame(mFrameTime); + } +} + bool RenderThread::threadLoop() { + initializeDisplayEventReceiver(); + int timeoutMillis = -1; for (;;) { - int result = mLooper->pollAll(timeoutMillis); + int result = mLooper->pollOnce(timeoutMillis); LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, "RenderThread Looper POLL_ERROR!"); @@ -159,6 +262,20 @@ void RenderThread::remove(RenderTask* task) { mQueue.remove(task); } +void RenderThread::postFrameCallback(IFrameCallback* callback) { + mFrameCallbacks.insert(callback); + if (!mVsyncRequested) { + mVsyncRequested = true; + status_t status = mDisplayEventReceiver->requestNextVsync(); + LOG_ALWAYS_FATAL_IF(status != NO_ERROR, + "requestNextVsync failed with status: %d", status); + } +} + +void RenderThread::removeFrameCallback(IFrameCallback* callback) { + mFrameCallbacks.erase(callback); +} + RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { AutoMutex _lock(mLock); RenderTask* next = mQueue.peek(); diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index e444aa0..b93dfd6 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -18,6 +18,10 @@ #define RENDERTHREAD_H_ #include "RenderTask.h" + +#include <memory> +#include <set> + #include <cutils/compiler.h> #include <utils/Looper.h> #include <utils/Mutex.h> @@ -25,9 +29,13 @@ #include <utils/Thread.h> namespace android { +class DisplayEventReceiver; + namespace uirenderer { namespace renderthread { +class DispatchFrameCallbacks; + class TaskQueue { public: TaskQueue(); @@ -42,6 +50,15 @@ private: RenderTask* mTail; }; +// Mimics android.view.Choreographer.FrameCallback +class IFrameCallback { +public: + virtual void doFrame(nsecs_t frameTimeNanos) = 0; + +protected: + ~IFrameCallback() {} +}; + class ANDROID_API RenderThread : public Thread, public Singleton<RenderThread> { public: // RenderThread takes complete ownership of tasks that are queued @@ -50,15 +67,25 @@ public: void queueDelayed(RenderTask* task, int delayMs); void remove(RenderTask* task); + // Mimics android.view.Choreographer + void postFrameCallback(IFrameCallback* callback); + void removeFrameCallback(IFrameCallback* callback); + protected: virtual bool threadLoop(); private: friend class Singleton<RenderThread>; + friend class DispatchFrameCallbacks; RenderThread(); virtual ~RenderThread(); + void initializeDisplayEventReceiver(); + static int displayEventReceiverCallback(int fd, int events, void* data); + void drainDisplayEventQueue(); + void dispatchFrameCallbacks(); + // Returns the next task to be run. If this returns NULL nextWakeup is set // to the time to requery for the nextTask to run. mNextWakeup is also // set to this time @@ -69,6 +96,13 @@ private: nsecs_t mNextWakeup; TaskQueue mQueue; + + DisplayEventReceiver* mDisplayEventReceiver; + bool mVsyncRequested; + std::set<IFrameCallback*> mFrameCallbacks; + bool mFrameCallbackTaskPending; + DispatchFrameCallbacks* mFrameCallbackTask; + nsecs_t mFrameTime; }; } /* namespace renderthread */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnSizeChangedListener.java b/libs/hwui/utils/Macros.h index 0377123..14a3ec0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/OnSizeChangedListener.java +++ b/libs/hwui/utils/Macros.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 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. @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#ifndef MACROS_H +#define MACROS_H -package com.android.systemui.statusbar.policy; +#define PREVENT_COPY_AND_ASSIGN(Type) \ + private: \ + Type(const Type&); \ + void operator=(const Type&) -import android.view.View; -public interface OnSizeChangedListener { - void onSizeChanged(View view, int w, int h, int oldw, int oldh); -} +#endif /* MACROS_H */ diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 04c6e97..ad0d459 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -88,12 +88,22 @@ public class AudioFormat { public static final int CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT; public static final int CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT); + // aka QUAD_BACK public static final int CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT); + /** @hide */ + public static final int CHANNEL_OUT_QUAD_SIDE = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | + CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT); public static final int CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER); + // aka 5POINT1_BACK public static final int CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT); + /** @hide */ + public static final int CHANNEL_OUT_5POINT1_SIDE = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | + CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | + CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT); + // TODO does this need an @deprecated ? // different from AUDIO_CHANNEL_OUT_7POINT1 public static final int CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | 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.ComponentName; 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 @@ import java.util.HashMap; */ 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 class AudioManager { public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE; private static IAudioService sService; + private MediaSessionLegacyHelper mSessionHelper; /** * @hide @@ -431,6 +439,9 @@ public class AudioManager { 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 @@ public class AudioManager { } catch (RemoteException e) { Log.e(TAG, "Dead object in registerMediaButtonIntent"+e); } + if (USE_SESSIONS) { + mSessionHelper.addMediaButtonListener(pi, mContext); + } } /** @@ -2239,6 +2253,9 @@ public class AudioManager { } catch (RemoteException e) { Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e); } + if (USE_SESSIONS) { + mSessionHelper.removeMediaButtonListener(pi); + } } /** @@ -2263,6 +2280,9 @@ public class AudioManager { } catch (RemoteException e) { Log.e(TAG, "Dead object in registerRemoteControlClient"+e); } + if (USE_SESSIONS) { + rcClient.registerWithSession(mSessionHelper); + } } /** @@ -2282,6 +2302,9 @@ public class AudioManager { } catch (RemoteException e) { Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e); } + if (USE_SESSIONS) { + rcClient.unregisterWithSession(mSessionHelper); + } } /** 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 @@ public class AudioService extends IAudioService.Stub { /** @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/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java index 2dea509..1c73c05 100644 --- a/media/java/android/media/MediaFocusControl.java +++ b/media/java/android/media/MediaFocusControl.java @@ -1250,8 +1250,6 @@ public class MediaFocusControl implements OnFinished { } if (prse.hasMatchingMediaButtonIntent(mediaIntent)) { inStackIndex = index; - // found it, ok to stop here - break; } } @@ -1272,7 +1270,11 @@ public class MediaFocusControl implements OnFinished { mPRStack.push(prse); } else { // and put it after the ones with active playback - mPRStack.add(lastPlayingIndex, prse); + if (inStackIndex > lastPlayingIndex) { + mPRStack.add(lastPlayingIndex, prse); + } else { + mPRStack.add(lastPlayingIndex - 1, prse); + } } } } @@ -2151,13 +2153,13 @@ public class MediaFocusControl implements OnFinished { // of this RemoteControlClient (note that it may not be in the stack) for (int index = mPRStack.size()-1; index >= 0; index--) { prse = mPRStack.elementAt(index); - if (prse.isPlaybackActive()) { - lastPlayingIndex = index; - } if (prse.getRccId() == rccId) { inStackIndex = index; prse.mPlaybackState = newState; } + if (prse.isPlaybackActive()) { + lastPlayingIndex = index; + } } if (inStackIndex != -1) { @@ -2177,7 +2179,11 @@ public class MediaFocusControl implements OnFinished { mPRStack.push(prse); } else { // and put it after the ones with active playback - mPRStack.add(lastPlayingIndex, prse); + if (inStackIndex > lastPlayingIndex) { + mPRStack.add(lastPlayingIndex, prse); + } else { + mPRStack.add(lastPlayingIndex - 1, prse); + } } } 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.CookieManager; 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 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { 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 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { try { disconnect(); + mAllowCrossDomainRedirect = true; mURL = new URL(uri); mHeaders = convertHeaderStringToMap(headers); } catch (MalformedURLException e) { @@ -68,6 +78,25 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { 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 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { 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,23 +138,74 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { teardownConnection(); try { - mConnection = (HttpURLConnection)mURL.openConnection(); + int response; + int redirectCount = 0; + + 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 (mHeaders != null) { - for (Map.Entry<String, String> entry : mHeaders.entrySet()) { + 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 (offset > 0) { - mConnection.setRequestProperty( - "Range", "bytes=" + offset + "-"); + if (response != HTTP_TEMP_REDIRECT) { + // update effective URL, unless it is a Temporary Redirect + mURL = url; + } } - int response = mConnection.getResponseCode(); - // remember the current, possibly redirected URL - mURL = mConnection.getURL(); + if (mAllowCrossDomainRedirect) { + // remember the current, potentially redirected URL if redirects + // were handled by HttpURLConnection + mURL = mConnection.getURL(); + } if (response == HttpURLConnection.HTTP_PARTIAL) { // Partial content, we cannot just use getContentLength @@ -207,6 +289,9 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } 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 @@ public abstract class MediaMetadataEditor { */ protected Bundle mEditorMetadata; + /** + * @hide + */ + protected MediaMetadata.Builder mMetadataBuilder; /** * Clears all the pending metadata changes set since the MediaMetadataEditor instance was @@ -120,6 +125,7 @@ public abstract class MediaMetadataEditor { } 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..8368df9 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -24,6 +24,11 @@ import android.graphics.Bitmap; 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 class RemoteControlClient */ 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 @@ public class RemoteControlClient } /** + * @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 class RemoteControlClient 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 class RemoteControlClient 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 class RemoteControlClient 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 @@ public class RemoteControlClient 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient 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 @@ public class RemoteControlClient 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient 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 @@ public class RemoteControlClient 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 @@ public class RemoteControlClient 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 @@ public class RemoteControlClient 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 @@ public class RemoteControlClient // 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 @@ public class RemoteControlClient 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.media.session.SessionInfo; 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 @@ public final class RouteRequest implements Parcelable { } @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/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 final class MediaMetadata implements Parcelable { 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 final class MediaMetadata implements Parcelable { 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 @@ public final class MediaMetadata implements Parcelable { 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 @@ public final class MediaMetadata implements Parcelable { 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 @@ public final class MediaMetadata implements Parcelable { } /** + * 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 @@ public final class MediaMetadata implements Parcelable { * @return a long value */ public long getLong(String key) { - return mBundle.getLong(key); + return mBundle.getLong(key, 0); } /** @@ -244,6 +294,27 @@ public final class MediaMetadata implements Parcelable { 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 @@ public final class MediaMetadata implements Parcelable { * <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 @@ public final class MediaMetadata implements Parcelable { * <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..4ee67d1 --- /dev/null +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.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.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.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.update(); + } + } + + private SessionHolder getHolder(PendingIntent pi, boolean createIfMissing) { + SessionHolder holder = mSessions.get(pi); + if (holder == null && createIfMissing) { + Session session = mSessionManager.createSession(TAG); + session.setTransportPerformerEnabled(); + session.publish(); + 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 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 final class PlaybackState implements Parcelable { 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 class PlaybackState implements Parcelable { */ 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 @@ public final class PlaybackState implements Parcelable { * @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 @@ public final class PlaybackState implements Parcelable { @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 @@ public final class PlaybackState implements Parcelable { } /** - * 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 @@ public final class PlaybackState implements Parcelable { * <li> {@link PlaybackState#PLAYSTATE_REWINDING}</li> * <li> {@link PlaybackState#PLAYSTATE_BUFFERING}</li> * <li> {@link PlaybackState#PLAYSTATE_ERROR}</li> - */ - public void setState(int mState) { - this.mState = mState; + * </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 state, long position, float rate) { + this.mState = state; + this.mPosition = position; + this.mRate = rate; + mUpdateTime = SystemClock.elapsedRealtime(); } /** @@ -247,13 +312,6 @@ public final class PlaybackState implements Parcelable { } /** - * 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 @@ public final class PlaybackState implements Parcelable { } /** - * Get 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 float getSpeed() { - return mSpeed; - } - - /** - * Set 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 void setSpeed(float speed) { - mSpeed = speed; + public float getRate() { + return mRate; } /** @@ -305,7 +356,7 @@ public final class PlaybackState implements Parcelable { * </ul> */ public long getActions() { - return mCapabilities; + return mActions; } /** @@ -324,7 +375,7 @@ public final class PlaybackState implements Parcelable { * </ul> */ public void setActions(long capabilities) { - mCapabilities = capabilities; + mActions = capabilities; } /** @@ -336,6 +387,17 @@ public final class PlaybackState implements Parcelable { } /** + * 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 @@ public final class PlaybackState implements Parcelable { 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/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 @@ public final class SessionInfo implements Parcelable { } @Override + public String toString() { + return "SessionInfo {id=" + mId + ", pkg=" + mPackageName + "}"; + } + + @Override public int describeContents() { return 0; } 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 @@ public final class TransportPerformer { /** * 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_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index d04b1f8..a710c03 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -255,7 +255,7 @@ status_t JMediaCodec::dequeueOutputBuffer( env, env->FindClass("android/media/MediaCodec$BufferInfo")); jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V"); - env->CallVoidMethod(bufferInfo, method, offset, size, timeUs, flags); + env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags); return OK; } diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp index 4e42ae3..157dd49 100644 --- a/media/jni/android_media_MediaMetadataRetriever.cpp +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -273,6 +273,13 @@ static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, width, height, config); + if (jBitmap == NULL) { + if (env->ExceptionCheck()) { + env->ExceptionClear(); + } + ALOGE("getFrameAtTime: create Bitmap failed!"); + return NULL; + } SkBitmap *bitmap = (SkBitmap *) env->GetLongField(jBitmap, fields.nativeBitmap); diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml index 65dbe18..ca76a7d 100644 --- a/packages/DocumentsUI/res/values-af/strings.xml +++ b/packages/DocumentsUI/res/values-af/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Stoor"</string> <string name="menu_share" msgid="3075149983979628146">"Deel"</string> <string name="menu_delete" msgid="8138799623850614177">"Vee uit"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Kies \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> gekies"</string> <string name="sort_name" msgid="9183560467917256779">"Volgens naam"</string> <string name="sort_date" msgid="586080032956151448">"Volgens datum gewysig"</string> diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml index 1003c0a..84879d5 100644 --- a/packages/DocumentsUI/res/values-am/strings.xml +++ b/packages/DocumentsUI/res/values-am/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"አስቀምጥ"</string> <string name="menu_share" msgid="3075149983979628146">"አጋራ"</string> <string name="menu_delete" msgid="8138799623850614177">"ሰርዝ"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"«<xliff:g id="DIRECTORY">^1</xliff:g>»ን ይምረጡ"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ተመርጠዋል"</string> <string name="sort_name" msgid="9183560467917256779">"በስም"</string> <string name="sort_date" msgid="586080032956151448">"በተለወጠበት ቀን"</string> diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml index e939b3e..5c5d863 100644 --- a/packages/DocumentsUI/res/values-ar/strings.xml +++ b/packages/DocumentsUI/res/values-ar/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"حفظ"</string> <string name="menu_share" msgid="3075149983979628146">"مشاركة"</string> <string name="menu_delete" msgid="8138799623850614177">"حذف"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"تحديد \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"تم تحديد <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string> <string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string> diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml index 18cdb9c..d1da879 100644 --- a/packages/DocumentsUI/res/values-bg/strings.xml +++ b/packages/DocumentsUI/res/values-bg/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Запазване"</string> <string name="menu_share" msgid="3075149983979628146">"Споделяне"</string> <string name="menu_delete" msgid="8138799623850614177">"Изтриване"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Избиране на „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string> <string name="mode_selected_count" msgid="459111894725594625">"Избрахте <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"По име"</string> <string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string> diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml index b883869..23e7284 100644 --- a/packages/DocumentsUI/res/values-ca/strings.xml +++ b/packages/DocumentsUI/res/values-ca/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Desa"</string> <string name="menu_share" msgid="3075149983979628146">"Comparteix"</string> <string name="menu_delete" msgid="8138799623850614177">"Suprimeix"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"Seleccionats: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Per nom"</string> <string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string> diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml index 3827b94..ad8897a 100644 --- a/packages/DocumentsUI/res/values-cs/strings.xml +++ b/packages/DocumentsUI/res/values-cs/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Uložit"</string> <string name="menu_share" msgid="3075149983979628146">"Sdílet"</string> <string name="menu_delete" msgid="8138799623850614177">"Smazat"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Vyberte adresář <xliff:g id="DIRECTORY">^1</xliff:g>"</string> <string name="mode_selected_count" msgid="459111894725594625">"Vybráno: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string> <string name="sort_date" msgid="586080032956151448">"Podle data úpravy"</string> diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml index 25c74e3..7ae5d1e 100644 --- a/packages/DocumentsUI/res/values-da/strings.xml +++ b/packages/DocumentsUI/res/values-da/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Gem"</string> <string name="menu_share" msgid="3075149983979628146">"Del"</string> <string name="menu_delete" msgid="8138799623850614177">"Slet"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Vælg \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> er valgt"</string> <string name="sort_name" msgid="9183560467917256779">"Efter navn"</string> <string name="sort_date" msgid="586080032956151448">"Efter ændringsdato"</string> diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml index 93fad32..98c1787 100644 --- a/packages/DocumentsUI/res/values-de/strings.xml +++ b/packages/DocumentsUI/res/values-de/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Speichern"</string> <string name="menu_share" msgid="3075149983979628146">"Teilen"</string> <string name="menu_delete" msgid="8138799623850614177">"Löschen"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" auswählen"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ausgewählt"</string> <string name="sort_name" msgid="9183560467917256779">"Nach Name"</string> <string name="sort_date" msgid="586080032956151448">"Nach Änderungsdatum"</string> diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml index db83aea..f0f7e10 100644 --- a/packages/DocumentsUI/res/values-el/strings.xml +++ b/packages/DocumentsUI/res/values-el/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Αποθήκευση"</string> <string name="menu_share" msgid="3075149983979628146">"Κοινοποίηση"</string> <string name="menu_delete" msgid="8138799623850614177">"Διαγραφή"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Επιλογή \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"Επιλέχθηκαν <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Κατά όνομα"</string> <string name="sort_date" msgid="586080032956151448">"Κατά ημερομηνία τροποποίησης"</string> diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml index a0fe3b7..d2af473 100644 --- a/packages/DocumentsUI/res/values-en-rGB/strings.xml +++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Save"</string> <string name="menu_share" msgid="3075149983979628146">"Share"</string> <string name="menu_delete" msgid="8138799623850614177">"Delete"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string> <string name="sort_name" msgid="9183560467917256779">"By name"</string> <string name="sort_date" msgid="586080032956151448">"By date modified"</string> diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml index a0fe3b7..d2af473 100644 --- a/packages/DocumentsUI/res/values-en-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Save"</string> <string name="menu_share" msgid="3075149983979628146">"Share"</string> <string name="menu_delete" msgid="8138799623850614177">"Delete"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selected"</string> <string name="sort_name" msgid="9183560467917256779">"By name"</string> <string name="sort_date" msgid="586080032956151448">"By date modified"</string> diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml index 3319011..daf18cf 100644 --- a/packages/DocumentsUI/res/values-es-rUS/strings.xml +++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Guardar"</string> <string name="menu_share" msgid="3075149983979628146">"Compartir"</string> <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Seleccionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> seleccionado(s)"</string> <string name="sort_name" msgid="9183560467917256779">"Por nombre"</string> <string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string> diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml index 7189f1d..573ee41 100644 --- a/packages/DocumentsUI/res/values-es/strings.xml +++ b/packages/DocumentsUI/res/values-es/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Guardar"</string> <string name="menu_share" msgid="3075149983979628146">"Compartir"</string> <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"Seleccionado: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Por nombre"</string> <string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string> diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml index a12b695..dae965a0 100644 --- a/packages/DocumentsUI/res/values-et-rEE/strings.xml +++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Salvesta"</string> <string name="menu_share" msgid="3075149983979628146">"Jaga"</string> <string name="menu_delete" msgid="8138799623850614177">"Kustuta"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Kataloogi „<xliff:g id="DIRECTORY">^1</xliff:g>” valimine"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> on valitud"</string> <string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string> <string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string> diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml index ba04522..a646eda 100644 --- a/packages/DocumentsUI/res/values-fa/strings.xml +++ b/packages/DocumentsUI/res/values-fa/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"ذخیره"</string> <string name="menu_share" msgid="3075149983979628146">"اشتراکگذاری"</string> <string name="menu_delete" msgid="8138799623850614177">"حذف"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"انتخاب «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> انتخاب شد"</string> <string name="sort_name" msgid="9183560467917256779">"بر اساس نام"</string> <string name="sort_date" msgid="586080032956151448">"بر اساس تاریخ اصلاح"</string> diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml index 8ea10be..aa118ed 100644 --- a/packages/DocumentsUI/res/values-fi/strings.xml +++ b/packages/DocumentsUI/res/values-fi/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Tallenna"</string> <string name="menu_share" msgid="3075149983979628146">"Jaa"</string> <string name="menu_delete" msgid="8138799623850614177">"Poista"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Valitse <xliff:g id="DIRECTORY">^1</xliff:g>"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valittua"</string> <string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string> <string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string> diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml index 0549707..b370a1e 100644 --- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml +++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string> <string name="menu_share" msgid="3075149983979628146">"Partager"</string> <string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Sélectionner « <xliff:g id="DIRECTORY">^1</xliff:g> »"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> sélectionné(s)"</string> <string name="sort_name" msgid="9183560467917256779">"Par nom"</string> <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string> diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml index 292ec86..070b130 100644 --- a/packages/DocumentsUI/res/values-fr/strings.xml +++ b/packages/DocumentsUI/res/values-fr/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Enregistrer"</string> <string name="menu_share" msgid="3075149983979628146">"Partager"</string> <string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Sélectionner \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> élément(s) sélectionné(s)"</string> <string name="sort_name" msgid="9183560467917256779">"Par nom"</string> <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string> diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml index 579bd37..66c707e 100644 --- a/packages/DocumentsUI/res/values-hi/strings.xml +++ b/packages/DocumentsUI/res/values-hi/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"सहेजें"</string> <string name="menu_share" msgid="3075149983979628146">"साझा करें"</string> <string name="menu_delete" msgid="8138799623850614177">"हटाएं"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" चुनें"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> चयनित"</string> <string name="sort_name" msgid="9183560467917256779">"नाम के अनुसार"</string> <string name="sort_date" msgid="586080032956151448">"बदलाव के दिनांक के अनुसार"</string> diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml index 6baae95..3438e73 100644 --- a/packages/DocumentsUI/res/values-hr/strings.xml +++ b/packages/DocumentsUI/res/values-hr/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Spremi"</string> <string name="menu_share" msgid="3075149983979628146">"Dijeli"</string> <string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Odaberi \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"Odabrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Po korisniku"</string> <string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string> diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml index b8ef2d4..2af559b 100644 --- a/packages/DocumentsUI/res/values-hu/strings.xml +++ b/packages/DocumentsUI/res/values-hu/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Mentés"</string> <string name="menu_share" msgid="3075149983979628146">"Megosztás"</string> <string name="menu_delete" msgid="8138799623850614177">"Törlés"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"A(z) „<xliff:g id="DIRECTORY">^1</xliff:g>” mappa kiválasztása"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> kiválasztva"</string> <string name="sort_name" msgid="9183560467917256779">"Név szerint"</string> <string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string> diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml index 69fdfb6..67a1f7e 100644 --- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml +++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Պահել"</string> <string name="menu_share" msgid="3075149983979628146">"Համօգտագործել"</string> <string name="menu_delete" msgid="8138799623850614177">"Ջնջել"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Ընտրել «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ընտրված"</string> <string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string> <string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string> diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml index d5c69bf..62057c7 100644 --- a/packages/DocumentsUI/res/values-in/strings.xml +++ b/packages/DocumentsUI/res/values-in/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Simpan"</string> <string name="menu_share" msgid="3075149983979628146">"Bagikan"</string> <string name="menu_delete" msgid="8138799623850614177">"Hapus"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string> <string name="sort_name" msgid="9183560467917256779">"Menurut nama"</string> <string name="sort_date" msgid="586080032956151448">"Menurut tanggal diubah"</string> diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml index 9d1fc94..bec4d00 100644 --- a/packages/DocumentsUI/res/values-it/strings.xml +++ b/packages/DocumentsUI/res/values-it/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Salva"</string> <string name="menu_share" msgid="3075149983979628146">"Condividi"</string> <string name="menu_delete" msgid="8138799623850614177">"Elimina"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Seleziona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selezionati"</string> <string name="sort_name" msgid="9183560467917256779">"Per nome"</string> <string name="sort_date" msgid="586080032956151448">"Per data di modifica"</string> diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml index af47c6c..c8a3fb9 100644 --- a/packages/DocumentsUI/res/values-iw/strings.xml +++ b/packages/DocumentsUI/res/values-iw/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"שמור"</string> <string name="menu_share" msgid="3075149983979628146">"שתף"</string> <string name="menu_delete" msgid="8138799623850614177">"מחק"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"בחר ב-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> נבחרו"</string> <string name="sort_name" msgid="9183560467917256779">"לפי שם"</string> <string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string> diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml index ca64914..1475005 100644 --- a/packages/DocumentsUI/res/values-ja/strings.xml +++ b/packages/DocumentsUI/res/values-ja/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"保存"</string> <string name="menu_share" msgid="3075149983979628146">"共有"</string> <string name="menu_delete" msgid="8138799623850614177">"削除"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"「<xliff:g id="DIRECTORY">^1</xliff:g>」を選択"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>件選択済み"</string> <string name="sort_name" msgid="9183560467917256779">"名前順"</string> <string name="sort_date" msgid="586080032956151448">"更新日順"</string> diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml index 3e3d509..c90768f 100644 --- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml +++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"შენახვა"</string> <string name="menu_share" msgid="3075149983979628146">"გაზიარება"</string> <string name="menu_delete" msgid="8138799623850614177">"წაშლა"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"„<xliff:g id="DIRECTORY">^1</xliff:g>“-ის არჩევა"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> მონიშნული"</string> <string name="sort_name" msgid="9183560467917256779">"სახელით"</string> <string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string> diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml index 2ecbba7..e8944ec 100644 --- a/packages/DocumentsUI/res/values-km-rKH/strings.xml +++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"រក្សាទុក"</string> <string name="menu_share" msgid="3075149983979628146">"ចែករំលែក"</string> <string name="menu_delete" msgid="8138799623850614177">"លុប"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"ជ្រើស \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"បានជ្រើស <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"តាមឈ្មោះ"</string> <string name="sort_date" msgid="586080032956151448">"តាមកាលបរិច្ឆេទបានកែប្រែ"</string> diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml index 0ece450..5996e66 100644 --- a/packages/DocumentsUI/res/values-ko/strings.xml +++ b/packages/DocumentsUI/res/values-ko/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"저장"</string> <string name="menu_share" msgid="3075149983979628146">"공유"</string> <string name="menu_delete" msgid="8138799623850614177">"삭제"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"\'<xliff:g id="DIRECTORY">^1</xliff:g>\' 선택"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g>개 선택됨"</string> <string name="sort_name" msgid="9183560467917256779">"이름순"</string> <string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string> diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml index 0bc0b8b..8452ae1 100644 --- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml +++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"ບັນທຶກ"</string> <string name="menu_share" msgid="3075149983979628146">"ແບ່ງປັນ"</string> <string name="menu_delete" msgid="8138799623850614177">"ລຶບ"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"ເລືອກ \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"ເລືອກແລ້ວ <xliff:g id="COUNT">%1$d</xliff:g> ລາຍການ"</string> <string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string> <string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string> diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml index 04825f9..8ec3e0b 100644 --- a/packages/DocumentsUI/res/values-lt/strings.xml +++ b/packages/DocumentsUI/res/values-lt/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Išsaugoti"</string> <string name="menu_share" msgid="3075149983979628146">"Bendrinti"</string> <string name="menu_delete" msgid="8138799623850614177">"Ištrinti"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Pasirinkti katalogą „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string> <string name="mode_selected_count" msgid="459111894725594625">"Pasirinkta: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string> <string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string> diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml index 5157327..caaf8ec 100644 --- a/packages/DocumentsUI/res/values-lv/strings.xml +++ b/packages/DocumentsUI/res/values-lv/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Saglabāt"</string> <string name="menu_share" msgid="3075149983979628146">"Kopīgot"</string> <string name="menu_delete" msgid="8138799623850614177">"Dzēst"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Atlasīt “<xliff:g id="DIRECTORY">^1</xliff:g>”"</string> <string name="mode_selected_count" msgid="459111894725594625">"Atlasīts: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string> <string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string> diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml index 8fd8f52..3d90cc1 100644 --- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml +++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Хадгалах"</string> <string name="menu_share" msgid="3075149983979628146">"Хуваалцах"</string> <string name="menu_delete" msgid="8138799623850614177">"Устгах"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\"-г сонгох"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> сонгогдсон"</string> <string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string> <string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string> diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml index 48e30305..9ea7119 100644 --- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml +++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Simpan"</string> <string name="menu_share" msgid="3075149983979628146">"Kongsi"</string> <string name="menu_delete" msgid="8138799623850614177">"Padam"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> dipilih"</string> <string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string> <string name="sort_date" msgid="586080032956151448">"Diubah suai mengikut tarikh"</string> diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml index 09a11d5..af7c282 100644 --- a/packages/DocumentsUI/res/values-nb/strings.xml +++ b/packages/DocumentsUI/res/values-nb/strings.xml @@ -29,8 +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> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Velg «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> valgt"</string> <string name="sort_name" msgid="9183560467917256779">"Etter navn"</string> <string name="sort_date" msgid="586080032956151448">"«Etter dato» endret"</string> diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml index ca626a8..a8cf114 100644 --- a/packages/DocumentsUI/res/values-nl/strings.xml +++ b/packages/DocumentsUI/res/values-nl/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Opslaan"</string> <string name="menu_share" msgid="3075149983979628146">"Delen"</string> <string name="menu_delete" msgid="8138799623850614177">"Verwijderen"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"<xliff:g id="DIRECTORY">^1</xliff:g> selecteren"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> geselecteerd"</string> <string name="sort_name" msgid="9183560467917256779">"Op naam"</string> <string name="sort_date" msgid="586080032956151448">"Op aanpassingsdatum"</string> diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml index 7a7978b..ead40e9 100644 --- a/packages/DocumentsUI/res/values-pl/strings.xml +++ b/packages/DocumentsUI/res/values-pl/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Zapisz"</string> <string name="menu_share" msgid="3075149983979628146">"Udostępnij"</string> <string name="menu_delete" msgid="8138799623850614177">"Usuń"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Zaznacz „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string> <string name="mode_selected_count" msgid="459111894725594625">"Wybrano: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string> <string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string> diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml index 0443c35..0003c05 100644 --- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml +++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Guardar"</string> <string name="menu_share" msgid="3075149983979628146">"Partilhar"</string> <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionado(s)"</string> <string name="sort_name" msgid="9183560467917256779">"Por nome"</string> <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string> diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml index f9038d1..4a5c72a 100644 --- a/packages/DocumentsUI/res/values-pt/strings.xml +++ b/packages/DocumentsUI/res/values-pt/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Salvar"</string> <string name="menu_share" msgid="3075149983979628146">"Compartilhar"</string> <string name="menu_delete" msgid="8138799623850614177">"Excluir"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selecionados"</string> <string name="sort_name" msgid="9183560467917256779">"Por nome"</string> <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string> diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml index 26cd77f..0dfa11d4 100644 --- a/packages/DocumentsUI/res/values-ro/strings.xml +++ b/packages/DocumentsUI/res/values-ro/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Salvați"</string> <string name="menu_share" msgid="3075149983979628146">"Distribuiți"</string> <string name="menu_delete" msgid="8138799623850614177">"Ștergeți"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Selectați „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> selectate"</string> <string name="sort_name" msgid="9183560467917256779">"După nume"</string> <string name="sort_date" msgid="586080032956151448">"După data modificării"</string> diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml index f8e1f1b..f86a4af 100644 --- a/packages/DocumentsUI/res/values-ru/strings.xml +++ b/packages/DocumentsUI/res/values-ru/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Сохранить"</string> <string name="menu_share" msgid="3075149983979628146">"Поделиться"</string> <string name="menu_delete" msgid="8138799623850614177">"Удалить"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Выбрать папку \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"Выбрано: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"По названию"</string> <string name="sort_date" msgid="586080032956151448">"По дате изменения"</string> diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml index cb4b718..5d03df6 100644 --- a/packages/DocumentsUI/res/values-sk/strings.xml +++ b/packages/DocumentsUI/res/values-sk/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Uložiť"</string> <string name="menu_share" msgid="3075149983979628146">"Zdieľať"</string> <string name="menu_delete" msgid="8138799623850614177">"Odstrániť"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Vyberte adresár <xliff:g id="DIRECTORY">^1</xliff:g>"</string> <string name="mode_selected_count" msgid="459111894725594625">"Vybraté: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string> <string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string> diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml index a6dc20b..b3e52dd 100644 --- a/packages/DocumentsUI/res/values-sl/strings.xml +++ b/packages/DocumentsUI/res/values-sl/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Shrani"</string> <string name="menu_share" msgid="3075149983979628146">"Skupna raba"</string> <string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Izbira mape »<xliff:g id="DIRECTORY">^1</xliff:g>«"</string> <string name="mode_selected_count" msgid="459111894725594625">"Št. izbranih: <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Po imenu"</string> <string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string> diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml index 06e0d08..892dbce 100644 --- a/packages/DocumentsUI/res/values-sr/strings.xml +++ b/packages/DocumentsUI/res/values-sr/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Сачувај"</string> <string name="menu_share" msgid="3075149983979628146">"Дели"</string> <string name="menu_delete" msgid="8138799623850614177">"Избриши"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Изабери „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string> <string name="mode_selected_count" msgid="459111894725594625">"Изабрано је <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Према имену"</string> <string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string> diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml index da8432e..fd6457d 100644 --- a/packages/DocumentsUI/res/values-sv/strings.xml +++ b/packages/DocumentsUI/res/values-sv/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Spara"</string> <string name="menu_share" msgid="3075149983979628146">"Dela"</string> <string name="menu_delete" msgid="8138799623850614177">"Ta bort"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Välj <xliff:g id="DIRECTORY">^1</xliff:g>"</string> <string name="mode_selected_count" msgid="459111894725594625">"Har valt <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Efter namn"</string> <string name="sort_date" msgid="586080032956151448">"Efter ändringsdatum"</string> diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml index c769a59..0948c71 100644 --- a/packages/DocumentsUI/res/values-sw/strings.xml +++ b/packages/DocumentsUI/res/values-sw/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Hifadhi"</string> <string name="menu_share" msgid="3075149983979628146">"Shiriki"</string> <string name="menu_delete" msgid="8138799623850614177">"Futa"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Chagua \" <xliff:g id="DIRECTORY">^1</xliff:g> \""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> zimechaguliwa"</string> <string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string> <string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string> diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml index bf92893..4bf3e4f 100644 --- a/packages/DocumentsUI/res/values-th/strings.xml +++ b/packages/DocumentsUI/res/values-th/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"บันทึก"</string> <string name="menu_share" msgid="3075149983979628146">"แชร์"</string> <string name="menu_delete" msgid="8138799623850614177">"ลบ"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"เลือก \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"เลือกไว้ <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string> <string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string> diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml index bc363e7..8ef8aa5 100644 --- a/packages/DocumentsUI/res/values-tl/strings.xml +++ b/packages/DocumentsUI/res/values-tl/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"I-save"</string> <string name="menu_share" msgid="3075149983979628146">"Ibahagi"</string> <string name="menu_delete" msgid="8138799623850614177">"Tanggalin"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Piliin ang \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> ang pinili"</string> <string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string> <string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string> diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml index 5d7a2be..93586d0 100644 --- a/packages/DocumentsUI/res/values-tr/strings.xml +++ b/packages/DocumentsUI/res/values-tr/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Kaydet"</string> <string name="menu_share" msgid="3075149983979628146">"Paylaş"</string> <string name="menu_delete" msgid="8138799623850614177">"Sil"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" dizinini seç"</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> tane seçildi"</string> <string name="sort_name" msgid="9183560467917256779">"Ada göre"</string> <string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string> diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml index dbd44b7..8f8865b 100644 --- a/packages/DocumentsUI/res/values-uk/strings.xml +++ b/packages/DocumentsUI/res/values-uk/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Зберегти"</string> <string name="menu_share" msgid="3075149983979628146">"Поділитися"</string> <string name="menu_delete" msgid="8138799623850614177">"Видалити"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Вибрати каталог \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"Вибрано <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"За назвою"</string> <string name="sort_date" msgid="586080032956151448">"За датою змінення"</string> diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml index 919708f..8b8ff1f 100644 --- a/packages/DocumentsUI/res/values-vi/strings.xml +++ b/packages/DocumentsUI/res/values-vi/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Lưu"</string> <string name="menu_share" msgid="3075149983979628146">"Chia sẻ"</string> <string name="menu_delete" msgid="8138799623850614177">"Xóa"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Chọn \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"Đã chọn <xliff:g id="COUNT">%1$d</xliff:g>"</string> <string name="sort_name" msgid="9183560467917256779">"Theo tên"</string> <string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string> diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml index a916b87..68ab5f8 100644 --- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"保存"</string> <string name="menu_share" msgid="3075149983979628146">"分享"</string> <string name="menu_delete" msgid="8138799623850614177">"删除"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"选择“<xliff:g id="DIRECTORY">^1</xliff:g>”"</string> <string name="mode_selected_count" msgid="459111894725594625">"已选择<xliff:g id="COUNT">%1$d</xliff:g>项"</string> <string name="sort_name" msgid="9183560467917256779">"按名称"</string> <string name="sort_date" msgid="586080032956151448">"按修改日期"</string> diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml index 7cae910..afd8b63 100644 --- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"儲存"</string> <string name="menu_share" msgid="3075149983979628146">"分享"</string> <string name="menu_delete" msgid="8138799623850614177">"刪除"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"選取「<xliff:g id="DIRECTORY">^1</xliff:g>」"</string> <string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個"</string> <string name="sort_name" msgid="9183560467917256779">"按名稱"</string> <string name="sort_date" msgid="586080032956151448">"按修改日期"</string> diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml index 387fdba..2e77f21 100644 --- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml +++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"儲存"</string> <string name="menu_share" msgid="3075149983979628146">"共用"</string> <string name="menu_delete" msgid="8138799623850614177">"刪除"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"選取「<xliff:g id="DIRECTORY">^1</xliff:g>」"</string> <string name="mode_selected_count" msgid="459111894725594625">"已選取 <xliff:g id="COUNT">%1$d</xliff:g> 個項目"</string> <string name="sort_name" msgid="9183560467917256779">"依名稱"</string> <string name="sort_date" msgid="586080032956151448">"依修改日期"</string> diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml index 564b2d7..55e2c75 100644 --- a/packages/DocumentsUI/res/values-zu/strings.xml +++ b/packages/DocumentsUI/res/values-zu/strings.xml @@ -29,8 +29,7 @@ <string name="menu_save" msgid="2394743337684426338">"Londoloza"</string> <string name="menu_share" msgid="3075149983979628146">"Yabelana"</string> <string name="menu_delete" msgid="8138799623850614177">"Susa"</string> - <!-- no translation found for menu_select (8711270657353563424) --> - <skip /> + <string name="menu_select" msgid="8711270657353563424">"Khetha i-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string> <string name="mode_selected_count" msgid="459111894725594625">"<xliff:g id="COUNT">%1$d</xliff:g> okukhethiwe"</string> <string name="sort_name" msgid="9183560467917256779">"Ngegama"</string> <string name="sort_date" msgid="586080032956151448">"Ngedethi yokuguqula"</string> diff --git a/packages/InputDevices/res/raw/keyboard_layout_czech.kcm b/packages/InputDevices/res/raw/keyboard_layout_czech.kcm index f710a8e..dc614db 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_czech.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_czech.kcm @@ -13,7 +13,7 @@ # limitations under the License. # -# Czech keyboard layout. +# Czech (EU - qwerty) keyboard layout. # type OVERLAY @@ -26,6 +26,8 @@ key GRAVE { label: ';' base: ';' shift: '\u00b0' + ralt: '\u0060' + shift+ralt: '\u007e' } key 1 { @@ -38,6 +40,7 @@ key 1 { key 2 { label: '2' base: '\u011b' + capslock: '\u011a' shift: '2' ralt: '@' } @@ -45,6 +48,7 @@ key 2 { key 3 { label: '3' base: '\u0161' + capslock: '\u0160' shift: '3' ralt: '#' } @@ -52,6 +56,7 @@ key 3 { key 4 { label: '4' base: '\u010d' + capslock: '\u010c' shift: '4' ralt: '$' } @@ -59,6 +64,7 @@ key 4 { key 5 { label: '5' base: '\u0159' + capslock: '\u0158' shift: '5' ralt: '%' } @@ -66,6 +72,7 @@ key 5 { key 6 { label: '6' base: '\u017e' + capslock: '\u017d' shift: '6' ralt: '^' } @@ -73,6 +80,7 @@ key 6 { key 7 { label: '7' base: '\u00fd' + capslock: '\u00dd' shift: '7' ralt: '&' } @@ -80,6 +88,7 @@ key 7 { key 8 { label: '8' base: '\u00e1' + capslock: '\u00c1' shift: '8' ralt: '*' } @@ -87,6 +96,7 @@ key 8 { key 9 { label: '9' base: '\u00ed' + capslock: '\u00cd' shift: '9' ralt: '(' } @@ -94,6 +104,7 @@ key 9 { key 0 { label: '0' base: '\u00e9' + capslock: '\u00c9' shift: '0' ralt: ')' } @@ -180,6 +191,7 @@ key P { key LEFT_BRACKET { label: '\u00fa' base: '\u00fa' + capslock: '\u00da' shift: '/' ralt: '[' ralt+shift: '{' @@ -252,6 +264,7 @@ key L { key SEMICOLON { label: '\u016f' base: '\u016f' + capslock: '\u016e' shift: '"' ralt: ';' ralt+shift: ':' @@ -261,8 +274,8 @@ key APOSTROPHE { label: '\u00a7' base: '\u00a7' shift: '!' - ralt: '\'' - ralt+shift: '"' + ralt: '\u00a4' + ralt+shift: '\u005e' } key BACKSLASH { @@ -279,6 +292,8 @@ key PLUS { label: '\\' base: '\\' shift: '|' + ralt: '\u00df' + shift+ralt: '\u02dd' } key Z { @@ -330,6 +345,7 @@ key COMMA { base: ',' shift: '?' ralt: '<' + shift+ralt: '\u00d7' } key PERIOD { @@ -337,6 +353,7 @@ key PERIOD { base: '.' shift: ':' ralt: '>' + shift+ralt: '\u00f7' } key SLASH { diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm index 0fabf02..66c1c98 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_english_us_intl.kcm @@ -122,7 +122,7 @@ key Q { base: 'q' shift, capslock: 'Q' ralt: '\u00e4' - shift+ralt: '\u00c4' + shift+ralt, capslock+ralt: '\u00c4' } key W { @@ -130,7 +130,7 @@ key W { base: 'w' shift, capslock: 'W' ralt: '\u00e5' - shift+ralt: '\u00c5' + shift+ralt, capslock+ralt: '\u00c5' } key E { @@ -138,7 +138,7 @@ key E { base: 'e' shift, capslock: 'E' ralt: '\u00e9' - shift+ralt: '\u00c9' + shift+ralt, capslock+ralt: '\u00c9' } key R { @@ -153,7 +153,7 @@ key T { base: 't' shift, capslock: 'T' ralt: '\u00fe' - shift+ralt: '\u00de' + shift+ralt, capslock+ralt: '\u00de' } key Y { @@ -161,7 +161,7 @@ key Y { base: 'y' shift, capslock: 'Y' ralt: '\u00fc' - shift+ralt: '\u00dc' + shift+ralt, capslock+ralt: '\u00dc' } key U { @@ -169,7 +169,7 @@ key U { base: 'u' shift, capslock: 'U' ralt: '\u00fa' - shift+ralt: '\u00da' + shift+ralt, capslock+ralt: '\u00da' } key I { @@ -177,7 +177,7 @@ key I { base: 'i' shift, capslock: 'I' ralt: '\u00ed' - shift+ralt: '\u00cd' + shift+ralt, capslock+ralt: '\u00cd' } key O { @@ -185,7 +185,7 @@ key O { base: 'o' shift, capslock: 'O' ralt: '\u00f3' - shift+ralt: '\u00d3' + shift+ralt, capslock+ralt: '\u00d3' } key P { @@ -193,7 +193,7 @@ key P { base: 'p' shift, capslock: 'P' ralt: '\u00f6' - shift+ralt: '\u00d6' + shift+ralt, capslock+ralt: '\u00d6' } key LEFT_BRACKET { @@ -225,7 +225,7 @@ key A { base: 'a' shift, capslock: 'A' ralt: '\u00e1' - shift+ralt: '\u00c1' + shift+ralt, ralt+capslock: '\u00c1' } key S { @@ -241,7 +241,7 @@ key D { base: 'd' shift, capslock: 'D' ralt: '\u00f0' - shift+ralt: '\u00d0' + shift+ralt, capslock+ralt: '\u00d0' } key F { @@ -279,7 +279,7 @@ key L { base: 'l' shift, capslock: 'L' ralt: '\u00f8' - shift+ralt: '\u00d8' + shift+ralt, capslock+ralt: '\u00d8' } key SEMICOLON { @@ -313,7 +313,7 @@ key Z { base: 'z' shift, capslock: 'Z' ralt: '\u00e6' - shift+ralt: '\u00c6' + shift+ralt, capslock+ralt: '\u00c6' } key X { @@ -347,7 +347,7 @@ key N { base: 'n' shift, capslock: 'N' ralt: '\u00f1' - shift+ralt: '\u00d1' + shift+ralt, capslock+ralt: '\u00d1' } key M { @@ -362,7 +362,7 @@ key COMMA { base: ',' shift: '<' ralt: '\u00e7' - shift+ralt: '\u00c7' + shift+ralt, capslock+ralt: '\u00c7' } key PERIOD { diff --git a/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm b/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm index 70c1fa4..2eb0f63 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_slovak.kcm @@ -13,7 +13,7 @@ # limitations under the License. # -# Slovak keyboard layout. +# Slovak (EU - qwerty) keyboard layout. # type OVERLAY @@ -26,94 +26,90 @@ key GRAVE { label: ';' base: ';' shift: '\u00b0' - ralt: '`' - ralt+shift: '~' } key 1 { label: '1' base: '+' shift: '1' - ralt: '!' + ralt: '~' } key 2 { label: '2' base: '\u013e' shift: '2' - ralt: '@' + ralt: '\u02c7' } key 3 { label: '3' base: '\u0161' shift: '3' - ralt: '#' + ralt: '\u0302' } key 4 { label: '4' base: '\u010d' shift: '4' - ralt: '$' + ralt: '\u02d8' } key 5 { label: '5' base: '\u0165' shift: '5' - ralt: '%' + ralt: '\u00b0' } key 6 { label: '6' base: '\u017e' shift: '6' - ralt: '^' + ralt: '\u02db' } key 7 { label: '7' base: '\u00fd' shift: '7' - ralt: '&' + ralt: '\u0300' } key 8 { label: '8' base: '\u00e1' shift: '8' - ralt: '*' + ralt: '\u02d9' } key 9 { label: '9' base: '\u00ed' shift: '9' - ralt: '(' + ralt: '\u0301' } key 0 { label: '0' base: '\u00e9' shift: '0' - ralt: ')' + ralt: '\u02dd' } key MINUS { label: '=' base: '=' shift: '%' - ralt: '-' - ralt+shift: '_' + ralt: '\u0308' } key EQUALS { label: '\u00b4' base: '\u0301' shift: '\u030c' - ralt: '=' - ralt+shift: '+' + ralt: '\u00b8' } ### ROW 2 @@ -179,22 +175,21 @@ key P { label: 'P' base: 'p' shift, capslock: 'P' + ralt: '\'' } key LEFT_BRACKET { label: '\u00fa' base: '\u00fa' shift: '/' - ralt: '[' - ralt+shift: '{' + ralt: '\u00f7' } key RIGHT_BRACKET { label: '\u00e4' base: '\u00e4' shift: '(' - ralt: ']' - ralt+shift: '}' + ralt: '\u00d7' } ### ROW 3 @@ -209,24 +204,28 @@ key S { label: 'S' base: 's' shift, capslock: 'S' + ralt: '\u0111' } key D { label: 'D' base: 'd' shift, capslock: 'D' + ralt: '\u0110' } key F { label: 'F' base: 'f' shift, capslock: 'F' + ralt: '[' } key G { label: 'G' base: 'g' shift, capslock: 'G' + ralt: ']' } key H { @@ -245,64 +244,65 @@ key K { label: 'K' base: 'k' shift, capslock: 'K' + ralt: '\u0142' } key L { label: 'L' base: 'l' shift, capslock: 'L' + ralt: '\u0141' } key SEMICOLON { label: '\u00f4' base: '\u00f4' shift: '"' - ralt: ';' - ralt+shift: ':' + ralt: '$' } key APOSTROPHE { label: '\u00a7' base: '\u00a7' shift: '!' - ralt: '\'' - ralt+shift: '"' + ralt: '\u00df' } key BACKSLASH { label: '\u0148' base: '\u0148' shift: ')' - ralt: '\\' - ralt+shift: '|' + ralt: '\u00a4' } ### ROW 4 key PLUS { - label: '\\' - base: '\\' - shift: '|' - ralt: '&' - ralt+shift: '*' + label: '&' + base: '&' + shift: '*' + ralt: '<' } key Z { label: 'Z' base: 'z' shift, capslock: 'Z' + ralt: '>' } key X { label: 'X' base: 'x' shift, capslock: 'X' + ralt: '#' } key C { label: 'C' base: 'c' shift, capslock: 'C' + ralt: '&' } key V { @@ -316,12 +316,14 @@ key B { label: 'B' base: 'b' shift, capslock: 'B' + ralt: '{' } key N { label: 'N' base: 'n' shift, capslock: 'N' + ralt: '}' } key M { @@ -348,6 +350,5 @@ key SLASH { label: '-' base: '-' shift: '_' - ralt: '/' - ralt+shift: '?' + ralt: '*' } diff --git a/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm b/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm index a75d154..9e20462 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_swiss_french.kcm @@ -56,12 +56,14 @@ key 4 { label: '4' base: '4' shift: '\u00e7' + ralt: '\u00b0' } key 5 { label: '5' base: '5' shift: '%' + ralt: '\u00a7' } key 6 { diff --git a/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm index ae93f4b..7fbd1a9 100644 --- a/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm +++ b/packages/InputDevices/res/raw/keyboard_layout_swiss_german.kcm @@ -56,12 +56,14 @@ key 4 { label: '4' base: '4' shift: '\u00e7' + ralt: '\u00b0' } key 5 { label: '5' base: '5' shift: '%' + ralt: '\u00a7' } key 6 { @@ -178,6 +180,8 @@ key LEFT_BRACKET { label: '\u00fc' base: '\u00fc' shift: '\u00e8' + capslock: '\u00dc' + capslock+shift: '\u00c8' ralt: '[' } @@ -248,12 +252,16 @@ key SEMICOLON { label: '\u00f6' base: '\u00f6' shift: '\u00e9' + capslock: '\u00d6' + capslock+shift: '\u00c9' } key APOSTROPHE { label: '\u00e4' base: '\u00e4' shift: '\u00e0' + capslock: '\u00c4' + capslock+shift: '\u00c0' ralt: '{' } 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/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml index 3b3a069..546ddd4 100644 --- a/packages/Keyguard/res/layout/keyguard_status_view.xml +++ b/packages/Keyguard/res/layout/keyguard_status_view.xml @@ -24,7 +24,7 @@ android:id="@+id/keyguard_status_view" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" androidprv:layout_maxWidth="@dimen/keyguard_security_width" androidprv:layout_maxHeight="@dimen/keyguard_security_height" android:gravity="center_horizontal|top" diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml index ea5ef27..25e86e1 100644 --- a/packages/Keyguard/res/values-sw600dp/dimens.xml +++ b/packages/Keyguard/res/values-sw600dp/dimens.xml @@ -32,7 +32,7 @@ <!-- Keyguard dimensions --> <!-- Size of the clock font in keyguard's status view --> - <dimen name="kg_status_clock_font_size">141dp</dimen> + <dimen name="kg_status_clock_font_size">120dp</dimen> <!-- Size of the generic status lines keyguard's status view --> <dimen name="kg_status_line_font_size">16sp</dimen> diff --git a/packages/Keyguard/res/values-sw720dp/dimens.xml b/packages/Keyguard/res/values-sw720dp/dimens.xml index 4853a7b..30b979c 100644 --- a/packages/Keyguard/res/values-sw720dp/dimens.xml +++ b/packages/Keyguard/res/values-sw720dp/dimens.xml @@ -19,7 +19,7 @@ <resources> <!-- Keyguard dimensions --> <!-- Size of the clock font in keyguard's status view --> - <dimen name="kg_status_clock_font_size">188dp</dimen> + <dimen name="kg_status_clock_font_size">140dp</dimen> <!-- Size of the generic status lines keyguard's status view --> <dimen name="kg_status_line_font_size">19sp</dimen> 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 @@ public class KeyguardUpdateMonitorCallback { /** * 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/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 24ccb2b..761ad42 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -54,51 +54,45 @@ android:ellipsize="marquee" android:textAppearance="?android:attr/textAppearanceMedium" /> - <LinearLayout + <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" - android:layout_marginBottom="@dimen/close_handle_underlap" - android:orientation="vertical" - android:animateLayoutChanges="false" - > + android:visibility="gone" /> - <include layout="@layout/status_bar_expanded_header" - android:layout_width="match_parent" - android:layout_height="@dimen/notification_panel_header_height" - /> + <TextView + android:id="@+id/emergency_calls_only" + android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:padding="4dp" + android:gravity="center" + android:visibility="gone" + /> + <FrameLayout + 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/keyguard_status_view" - android:visibility="gone" /> - - <TextView - android:id="@+id/emergency_calls_only" - android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly" - android:layout_height="wrap_content" + layout="@layout/flip_settings" + android:layout_marginTop="@dimen/notification_panel_header_height" android:layout_width="match_parent" - android:padding="4dp" - android:gravity="center" - android:visibility="gone" + android:layout_height="wrap_content" /> - <FrameLayout - android:id="@+id/notification_container_parent" + <com.android.systemui.statusbar.stack.NotificationStackScrollLayout + android:id="@+id/notification_stack_scroller" android:layout_width="match_parent" android:layout_height="wrap_content" - > - <include - layout="@layout/flip_settings" - android:layout_width="match_parent" - android:layout_height="wrap_content" - /> - - <com.android.systemui.statusbar.stack.NotificationStackScrollLayout - android:id="@+id/notification_stack_scroller" - android:layout_width="match_parent" - android:layout_height="wrap_content" - /> - </FrameLayout> - </LinearLayout> + /> + </FrameLayout> <include layout="@layout/keyguard_bottom_area" 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 d81e525..2e08bff 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml @@ -18,10 +18,9 @@ <com.android.systemui.statusbar.NotificationOverflowContainer xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="32dp" android:focusable="true" android:clickable="true" - android:background="@*android:drawable/notification_quantum_bg_dim" > <TextView android:id="@+id/more_text" diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml index 41e7dac..8959a5b 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_row.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml @@ -4,14 +4,13 @@ android:layout_height="wrap_content" android:focusable="true" android:clickable="true" - android:background="@*android:drawable/notification_quantum_bg" > - <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expanded" + <com.android.systemui.statusbar.NotificationContentView android:id="@+id/expanded" android:layout_width="match_parent" android:layout_height="wrap_content" /> - <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/expandedPublic" + <com.android.systemui.statusbar.NotificationContentView android:id="@+id/expandedPublic" android:layout_width="match_parent" android:layout_height="wrap_content" /> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 285978b..d8a3114 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d meer"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Tik weer om oop te maak"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Sleep op om te ontsluit"</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 430c209..9d1e036 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d ማሳወቂያዎች ተደብቀዋል"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"ለማሳየት ነካ ያድርጉ"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"አይረብሹ"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d ተጨማሪ"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"ለመክፈት ዳግም መታ ያድርጉ"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"ለማስከፈት ወደ ላይ ያንሸራትቱ"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 3186791..22a032a 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d أخرى"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"انقر مرة أخرى للفتح"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"مرر سريعًا لأعلى لإلغاء القفل"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index b79429c..00ac707 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d известия са скрити"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Докоснете за показване"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Не ме безпокойте"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Още %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Докоснете отново, за да отворите"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Прекарайте пръст нагоре, за да отключите"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 1841622..bfad5bc 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -222,4 +222,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d més"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Torna a tocar per obrir-la."</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Fes lliscar el dit cap amunt per desbloquejar el teclat."</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 1c2e122..94ba5c7 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -218,9 +218,10 @@ <item quantity="other" msgid="7388721375827338153">"Skrytá oznámení: %d"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Oznámení zobrazíte kliknutím"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Nerušit"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Další: %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Oznámení otevřete opětovným klepnutím"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Zařízení odemknete přejetím prstem nahoru"</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 62ab0c3..df442ab 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d mere"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Tryk igen for at åbne"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Stryg for at låse op"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index a73e6d7..451476c 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -222,4 +222,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d mehr"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Erneut tippen, um Benachrichtigung zu öffnen"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Zum Entsperren nach oben wischen"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index caf64f5..6dcffcf 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -222,4 +222,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d ακόμη"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Πατήστε ξανά για να ανοίξετε"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Σύρετε για να ξεκλειδώσετε"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 7eff6ee..91a334a 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Do not disturb"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d more"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 7eff6ee..91a334a 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d notifications hidden"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Touch to show"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Do not disturb"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d more"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Tap again to open"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index d2a1125..2150cbe 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -222,4 +222,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d más"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Presionar de nuevo para abrir"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar el dedo hacia arriba para desbloquear"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 822db03..3424166 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d más"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Toca de nuevo para abrir"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Desliza el dedo hacia arriba para desbloquear"</string> </resources> diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml index 027de0c..8dbf9af 100644 --- a/packages/SystemUI/res/values-et-rEE/strings.xml +++ b/packages/SystemUI/res/values-et-rEE/strings.xml @@ -214,9 +214,10 @@ <!-- String.format failed for translation --> <!-- no translation found for zen_mode_notification_title:other (7388721375827338153) --> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Puudutage kuvamiseks"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Mitte segada"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Veel %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Avamiseks puudutage uuesti"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Lukustuse tühistamiseks pühkige üles"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 53353ae..b2ac990 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d اعلان پنهان شده"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"برای نمایش لمس کنید"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"مزاحم نشوید"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d بیشتر"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"برای باز کردن دوباره ضربه بزنید"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"برای باز کردن قفل سریع به بالا بکشید"</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index dad857c..af0df4d 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -206,8 +206,7 @@ <string name="quick_settings_color_space_label" msgid="853443689745584770">"Värinkorjaustila"</string> <string name="recents_empty_message" msgid="2269156590813544104">"VIIMEISIMMÄT"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string> - <!-- no translation found for recents_search_bar_label (8074997400187836677) --> - <skip /> + <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string> <string name="description_target_search" msgid="3091587249776033139">"Haku"</string> <string name="description_direction_up" msgid="7169032478259485180">"Liu\'uta ylös ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -217,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d ilmoitusta piilotettu"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Näytä koskettamalla"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Älä häiritse"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d muuta"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Avaa napauttamalla uudelleen"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Avaa lukitus pyyhkäisemällä ylös"</string> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index f0eb784..f01c99a 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -222,4 +222,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d autres"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Touchez à nouveau pour ouvrir"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Glissez vers le haut pour déverrouiller"</string> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 84dae3f..5efbd2f 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -218,9 +218,10 @@ <item quantity="other" msgid="7388721375827338153">"%d notifications masquées"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Appuyer pour afficher"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Ne pas déranger"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"+ %d autres"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Appuyer à nouveau pour ouvrir"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Faire glisser pour déverrouiller"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 2cdff20..e6d38ef 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d और"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"खोलने के लिए पुन: टैप करें"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करने के लिए ऊपर स्वाइप करें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 8b69a4d..b777b8f 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"Broj skrivenih obavijesti: %d"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Dodirnite za prikaz"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Ne ometaj"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Još %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite opet za otvaranje"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Prijeđite prstom prema gore za otključavanje"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index e9c7c7b..10732fe 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d további"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Koppintson rá ismét a megnyitáshoz"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Húzza felfelé az ujját a feloldáshoz"</string> </resources> diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index e2d69a0..f1c4869 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -206,8 +206,7 @@ <string name="quick_settings_color_space_label" msgid="853443689745584770">"Գույների կարգավորման ռեժիմ"</string> <string name="recents_empty_message" msgid="2269156590813544104">"ՎԵՐՋԻՆՆԵՐԸ"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string> - <!-- no translation found for recents_search_bar_label (8074997400187836677) --> - <skip /> + <string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string> <string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string> <string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string> @@ -217,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d ծանուցում թաքցված է"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Հպեք՝ ցուցադրելու համար"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Չխանգարել"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Եվս %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Կրկին հպեք՝ բացելու համար"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Սահեցրեք վերև` ապակողպելու համար"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index c3ec03b..f0b0713 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d lainnya"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Ketuk lagi untuk membuka"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 60f9fc8..6a57682 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -222,4 +222,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Altre %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Tocca ancora per aprire"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Scorri verso l\'alto per sbloccare"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index f9dc2e7..3e87b76 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"עוד %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"הקש שוב כדי לפתוח"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"החלק מעלה כדי לבטל את הנעילה"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 73fb622..1edb630 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -218,9 +218,10 @@ <item quantity="other" msgid="7388721375827338153">"%d件の通知が非表示"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"表示するにはタップします"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"通知を非表示"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"他%d件"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"開くにはもう一度タップしてください"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"ロック解除するには上にスワイプしてください"</string> </resources> diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml index 0cd7812..9d4344a 100644 --- a/packages/SystemUI/res/values-ka-rGE/strings.xml +++ b/packages/SystemUI/res/values-ka-rGE/strings.xml @@ -206,8 +206,7 @@ <string name="quick_settings_color_space_label" msgid="853443689745584770">"ფერთა კორექციის რეჟიმი"</string> <string name="recents_empty_message" msgid="2269156590813544104">"ბოლო დროის"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string> - <!-- no translation found for recents_search_bar_label (8074997400187836677) --> - <skip /> + <string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string> <string name="description_target_search" msgid="3091587249776033139">"ძიება"</string> <string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string> @@ -217,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d შეტყობინება დამალულია"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"შეეხეთ საჩვენებლად"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"არ შემაწუხოთ"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d სხვა"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"შეეხეთ ისევ გასახსნელად"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"გაასრიალეთ ზევით განსაბლოკად"</string> </resources> diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index 30eae2e..bb2d3b9 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d ទៀត"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"ប៉ះម្ដងទៀត ដើម្បីបើក"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"អូសឡើងលើ ដើម្បីដោះសោ"</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index e1ab831..83ffa9f 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"알림 %d개 숨김"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"표시하려면 터치"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"알림 일시중지"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d개 더보기"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"다시 탭하여 열기"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"위로 스와이프하여 잠금 해제"</string> </resources> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index 3ade551..9a3d483 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"ເຊື່ອງ %d ການແຈ້ງເຕືອນແລ້ວ"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"ແຕະເພື່ອສະແດງ"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"ຫ້າມລົບກວນ"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d ເພີ່ມເຕີມ"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"ແຕະອີກຄັ້ງເພື່ອເປີດ"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"ເລື່ອນຂຶ້ນເພື່ອປົດລັອກ"</string> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 3dc6a7a..379cfce 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> @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Dar %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Palieskite dar kartą, kad atidarytumėte"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Perbraukite aukštyn, kad atrakintumėte"</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 9405545..ca07095 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"vēl %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Pieskarieties vēlreiz, lai atvērtu"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Velciet uz augšu, lai atbloķētu"</string> </resources> diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml index 99ecacf..4545301 100644 --- a/packages/SystemUI/res/values-mn-rMN/strings.xml +++ b/packages/SystemUI/res/values-mn-rMN/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"өөр %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Нээхийн тулд дахин товшино уу"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Түгжээг тайлах бол шудрана уу"</string> </resources> diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml index 886d644..587b84f 100644 --- a/packages/SystemUI/res/values-ms-rMY/strings.xml +++ b/packages/SystemUI/res/values-ms-rMY/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d pemberitahuan disembunyikan"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Sentuh untuk menunjukkan"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Jangan ganggu"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d lagi"</item> </plurals> + <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 1892632..001e733 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d varsler er skjult"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Trykk for å vise"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Ikke forstyrr"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d til"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Trykk på nytt for å åpne"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Sveip oppover for å låse opp"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index bf4d765..8a6e33b 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Nog %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Tik nogmaals om te openen"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Veeg omhoog om te ontgrendelen"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 57605b2..4862d1b 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d więcej"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Kliknij ponownie, by otworzyć"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Przesuń w górę, by odblokować"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index fc71887..012283a 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Mais %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar rapidamente com o dedo para cima para desbloquear"</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index d1ed7ac..0978d18 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -218,9 +218,10 @@ <item quantity="other" msgid="7388721375827338153">"%d notificações ocultas"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Toque para mostrar"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Não perturbe"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Mais %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Toque novamente para abrir"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Deslize para cima para desbloquear"</string> </resources> diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml index 4e0f0f6..25f643f 100644 --- a/packages/SystemUI/res/values-rm/strings.xml +++ b/packages/SystemUI/res/values-rm/strings.xml @@ -399,4 +399,8 @@ <!-- no translation found for zen_mode_title (8793432092004749188) --> <skip /> <!-- no translation found for keyguard_more_overflow_text:other (9180696159506883684) --> + <!-- no translation found for notification_tap_again (7590196980943943842) --> + <skip /> + <!-- no translation found for keyguard_unlock (8043466894212841998) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index cef305c..5c9764a 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -206,8 +206,7 @@ <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mod de corectare a culorilor"</string> <string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string> <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string> - <!-- no translation found for recents_search_bar_label (8074997400187836677) --> - <skip /> + <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string> <string name="description_target_search" msgid="3091587249776033139">"Căutaţi"</string> <string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> @@ -217,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d de notificări ascunse"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Atingeți pentru a afișa"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Nu deranjaţi"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Încă %d"</item> </plurals> + <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 ef4b6ee..976a793 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -218,9 +218,10 @@ <item quantity="other" msgid="7388721375827338153">"Скрыто оповещений: %d"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Нажмите, чтобы открыть"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Не беспокоить"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Ещё %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Нажмите ещё раз, чтобы открыть"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Для разблокировки проведите пальцем по экрану"</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 11e8b26..1224c3a 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -218,9 +218,10 @@ <item quantity="other" msgid="7388721375827338153">"Skryté upozornenia: %d"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Upozornenie zobrazíte dotykom"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Nerušiť"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d ďalších"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Upozornenie otvoríte opätovným klepnutím"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Zariadenie odomknete prejdením prstom nahor"</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 00d0086..10011bc 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"še %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Znova se dotaknite, da odprete"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Povlecite, da odklenete"</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 0f8686c..0c6a939 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"Сакривена обавештења: %d"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Додирните за приказ"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Не узнемиравај"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Још %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Додирните поново да бисте отворили"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Превуците нагоре да бисте откључали"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index a0e1468..d8bd1b1 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d till"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Tryck igen för att öppna"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Dra uppåt om du vill låsa upp"</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 2c84b19..d308b51 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -214,9 +214,10 @@ <item quantity="other" msgid="7388721375827338153">"Arifa %d zimefichwa"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Gusa ili zionekane"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Usisumbue"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d zaidi"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Gonga tena ili ufungue"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Telezesha kidole ili ufungue"</string> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 1ebe21c..7929a30 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"อีก %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"แตะอีกครั้งเพื่อเปิด"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"กวาดขึ้นเพื่อปลดล็อก"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index eb8f236..92473a4 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"Nakatago ang %d (na) notification"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Pindutin upang ipakita"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Huwag istorbohin"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d pa"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"I-tap ulit upang buksan"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Mag-swipe pataas upang i-unlock"</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 1b57a94..9837ff8 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d bildirim gizli"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Görüntülemek için dokunun"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Rahatsız etmeyin"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d adet daha"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Açmak için tekrar hafifçe vurun"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Kilidi açmak için hızlıca yukarı kaydırın"</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 60192d7..534f520 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"Ще %d"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Торкніться знову, щоб відкрити"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Проведіть пальцем угору, щоб розблокувати"</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 8770854..56fc89c 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -216,9 +216,10 @@ <item quantity="other" msgid="7388721375827338153">"%d thông báo ẩn"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"Chạm để hiển thị"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"Không làm phiền"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d thông báo khác"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Nhấn lại để mở"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Vuốt lên để mở khóa"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 89250a5..442fdb7 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -218,9 +218,10 @@ <item quantity="other" msgid="7388721375827338153">"隐藏了%d条通知"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"触摸即可显示"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"勿扰"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"还有%d条"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"再次点按即可打开"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑动即可解锁"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 6fb723e..54a3b1e 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -222,4 +222,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"還有 %d 個"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"向上快速滑動即可解鎖"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 9ceb4e9..fc74f53 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -218,9 +218,10 @@ <item quantity="other" msgid="7388721375827338153">"已隱藏 %d 則通知"</item> </plurals> <string name="zen_mode_notification_text" msgid="8336623711388065713">"輕觸即可顯示"</string> - <!-- no translation found for zen_mode_title (8793432092004749188) --> - <skip /> + <string name="zen_mode_title" msgid="8793432092004749188">"請勿打擾"</string> <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"還有 %d 則"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"再次輕按即可開啟"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑動即可解鎖"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 81a08d9..dfe8838 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -220,4 +220,6 @@ <plurals name="keyguard_more_overflow_text"> <item quantity="other" msgid="9180696159506883684">"%d okuningi"</item> </plurals> + <string name="notification_tap_again" msgid="7590196980943943842">"Thepha futhi ukuze uvule"</string> + <string name="keyguard_unlock" msgid="8043466894212841998">"Swayiphela phezulu ukuze uvule"</string> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 722ca15..024f1eb 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -115,8 +115,10 @@ <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. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index aadeebe..1900fea 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -176,7 +176,7 @@ <dimen name="carrier_label_height">24dp</dimen> <!-- The distance you can pull a notification before it pops open --> - <dimen name="one_finger_pop_limit">32dp</dimen> + <dimen name="one_finger_pop_limit">0dp</dimen> <!-- The fixed height of each tile --> <dimen name="quick_settings_cell_height">110dp</dimen> @@ -188,7 +188,7 @@ Not used at this screen size. --> <item type="dimen" name="notification_panel_min_height_frac">0%</item> - <dimen name="blinds_pop_threshold">32dp</dimen> + <dimen name="blinds_pop_threshold">0dp</dimen> <!-- The size of the gesture span needed to activate the "pull" notification expansion --> <dimen name="pull_span_min">25dp</dimen> @@ -231,10 +231,7 @@ <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. --> @@ -266,4 +263,9 @@ <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/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index c585a5b..4d6d815 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -29,16 +29,16 @@ import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector.OnScaleGestureListener; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewConfiguration; -import android.view.ViewGroup; +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); @@ -47,9 +47,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { 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; @@ -114,10 +112,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { float focusX = detector.getFocusX(); float focusY = detector.getFocusY(); - final View underFocus = findView(focusX, focusY); - if (underFocus != null) { - startExpanding(underFocus, STRETCH); - } + final ExpandableView underFocus = findView(focusX, focusY); + startExpanding(underFocus, STRETCH); return mExpanding; } @@ -133,41 +129,21 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { }; private class ViewScaler { - View mView; + ExpandableView mView; public ViewScaler() {} - public void setView(View v) { + public void setView(ExpandableView v) { mView = v; } public void setHeight(float h) { if (DEBUG_SCALE) Log.v(TAG, "SetHeight: setting to " + h); - ViewGroup.LayoutParams lp = mView.getLayoutParams(); - lp.height = (int)h; - mView.setLayoutParams(lp); - mView.requestLayout(); + mView.setActualHeight((int) h); } public float getHeight() { - int height = mView.getLayoutParams().height; - if (height < 0) { - height = mView.getMeasuredHeight(); - } - return height; + return mView.getActualHeight(); } public int getNaturalHeight(int maximum) { - ViewGroup.LayoutParams lp = mView.getLayoutParams(); - if (DEBUG_SCALE) Log.v(TAG, "Inspecting a child of type: " + - mView.getClass().getName()); - int oldHeight = lp.height; - lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; - mView.setLayoutParams(lp); - mView.measure( - View.MeasureSpec.makeMeasureSpec(mView.getMeasuredWidth(), - View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(maximum, - View.MeasureSpec.AT_MOST)); - lp.height = oldHeight; - mView.setLayoutParams(lp); - return mView.getMeasuredHeight(); + return Math.min(maximum, mView.getMaxHeight()); } } @@ -189,34 +165,10 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { mGravity = Gravity.TOP; mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f); mScaleAnimation.setDuration(EXPAND_DURATION); - mScaleAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mCallback.setUserLockedChild(mCurrView, false); - } - }); mPopLimit = mContext.getResources().getDimension(R.dimen.blinds_pop_threshold); 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(); @@ -248,8 +200,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { 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); @@ -298,15 +250,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { 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(); @@ -340,10 +283,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { // 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); - if (underFocus != null) { - startExpanding(underFocus, PULL); - } + final ExpandableView underFocus = findView(x, y); + startExpanding(underFocus, PULL); return true; } if (mScrollAdapter != null && !mScrollAdapter.isScrolledToTop()) { @@ -357,9 +298,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { if (yDiff > mTouchSlop) { if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)"); mLastMotionY = y; - final View underFocus = findView(x, y); - if (underFocus != null) { - startExpanding(underFocus, BLINDS); + final ExpandableView underFocus = findView(x, y); + if (startExpanding(underFocus, BLINDS)) { mInitialTouchY = mLastMotionY; mHasPopped = false; } @@ -424,7 +364,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { 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); @@ -459,16 +399,22 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { return true; } - private void startExpanding(View v, int expandType) { + /** + * @return True if the view is expandable, false otherwise. + */ + private boolean startExpanding(ExpandableView v, int expandType) { + if (!(v instanceof ExpandableNotificationRow)) { + return false; + } mExpansionStyle = expandType; - if (mExpanding && v == mCurrView) { - return; + if (mExpanding && v == mCurrView) { + return true; } mExpanding = true; if (DEBUG) Log.d(TAG, "scale type " + expandType + " beginning on view: " + v); mCallback.setUserLockedChild(v, true); setView(v); - mScaler.setView(v); + mScaler.setView((ExpandableView) v); mOldHeight = mScaler.getHeight(); if (mCallback.canChildBeExpanded(v)) { if (DEBUG) Log.d(TAG, "working on an expandable child"); @@ -480,6 +426,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { if (DEBUG) Log.d(TAG, "got mOldHeight: " + mOldHeight + " mNaturalHeight: " + mNaturalHeight); v.getParent().requestDisallowInterceptTouchEvent(true); + return true; } private void finishExpanding(boolean force) { @@ -499,10 +446,18 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { if (mScaleAnimation.isRunning()) { mScaleAnimation.cancel(); } - mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight); + mCallback.setUserExpandedChild(mCurrView, targetHeight == mNaturalHeight); if (targetHeight != currentHeight) { mScaleAnimation.setFloatValues(targetHeight); mScaleAnimation.setupStartValues(); + final View scaledView = mCurrView; + mScaleAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCallback.setUserLockedChild(scaledView, false); + mScaleAnimation.removeListener(this); + } + }); mScaleAnimation.start(); } else { mCallback.setUserLockedChild(mCurrView, false); @@ -527,13 +482,6 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener { 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/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 74483cc..4857adc 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -211,6 +211,7 @@ public class ImageWallpaper extends WallpaperService { if (mReceiver != null) { unregisterReceiver(mReceiver); } + mBackground = null; } void updateSurfaceSize(SurfaceHolder surfaceHolder) { 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 @@ public class SystemUIApplication extends Application { // 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 @@ public class SystemUIApplication extends Application { } } } - }, 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 @@ public class KeyguardViewMediator extends SystemUI { /** * 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 @@ public class KeyguardViewMediator extends SystemUI { } 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/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 class Console { 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 72d9a52..bc8ab45 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -26,10 +26,11 @@ public class Constants { public static final boolean Verbose = false; public static class App { - public static final boolean EnableTaskFiltering = true; + public static final boolean EnableTaskFiltering = false; public static final boolean EnableTaskStackClipping = false; + public static final boolean EnableTaskBarThemeColors = true; public static final boolean EnableInfoPane = true; - public static final boolean EnableSearchButton = false; + public static final boolean EnableSearchButton = true; // This disables the bitmap and icon caches public static final boolean DisableBackgroundCache = false; @@ -51,6 +52,7 @@ public class Constants { 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 { @@ -71,6 +73,10 @@ public class Constants { } 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; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 71c45f2..110130b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -17,11 +17,17 @@ 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.content.SharedPreferences; import android.os.Bundle; +import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; @@ -33,13 +39,37 @@ import com.android.systemui.recents.views.RecentsView; 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; @@ -102,6 +132,75 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } + /** Attempts to allocate and bind the search bar app widget */ + void bindSearchBarAppWidget() { + if (Constants.DebugFlags.App.EnableSearchButton) { + 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.DebugFlags.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.DebugFlags.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.EnableSearchButton) { + RecentsConfiguration config = RecentsConfiguration.getInstance(); + int appWidgetId = config.searchBarAppWidgetId; + if (appWidgetId >= 0) { + Console.log(Constants.DebugFlags.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) { @@ -127,6 +226,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView 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 +247,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Update the recent tasks updateRecentsTasks(getIntent()); + + // Bind the search app widget when we first start up + bindSearchBarAppWidget(); + // Add the search bar layout + addSearchBarAppWidgetView(); } @Override @@ -165,6 +272,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Update the recent tasks updateRecentsTasks(intent); + + // Don't attempt to rebind the search bar widget, but just add the search bar layout + addSearchBarAppWidgetView(); } @Override @@ -172,6 +282,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStart]", "", Console.AnsiRed); super.onStart(); + mAppWidgetHost.startListening(); mVisible = true; } @@ -225,6 +336,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView Console.AnsiRed); super.onStop(); + mAppWidgetHost.stopListening(); mVisible = false; mTaskLaunched = false; } @@ -265,4 +377,18 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView 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..5a1dc8d 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,25 @@ public class RecentsConfiguration { public Rect systemInsets = new Rect(); public Rect displayRect = new Rect(); + boolean isLandscape; + 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 taskViewRoundedCornerRadiusPx; public int searchBarSpaceHeightPx; - public int searchBarSpaceEdgeMarginsPx; + + public int taskBarViewDefaultBackgroundColor; + public int taskBarViewDefaultTextColor; + public int taskBarViewLightTextColor; + public int taskBarViewDarkTextColor; public boolean launchedWithThumbnailAnimation; @@ -72,7 +81,7 @@ public class RecentsConfiguration { DisplayMetrics dm = res.getDisplayMetrics(); mDisplayMetrics = dm; - boolean isLandscape = res.getConfiguration().orientation == + isLandscape = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait", @@ -87,6 +96,8 @@ public class RecentsConfiguration { 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); @@ -95,8 +106,20 @@ public class RecentsConfiguration { taskViewRoundedCornerRadiusPx = res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius); 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 +127,57 @@ public class RecentsConfiguration { 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) { + // 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) { 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) { + // 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..0c6ed84 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java @@ -60,39 +60,41 @@ class SystemUIMessageHandler extends Handler { 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)); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java index 52bba4a..4a19027 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java @@ -415,17 +415,23 @@ public class RecentsTaskLoader { 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)) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java index 33ac0a8..68af663 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.ActivityManager; 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.Bundle; 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,6 +49,7 @@ import java.util.Random; */ public class SystemServicesProxy { ActivityManager mAm; + AppWidgetManager mAwm; PackageManager mPm; IPackageManager mIpm; UserManager mUm; @@ -59,6 +61,7 @@ public class SystemServicesProxy { /** 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(); @@ -91,10 +94,13 @@ public class SystemServicesProxy { 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 +109,7 @@ public class SystemServicesProxy { 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,7 +168,7 @@ public class SystemServicesProxy { /** * 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) { @@ -177,6 +183,23 @@ public class SystemServicesProxy { } } + /** + * 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 null; + + 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 +231,70 @@ public class SystemServicesProxy { return icon; } - /** - * Composes an intent to launch the global search activity. + * Resolves and binds the search app widget that is to appear in the recents. */ - public Intent getGlobalSearchIntent(Rect sourceBounds) { - if (mSm == null) return null; + public Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host) { + if (mAwm == null) return null; - // Try and get the global search activity + // Ensure we have a global search activity ComponentName globalSearchActivity = mSm.getGlobalSearchActivity(); if (globalSearchActivity == null) return null; - // Bundle the source of the search - Bundle appSearchData = new Bundle(); - appSearchData.putString("source", mPackage); - - // 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; + // Resolve the search widget provider from the search activity + ActivityInfo searchActivityInfo = getActivityInfo(globalSearchActivity); + if (searchActivityInfo == null) return null; + + String key = "com.android.recents.search_widget_provider"; + ComponentName searchWidgetCn = null; + Bundle searchMetaData = searchActivityInfo.metaData; + String searchWidgetProvider = searchMetaData.getString(key, ""); + if (searchWidgetProvider.length() != 0) { + searchWidgetCn = ComponentName.unflattenFromString(searchWidgetProvider); + } else { + return null; + } + + // Find the first Recents widget from the same package as the global search activity + List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(); + AppWidgetProviderInfo searchWidgetInfo = null; + for (AppWidgetProviderInfo info : widgets) { + if (info.provider.equals(searchWidgetCn)) { + 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); + } + + /** + * Returns the app widget info for the specified app widget id. + */ + public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { + if (mAwm == null) return null; + + return mAwm.getAppWidgetInfo(appWidgetId); + } + + /** + * Destroys the specified app widget. + */ + public void unbindSearchAppWidget(AppWidgetHost host, int appWidgetId) { + if (mAwm == null) return; + + // 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 @@ public class Utilities { 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 class Task { 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 class Task { } 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..c2e8275 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.graphics.Rect; 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.RecentsTaskLoader; 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 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // 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 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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.EnableSearchButton) { + // 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.DebugFlags.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); @@ -155,22 +157,26 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup, Constants.DebugFlags.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,6 +189,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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]", @@ -190,21 +199,24 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup, Constants.DebugFlags.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,9 +224,8 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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()); } } } @@ -374,24 +385,4 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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/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 @@ package com.android.systemui.recents.views; 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 @@ class TaskBarView extends FrameLayout { /** 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 @@ class TaskBarView extends FrameLayout { 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..983ad49 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java @@ -29,7 +29,10 @@ 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 +146,16 @@ class TaskInfoView extends FrameLayout { .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); + } 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 a77e61d..e273ecf 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -547,7 +547,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } /** 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,6 +555,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // 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); @@ -582,6 +583,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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); @@ -592,7 +598,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // 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) { @@ -630,6 +638,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal 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]", @@ -976,8 +989,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } else { mStack.filterTasks(tv.getTask()); } - } else { - Console.logError(getContext(), "Task Filtering TBD"); } } 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..ecd0c45 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -197,18 +197,9 @@ public class TaskView extends FrameLayout implements View.OnClickListener, /** 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 +210,11 @@ public class TaskView extends FrameLayout implements View.OnClickListener, /** 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 +338,7 @@ public class TaskView extends FrameLayout implements View.OnClickListener, // 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); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index d647dfa..1c88ea7 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; @@ -29,12 +35,11 @@ import com.android.internal.R; * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer} * to implement dimming/activating on Keyguard for the double-tap gesture */ -public class ActivatableNotificationView extends FrameLayout { +public abstract class ActivatableNotificationView extends ExpandableOutlineView { private static final long DOUBLETAP_TIMEOUT_MS = 1000; private boolean mDimmed; - private boolean mLocked; private int mBgResId = R.drawable.notification_quantum_bg; private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim; @@ -51,12 +56,20 @@ public class ActivatableNotificationView extends FrameLayout { 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() { @@ -65,32 +78,58 @@ public class ActivatableNotificationView extends FrameLayout { }; @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: mDownX = event.getX(); mDownY = event.getY(); - - // 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); + if (mDownY > getActualHeight()) { + return false; } break; case MotionEvent.ACTION_MOVE: @@ -105,8 +144,8 @@ public class ActivatableNotificationView extends FrameLayout { makeActive(event.getX(), event.getY()); postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS); } else { - performClick(); makeInactive(); + performClick(); } } else { makeInactive(); @@ -122,8 +161,11 @@ public class ActivatableNotificationView extends FrameLayout { } private void makeActive(float x, float y) { - getBackground().setHotspot(0, x, y); + mBackgroundDimmed.setHotspot(0, x, y); mActivated = true; + if (mOnActivatedListener != null) { + mOnActivatedListener.onActivated(this); + } } /** @@ -132,8 +174,8 @@ public class ActivatableNotificationView extends FrameLayout { private void makeInactive() { if (mActivated) { // Make sure that we clear the hotspot from the center. - getBackground().setHotspot(0, getWidth() / 2, getHeight() / 2); - getBackground().removeHotspot(0); + mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2); + mBackgroundDimmed.removeHotspot(0); mActivated = false; } if (mOnActivatedListener != null) { @@ -149,23 +191,22 @@ public class ActivatableNotificationView extends FrameLayout { /** * Sets the notification as dimmed, meaning that it will appear in a more gray variant. + * + * @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) { + 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. @@ -177,8 +218,111 @@ public class ActivatableNotificationView extends FrameLayout { updateBackgroundResource(); } + private void fadeBackgroundResource() { + if (mDimmed) { + setBackgroundDimmed(mDimmedBgResId); + } else { + setBackgroundNormal(mBgResId); + } + int startAlpha = mDimmed ? 255 : 0; + int endAlpha = mDimmed ? 0 : 255; + int duration = NotificationActivator.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() { - setBackgroundResource(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); + } + + @Override + public void setActualHeight(int actualHeight) { + super.setActualHeight(actualHeight); + invalidate(); + setPivotY(actualHeight / 2); + } + + @Override + public void setClipTopAmount(int clipTopAmount) { + super.setClipTopAmount(clipTopAmount); + invalidate(); } public void setOnActivatedListener(OnActivatedListener onActivatedListener) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 3e21640..edf54d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -71,7 +71,6 @@ 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.widget.SizeAdaptiveLayout; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SearchPanelView; @@ -168,7 +167,12 @@ public abstract class BaseStatusBar extends SystemUI implements 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() { @@ -760,9 +764,10 @@ public abstract class BaseStatusBar extends SystemUI implements // NB: the large icon is now handled entirely by the template // bind the click event to the content area - SizeAdaptiveLayout expanded = (SizeAdaptiveLayout)row.findViewById(R.id.expanded); - SizeAdaptiveLayout expandedPublic - = (SizeAdaptiveLayout)row.findViewById(R.id.expandedPublic); + NotificationContentView expanded = + (NotificationContentView) row.findViewById(R.id.expanded); + NotificationContentView expandedPublic = + (NotificationContentView) row.findViewById(R.id.expandedPublic); row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); @@ -794,19 +799,11 @@ public abstract class BaseStatusBar extends SystemUI implements if (contentViewLocal != null) { contentViewLocal.setIsRootNamespace(true); - SizeAdaptiveLayout.LayoutParams params = - new SizeAdaptiveLayout.LayoutParams(contentViewLocal.getLayoutParams()); - params.minHeight = minHeight; - params.maxHeight = minHeight; - expanded.addView(contentViewLocal, params); + expanded.setContractedChild(contentViewLocal); } if (bigContentViewLocal != null) { bigContentViewLocal.setIsRootNamespace(true); - SizeAdaptiveLayout.LayoutParams params = - new SizeAdaptiveLayout.LayoutParams(bigContentViewLocal.getLayoutParams()); - params.minHeight = minHeight+1; - params.maxHeight = maxHeight; - expanded.addView(bigContentViewLocal, params); + expanded.setExpandedChild(bigContentViewLocal); } PackageManager pm = mContext.getPackageManager(); @@ -820,11 +817,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (publicViewLocal != null) { publicViewLocal.setIsRootNamespace(true); - SizeAdaptiveLayout.LayoutParams params = - new SizeAdaptiveLayout.LayoutParams(publicViewLocal.getLayoutParams()); - params.minHeight = minHeight; - params.maxHeight = minHeight; - expandedPublic.addView(publicViewLocal, params); + expandedPublic.setContractedChild(publicViewLocal); } } catch (RuntimeException e) { @@ -1069,33 +1062,39 @@ public abstract class BaseStatusBar extends SystemUI implements 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) { - entry.row.setSystemExpanded(false); + if (onKeyguard) { + entry.row.setExpansionDisabled(true); } else { + entry.row.setExpansionDisabled(false); if (!entry.row.isUserLocked()) { boolean top = (i == n-1); - entry.row.setSystemExpanded(top || entry.row.isUserExpanded()); + entry.row.setSystemExpanded(top); } } - entry.row.setDimmed(mOnKeyguard); - entry.row.setLocked(mOnKeyguard); + entry.row.setDimmed(onKeyguard, false /* fade */); boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification); - if (mOnKeyguard && (visibleNotifications >= maxKeyguardNotifications + if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications || !showOnKeyguard)) { entry.row.setVisibility(View.GONE); if (showOnKeyguard) { mKeyguardIconOverflowContainer.getIconsView().addNotification(entry); } } else { + if (entry.row.getVisibility() == View.GONE) { + // notify the scroller of a child addition + mStackScroller.generateAddAnimation(entry.row); + } entry.row.setVisibility(View.VISIBLE); visibleNotifications++; } } - if (mOnKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) { + if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) { mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE); + mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, false /* fade */); } else { mKeyguardIconOverflowContainer.setVisibility(View.GONE); } @@ -1289,8 +1288,8 @@ public abstract class BaseStatusBar extends SystemUI implements final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion(); if (userChangedExpansion) { boolean userExpanded = oldEntry.row.isUserExpanded(); - newEntry.row.applyExpansionToLayout(userExpanded); newEntry.row.setUserExpanded(userExpanded); + newEntry.row.notifyHeightChanged(); } } @@ -1352,6 +1351,7 @@ public abstract class BaseStatusBar extends SystemUI implements } else { entry.row.setOnClickListener(null); } + entry.row.notifyContentUpdated(); } protected void notifyHeadsUpScreenOn(boolean screenOn) { @@ -1404,6 +1404,17 @@ public abstract class BaseStatusBar extends SystemUI implements // 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/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java new file mode 100644 index 0000000..e471754 --- /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.onReset(); + } + } + 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.onReset(); + } + + 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 onReset(); + 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 35c02eb..e5512a3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -19,10 +19,8 @@ package com.android.systemui.statusbar; import android.content.Context; import android.util.AttributeSet; import android.view.View; -import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; -import com.android.internal.widget.SizeAdaptiveLayout; import com.android.systemui.R; public class ExpandableNotificationRow extends ActivatableNotificationView { @@ -45,12 +43,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { * user expansion. */ private boolean mIsSystemExpanded; - private SizeAdaptiveLayout mPublicLayout; - private SizeAdaptiveLayout mPrivateLayout; + + /** + * Whether the notification expansion is disabled. This is the case on Keyguard. + */ + private boolean mExpansionDisabled; + + private NotificationContentView mPublicLayout; + private NotificationContentView mPrivateLayout; private int mMaxExpandHeight; - private boolean mMaxHeightNeedsUpdate; private NotificationActivator mActivator; - private boolean mSelfInitiatedLayout; public ExpandableNotificationRow(Context context, AttributeSet attrs) { super(context, attrs); @@ -59,10 +61,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { @Override protected void onFinishInflate() { super.onFinishInflate(); - mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic); - mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded); + mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic); + mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded); - mActivator = new NotificationActivator(this); + mActivator = new NotificationActivator(this, this); } @Override @@ -82,7 +84,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { public void setHeightRange(int rowMinHeight, int rowMaxHeight) { mRowMinHeight = rowMinHeight; mRowMaxHeight = rowMaxHeight; - mMaxHeightNeedsUpdate = true; } public boolean isExpandable() { @@ -136,31 +137,34 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { */ public void setSystemExpanded(boolean expand) { mIsSystemExpanded = expand; - applyExpansionToLayout(expand); + notifyHeightChanged(); + } + + /** + * @param expansionDisabled whether to prevent notification expansion + */ + public void setExpansionDisabled(boolean expansionDisabled) { + mExpansionDisabled = expansionDisabled; + notifyHeightChanged(); } /** * Apply an expansion state to the layout. - * - * @param expand should the layout be in the expanded state */ - public void applyExpansionToLayout(boolean expand) { - ViewGroup.LayoutParams lp = getLayoutParams(); + public void applyExpansionToLayout() { + boolean expand = isExpanded(); if (expand && mExpandable) { - lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; + setActualHeight(mMaxExpandHeight); } else { - lp.height = mRowMinHeight; + setActualHeight(mRowMinHeight); } - setLayoutParams(lp); } - /** - * 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(); + } boolean inExpansionState = isExpanded(); if (!inExpansionState) { // not expanded, so we return the collapsed size @@ -170,31 +174,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { return mShowingPublic ? mRowMinHeight : getMaxExpandHeight(); } - private void updateMaxExpandHeight() { - - // We don't want this method to trigger a layout of the whole view hierarchy, - // as the layout parameters in the end are the same which they were in the beginning. - // Otherwise a loop may occur if this method is called on the layout of a parent. - mSelfInitiatedLayout = true; - ViewGroup.LayoutParams lp = getLayoutParams(); - int oldHeight = lp.height; - lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; - setLayoutParams(lp); - measure(View.MeasureSpec.makeMeasureSpec(getWidth(), View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(mRowMaxHeight, View.MeasureSpec.AT_MOST)); - lp.height = oldHeight; - setLayoutParams(lp); - mMaxExpandHeight = getMeasuredHeight(); - mSelfInitiatedLayout = false; - } - - @Override - public void requestLayout() { - if (!mSelfInitiatedLayout) { - super.requestLayout(); - } - } - /** * Check whether the view state is currently expanded. This is given by the system in {@link * #setSystemExpanded(boolean)} and can be overridden by user expansion or @@ -204,13 +183,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { * @return whether the view state is currently expanded. */ private boolean isExpanded() { - return !hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded(); + return !mExpansionDisabled + && (!hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded()); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - mMaxHeightNeedsUpdate = true; + boolean updateExpandHeight = mMaxExpandHeight == 0; + mMaxExpandHeight = mPrivateLayout.getMaxHeight(); + if (updateExpandHeight) { + applyExpansionToLayout(); + } } public void setShowingPublic(boolean show) { @@ -227,16 +211,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { /** * 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); + @Override + public void setDimmed(boolean dimmed, boolean fade) { + super.setDimmed(dimmed, fade); + mActivator.setDimmed(dimmed, fade); } public int getMaxExpandHeight() { - if (mMaxHeightNeedsUpdate) { - updateMaxExpandHeight(); - mMaxHeightNeedsUpdate = false; - } return mMaxExpandHeight; } @@ -248,6 +229,38 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { * @return the potential height this view could expand in addition. */ public int getExpandPotential() { - return getMaximumAllowedExpandHeight() - getHeight(); + return getIntrinsicHeight() - getActualHeight(); + } + + @Override + public boolean isContentExpandable() { + return mPrivateLayout.isContentExpandable(); + } + + @Override + public void setActualHeight(int height) { + mPrivateLayout.setActualHeight(height); + invalidate(); + super.setActualHeight(height); + } + + @Override + public int getMaxHeight() { + return mPrivateLayout.getMaxHeight(); + } + + @Override + public int getMinHeight() { + return mPrivateLayout.getMinHeight(); + } + + @Override + public void setClipTopAmount(int clipTopAmount) { + super.setClipTopAmount(clipTopAmount); + mPrivateLayout.setClipTopAmount(clipTopAmount); + } + + public void notifyContentUpdated() { + mPrivateLayout.notifyContentUpdated(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java new file mode 100644 index 0000000..43eb5b5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar; + +import android.content.Context; +import android.graphics.Outline; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +/** + * Like {@link ExpandableView}, but setting an outline for the height and clipping. + */ +public abstract class ExpandableOutlineView extends ExpandableView { + + private final Outline mOutline = new Outline(); + + public ExpandableOutlineView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void setActualHeight(int actualHeight) { + super.setActualHeight(actualHeight); + updateOutline(); + } + + @Override + public void setClipTopAmount(int clipTopAmount) { + super.setClipTopAmount(clipTopAmount); + updateOutline(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + updateOutline(); + } + + private void updateOutline() { + mOutline.setRect(0, + mClipTopAmount, + getWidth(), + Math.max(mActualHeight, mClipTopAmount)); + setOutline(mOutline); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java new file mode 100644 index 0000000..33e9051 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.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; + +/** + * An abstract view for expandable views. + */ +public abstract class ExpandableView extends FrameLayout { + + private OnHeightChangedListener mOnHeightChangedListener; + protected int mActualHeight; + protected int mClipTopAmount; + private boolean mActualHeightInitialized; + + public ExpandableView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @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) { + mActualHeight = getHeight(); + } + 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. + */ + public void setActualHeight(int actualHeight) { + mActualHeight = actualHeight; + notifyHeightChanged(); + } + + /** + * See {@link #setActualHeight}. + * + * @return The current actual height of this notification. + */ + public int getActualHeight() { + return mActualHeight; + } + + /** + * @return The maximum height of this notification. + */ + public int getMaxHeight() { + return getHeight(); + } + + /** + * @return The minimum height of this notification. + */ + public int getMinHeight() { + return getHeight(); + } + + /** + * @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 + * notification is scrolling in the top or bottom stack. + * + * @param clipTopAmount The amount of pixels this view should be clipped from top. + */ + public void setClipTopAmount(int clipTopAmount) { + mClipTopAmount = clipTopAmount; + } + + public void setOnHeightChangedListener(OnHeightChangedListener listener) { + mOnHeightChangedListener = listener; + } + + /** + * @return Whether we can expand this views content. + */ + public boolean isContentExpandable() { + return false; + } + + public void notifyHeightChanged() { + if (mOnHeightChangedListener != null) { + mOnHeightChangedListener.onHeightChanged(this); + } + } + + /** + * A listener notifying when {@link #getActualHeight} changes. + */ + public interface OnHeightChangedListener { + void onHeightChanged(ExpandableView view); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java index 620e457..a03aeec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java @@ -30,18 +30,44 @@ import com.android.systemui.R; */ public class NotificationActivator { - private static final int ANIMATION_LENGTH_MS = 220; + public 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; + /** + * Normal state. Notification is fully interactable. + */ + private static final int STATE_NORMAL = 0; + + /** + * Dimmed state. Neutral state when on the lockscreen, with slight transparency and scaled down + * a bit. + */ + private static final int STATE_DIMMED = 1; + + /** + * Activated state. Used after tapping a notification on the lockscreen. Normal transparency and + * normal scale. + */ + private static final int STATE_ACTIVATED = 2; + /** + * Inverse activated state. Used for the other notifications on the lockscreen when tapping on + * one. + */ + private static final int STATE_ACTIVATED_INVERSE = 3; + + private final View mTargetView; + private final View mHotspotView; private final Interpolator mFastOutSlowInInterpolator; private final Interpolator mLinearOutSlowInInterpolator; private final int mTranslationZ; - public NotificationActivator(View targetView) { + private int mState; + + public NotificationActivator(View targetView, View hotspotView) { mTargetView = targetView; + mHotspotView = hotspotView; Context ctx = targetView.getContext(); mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in); @@ -53,18 +79,37 @@ public class NotificationActivator { } public void activateInverse() { + if (mState == STATE_ACTIVATED_INVERSE) { + return; + } + mTargetView.animate().cancel(); mTargetView.animate().withLayer().alpha(INVERSE_ALPHA); + mState = STATE_ACTIVATED_INVERSE; + } + + public void addHotspot() { + mHotspotView.getBackground().setHotspot( + 0, mHotspotView.getWidth()/2, mHotspotView.getHeight()/2); } public void activate() { + if (mState == STATE_ACTIVATED) { + return; + } + mTargetView.animate().cancel(); mTargetView.animate() .setInterpolator(mLinearOutSlowInInterpolator) .scaleX(1) .scaleY(1) .translationZBy(mTranslationZ); + mState = STATE_ACTIVATED; } public void reset() { + if (mState == STATE_DIMMED) { + return; + } + mTargetView.animate().cancel(); mTargetView.animate() .setInterpolator(mFastOutSlowInInterpolator) .scaleX(DIMMED_SCALE) @@ -73,15 +118,35 @@ public class NotificationActivator { if (mTargetView.getAlpha() != 1.0f) { mTargetView.animate().withLayer().alpha(1); } + mState = STATE_DIMMED; } - public void setDimmed(boolean dimmed) { + public void setDimmed(boolean dimmed, boolean fade) { if (dimmed) { - mTargetView.setScaleX(DIMMED_SCALE); - mTargetView.setScaleY(DIMMED_SCALE); + mTargetView.animate().cancel(); + if (fade) { + mTargetView.animate() + .setInterpolator(mFastOutSlowInInterpolator) + .scaleX(DIMMED_SCALE) + .scaleY(DIMMED_SCALE); + } else { + mTargetView.setScaleX(DIMMED_SCALE); + mTargetView.setScaleY(DIMMED_SCALE); + } + mState = STATE_DIMMED; } else { - mTargetView.setScaleX(1); - mTargetView.setScaleY(1); + mTargetView.animate().cancel(); + if (fade) { + mTargetView.animate() + .setInterpolator(mFastOutSlowInInterpolator) + .scaleX(1) + .scaleY(1); + } else { + mTargetView.animate().cancel(); + mTargetView.setScaleX(1); + mTargetView.setScaleY(1); + } + mState = STATE_NORMAL; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java new file mode 100644 index 0000000..1f15eaf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.graphics.Rect; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; + +import com.android.systemui.R; + +/** + * A frame layout containing the actual payload of the notification, including the contracted and + * expanded layout. This class is responsible for clipping the content and and switching between the + * expanded and contracted view depending on its clipped size. + */ +public class NotificationContentView extends ExpandableView { + + private final Rect mClipBounds = new Rect(); + + private View mContractedChild; + private View mExpandedChild; + + private int mSmallHeight; + + public NotificationContentView(Context context, AttributeSet attrs) { + super(context, attrs); + mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); + mActualHeight = mSmallHeight; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + updateClipping(); + } + + public void setContractedChild(View child) { + if (mContractedChild != null) { + removeView(mContractedChild); + } + sanitizeContractedLayoutParams(child); + addView(child); + mContractedChild = child; + selectLayout(); + } + + public void setExpandedChild(View child) { + if (mExpandedChild != null) { + removeView(mExpandedChild); + } + addView(child); + mExpandedChild = child; + selectLayout(); + } + + @Override + public void setActualHeight(int actualHeight) { + super.setActualHeight(actualHeight); + selectLayout(); + updateClipping(); + } + + @Override + public int getMaxHeight() { + + // The maximum height is just the laid out height. + return getHeight(); + } + + @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); + } + + private void sanitizeContractedLayoutParams(View contractedChild) { + LayoutParams lp = (LayoutParams) contractedChild.getLayoutParams(); + lp.height = mSmallHeight; + contractedChild.setLayoutParams(lp); + } + + private void selectLayout() { + if (mActualHeight <= mSmallHeight || mExpandedChild == null) { + if (mContractedChild.getVisibility() != View.VISIBLE) { + mContractedChild.setVisibility(View.VISIBLE); + } + if (mExpandedChild != null && mExpandedChild.getVisibility() != View.INVISIBLE) { + mExpandedChild.setVisibility(View.INVISIBLE); + } + } else { + if (mExpandedChild.getVisibility() != View.VISIBLE) { + mExpandedChild.setVisibility(View.VISIBLE); + } + if (mContractedChild.getVisibility() != View.INVISIBLE) { + mContractedChild.setVisibility(View.INVISIBLE); + } + } + } + + 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 af91314..e6b5600 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java @@ -35,14 +35,34 @@ public class NotificationOverflowContainer extends ActivatableNotificationView { } @Override + public void setActualHeight(int currentHeight) { + // noop + } + + @Override + public int getActualHeight() { + return getHeight(); + } + + @Override + public void setClipTopAmount(int clipTopAmount) { + // noop + } + + @Override protected void onFinishInflate() { super.onFinishInflate(); mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view); mIconsView.setMoreText((TextView) findViewById(R.id.more_text)); - mActivator = new NotificationActivator(this); - mActivator.setDimmed(true); - setLocked(true); + mActivator = new NotificationActivator(this, this); + setDimmed(true, false); + } + + @Override + public void setDimmed(boolean dimmed, boolean fade) { + super.setDimmed(dimmed, fade); + mActivator.setDimmed(dimmed, fade); } public NotificationOverflowIconsView getIconsView() { 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/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 5d75801..627b80f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -23,10 +23,13 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; 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 { +public class NotificationPanelView extends PanelView implements + ExpandableView.OnHeightChangedListener { public static final boolean DEBUG_GESTURES = true; PhoneStatusBar mStatusBar; @@ -34,11 +37,9 @@ public class NotificationPanelView extends PanelView { private View mKeyguardStatusView; private NotificationStackScrollLayout mNotificationStackScroller; - private int[] mTempLocation = new int[2]; - private int[] mTempChildLocation = new int[2]; - private View mNotificationParent; private boolean mTrackingSettings; - private float mExpandedHeight = -1; + private int mNotificationTopPadding; + private boolean mAnimateNextTopPaddingChange; public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -67,7 +68,26 @@ public class NotificationPanelView extends PanelView { mKeyguardStatusView = findViewById(R.id.keyguard_status_view); mNotificationStackScroller = (NotificationStackScrollLayout) findViewById(R.id.notification_stack_scroller); - mNotificationParent = findViewById(R.id.notification_container_parent); + mNotificationStackScroller.setOnHeightChangedListener(this); + mNotificationTopPadding = getResources().getDimensionPixelSize( + R.dimen.notifications_top_padding); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + int keyguardBottomMargin = + ((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin; + mNotificationStackScroller.setTopPadding(mStatusBar.getBarState() == StatusBarState.KEYGUARD + ? mKeyguardStatusView.getBottom() + keyguardBottomMargin + : mHeader.getBottom() + mNotificationTopPadding, + mAnimateNextTopPaddingChange); + mAnimateNextTopPaddingChange = false; + } + + public void animateNextTopPaddingChange() { + mAnimateNextTopPaddingChange = true; + requestLayout(); } @Override @@ -92,30 +112,22 @@ public class NotificationPanelView extends PanelView { return super.dispatchPopulateAccessibilityEvent(event); } - /** - * Gets the relative position of a view on the screen in regard to this view. - * - * @param requestedView the view we want to find the relative position for - * @return - */ - private int getRelativeTop(View requestedView) { - getLocationOnScreen(mTempLocation); - requestedView.getLocationOnScreen(mTempChildLocation); - return mTempChildLocation[1] - mTempLocation[1]; - } - @Override public boolean onInterceptTouchEvent(MotionEvent event) { // intercept for quick settings if (event.getAction() == MotionEvent.ACTION_DOWN) { - final View target = mStatusBar.isOnKeyguard() ? mKeyguardStatusView : mHeader; + final View target = mStatusBar.getBarState() == StatusBarState.KEYGUARD + ? mKeyguardStatusView + : mHeader; final boolean inTarget = PhoneStatusBar.inBounds(target, event, true); if (inTarget && !isInSettings()) { mTrackingSettings = true; + requestDisallowInterceptTouchEvent(true); return true; } if (!inTarget && isInSettings()) { mTrackingSettings = true; + requestDisallowInterceptTouchEvent(true); return true; } } @@ -164,42 +176,7 @@ public class NotificationPanelView extends PanelView { @Override protected void onHeightUpdated(float expandedHeight) { - updateNotificationStackHeight(expandedHeight); - } - - /** - * Update the height of the {@link #mNotificationStackScroller} to the new expanded height. - * This is much more efficient than doing it over the layout pass. - * - * @param expandedHeight the new expanded height - */ - private void updateNotificationStackHeight(float expandedHeight) { - if (mExpandedHeight == expandedHeight) return; - mExpandedHeight = expandedHeight; - mNotificationStackScroller.setIsExpanded(expandedHeight > 0.0f); - float childOffset = getRelativeTop(mNotificationStackScroller) - - mNotificationParent.getTranslationY(); - int newStackHeight = (int) (expandedHeight - childOffset); - int itemHeight = mNotificationStackScroller.getItemHeight(); - int bottomStackPeekSize = mNotificationStackScroller.getBottomStackPeekSize(); - int minStackHeight = itemHeight + bottomStackPeekSize; - if (newStackHeight >= minStackHeight) { - mNotificationParent.setTranslationY(0); - mNotificationStackScroller.setCurrentStackHeight(newStackHeight); - } else { - - // We did not reach the position yet where we actually start growing, - // so we translate the stack upwards. - int translationY = (newStackHeight - minStackHeight); - // A slight parallax effect is introduced in order for the stack to catch up with - // the top card. - float partiallyThere = (float) newStackHeight / minStackHeight; - partiallyThere = Math.max(0, partiallyThere); - translationY += (1 - partiallyThere) * bottomStackPeekSize; - mNotificationParent.setTranslationY(translationY); - mNotificationStackScroller.setCurrentStackHeight( - (int) (expandedHeight - (childOffset + translationY))); - } + mNotificationStackScroller.setStackHeight(expandedHeight); } @Override @@ -218,4 +195,9 @@ public class NotificationPanelView extends PanelView { super.onExpandingFinished(); mNotificationStackScroller.onExpansionStopped(); } + + @Override + public void onHeightChanged(ExpandableView view) { + requestPanelHeightUpdate(); + } } 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 e154b24..0db6914 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -96,6 +96,8 @@ import com.android.systemui.R; 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; @@ -103,6 +105,7 @@ import com.android.systemui.statusbar.NotificationData.Entry; 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; @@ -120,7 +123,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -public class PhoneStatusBar extends BaseStatusBar implements DemoMode { +public class PhoneStatusBar extends BaseStatusBar implements DemoMode, + DragDownHelper.OnDragDownListener { static final String TAG = "PhoneStatusBar"; public static final boolean DEBUG = BaseStatusBar.DEBUG; public static final boolean SPEW = false; @@ -233,6 +237,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { View mNotificationPanelHeader; View mKeyguardStatusView; View mKeyguardBottomArea; + boolean mLeaveOpenOnKeyguardHide; KeyguardIndicationTextView mKeyguardIndicationTextView; // TODO: Fetch phrase from search/hotword provider. @@ -380,7 +385,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { private boolean mSettingsStarted; private boolean mSettingsCancelled; private boolean mSettingsClosing; - private int mNotificationPadding; + private boolean mVisible; private final OnChildLocationsChangedListener mOnChildLocationsChangedListener = new OnChildLocationsChangedListener() { @@ -470,6 +475,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } }; + 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); @@ -619,6 +631,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); mKeyguardIconOverflowContainer.setOnActivatedListener(this); mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text); + // TODO: Comment in when transition is ready. + //mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener); mStackScroller.addView(mKeyguardIconOverflowContainer); mExpandedContents = mStackScroller; @@ -720,8 +734,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } // 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) @@ -786,7 +798,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } 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 FlipperButton flipper = mState == StatusBarState.KEYGUARD + ? mKeyguardFlipper + : mHeaderFlipper; final boolean inButton = flipper.inHolderBounds(event); final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop; if (!qsTap && !inButton) { @@ -1194,7 +1208,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0 - && !mNotificationPanel.isTracking() && !mOnKeyguard) { + && !mNotificationPanel.isTracking() && mState != StatusBarState.KEYGUARD) { animateCollapsePanels(); } } @@ -1348,7 +1362,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { && mStackScroller.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight) && mStackScroller.getVisibility() == View.VISIBLE - && !mOnKeyguard; + && mState != StatusBarState.KEYGUARD; if (force || mCarrierLabelVisible != makeVisible) { mCarrierLabelVisible = makeVisible; @@ -2099,7 +2113,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { 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; } @@ -2560,12 +2574,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { 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(); @@ -2739,22 +2755,40 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { @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()) { @@ -2939,28 +2973,38 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } } - 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 (mState == StatusBarState.KEYGUARD) { if (isFlippedToSettings()) { flipToNotifications(false /*animate*/); } @@ -2992,17 +3036,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } 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(); @@ -3011,7 +3055,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } private void showBouncer() { - if (mOnKeyguard) { + if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { mStatusBarKeyguardViewManager.dismiss(); } } @@ -3047,6 +3091,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { super.onActivated(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); @@ -3054,13 +3106,13 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } 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); } } @@ -3074,6 +3126,67 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { return mNavigationBarView; } + // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------ + + @Override + public void onDraggedDown(View startingChild) { + goToLockedShade(startingChild); + } + + @Override + public void onReset() { + 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.setDimmed(true /* dimmed */, true /* fade */); + } + } + if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) { + mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, true /* fade */); + } + } + + public void onThresholdReached() { + 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.setDimmed(false /* dimmed */, true /* fade */); + } + } + if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) { + mKeyguardIconOverflowContainer.setDimmed(false /* dimmed */, true /* fade */); + } + } + + /** + * 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 */ 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..10c1625 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 @@ package com.android.systemui.statusbar.phone; 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 android.view.accessibility.AccessibilityEvent; 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 @@ public class PhoneStatusBarView extends PanelBar { 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; 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 db244fe..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 @@ package com.android.systemui.statusbar.phone; 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 @@ public class StatusBarKeyguardViewManager { mShowing = true; mStatusBarWindowManager.setKeyguardShowing(true); showBouncerOrKeyguard(); - updateBackButtonState(); + updateStates(); } /** @@ -102,9 +94,9 @@ public class StatusBarKeyguardViewManager { } } - public void showBouncer() { + private void showBouncer() { mBouncer.show(); - updateBackButtonState(); + updateStates(); } /** @@ -112,7 +104,7 @@ public class StatusBarKeyguardViewManager { */ public void reset() { showBouncerOrKeyguard(); - updateBackButtonState(); + updateStates(); } public void onScreenTurnedOff() { @@ -155,7 +147,7 @@ public class StatusBarKeyguardViewManager { public void setOccluded(boolean occluded) { mOccluded = occluded; mStatusBarWindowManager.setKeyguardOccluded(occluded); - updateBackButtonState(); + updateStates(); } /** @@ -167,7 +159,7 @@ public class StatusBarKeyguardViewManager { mStatusBarWindowManager.setKeyguardShowing(false); mBouncer.hide(); mViewMediatorCallback.keyguardGone(); - updateBackButtonState(); + updateStates(); } /** @@ -199,13 +191,13 @@ public class StatusBarKeyguardViewManager { 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) { @@ -220,6 +212,7 @@ public class StatusBarKeyguardViewManager { 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.ViewGroup; 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 @@ public class StatusBarWindowManager { } 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 @@ public class StatusBarWindowManager { } 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 @@ public class StatusBarWindowManager { 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 @@ public class StatusBarWindowManager { 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..acc3a0b 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 android.widget.FrameLayout; 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; @@ -75,6 +76,7 @@ public class StatusBarWindowView extends FrameLayout 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 +108,13 @@ public class StatusBarWindowView extends FrameLayout boolean intercept = false; if (mNotificationPanel.isFullyExpanded() && mStackScrollLayout.getVisibility() == View.VISIBLE - && !mService.isOnKeyguard()) { + && mService.getBarState() != StatusBarState.KEYGUARD) { 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 +131,11 @@ public class StatusBarWindowView extends FrameLayout @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/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 @@ public class ZenModeView extends RelativeLayout { @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 a5e016a..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 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { 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 } @@ -92,12 +92,13 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { mExitIndex = 0; dispatchChanged(); } + setZenModeCondition(); } @Override public void dispose() { try { - mNoMan.requestZenModeConditions(mListener, false /*requested*/); + mNoMan.requestZenModeConditions(mListener, 0 /*none*/); } catch (RemoteException e) { // noop } @@ -143,7 +144,15 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { } mExitIndex = i; dispatchChanged(); - final Uri conditionUri = (Uri) ec.tag; + setZenModeCondition(); + } + + private void setZenModeCondition() { + if (mExitIndex < 0 || mExitIndex >= mExits.size()) { + Log.w(TAG, "setZenModeCondition to bad index " + mExitIndex + " of " + mExits.size()); + return; + } + final Uri conditionUri = (Uri) mExits.get(mExitIndex).tag; try { mNoMan.setZenModeCondition(conditionUri); } catch (RemoteException e) { @@ -213,7 +222,7 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { 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..72e22e9 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.Gefingerpoken; 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 @@ public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper. // 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; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java deleted file mode 100644 index 266cecf..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.policy; - -import android.animation.LayoutTransition; -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -import com.android.systemui.ExpandHelper; -import com.android.systemui.R; -import com.android.systemui.SwipeHelper; -import com.android.systemui.statusbar.ExpandableNotificationRow; - -import java.util.HashMap; - -public class NotificationRowLayout - extends LinearLayout - implements SwipeHelper.Callback, ExpandHelper.Callback -{ - private static final String TAG = "NotificationRowLayout"; - private static final boolean DEBUG = false; - private static final boolean SLOW_ANIMATIONS = DEBUG; - - private static final int APPEAR_ANIM_LEN = SLOW_ANIMATIONS ? 5000 : 250; - private static final int DISAPPEAR_ANIM_LEN = APPEAR_ANIM_LEN; - - boolean mAnimateBounds = true; - - Rect mTmpRect = new Rect(); - - HashMap<View, ValueAnimator> mAppearingViews = new HashMap<View, ValueAnimator>(); - HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>(); - - private SwipeHelper mSwipeHelper; - - private OnSizeChangedListener mOnSizeChangedListener; - - // Flag set during notification removal animation to avoid causing too much work until - // animation is done - boolean mRemoveViews = true; - - private LayoutTransition mRealLayoutTransition; - - public NotificationRowLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public NotificationRowLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mRealLayoutTransition = new LayoutTransition(); - mRealLayoutTransition.setAnimateParentHierarchy(true); - setLayoutTransitionsEnabled(true); - - setOrientation(LinearLayout.VERTICAL); - - if (DEBUG) { - setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() { - @Override - public void onChildViewAdded(View parent, View child) { - Log.d(TAG, "view added: " + child + "; new count: " + getChildCount()); - } - @Override - public void onChildViewRemoved(View parent, View child) { - Log.d(TAG, "view removed: " + child + "; new count: " + (getChildCount() - 1)); - } - }); - - setBackgroundColor(0x80FF8000); - } - - float densityScale = getResources().getDisplayMetrics().density; - float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); - mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); - } - - public void setLongPressListener(View.OnLongClickListener listener) { - mSwipeHelper.setLongPressListener(listener); - } - - public void setOnSizeChangedListener(OnSizeChangedListener l) { - mOnSizeChangedListener = l; - } - - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - super.onWindowFocusChanged(hasWindowFocus); - if (!hasWindowFocus) { - mSwipeHelper.removeLongPressCallback(); - } - } - - public void setAnimateBounds(boolean anim) { - mAnimateBounds = anim; - } - - private void logLayoutTransition() { - Log.v(TAG, "layout " + - (mRealLayoutTransition.isChangingLayout() ? "is " : "is not ") + - "in transition and animations " + - (mRealLayoutTransition.isRunning() ? "are " : "are not ") + - "running."); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()"); - if (DEBUG) logLayoutTransition(); - - return mSwipeHelper.onInterceptTouchEvent(ev) || - super.onInterceptTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (DEBUG) Log.v(TAG, "onTouchEvent()"); - if (DEBUG) logLayoutTransition(); - - return mSwipeHelper.onTouchEvent(ev) || - super.onTouchEvent(ev); - } - - public boolean canChildBeDismissed(View v) { - final View veto = v.findViewById(R.id.veto); - return (veto != null && veto.getVisibility() != View.GONE); - } - - public boolean canChildBeExpanded(View v) { - return v instanceof ExpandableNotificationRow - && ((ExpandableNotificationRow) v).isExpandable(); - } - - public void setUserExpandedChild(View v, boolean userExpanded) { - if (v instanceof ExpandableNotificationRow) { - ((ExpandableNotificationRow) v).setUserExpanded(userExpanded); - } - } - - public void setUserLockedChild(View v, boolean userLocked) { - if (v instanceof ExpandableNotificationRow) { - ((ExpandableNotificationRow) v).setUserLocked(userLocked); - } - } - - public void onChildDismissed(View v) { - if (DEBUG) Log.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews); - final View veto = v.findViewById(R.id.veto); - if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) { - veto.performClick(); - } - } - - public void onBeginDrag(View v) { - // We need to prevent the surrounding ScrollView from intercepting us now; - // the scroll position will be locked while we swipe - requestDisallowInterceptTouchEvent(true); - } - - public void onDragCancelled(View v) { - } - - public View getChildAtPosition(MotionEvent ev) { - return getChildAtPosition(ev.getX(), ev.getY()); - } - - public View getChildAtRawPosition(float touchX, float touchY) { - int[] location = new int[2]; - getLocationOnScreen(location); - return getChildAtPosition((float) (touchX - location[0]), (float) (touchY - location[1])); - } - - public View getChildAtPosition(float touchX, float touchY) { - // find the view under the pointer, accounting for GONE views - final int count = getChildCount(); - int y = 0; - int childIdx = 0; - View slidingChild; - for (; childIdx < count; childIdx++) { - slidingChild = getChildAt(childIdx); - if (slidingChild.getVisibility() == GONE) { - continue; - } - y += slidingChild.getMeasuredHeight(); - if (touchY < y) return slidingChild; - } - return null; - } - - public View getChildContentView(View v) { - return v; - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - float densityScale = getResources().getDisplayMetrics().density; - mSwipeHelper.setDensityScale(densityScale); - float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); - mSwipeHelper.setPagingTouchSlop(pagingTouchSlop); - } - - - /** - * Sets a flag to tell us whether to actually remove views. Removal is delayed by setting this - * to false during some animations to smooth out performance. Callers should restore the - * flag to true after the animation is done, and then they should make sure that the views - * get removed properly. - */ - public void setViewRemoval(boolean removeViews) { - if (DEBUG) Log.v(TAG, "setViewRemoval: " + removeViews); - mRemoveViews = removeViews; - } - - // Suppress layout transitions for a little while. - public void setLayoutTransitionsEnabled(boolean b) { - if (b) { - setLayoutTransition(mRealLayoutTransition); - } else { - if (mRealLayoutTransition.isRunning()) { - mRealLayoutTransition.cancel(); - } - setLayoutTransition(null); - } - } - - public void dismissRowAnimated(View child) { - dismissRowAnimated(child, 0); - } - - public void dismissRowAnimated(View child, int vel) { - mSwipeHelper.dismissChild(child, vel); - } - - @Override - public void onFinishInflate() { - super.onFinishInflate(); - if (DEBUG) setWillNotDraw(false); - } - - @Override - public void onDraw(android.graphics.Canvas c) { - super.onDraw(c); - if (DEBUG) logLayoutTransition(); - if (DEBUG) { - //Log.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: " - // + getMeasuredHeight() + "px"); - c.save(); - c.clipRect(6, 6, c.getWidth() - 6, getMeasuredHeight() - 6, - android.graphics.Region.Op.DIFFERENCE); - c.drawColor(0xFFFF8000); - c.restore(); - } - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - if (mOnSizeChangedListener != null) { - mOnSizeChangedListener.onSizeChanged(this, w, h, oldw, oldh); - } - } -} 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 948ef90..e4e5fb1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -31,20 +31,25 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.view.animation.AnimationUtils; import android.widget.OverScroller; import com.android.systemui.ExpandHelper; import com.android.systemui.R; import com.android.systemui.SwipeHelper; import com.android.systemui.statusbar.ExpandableNotificationRow; +import com.android.systemui.statusbar.ExpandableView; import com.android.systemui.statusbar.stack.StackScrollState.ViewState; import com.android.systemui.statusbar.policy.ScrollAdapter; +import java.util.ArrayList; + /** * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack. */ public class NotificationStackScrollLayout extends ViewGroup - implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter { + implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter, + ExpandableView.OnHeightChangedListener { private static final String TAG = "NotificationStackScrollLayout"; private static final boolean DEBUG = false; @@ -78,6 +83,8 @@ public class NotificationStackScrollLayout extends ViewGroup private int mBottomStackPeekSize; private int mEmptyMarginBottom; private int mPaddingBetweenElements; + private int mTopPadding; + private boolean mListenForHeightChanges = true; /** * The algorithm which calculates the properties for our children @@ -87,9 +94,30 @@ public class NotificationStackScrollLayout extends ViewGroup /** * The current State this Layout is in */ - private final StackScrollState mCurrentStackScrollState = new StackScrollState(this); + private StackScrollState mCurrentStackScrollState = new StackScrollState(this); + private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>(); + private ArrayList<View> mChildrenToRemoveAnimated = 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 mNeedsAnimation; + private boolean mTopPaddingNeedsAnimation; + private boolean mIsExpanded = true; + private boolean mChildrenUpdateRequested; + private ViewTreeObserver.OnPreDrawListener mChildrenUpdater + = new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + updateChildren(); + mChildrenUpdateRequested = false; + getViewTreeObserver().removeOnPreDrawListener(this); + return true; + } + }; public NotificationStackScrollLayout(Context context) { this(context, null); @@ -132,6 +160,7 @@ public class NotificationStackScrollLayout extends ViewGroup mScroller = new OverScroller(getContext()); setFocusable(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + setClipChildren(false); final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = configuration.getScaledTouchSlop(); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); @@ -180,16 +209,8 @@ public class NotificationStackScrollLayout extends ViewGroup } setMaxLayoutHeight(getHeight() - mEmptyMarginBottom); updateContentHeight(); - getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - updateScrollPositionIfNecessary(); - updateChildren(); - getViewTreeObserver().removeOnPreDrawListener(this); - return true; - } - }); - + updateScrollPositionIfNecessary(); + requestChildrenUpdate(); } public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) { @@ -212,11 +233,31 @@ public class NotificationStackScrollLayout extends ViewGroup private void setMaxLayoutHeight(int maxLayoutHeight) { mMaxLayoutHeight = maxLayoutHeight; - updateAlgorithmHeight(); + updateAlgorithmHeightAndPadding(); } - private void updateAlgorithmHeight() { + private void updateAlgorithmHeightAndPadding() { mStackScrollAlgorithm.setLayoutHeight(getLayoutHeight()); + mStackScrollAlgorithm.setTopPadding(mTopPadding); + } + + /** + * @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; } /** @@ -224,20 +265,25 @@ public class NotificationStackScrollLayout extends ViewGroup * modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout. */ private void updateChildren() { - if (!isCurrentlyAnimating()) { - mCurrentStackScrollState.setScrollY(mOwnScrollY); - mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState); - mCurrentStackScrollState.apply(); - if (mListener != null) { - mListener.onChildLocationsChanged(this); - } + mCurrentStackScrollState.setScrollY(mOwnScrollY); + mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState); + if (!isCurrentlyAnimating() && !mNeedsAnimation) { + applyCurrentState(); } else { - // TODO: handle animation + startAnimationToState(); + } + } + + private void requestChildrenUpdate() { + if (!mChildrenUpdateRequested) { + getViewTreeObserver().addOnPreDrawListener(mChildrenUpdater); + mChildrenUpdateRequested = true; + invalidate(); } } private boolean isCurrentlyAnimating() { - return false; + return mStateAnimator.isRunning(); } private void updateScrollPositionIfNecessary() { @@ -247,10 +293,59 @@ public class NotificationStackScrollLayout extends ViewGroup } } - public void setCurrentStackHeight(int currentStackHeight) { - this.mCurrentStackHeight = currentStackHeight; - updateAlgorithmHeight(); - updateChildren(); + public int getTopPadding() { + return mTopPadding; + } + + public void setTopPadding(int topPadding, boolean animate) { + if (mTopPadding != topPadding) { + mTopPadding = topPadding; + updateAlgorithmHeightAndPadding(); + updateContentHeight(); + if (animate) { + mTopPaddingNeedsAnimation = true; + mNeedsAnimation = true; + } + requestChildrenUpdate(); + if (mOnHeightChangedListener != null) { + mOnHeightChangedListener.onHeightChanged(null); + } + } + } + + /** + * Update the height of the stack to a new height. + * + * @param height the new height of the stack + */ + public void setStackHeight(float height) { + setIsExpanded(height > 0.0f); + int newStackHeight = (int) height; + int itemHeight = getItemHeight(); + int bottomStackPeekSize = mBottomStackPeekSize; + int minStackHeight = itemHeight + bottomStackPeekSize; + int stackHeight; + if (newStackHeight - mTopPadding >= minStackHeight) { + setTranslationY(0); + stackHeight = newStackHeight; + } else { + + // We did not reach the position yet where we actually start growing, + // so we translate the stack upwards. + int translationY = (newStackHeight - minStackHeight); + // A slight parallax effect is introduced in order for the stack to catch up with + // the top card. + float partiallyThere = (float) (newStackHeight - mTopPadding) / minStackHeight; + partiallyThere = Math.max(0, partiallyThere); + translationY += (1 - partiallyThere) * bottomStackPeekSize; + setTranslationY(translationY - mTopPadding); + stackHeight = (int) (height - (translationY - mTopPadding)); + } + if (stackHeight != mCurrentStackHeight) { + mCurrentStackHeight = stackHeight; + updateAlgorithmHeightAndPadding(); + requestChildrenUpdate(); + } } /** @@ -282,6 +377,7 @@ public class NotificationStackScrollLayout extends ViewGroup veto.performClick(); } setSwipingInProgress(false); + mSwipedOutViews.add(v); } public void onBeginDrag(View v) { @@ -296,22 +392,22 @@ public class NotificationStackScrollLayout extends ViewGroup 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++) { - View slidingChild = getChildAt(childIdx); + ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx); if (slidingChild.getVisibility() == GONE) { continue; } float top = slidingChild.getTranslationY(); - float bottom = top + slidingChild.getHeight(); + float bottom = top + slidingChild.getActualHeight(); int left = slidingChild.getLeft(); int right = slidingChild.getRight(); @@ -582,19 +678,13 @@ public class NotificationStackScrollLayout extends ViewGroup } } - 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; @@ -615,18 +705,19 @@ public class NotificationStackScrollLayout extends ViewGroup private int getScrollRange() { int scrollRange = 0; - View firstChild = getFirstChildNotGone(); + ExpandableView firstChild = (ExpandableView) getFirstChildNotGone(); if (firstChild != null) { int contentHeight = getContentHeight(); int firstChildMaxExpandHeight = getMaxExpandHeight(firstChild); - int firstChildExpandPotential = firstChildMaxExpandHeight - firstChild.getHeight(); - // If we already scrolled in, the first child is layouted smaller than it actually - // could be when expanded. We have to compensate for this loss of the contentHeight - // by adding the expand potential again. - contentHeight += firstChildExpandPotential; 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); @@ -649,10 +740,24 @@ public class NotificationStackScrollLayout extends ViewGroup 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(); } @@ -666,13 +771,20 @@ public class NotificationStackScrollLayout extends ViewGroup for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child.getVisibility() != View.GONE) { - height += child.getHeight(); - if (i < getChildCount()-1) { + if (height != 0) { + // add the padding before this element height += mPaddingBetweenElements; } + if (child instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) child; + height += row.getIntrinsicHeight(); + } else if (child instanceof ExpandableView) { + ExpandableView expandableView = (ExpandableView) child; + height += expandableView.getActualHeight(); + } } } - mContentHeight = height; + mContentHeight = height + mTopPadding; } /** @@ -723,14 +835,135 @@ public class NotificationStackScrollLayout extends ViewGroup @Override protected void onViewRemoved(View child) { super.onViewRemoved(child); + ((ExpandableView) child).setOnHeightChangedListener(null); mCurrentStackScrollState.removeViewStateForView(child); mStackScrollAlgorithm.notifyChildrenChanged(this); + updateScrollStateForRemovedChild(child); + if (mIsExpanded) { + + if (!mChildrenToAddAnimated.contains(child)) { + // Generate Animations + mChildrenToRemoveAnimated.add(child); + mNeedsAnimation = true; + } else { + mChildrenToAddAnimated.remove(child); + } + } + } + + /** + * Updates the scroll position when a child was removed + * + * @param removedChild the removed child + */ + private void updateScrollStateForRemovedChild(View removedChild) { + int startingPosition = getPositionInLinearLayout(removedChild); + int childHeight = removedChild.getHeight() + mPaddingBetweenElements; + int endPosition = startingPosition + childHeight; + if (endPosition <= mOwnScrollY) { + // This child is fully scrolled of the top, so we have to deduct its height from the + // scrollPosition + mOwnScrollY -= childHeight; + } else if (startingPosition < mOwnScrollY) { + // This child is currently being scrolled into, set the scroll position to the start of + // this child + mOwnScrollY = startingPosition; + } + } + + private int getPositionInLinearLayout(View requestedChild) { + int position = 0; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child == requestedChild) { + return position; + } + if (child.getVisibility() != View.GONE) { + position += child.getHeight(); + if (i < getChildCount()-1) { + position += mPaddingBetweenElements; + } + } + } + return 0; } @Override protected void onViewAdded(View child) { super.onViewAdded(child); mStackScrollAlgorithm.notifyChildrenChanged(this); + ((ExpandableView) child).setOnHeightChangedListener(this); + if (child.getVisibility() != View.GONE) { + generateAddAnimation(child); + } + } + + public void generateAddAnimation(View child) { + if (mIsExpanded) { + + // Generate Animations + mChildrenToAddAnimated.add(child); + mNeedsAnimation = true; + } + } + + /** + * Change the position of child to a new location + * + * @param child the view to change the position for + * @param newIndex the new index + */ + public void changeViewPosition(View child, int newIndex) { + if (child != null && child.getParent() == this) { + // TODO: handle this + } + } + + private void startAnimationToState() { + if (mNeedsAnimation) { + generateChildHierarchyEvents(); + mNeedsAnimation = false; + } + if (!mAnimationEvents.isEmpty()) { + mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState); + } else { + applyCurrentState(); + } + } + + private void generateChildHierarchyEvents() { + generateChildAdditionEvents(); + generateChildRemovalEvents(); + generateTopPaddingEvent(); + mNeedsAnimation = false; + } + + private void generateChildRemovalEvents() { + for (View child : mChildrenToRemoveAnimated) { + boolean childWasSwipedOut = mSwipedOutViews.contains(child); + int animationType = childWasSwipedOut + ? 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 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 boolean onInterceptTouchEventScroll(MotionEvent ev) { @@ -873,7 +1106,11 @@ public class NotificationStackScrollLayout extends ViewGroup } 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() { @@ -884,17 +1121,68 @@ public class NotificationStackScrollLayout extends ViewGroup mStackScrollAlgorithm.onExpansionStopped(); } - public void setIsExpanded(boolean isExpanded) { + private void setIsExpanded(boolean isExpanded) { + mIsExpanded = isExpanded; mStackScrollAlgorithm.setIsExpanded(isExpanded); if (!isExpanded) { mOwnScrollY = 0; } } + @Override + public void onHeightChanged(ExpandableView view) { + if (mListenForHeightChanges && !isCurrentlyAnimating()) { + updateContentHeight(); + updateScrollPositionIfNecessary(); + if (mOnHeightChangedListener != null) { + mOnHeightChangedListener.onHeightChanged(view); + } + requestChildrenUpdate(); + } + } + + public void setOnHeightChangedListener( + ExpandableView.OnHeightChangedListener mOnHeightChangedListener) { + this.mOnHeightChangedListener = mOnHeightChangedListener; + } + + public void onChildAnimationFinished() { + requestChildrenUpdate(); + mAnimationEvents.clear(); + } + + private void applyCurrentState() { + mListenForHeightChanges = false; + mCurrentStackScrollState.apply(); + mListenForHeightChanges = true; + if (mListener != null) { + mListener.onChildLocationsChanged(this); + } + } + /** * A listener that is notified when some child locations might have changed. */ public interface OnChildLocationsChangedListener { public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout); } + + static class AnimationEvent { + + static int ANIMATION_TYPE_ADD = 1; + static int ANIMATION_TYPE_REMOVE = 2; + static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 3; + static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 4; + + final long eventStartTime; + final View changingView; + final int animationType; + + AnimationEvent(View view, int type) { + eventStartTime = AnimationUtils.currentAnimationTimeMillis(); + changingView = view; + animationType = type; + } + } + } 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 2a6e4ae..09d8d50 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -23,6 +23,7 @@ import android.view.ViewGroup; import com.android.systemui.R; import com.android.systemui.statusbar.ExpandableNotificationRow; +import com.android.systemui.statusbar.ExpandableView; import java.util.ArrayList; @@ -49,11 +50,15 @@ public class StackScrollAlgorithm { private StackIndentationFunctor mBottomStackIndentationFunctor; private int mLayoutHeight; + + /** mLayoutHeight - mTopPadding */ + private int mInnerHeight; + private int mTopPadding; private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState(); private boolean mIsExpansionChanging; private int mFirstChildMaxHeight; private boolean mIsExpanded; - private View mFirstChildWhileExpanding; + private ExpandableView mFirstChildWhileExpanding; private boolean mExpandedOnStart; private int mTopStackTotalSize; @@ -82,7 +87,7 @@ public class StackScrollAlgorithm { mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor( MAX_ITEMS_IN_BOTTOM_STACK, mBottomStackPeekSize, - mCollapsedSize + mPaddingBetweenElements + mBottomStackPeekSize, + mCollapsedSize + mBottomStackPeekSize + mPaddingBetweenElements, 0.5f); } @@ -101,11 +106,10 @@ public class StackScrollAlgorithm { algorithmState.scrolledPixelsTop = 0; algorithmState.itemsInBottomStack = 0.0f; algorithmState.partialInBottom = 0.0f; + algorithmState.scrollY = resultState.getScrollY() + mCollapsedSize; updateVisibleChildren(resultState, algorithmState); - algorithmState.scrollY = getAlgorithmScrollPosition(resultState, algorithmState); - // Phase 1: findNumberOfItemsInTopStackAndUpdateState(resultState, algorithmState); @@ -117,42 +121,6 @@ public class StackScrollAlgorithm { } /** - * Calculates the scroll offset of the algorithm, based on the resultState. - * - * @param resultState the state to base the calculation on - * @param algorithmState The state in which the current pass of the algorithm is currently in - * @return the scroll offset used for the algorithm - */ - private int getAlgorithmScrollPosition(StackScrollState resultState, - StackScrollAlgorithmState algorithmState) { - - int resultScroll = resultState.getScrollY() + mCollapsedSize; - - // If the first child was collapsed in an earlier pass, we have to decrease the scroll - // position to get into the same state again. - if (algorithmState.visibleChildren.size() > 0) { - View firstView = algorithmState.visibleChildren.get(0); - if (firstView instanceof ExpandableNotificationRow) { - ExpandableNotificationRow firstRow = (ExpandableNotificationRow) firstView; - if (firstRow.isUserLocked()) { - // User is currently modifying this height. - return resultScroll; - } - int scrolledInAmount = 0; - // If the child size was not decreased due to scrolling, we don't substract it, - if (!mIsExpansionChanging) { - scrolledInAmount = firstRow.getExpandPotential(); - } else if (mExpandedOnStart && mFirstChildWhileExpanding == firstView) { - scrolledInAmount = firstRow.getMaximumAllowedExpandHeight() - - mFirstChildMaxHeight; - } - resultScroll -= scrolledInAmount; - } - } - return resultScroll; - } - - /** * Update the visible children on the state. */ private void updateVisibleChildren(StackScrollState resultState, @@ -162,7 +130,7 @@ public class StackScrollAlgorithm { state.visibleChildren.clear(); state.visibleChildren.ensureCapacity(childCount); for (int i = 0; i < childCount; i++) { - View v = hostView.getChildAt(i); + ExpandableView v = (ExpandableView) hostView.getChildAt(i); if (v.getVisibility() != View.GONE) { state.visibleChildren.add(v); } @@ -180,7 +148,7 @@ public class StackScrollAlgorithm { StackScrollAlgorithmState algorithmState) { // The starting position of the bottom stack peek - float bottomPeekStart = mLayoutHeight - mBottomStackPeekSize; + float bottomPeekStart = mInnerHeight - mBottomStackPeekSize; // The position where the bottom stack starts. float bottomStackStart = bottomPeekStart - mCollapsedSize; @@ -194,10 +162,10 @@ public class StackScrollAlgorithm { int childCount = algorithmState.visibleChildren.size(); int numberOfElementsCompletelyIn = (int) algorithmState.itemsInTopStack; for (int i = 0; i < childCount; i++) { - View child = algorithmState.visibleChildren.get(i); + ExpandableView child = algorithmState.visibleChildren.get(i); StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN; - int childHeight = child.getHeight(); + int childHeight = getMaxAllowedChildHeight(child); float yPositionInScrollViewAfterElement = yPositionInScrollView + childHeight + mPaddingBetweenElements; @@ -224,7 +192,7 @@ public class StackScrollAlgorithm { 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; @@ -262,6 +230,8 @@ public class StackScrollAlgorithm { } currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements; yPositionInScrollView = yPositionInScrollViewAfterElement; + + childViewState.yTranslation += mTopPadding; } } @@ -286,12 +256,12 @@ public class StackScrollAlgorithm { private void clampPositionToBottomStackStart(StackScrollState.ViewState childViewState, int childHeight) { childViewState.yTranslation = Math.min(childViewState.yTranslation, - mLayoutHeight - mBottomStackPeekSize - childHeight); + mInnerHeight - mBottomStackPeekSize - childHeight); } /** * Clamp the yTranslation of the child up such that its end is at lest on the end of the top - * stack. + * stack.get * * @param childViewState the view state of the child * @param childHeight the height of this child @@ -305,9 +275,12 @@ public class StackScrollAlgorithm { 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(); } - return child.getHeight(); + return child == null? mCollapsedSize : child.getHeight(); } private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState, @@ -351,7 +324,7 @@ public class StackScrollAlgorithm { childViewState.alpha = 1.0f - algorithmState.partialInBottom; } childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_HIDDEN; - currentYPosition = mLayoutHeight; + currentYPosition = mInnerHeight; } childViewState.yTranslation = currentYPosition - childHeight; clampPositionToTopStackEnd(childViewState, childHeight); @@ -419,9 +392,9 @@ public class StackScrollAlgorithm { // find the number of elements in the top stack. for (int i = 0; i < childCount; i++) { - View child = algorithmState.visibleChildren.get(i); + ExpandableView child = algorithmState.visibleChildren.get(i); StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); - int childHeight = child.getHeight(); + int childHeight = getMaxAllowedChildHeight(child); float yPositionInScrollViewAfterElement = yPositionInScrollView + childHeight + mPaddingBetweenElements; @@ -429,7 +402,7 @@ public class StackScrollAlgorithm { if (i == 0 && algorithmState.scrollY == mCollapsedSize) { // The starting position of the bottom stack peek - int bottomPeekStart = mLayoutHeight - mBottomStackPeekSize; + int bottomPeekStart = mInnerHeight - mBottomStackPeekSize; // Collapse and expand the first child while the shade is being expanded float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding ? mFirstChildMaxHeight @@ -508,12 +481,18 @@ public class StackScrollAlgorithm { } } - public int getLayoutHeight() { - return mLayoutHeight; - } - public void setLayoutHeight(int layoutHeight) { this.mLayoutHeight = layoutHeight; + updateInnerHeight(); + } + + public void setTopPadding(int topPadding) { + mTopPadding = topPadding; + updateInnerHeight(); + } + + private void updateInnerHeight() { + mInnerHeight = mLayoutHeight - mTopPadding; } public void onExpansionStarted(StackScrollState currentState) { @@ -524,13 +503,13 @@ public class StackScrollAlgorithm { } private void updateFirstChildHeightWhileExpanding(ViewGroup hostView) { - mFirstChildWhileExpanding = findFirstVisibleChild(hostView); + mFirstChildWhileExpanding = (ExpandableView) findFirstVisibleChild(hostView); if (mFirstChildWhileExpanding != null) { if (mExpandedOnStart) { // We are collapsing the shade, so the first child can get as most as high as the // current height. - mFirstChildMaxHeight = mFirstChildWhileExpanding.getHeight(); + mFirstChildMaxHeight = mFirstChildWhileExpanding.getActualHeight(); } else { // We are expanding the shade, expand it to its full height. @@ -627,7 +606,7 @@ public class StackScrollAlgorithm { /** * The children from the host view which are not gone. */ - public final ArrayList<View> visibleChildren = new ArrayList<View>(); + public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>(); } } 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 6e2e87e..26cef36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java @@ -22,7 +22,7 @@ import android.util.Log; import android.view.View; import android.view.ViewGroup; -import com.android.systemui.R; +import com.android.systemui.statusbar.ExpandableView; import java.util.HashMap; import java.util.Map; @@ -36,12 +36,11 @@ public class StackScrollState { private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild"; private final ViewGroup mHostView; - private Map<View, ViewState> mStateMap; + private Map<ExpandableView, ViewState> mStateMap; private int mScrollY; private final Rect mClipRect = new Rect(); private int mBackgroundRoundedRectCornerRadius; private final Outline mChildOutline = new Outline(); - private final int mChildDividerHeight; public int getScrollY() { return mScrollY; @@ -53,11 +52,9 @@ public class StackScrollState { public StackScrollState(ViewGroup hostView) { mHostView = hostView; - mStateMap = new HashMap<View, ViewState>(); + mStateMap = new HashMap<ExpandableView, ViewState>(); mBackgroundRoundedRectCornerRadius = hostView.getResources().getDimensionPixelSize( com.android.internal.R.dimen.notification_quantum_rounded_rect_radius); - mChildDividerHeight = hostView.getResources().getDimensionPixelSize(R.dimen - .notification_divider_height); } public ViewGroup getHostView() { @@ -67,20 +64,19 @@ public class StackScrollState { public void resetViewStates() { int numChildren = mHostView.getChildCount(); for (int i = 0; i < numChildren; i++) { - View child = mHostView.getChildAt(i); + ExpandableView child = (ExpandableView) mHostView.getChildAt(i); ViewState viewState = mStateMap.get(child); if (viewState == null) { viewState = new ViewState(); mStateMap.put(child, viewState); } // initialize with the default values of the view - viewState.height = child.getHeight(); - viewState.alpha = 1; + viewState.height = child.getIntrinsicHeight(); viewState.gone = child.getVisibility() == View.GONE; + viewState.alpha = 1; } } - public ViewState getViewStateForView(View requestedView) { return mStateMap.get(requestedView); } @@ -98,7 +94,7 @@ public class StackScrollState { float previousNotificationEnd = 0; float previousNotificationStart = 0; for (int i = 0; i < numChildren; i++) { - View child = mHostView.getChildAt(i); + ExpandableView child = (ExpandableView) mHostView.getChildAt(i); ViewState state = mStateMap.get(child); if (state == null) { Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " + @@ -109,7 +105,7 @@ public class StackScrollState { float alpha = child.getAlpha(); float yTranslation = child.getTranslationY(); float zTranslation = child.getTranslationZ(); - int height = child.getHeight(); + int height = child.getActualHeight(); float newAlpha = state.alpha; float newYTranslation = state.yTranslation; float newZTranslation = state.zTranslation; @@ -152,14 +148,14 @@ public class StackScrollState { // apply height if (height != newHeight) { - applyNewHeight(child, newHeight); + child.setActualHeight(newHeight); } // apply clipping and shadow float newNotificationEnd = newYTranslation + newHeight; - updateChildClippingAndShadow(child, newHeight, - newNotificationEnd - (previousNotificationEnd - mChildDividerHeight), - newHeight - (previousNotificationStart - newYTranslation)); + updateChildClippingAndBackground(child, newHeight, + newNotificationEnd - (previousNotificationEnd), + (int) (newHeight - (previousNotificationStart - newYTranslation))); previousNotificationStart = newYTranslation; previousNotificationEnd = newNotificationEnd; @@ -173,20 +169,21 @@ public class StackScrollState { * @param child the view to update * @param realHeight the currently applied height of the view * @param clipHeight the desired clip height, the rest of the view will be clipped from the top - * @param shadowHeight the desired height of the shadow, the shadow ends on the bottom + * @param backgroundHeight the desired background height. The shadows of the view will be + * based on this height and the content will be clipped from the top */ - private void updateChildClippingAndShadow(View child, int realHeight, float clipHeight, - float shadowHeight) { - if (realHeight > shadowHeight) { - updateChildOutline(child, realHeight, shadowHeight); - } else { - updateChildOutline(child, realHeight, realHeight); - } + private void updateChildClippingAndBackground(ExpandableView child, int realHeight, + float clipHeight, int backgroundHeight) { if (realHeight > clipHeight) { updateChildClip(child, realHeight, clipHeight); } else { child.setClipBounds(null); } + if (realHeight > backgroundHeight) { + child.setClipTopAmount(realHeight - backgroundHeight); + } else { + child.setClipTopAmount(0); + } } /** @@ -205,37 +202,6 @@ public class StackScrollState { child.setClipBounds(mClipRect); } - /** - * Updates the outline of a view - * - * @param child the view to update - * @param height the currently applied height of the view - * @param outlineHeight the desired height of the outline, the outline ends on the bottom - */ - private void updateChildOutline(View child, int height, - float outlineHeight) { - int shadowInset = (int) (height - outlineHeight); - getOutlineForSize(child.getLeft(), - child.getTop() + shadowInset, - child.getWidth(), - child.getHeight() - shadowInset, - mChildOutline); - child.setOutline(mChildOutline); - } - - private void getOutlineForSize(int leftInset, int topInset, int width, int height, - Outline result) { - result.setRoundRect(leftInset, topInset, leftInset + width, topInset + height, - mBackgroundRoundedRectCornerRadius); - } - - private void applyNewHeight(View child, int newHeight) { - ViewGroup.LayoutParams lp = child.getLayoutParams(); - lp.height = newHeight; - child.setLayoutParams(lp); - } - - public static class ViewState { // These are flags such that we can create masks for filtering. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java new file mode 100644 index 0000000..4dce288 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar.stack; + +import android.animation.ValueAnimator; +import android.view.View; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import com.android.systemui.statusbar.ExpandableView; + +import java.util.ArrayList; + +/** + * An stack state animator which handles animations to new StackScrollStates + */ +public class StackStateAnimator { + + private static final int ANIMATION_DURATION = 360; + + private final Interpolator mFastOutSlowInInterpolator; + public NotificationStackScrollLayout mHostLayout; + private boolean mAnimationIsRunning; + private ArrayList<NotificationStackScrollLayout.AnimationEvent> mHandledEvents = + new ArrayList<>(); + + public StackStateAnimator(NotificationStackScrollLayout hostLayout) { + mHostLayout = hostLayout; + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(), + android.R.interpolator.fast_out_slow_in); + } + + public boolean isRunning() { + return mAnimationIsRunning; + } + + public void startAnimationForEvents( + 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); + int childCount = mHostLayout.getChildCount(); + boolean isFirstAnimatingView = true; + 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); + + // 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) + .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); + } + } + }); + if (alpha != child.getAlpha()) { + child.animate().withLayer().alpha(alpha); + } + } + + 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(); + } + + /** + * Initialize the viewStates for the added children + * + * @param animationEvents the animation events who contain the added children + * @param finalState the final state to animate to + */ + private void initializeAddedViewStates( + ArrayList<NotificationStackScrollLayout.AnimationEvent> animationEvents, + StackScrollState finalState) { + for (NotificationStackScrollLayout.AnimationEvent event: animationEvents) { + View changingView = event.changingView; + if (event.animationType == NotificationStackScrollLayout.AnimationEvent + .ANIMATION_TYPE_ADD && !mHandledEvents.contains(event)) { + + // 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); + mHandledEvents.add(event); + } + } + } +} diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 0550dd4..50e2a2e 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -3573,14 +3573,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { }); 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 77e2462..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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Match current screen state. if (mPowerManager.isInteractive()) { - screenTurningOn(null); + wakingUp(null); } else { - screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER); + goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER); } } @@ -3859,12 +3860,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardDelegate.isShowingAndNotOccluded() : mKeyguardDelegate.isShowing())); - if (keyCode == KeyEvent.KEYCODE_POWER - || keyCode == KeyEvent.KEYCODE_SLEEP - || keyCode == KeyEvent.KEYCODE_WAKEUP) { - policyFlags |= WindowManagerPolicy.FLAG_WAKE; - } - if (DEBUG_INPUT) { Log.d(TAG, "interceptKeyTq keycode=" + keyCode + " interactive=" + interactive + " keyguardActive=" + keyguardActive @@ -3878,8 +3873,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Basic policy based on interactive state. int result; - boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE - | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; + boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 + || event.isWakeKey(); if (interactive || (isInjected && !isWakeKey)) { // When the screen is on or if the key is injected pass the key to the application. result = ACTION_PASS_TO_USER; @@ -4320,7 +4315,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public void screenTurnedOff(int why) { + public void goingToSleep(int why) { EventLog.writeEvent(70000, 0); synchronized (mLock) { mScreenOnEarly = false; @@ -4336,7 +4331,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public void screenTurningOn(final ScreenOnListener screenOnListener) { + public void wakingUp(final ScreenOnListener screenOnListener) { EventLog.writeEvent(70000, 1); if (false) { RuntimeException here = new RuntimeException("here"); @@ -4782,7 +4777,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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/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 @@ public class AppWidgetService extends SystemService implements WidgetBackupProvi // 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 @@ public class AppWidgetService extends SystemService implements WidgetBackupProvi // 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 @@ class BluetoothManagerService extends IBluetoothManager.Stub { 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/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 62deec2..d6ecb46 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -426,29 +426,33 @@ public class LocationManagerService extends ILocationManager.Stub { Slog.e(TAG, "no geocoder provider found"); } - // bind to fused provider - FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext); - FusedProxy fusedProxy = FusedProxy.createAndBind( - mContext, - mLocationHandler, - flpHardwareProvider.getLocationHardware(), - com.android.internal.R.bool.config_enableFusedLocationOverlay, - com.android.internal.R.string.config_fusedLocationProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames); - if(fusedProxy == null) { - Slog.e(TAG, "No FusedProvider found."); - } - - // bind to geofence provider - GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, - com.android.internal.R.bool.config_enableGeofenceOverlay, - com.android.internal.R.string.config_geofenceProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames, - mLocationHandler, - gpsProvider.getGpsGeofenceProxy(), - flpHardwareProvider.getGeofenceHardware()); - if (provider == null) { - Slog.e(TAG, "no geofence provider found"); + // bind to fused provider if supported + if (FlpHardwareProvider.isSupported()) { + FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext); + FusedProxy fusedProxy = FusedProxy.createAndBind( + mContext, + mLocationHandler, + flpHardwareProvider.getLocationHardware(), + com.android.internal.R.bool.config_enableFusedLocationOverlay, + com.android.internal.R.string.config_fusedLocationProviderPackageName, + com.android.internal.R.array.config_locationProviderPackageNames); + if(fusedProxy == null) { + Slog.e(TAG, "Unable to bind FusedProxy."); + } + + // bind to geofence provider + GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, + com.android.internal.R.bool.config_enableGeofenceOverlay, + com.android.internal.R.string.config_geofenceProviderPackageName, + com.android.internal.R.array.config_locationProviderPackageNames, + mLocationHandler, + gpsProvider.getGpsGeofenceProxy(), + flpHardwareProvider.getGeofenceHardware()); + if (provider == null) { + Slog.e(TAG, "Unable to bind FLP Geofence proxy."); + } + } else { + Slog.e(TAG, "FLP HAL not supported."); } String[] testProviderStrings = resources.getStringArray( 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.Manifest.permission; 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 @@ public class NetworkScoreService extends INetworkScoreService.Stub { 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 @@ public class NetworkScoreService extends INetworkScoreService.Stub { " 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 @@ public class NetworkScoreService extends INetworkScoreService.Stub { /** 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 @@ public class NetworkScoreService extends INetworkScoreService.Stub { 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 @@ public class RecognitionManagerService extends Binder { 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 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { 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 0c91907..f908de2 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.INotificationManager; 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; @@ -703,13 +702,6 @@ public final class ActivityManagerService extends ActivityManagerNative 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; /** @@ -1017,11 +1009,11 @@ public final class ActivityManagerService extends ActivityManagerNative static class ProcessChangeItem { static final int CHANGE_ACTIVITIES = 1<<0; - static final int CHANGE_IMPORTANCE= 1<<1; + static final int CHANGE_PROCESS_STATE = 1<<1; int changes; int uid; int pid; - int importance; + int processState; boolean foregroundActivities; } @@ -3200,11 +3192,10 @@ public final class ActivityManagerService extends ActivityManagerNative observer.onForegroundActivitiesChanged(item.pid, item.uid, item.foregroundActivities); } - if ((item.changes&ProcessChangeItem.CHANGE_IMPORTANCE) != 0) { - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "IMPORTANCE CHANGED pid=" - + item.pid + " uid=" + item.uid + ": " + item.importance); - observer.onImportanceChanged(item.pid, item.uid, - item.importance); + if ((item.changes&ProcessChangeItem.CHANGE_PROCESS_STATE) != 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "PROCSTATE CHANGED pid=" + + item.pid + " uid=" + item.uid + ": " + item.processState); + observer.onProcessStateChanged(item.pid, item.uid, item.processState); } } } catch (RemoteException e) { @@ -5453,21 +5444,15 @@ public final class ActivityManagerService extends ActivityManagerNative 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); @@ -6983,66 +6968,24 @@ public final class ActivityManagerService extends ActivityManagerNative // ========================================================= @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; @@ -7055,12 +6998,18 @@ public final class ActivityManagerService extends ActivityManagerNative @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; @@ -7095,6 +7044,13 @@ public final class ActivityManagerService extends ActivityManagerNative || (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; @@ -7114,8 +7070,7 @@ public final class ActivityManagerService extends ActivityManagerNative final ArrayList<ActivityRecord> activities = tr.mActivities; int activityNdx; final int numActivities = activities.size(); - for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; - ++activityNdx) { + for (activityNdx = 0; activityNdx < numActivities; ++activityNdx) { final ActivityRecord r = activities.get(activityNdx); if (r.intent != null && (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) @@ -7123,14 +7078,34 @@ public final class ActivityManagerService extends ActivityManagerNative 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) { @@ -7198,13 +7173,11 @@ public final class ActivityManagerService extends ActivityManagerNative } @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; } } } @@ -7636,82 +7609,6 @@ public final class ActivityManagerService extends ActivityManagerNative } // ========================================================= - // 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 // ========================================================= @@ -10635,6 +10532,7 @@ public final class ActivityManagerService extends ActivityManagerNative int adj = app.curAdj; outInfo.importance = oomAdjToImportance(adj, outInfo); outInfo.importanceReasonCode = app.adjTypeCode; + outInfo.processState = app.curProcState; } public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() { @@ -14690,7 +14588,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.keeping = true; app.curSchedGroup = Process.THREAD_GROUP_DEFAULT; app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT; - // System process can do UI, and when they do we want to have + // System processes can do UI, and when they do we want to have // them trim their memory after the user leaves the UI. To // facilitate this, here we need to determine whether or not it // is currently showing UI. @@ -15305,89 +15203,10 @@ public final class ActivityManagerService extends ActivityManagerNative // 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; - - int importance = app.memImportance; - if (importance == 0 || adj != app.curAdj || schedGroup != app.curSchedGroup) { - app.curAdj = adj; - app.curSchedGroup = schedGroup; - if (!interesting) { - // For this reporting, if there is not something explicitly - // interesting in this process then we will push it to the - // background importance. - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; - } else if (adj >= ProcessList.CACHED_APP_MIN_ADJ) { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; - } else if (adj >= ProcessList.SERVICE_B_ADJ) { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; - } else if (adj >= ProcessList.HOME_APP_ADJ) { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; - } else if (adj >= ProcessList.SERVICE_ADJ) { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; - } else if (adj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE; - } else if (adj >= ProcessList.PERCEPTIBLE_APP_ADJ) { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE; - } else if (adj >= ProcessList.VISIBLE_APP_ADJ) { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; - } else if (adj >= ProcessList.FOREGROUND_APP_ADJ) { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; - } else { - importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERSISTENT; - } - } - - int changes = importance != app.memImportance ? ProcessChangeItem.CHANGE_IMPORTANCE : 0; - if (foregroundActivities != app.foregroundActivities) { - changes |= ProcessChangeItem.CHANGE_ACTIVITIES; - } - if (changes != 0) { - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes); - app.memImportance = importance; - app.foregroundActivities = foregroundActivities; - int i = mPendingProcessChanges.size()-1; - ProcessChangeItem item = null; - while (i >= 0) { - item = mPendingProcessChanges.get(i); - if (item.pid == app.pid) { - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item); - break; - } - i--; - } - if (i < 0) { - // No existing item in pending changes; need a new one. - final int NA = mAvailProcessChanges.size(); - if (NA > 0) { - item = mAvailProcessChanges.remove(NA-1); - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item); - } else { - item = new ProcessChangeItem(); - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item); - } - item.changes = 0; - item.pid = app.pid; - item.uid = app.info.uid; - if (mPendingProcessChanges.size() == 0) { - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, - "*** Enqueueing dispatch processes changed!"); - mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget(); - } - mPendingProcessChanges.add(item); - } - item.changes |= changes; - item.importance = importance; - item.foregroundActivities = foregroundActivities; - if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item " - + Integer.toHexString(System.identityHashCode(item)) - + " " + app.toShortString() + ": changes=" + item.changes - + " importance=" + item.importance - + " foreground=" + item.foregroundActivities - + " type=" + app.adjType + " source=" + app.adjSource - + " target=" + app.adjTarget); - } + app.foregroundActivities = foregroundActivities; return app.curRawAdj; } @@ -15660,7 +15479,7 @@ public final class ActivityManagerService extends ActivityManagerNative } private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping, - ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) { + ProcessRecord TOP_APP, boolean doingAll, long now) { boolean success = true; if (app.curRawAdj != app.setRawAdj) { @@ -15679,6 +15498,8 @@ public final class ActivityManagerService extends ActivityManagerNative app.setRawAdj = app.curRawAdj; } + int changes = 0; + if (app.curAdj != app.setAdj) { ProcessList.setOomAdj(app.pid, app.curAdj); if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v( @@ -15720,9 +15541,14 @@ public final class ActivityManagerService extends ActivityManagerNative app.curSchedGroup <= Process.THREAD_GROUP_BG_NONINTERACTIVE); } } + if (app.repForegroundActivities != app.foregroundActivities) { + app.repForegroundActivities = app.foregroundActivities; + changes |= ProcessChangeItem.CHANGE_ACTIVITIES; + } if (app.repProcState != app.curProcState) { app.repProcState = app.curProcState; - if (!reportingProcessState && app.thread != null) { + changes |= ProcessChangeItem.CHANGE_PROCESS_STATE; + if (app.thread != null) { try { if (false) { //RuntimeException h = new RuntimeException("here"); @@ -15767,6 +15593,51 @@ public final class ActivityManagerService extends ActivityManagerNative app.procStateChanged = true; } } + + if (changes != 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes); + int i = mPendingProcessChanges.size()-1; + ProcessChangeItem item = null; + while (i >= 0) { + item = mPendingProcessChanges.get(i); + if (item.pid == app.pid) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item); + break; + } + i--; + } + if (i < 0) { + // No existing item in pending changes; need a new one. + final int NA = mAvailProcessChanges.size(); + if (NA > 0) { + item = mAvailProcessChanges.remove(NA-1); + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item); + } else { + item = new ProcessChangeItem(); + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item); + } + item.changes = 0; + item.pid = app.pid; + item.uid = app.info.uid; + if (mPendingProcessChanges.size() == 0) { + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, + "*** Enqueueing dispatch processes changed!"); + mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget(); + } + mPendingProcessChanges.add(item); + } + item.changes |= changes; + item.processState = app.repProcState; + item.foregroundActivities = app.repForegroundActivities; + if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item " + + Integer.toHexString(System.identityHashCode(item)) + + " " + app.toShortString() + ": changes=" + item.changes + + " procState=" + item.processState + + " foreground=" + item.foregroundActivities + + " type=" + app.adjType + " source=" + app.adjSource + + " target=" + app.adjTarget); + } + return success; } @@ -15777,7 +15648,7 @@ public final class ActivityManagerService extends ActivityManagerNative } private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj, - ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) { + ProcessRecord TOP_APP, boolean doingAll, long now) { if (app.thread == null) { return false; } @@ -15786,8 +15657,7 @@ public final class ActivityManagerService extends ActivityManagerNative computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now); - return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll, - reportingProcessState, now); + return applyOomAdjLocked(app, wasKeeping, TOP_APP, doingAll, now); } final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground, @@ -15853,10 +15723,6 @@ public final class ActivityManagerService extends ActivityManagerNative } final boolean updateOomAdjLocked(ProcessRecord app) { - return updateOomAdjLocked(app, false); - } - - final boolean updateOomAdjLocked(ProcessRecord app, boolean doingProcessState) { final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; final boolean wasCached = app.cached; @@ -15869,7 +15735,7 @@ public final class ActivityManagerService extends ActivityManagerNative // need to do a complete oom adj. final int cachedAdj = app.curRawAdj >= ProcessList.CACHED_APP_MIN_ADJ ? app.curRawAdj : ProcessList.UNKNOWN_ADJ; - boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, doingProcessState, + boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false, SystemClock.uptimeMillis()); if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) { // Changed to/from cached state, so apps after it in the LRU @@ -16002,7 +15868,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now); + applyOomAdjLocked(app, wasKeeping, TOP_APP, true, now); // Count the number of process types. switch (app.curProcState) { diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 7a44473..f506eab 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -23,6 +23,7 @@ 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 +132,6 @@ final class ActivityRecord { 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 +148,7 @@ final class ActivityRecord { 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 +238,6 @@ final class ActivityRecord { 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 +373,6 @@ final class ActivityRecord { 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..d5ab277 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -53,7 +53,6 @@ import android.app.ActivityManager; 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 +72,6 @@ import android.os.Looper; 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 +1096,36 @@ final class ActivityStack { 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 +1150,8 @@ final class ActivityStack { // 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 +2565,6 @@ final class ActivityStack { 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 +2803,6 @@ final class ActivityStack { 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 +3549,7 @@ final class ActivityStack { 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 +3560,9 @@ final class ActivityStack { 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 +3596,8 @@ final class ActivityStack { 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() { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 3770a07..9107cb6 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.IActivityContainer; 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,10 +190,6 @@ public final class ActivityStackSupervisor implements DisplayListener { /** 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>(); @@ -591,10 +586,7 @@ public final class ActivityStackSupervisor implements DisplayListener { 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 +597,7 @@ public final class ActivityStackSupervisor implements DisplayListener { 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 +624,6 @@ public final class ActivityStackSupervisor implements DisplayListener { break; } } - - return r; } ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags, @@ -1912,7 +1899,6 @@ public final class ActivityStackSupervisor implements DisplayListener { ArrayList<UserStartedState> startingUsers = null; int NS = 0; int NF = 0; - IApplicationThread sendThumbnail = null; boolean booting = false; boolean enableScreen = false; boolean activityRemoved = false; @@ -1940,11 +1926,6 @@ public final class ActivityStackSupervisor implements DisplayListener { // 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 +1957,6 @@ public final class ActivityStackSupervisor implements DisplayListener { 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 +1967,6 @@ public final class ActivityStackSupervisor implements DisplayListener { 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++) { diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index dbe773c..83e8a4b 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -110,6 +110,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub { return data; } + public long computeBatteryTimeRemaining() { + synchronized (mStats) { + long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime()); + return time >= 0 ? (time/1000) : time; + } + } + + public long computeChargeTimeRemaining() { + synchronized (mStats) { + long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime()); + return time >= 0 ? (time/1000) : time; + } + } + public void addIsolatedUid(int isolatedUid, int appUid) { enforceCallingPermission(); synchronized (mStats) { diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index b15fa5d..9d6481a 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -503,7 +503,7 @@ public final class BroadcastQueue { // are already core system stuff so don't matter for this. r.curApp = filter.receiverList.app; filter.receiverList.app.curReceiver = r; - mService.updateOomAdjLocked(r.curApp, true); + mService.updateOomAdjLocked(r.curApp); } } try { 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/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index d04a6b2..8d7d300 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -77,7 +77,6 @@ final class ProcessRecord { int curSchedGroup; // Currently desired scheduling class int setSchedGroup; // Last set to background scheduling class int trimMemoryLevel; // Last selected memory trimming level - int memImportance; // Importance constant computed from curAdj int curProcState = -1; // Currently computed process state: ActivityManager.PROCESS_STATE_* int repProcState = -1; // Last reported process state int setProcState = -1; // Last set process state in process tracker @@ -91,6 +90,7 @@ final class ProcessRecord { boolean hasStartedServices; // Are there any started services running in this process? boolean foregroundServices; // Running any services that are foreground? boolean foregroundActivities; // Running any activities that are foreground? + boolean repForegroundActivities; // Last reported foreground activities. boolean systemNoUi; // This is a system process, but not currently showing UI. boolean hasShownUi; // Has UI been shown in this process since it was started? boolean pendingUiClean; // Want to clean up resources from showing UI? @@ -267,9 +267,10 @@ final class ProcessRecord { pw.print(prefix); pw.print("persistent="); pw.print(persistent); pw.print(" removed="); pw.println(removed); } - if (hasClientActivities || foregroundActivities) { + if (hasClientActivities || foregroundActivities || repForegroundActivities) { pw.print(prefix); pw.print("hasClientActivities="); pw.print(hasClientActivities); - pw.print(" foregroundActivities="); pw.println(foregroundActivities); + pw.print(" foregroundActivities="); pw.print(foregroundActivities); + pw.print(" (rep="); pw.print(repForegroundActivities); pw.println(")"); } if (hasStartedServices) { pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices); diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 68da54d..9f0bc10 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 @@ final class TaskRecord extends ThumbnailHolder { 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,9 +137,8 @@ final class TaskRecord extends ThumbnailHolder { rootWasReset = true; } - if (info.applicationInfo != null) { - userId = UserHandle.getUserId(info.applicationInfo.uid); - } + userId = UserHandle.getUserId(info.applicationInfo.uid); + creatorUid = info.applicationInfo.uid; } void disposeThumbnail() { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } times.incCount(); } - + void addLaunchTime(String comp, int millis) { TimeStats times = mLaunchTimes.get(comp); if (times == null) { @@ -260,7 +263,7 @@ public final class UsageStatsService extends IUsageStats.Stub { mFullyDrawnTimes.valueAt(i).writeToParcel(out); } } - + void clear() { mLaunchTimes.clear(); mFullyDrawnTimes.clear(); @@ -268,32 +271,25 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { */ 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } } } - + 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } } - 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { sService = asInterface(b); return sService; } - + + @Override public void noteResumeComponent(ComponentName componentName) { enforceCallingPermission(); String pkgName; @@ -720,7 +721,7 @@ public final class UsageStatsService extends IUsageStats.Stub { ((pkgName = componentName.getPackageName()) == null)) { return; } - + final boolean samePackage = pkgName.equals(mLastResumedPkg); if (mIsResumed) { if (mLastResumedPkg != null) { @@ -734,14 +735,14 @@ public final class UsageStatsService extends IUsageStats.Stub { } } } - + 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } } + @Override public void notePauseComponent(ComponentName componentName) { enforceCallingPermission(); - + synchronized (mStatsLock) { String pkgName; if ((componentName == null) || @@ -777,9 +779,9 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } 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 @@ public final class UsageStatsService extends IUsageStats.Stub { ((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 final class UsageStatsService extends IUsageStats.Stub { } } } - + public void noteFullyDrawnTime(ComponentName componentName, int millis) { enforceCallingPermission(); String pkgName; @@ -838,7 +841,8 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { return new PkgUsageStats(pkgName, launchCount, usageTime, lastResumeTimes); } } - + + @Override public PkgUsageStats[] getAllPkgUsageStats() { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.PACKAGE_USAGE_STATS, null); @@ -884,8 +889,8 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } } } - + private void collectDumpInfoFLOCK(PrintWriter pw, boolean isCompactOutput, boolean deleteAfterPrint, HashSet<String> packages) { List<String> fileList = getUsageStatsFileListFLOCK(); @@ -932,15 +937,12 @@ public final class UsageStatsService extends IUsageStats.Stub { // 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { } return false; } - + /** * Searches array of arguments for the specified string's data * @param args array of argument strings @@ -1123,11 +1125,11 @@ public final class UsageStatsService extends IUsageStats.Stub { } 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 @@ public final class UsageStatsService extends IUsageStats.Stub { 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 @@ public final class UsageStatsService extends IUsageStats.Stub { Slog.w(TAG, "Checkin without packages"); return; } - + synchronized (mFileLock) { collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint, packages); } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 026fd29..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 @@ public class SyncManager { 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/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..c87fc99 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 @@ -32,17 +43,48 @@ import android.os.Message; 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 @@ class HdmiCecController { * 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,263 @@ class HdmiCecController { 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. + /** + * 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); + } + + /** + * 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 + */ + 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; + } + } } - }; - mMessageHandler = messageHandler; + 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); + } + + 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 an HDMI-CEC message arrived. + * Called by native when a hotplug event issues. */ - private void handleMessage(int srcAddress, int dstAddres, int opcode, byte[] params) { - // TODO: Translate message and delegate it to main message handler. + 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 contollerPtr, int srcAddress, + int dstAddress, byte[] body); } 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 @@ package com.android.server.hdmi; 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 @@ public final class HdmiControlService extends SystemService { // 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 @@ public final class HdmiControlService extends SystemService { @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/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java index 79f192d..09f1c56 100644 --- a/services/core/java/com/android/server/location/FlpHardwareProvider.java +++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java @@ -69,6 +69,7 @@ public class FlpHardwareProvider { sSingletonInstance = new FlpHardwareProvider(context); } + nativeInit(); return sSingletonInstance; } @@ -96,6 +97,7 @@ public class FlpHardwareProvider { } public static boolean isSupported() { + nativeInit(); return nativeIsSupported(); } @@ -216,9 +218,9 @@ public class FlpHardwareProvider { // Core members private static native void nativeClassInit(); private static native boolean nativeIsSupported(); + private static native void nativeInit(); // FlpLocationInterface members - private native void nativeInit(); private native int nativeGetBatchSize(); private native void nativeStartBatching(int requestId, FusedBatchOptions options); private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject); @@ -258,12 +260,10 @@ public class FlpHardwareProvider { public static final String GEOFENCING = "Geofencing"; public IFusedLocationHardware getLocationHardware() { - nativeInit(); return mLocationHardware; } public IFusedGeofenceHardware getGeofenceHardware() { - nativeInit(); return mGeofenceHardwareService; } 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.os.UserHandle; 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 @@ public class MediaRouteProviderProxy { private final String mId; private final ComponentName mComponentName; private final int mUserId; - - 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 final ArrayList<String> mInterfaces = new ArrayList<String>(); + private final ArrayList<RouteConnectionRecord> mConnections = new ArrayList<RouteConnectionRecord>(); + private final Handler mHandler = new Handler(); + private Intent mBindIntent; private IRouteProvider mBinder; private boolean mRunning; private boolean mInterested; @@ -76,7 +76,9 @@ public class MediaRouteProviderProxy { 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 @@ public class MediaRouteProviderProxy { 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 @@ public class MediaRouteProviderProxy { 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..3dc17fc 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -40,12 +40,14 @@ import android.os.Looper; 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; @@ -226,6 +228,36 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { 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=" + mIsPublished); + pw.println(indent + "transport controls enabled=" + mTransportPerformerEnabled); + pw.println(indent + "rating type=" + mRatingType); + pw.println(indent + "controllers: " + mControllerCallbacks.size()); + pw.println(indent + "state=" + 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 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 +333,34 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } + 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 @@ -603,7 +663,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { @Override public PlaybackState getPlaybackState() { - return mPlaybackState; + return getStateWithUpdatedPosition(); } @Override diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index bc91370..107f6ad 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -16,7 +16,9 @@ package com.android.server.media; +import android.Manifest; import android.content.Context; +import android.content.pm.PackageManager; import android.media.routeprovider.RouteRequest; import android.media.session.ISession; import android.media.session.ISessionCallback; @@ -30,13 +32,17 @@ 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; /** * 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); @@ -69,6 +75,7 @@ public class MediaSessionService extends SystemService { public void onStart() { publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl); mRouteProviderWatcher.start(); + Watchdog.getInstance().addMonitor(this); } /** @@ -114,14 +121,21 @@ public class MediaSessionService extends SystemService { } } + @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); } } @@ -160,9 +174,7 @@ public class MediaSessionService extends SystemService { } catch (RemoteException e) { throw new RuntimeException("Media Session owner died prematurely.", e); } - synchronized (mSessions) { - mSessions.add(session); - } + mSessions.add(session); if (DEBUG) { Log.d(TAG, "Created session for package " + packageName + " with tag " + tag); } @@ -259,6 +271,36 @@ public class MediaSessionService extends SystemService { 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) { + int count = mSessions.size(); + pw.println("Sessions - have " + count + " states:"); + for (int i = 0; i < count; i++) { + MediaSessionRecord record = mSessions.get(i); + pw.println(); + record.dump(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/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 @@ import android.util.Log; 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 @@ public class RouteConnectionRecord { } } + @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/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 855ae23..416a6b1 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -410,7 +410,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void onImportanceChanged(int pid, int uid, int importance) { + public void onProcessStateChanged(int pid, int uid, int procState) { } @Override diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index 29af433..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.Condition; 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 class ConditionProviders extends ManagedServices { 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,23 +89,49 @@ public class ConditionProviders extends ManagedServices { } @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; - for (int i = mConditions.size() - 1; i >= 0; i--) { - if (removed.equals(mConditions.valueAt(i))) { - mConditions.removeAt(i); + 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); + } + if (r.isAutomatic) { + // removing an automatic condition, exit zen + mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF); } + mRecords.remove(i); } } @@ -121,14 +141,15 @@ public class ConditionProviders extends ManagedServices { } } - 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()) { @@ -138,25 +159,51 @@ public class ConditionProviders extends ManagedServices { } } + 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); @@ -164,64 +211,156 @@ public class ConditionProviders extends ManagedServices { 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"); + public void setZenModeCondition(Uri conditionId) { + if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId); + synchronized(mMutex) { + 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; + } + } } - mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF); - unsubscribeLocked(mCurrentConditionId); - mCurrentConditionId = null; } - public void setZenModeCondition(Uri conditionId) { - synchronized(mMutex) { - if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId); - if (Objects.equal(mCurrentConditionId, conditionId)) return; + 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); + } + } - if (mCurrentConditionId != null) { - unsubscribeLocked(mCurrentConditionId); + 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); } - 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); + } + 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; } } - mCurrentConditionId = conditionId; + if (save && changed) { + saveZenConfigLocked(); + } } } - private void unsubscribeLocked(Uri conditionId) { - final ManagedServiceInfo info = mConditions.get(mCurrentConditionId); - final IConditionProvider provider = provider(info); - if (provider == null) return; + 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(conditionId); + provider.onUnsubscribe(r.id); } catch (RemoteException e) { - Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, 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) { return info == null ? null : (IConditionProvider) info.service; } @@ -238,20 +377,99 @@ public class ConditionProviders extends ManagedServices { } } + 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 public class ManagedServices { 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 @@ abstract public class ManagedServices { @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 @@ abstract public class ManagedServices { } } if (added) { - onServiceAdded(mService); + onServiceAdded(info); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 6e4eb56..6ceee5c 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1355,9 +1355,9 @@ public class NotificationManagerService extends SystemService { } @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 +1366,18 @@ public class NotificationManagerService extends SystemService { 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 +1612,8 @@ public class NotificationManagerService extends SystemService { // 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 +2333,8 @@ public class NotificationManagerService extends SystemService { } @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/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 137730a..154ac96 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -84,6 +84,9 @@ public class ZenModeHelper { "com.google.android.talk", "com.android.mms" )); + private static final Set<String> ALARM_PACKAGES = new HashSet<String>(Arrays.asList( + "com.google.android.deskclock" + )); public ZenModeHelper(Context context, Handler handler) { mContext = context; @@ -122,6 +125,9 @@ public class ZenModeHelper { public boolean shouldIntercept(String pkg, Notification n) { if (mZenMode != Global.ZEN_MODE_OFF) { + if (isAlarm(pkg, n)) { + return false; + } if (isCall(pkg, n)) { return !mConfig.allowCalls; } @@ -223,6 +229,10 @@ public class ZenModeHelper { } } + private boolean isAlarm(String pkg, Notification n) { + return ALARM_PACKAGES.contains(pkg); + } + private boolean isCall(String pkg, Notification n) { return CALL_PACKAGES.contains(pkg); } diff --git a/services/core/java/com/android/server/pm/ForwardingIntentFilter.java b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java new file mode 100644 index 0000000..aba796b --- /dev/null +++ b/services/core/java/com/android/server/pm/ForwardingIntentFilter.java @@ -0,0 +1,102 @@ +/* + * 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 com.android.server.pm; + +import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; +import android.content.IntentFilter; +import android.util.Log; +import java.io.IOException; +import android.os.UserHandle; + +/** + * The {@link PackageManagerService} maintains some {@link ForwardingIntentFilter}s for every user. + * If an {@link Intent} matches the {@link ForwardingIntentFilter}, then it can be forwarded to the + * {@link #mUserIdDest}. + */ +class ForwardingIntentFilter extends IntentFilter { + private static final String ATTR_USER_ID_DEST = "userIdDest"; + 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; + + ForwardingIntentFilter(IntentFilter filter, int userIdDest) { + super(filter); + mUserIdDest = userIdDest; + } + + public int getUserIdDest() { + return mUserIdDest; + } + + ForwardingIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException { + String userIdDestString = parser.getAttributeValue(null, ATTR_USER_ID_DEST); + if (userIdDestString == null) { + String msg = "Missing element under " + TAG +": " + ATTR_USER_ID_DEST + " at " + + parser.getPositionDescription(); + PackageManagerService.reportSettingsProblem(Log.WARN, msg); + mUserIdDest = UserHandle.USER_NULL; + } else { + mUserIdDest = Integer.parseInt(userIdDestString); + } + int outerDepth = parser.getDepth(); + String tagName = parser.getName(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + tagName = parser.getName(); + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } else if (type == XmlPullParser.START_TAG) { + if (tagName.equals(ATTR_FILTER)) { + break; + } else { + String msg = "Unknown element under " + Settings.TAG_FORWARDING_INTENT_FILTERS + + ": " + tagName + " at " + parser.getPositionDescription(); + PackageManagerService.reportSettingsProblem(Log.WARN, msg); + XmlUtils.skipCurrentTag(parser); + } + } + } + if (tagName.equals(ATTR_FILTER)) { + readFromXml(parser); + } else { + String msg = "Missing element under " + TAG + ": " + ATTR_FILTER + + " at " + parser.getPositionDescription(); + PackageManagerService.reportSettingsProblem(Log.WARN, msg); + XmlUtils.skipCurrentTag(parser); + } + } + + public void writeToXml(XmlSerializer serializer) throws IOException { + serializer.attribute(null, ATTR_USER_ID_DEST, Integer.toString(mUserIdDest)); + serializer.startTag(null, ATTR_FILTER); + super.writeToXml(serializer); + serializer.endTag(null, ATTR_FILTER); + } + + @Override + public String toString() { + return "ForwardingIntentFilter{0x" + Integer.toHexString(System.identityHashCode(this)) + + " " + Integer.toString(mUserIdDest) + "}"; + } +} diff --git a/services/core/java/com/android/server/pm/ForwardingIntentResolver.java b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java new file mode 100644 index 0000000..1616395 --- /dev/null +++ b/services/core/java/com/android/server/pm/ForwardingIntentResolver.java @@ -0,0 +1,44 @@ +/* + * 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 com.android.server.pm; + + +import java.io.PrintWriter; +import com.android.server.IntentResolver; +import java.util.List; + +/** + * Used to find a list of {@link ForwardingIntentFilter}s that match an intent. + */ +class ForwardingIntentResolver + extends IntentResolver<ForwardingIntentFilter, ForwardingIntentFilter> { + @Override + protected ForwardingIntentFilter[] newArray(int size) { + return new ForwardingIntentFilter[size]; + } + + @Override + protected boolean isPackageForFilter(String packageName, ForwardingIntentFilter filter) { + return false; + } + + @Override + protected void sortResults(List<ForwardingIntentFilter> results) { + //We don't sort the results + } +} diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index ff816ea..82d3f53 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -211,7 +211,7 @@ public final class Installer extends SystemService { return execute(builder.toString()); } - public int dexopt(String apkPath, int uid, boolean isPublic) { + public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) { StringBuilder builder = new StringBuilder("dexopt"); builder.append(' '); builder.append(apkPath); @@ -219,10 +219,13 @@ public final class Installer extends SystemService { builder.append(uid); builder.append(isPublic ? " 1" : " 0"); builder.append(" *"); // No pkgName arg present + builder.append(' '); + builder.append(instructionSet); return execute(builder.toString()); } - public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName) { + public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, + String instructionSet) { StringBuilder builder = new StringBuilder("dexopt"); builder.append(' '); builder.append(apkPath); @@ -231,6 +234,8 @@ public final class Installer extends SystemService { builder.append(isPublic ? " 1" : " 0"); builder.append(' '); builder.append(pkgName); + builder.append(' '); + builder.append(instructionSet); return execute(builder.toString()); } @@ -245,19 +250,23 @@ public final class Installer extends SystemService { return execute(builder.toString()); } - public int movedex(String srcPath, String dstPath) { + public int movedex(String srcPath, String dstPath, String instructionSet) { StringBuilder builder = new StringBuilder("movedex"); builder.append(' '); builder.append(srcPath); builder.append(' '); builder.append(dstPath); + builder.append(' '); + builder.append(instructionSet); return execute(builder.toString()); } - public int rmdex(String codePath) { + public int rmdex(String codePath, String instructionSet) { StringBuilder builder = new StringBuilder("rmdex"); builder.append(' '); builder.append(codePath); + builder.append(' '); + builder.append(instructionSet); return execute(builder.toString()); } @@ -344,7 +353,7 @@ public final class Installer extends SystemService { } public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath, - String fwdLockApkPath, String asecPath, PackageStats pStats) { + String fwdLockApkPath, String asecPath, String instructionSet, PackageStats pStats) { StringBuilder builder = new StringBuilder("getsize"); builder.append(' '); builder.append(pkgName); @@ -358,6 +367,8 @@ public final class Installer extends SystemService { builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!"); builder.append(' '); builder.append(asecPath != null ? asecPath : "!"); + builder.append(' '); + builder.append(instructionSet); String s = transaction(builder.toString()); String res[] = s.split(" "); diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 6030d4d..48e9737 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -16,14 +16,18 @@ package com.android.server.pm; +import android.app.AppGlobals; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ActivityInfo; import android.content.pm.ILauncherApps; import android.content.pm.IOnAppsChangedListener; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.PackageInfo; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.graphics.Rect; @@ -34,6 +38,7 @@ import android.os.RemoteCallbackList; 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; @@ -46,7 +51,7 @@ import java.util.List; * 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; @@ -69,11 +74,17 @@ public class LauncherAppsService extends ILauncherApps.Stub { @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()); } } @@ -85,6 +96,9 @@ public class LauncherAppsService extends ILauncherApps.Stub { 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(); @@ -103,11 +117,17 @@ public class LauncherAppsService extends ILauncherApps.Stub { * 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(); } @@ -170,6 +190,34 @@ public class LauncherAppsService extends ILauncherApps.Stub { } @Override + public boolean isPackageEnabled(String packageName, UserHandle user) + throws RemoteException { + ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user); + long ident = Binder.clearCallingIdentity(); + try { + IPackageManager pm = AppGlobals.getPackageManager(); + PackageInfo info = pm.getPackageInfo(packageName, 0, user.getIdentifier()); + return info != null && info.applicationInfo.enabled; + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public boolean isActivityEnabled(ComponentName component, UserHandle user) + throws RemoteException { + ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user); + long ident = Binder.clearCallingIdentity(); + try { + IPackageManager pm = AppGlobals.getPackageManager(); + ActivityInfo info = pm.getActivityInfo(component, 0, user.getIdentifier()); + return info != null && info.isEnabled(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override public void startActivityAsUser(ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user); @@ -191,13 +239,44 @@ public class LauncherAppsService extends ILauncherApps.Stub { private class MyPackageMonitor extends PackageMonitor { + /** Checks if user is a profile of or same as listeningUser. */ + private boolean isProfileOf(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) { + 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 (!isProfileOf(user, listeningUser, "onPackageAdded")) continue; try { listener.onPackageAdded(user, packageName); } catch (RemoteException re) { @@ -212,10 +291,11 @@ public class LauncherAppsService extends ILauncherApps.Stub { @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 (!isProfileOf(user, listeningUser, "onPackageRemoved")) continue; try { listener.onPackageRemoved(user, packageName); } catch (RemoteException re) { @@ -230,10 +310,11 @@ public class LauncherAppsService extends ILauncherApps.Stub { @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 (!isProfileOf(user, listeningUser, "onPackageModified")) continue; try { listener.onPackageChanged(user, packageName); } catch (RemoteException re) { @@ -248,10 +329,11 @@ public class LauncherAppsService extends ILauncherApps.Stub { @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 (!isProfileOf(user, listeningUser, "onPackagesAvailable")) continue; try { listener.onPackagesAvailable(user, packages, isReplacing()); } catch (RemoteException re) { @@ -266,10 +348,11 @@ public class LauncherAppsService extends ILauncherApps.Stub { @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 (!isProfileOf(user, listeningUser, "onPackagesUnavailable")) continue; try { listener.onPackagesUnavailable(user, packages, isReplacing()); } catch (RemoteException re) { @@ -284,7 +367,6 @@ public class LauncherAppsService extends ILauncherApps.Stub { } 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 3111cce..a133d42 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -28,9 +28,12 @@ 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_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.util.ArrayUtils.appendInt; import static com.android.internal.util.ArrayUtils.removeInt; +import android.content.pm.PackageParser.*; import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; import com.android.internal.content.NativeLibraryHelper; @@ -80,7 +83,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageStats; import android.content.pm.PackageUserState; import android.content.pm.ParceledListSlice; @@ -145,6 +147,8 @@ import java.io.IOException; import java.io.PrintWriter; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -160,9 +164,11 @@ import java.util.List; import java.util.Map; import java.util.Set; +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; /** @@ -267,6 +273,8 @@ public class PackageManagerService extends IPackageManager.Stub { static final String mTempContainerPrefix = "smdl2tmp"; + private static String sPreferredInstructionSet; + final ServiceThread mHandlerThread; private static final String IDMAP_PREFIX = "/data/resource-cache/"; @@ -1239,27 +1247,38 @@ public class PackageManagerService extends IPackageManager.Stub { boolean didDexOpt = false; + final List<String> instructionSets = getAllInstructionSets(); + /** * Ensure all external libraries have had dexopt run on them. */ if (mSharedLibraries.size() > 0) { - Iterator<SharedLibraryEntry> libs = mSharedLibraries.values().iterator(); - while (libs.hasNext()) { - String lib = libs.next().path; - if (lib == null) { - continue; - } - try { - if (dalvik.system.DexFile.isDexOptNeededInternal(lib, null, false)) { - alreadyDexOpted.add(lib); - mInstaller.dexopt(lib, Process.SYSTEM_UID, true); - didDexOpt = true; + // NOTE: For now, we're compiling these system "shared libraries" + // (and framework jars) into all available architectures. It's possible + // to compile them only when we come across an app that uses them (there's + // already logic for that in scanPackageLI) but that adds some complexity. + for (String instructionSet : instructionSets) { + for (SharedLibraryEntry libEntry : mSharedLibraries.values()) { + final String lib = libEntry.path; + if (lib == null) { + continue; + } + + try { + if (dalvik.system.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; + } + } catch (FileNotFoundException e) { + Slog.w(TAG, "Library not found: " + lib); + } catch (IOException e) { + Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? " + + e.getMessage()); } - } catch (FileNotFoundException e) { - Slog.w(TAG, "Library not found: " + lib); - } catch (IOException e) { - Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? " - + e.getMessage()); } } } @@ -1282,49 +1301,37 @@ public class PackageManagerService extends IPackageManager.Stub { */ String[] frameworkFiles = frameworkDir.list(); if (frameworkFiles != null) { - for (int i=0; i<frameworkFiles.length; i++) { - File libPath = new File(frameworkDir, frameworkFiles[i]); - String path = libPath.getPath(); - // Skip the file if we alrady did it. - if (alreadyDexOpted.contains(path)) { - continue; - } - // Skip the file if it is not a type we want to dexopt. - if (!path.endsWith(".apk") && !path.endsWith(".jar")) { - continue; - } - try { - if (dalvik.system.DexFile.isDexOptNeededInternal(path, null, false)) { - mInstaller.dexopt(path, Process.SYSTEM_UID, true); - didDexOpt = true; + // TODO: We could compile these only for the most preferred ABI. We should + // first double check that the dex files for these commands are not referenced + // by other system apps. + for (String instructionSet : instructionSets) { + for (int i=0; i<frameworkFiles.length; i++) { + File libPath = new File(frameworkDir, frameworkFiles[i]); + String path = libPath.getPath(); + // Skip the file if we already did it. + if (alreadyDexOpted.contains(path)) { + continue; + } + // Skip the file if it is not a type we want to dexopt. + if (!path.endsWith(".apk") && !path.endsWith(".jar")) { + continue; + } + try { + if (dalvik.system.DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) { + mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet); + didDexOpt = true; + } + } catch (FileNotFoundException e) { + Slog.w(TAG, "Jar not found: " + path); + } catch (IOException e) { + Slog.w(TAG, "Exception reading jar: " + path, e); } - } catch (FileNotFoundException e) { - Slog.w(TAG, "Jar not found: " + path); - } catch (IOException e) { - Slog.w(TAG, "Exception reading jar: " + path, e); } } } if (didDexOpt) { - File dalvikCacheDir = new File(dataDir, "dalvik-cache"); - - // If we had to do a dexopt of one of the previous - // things, then something on the system has changed. - // Consider this significant, and wipe away all other - // existing dexopt files to ensure we don't leave any - // dangling around. - String[] files = dalvikCacheDir.list(); - if (files != null) { - for (int i=0; i<files.length; i++) { - String fn = files[i]; - if (fn.startsWith("data@app@") - || fn.startsWith("data@app-private@")) { - Slog.i(TAG, "Pruning dalvik file: " + fn); - (new File(dalvikCacheDir, fn)).delete(); - } - } - } + pruneDexFiles(new File(dataDir, "dalvik-cache")); } // Collect vendor overlay packages. @@ -1502,6 +1509,12 @@ public class PackageManagerService extends IPackageManager.Stub { // the correct library paths. updateAllSharedLibrariesLPw(); + + for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) { + adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */, + false /* force dexopt */, false /* defer dexopt */); + } + EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); Slog.i(TAG, "Time to scan packages: " @@ -1551,6 +1564,37 @@ public class PackageManagerService extends IPackageManager.Stub { } // synchronized (mInstallLock) } + private static void pruneDexFiles(File cacheDir) { + // If we had to do a dexopt of one of the previous + // things, then something on the system has changed. + // Consider this significant, and wipe away all other + // existing dexopt files to ensure we don't leave any + // dangling around. + // + // Additionally, delete all dex files from the root directory + // since there shouldn't be any there anyway. + File[] files = cacheDir.listFiles(); + if (files != null) { + for (File file : files) { + if (!file.isDirectory()) { + Slog.i(TAG, "Pruning dalvik file: " + file.getAbsolutePath()); + file.delete(); + } else { + File[] subDirList = file.listFiles(); + if (subDirList != null) { + for (File subDirFile : subDirList) { + final String fn = subDirFile.getName(); + if (fn.startsWith("data@app@") || fn.startsWith("data@app-private@")) { + Slog.i(TAG, "Pruning dalvik file: " + fn); + subDirFile.delete(); + } + } + } + } + } + } + } + public boolean isFirstBoot() { return !mRestoredSettings; } @@ -1840,7 +1884,6 @@ public class PackageManagerService extends IPackageManager.Stub { PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) { if (!sUserManager.exists(userId)) return null; - PackageInfo pi; final PackageSetting ps = (PackageSetting) p.mExtras; if (ps == null) { return null; @@ -2718,6 +2761,59 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.SIGNATURE_NO_MATCH; } + /** + * If the database version for this type of package (internal storage or + * external storage) is less than the version where package signatures + * were updated, return true. + */ + private boolean isCompatSignatureUpdateNeeded(PackageParser.Package scannedPkg) { + return (isExternal(scannedPkg) && mSettings.isExternalDatabaseVersionOlderThan( + DatabaseVersion.SIGNATURE_END_ENTITY)) + || (!isExternal(scannedPkg) && mSettings.isInternalDatabaseVersionOlderThan( + DatabaseVersion.SIGNATURE_END_ENTITY)); + } + + /** + * Used for backward compatibility to make sure any packages with + * certificate chains get upgraded to the new style. {@code existingSigs} + * will be in the old format (since they were stored on disk from before the + * system upgrade) and {@code scannedSigs} will be in the newer format. + */ + private int compareSignaturesCompat(PackageSignatures existingSigs, + PackageParser.Package scannedPkg) { + if (!isCompatSignatureUpdateNeeded(scannedPkg)) { + return PackageManager.SIGNATURE_NO_MATCH; + } + + HashSet<Signature> existingSet = new HashSet<Signature>(); + for (Signature sig : existingSigs.mSignatures) { + existingSet.add(sig); + } + HashSet<Signature> scannedCompatSet = new HashSet<Signature>(); + for (Signature sig : scannedPkg.mSignatures) { + try { + Signature[] chainSignatures = sig.getChainSignatures(); + for (Signature chainSig : chainSignatures) { + scannedCompatSet.add(chainSig); + } + } catch (CertificateEncodingException e) { + scannedCompatSet.add(sig); + } + } + /* + * Make sure the expanded scanned set contains all signatures in the + * existing one. + */ + if (scannedCompatSet.equals(existingSet)) { + // Migrate the old signatures to the new scheme. + existingSigs.assignSignatures(scannedPkg.mSignatures); + // The new KeySets will be re-added later in the scanning process. + mSettings.mKeySetManager.removeAppKeySetData(scannedPkg.packageName); + return PackageManager.SIGNATURE_MATCH; + } + return PackageManager.SIGNATURE_NO_MATCH; + } + public String[] getPackagesForUid(int uid) { uid = UserHandle.getAppId(uid); // reader @@ -3068,6 +3164,33 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } + /* + * Returns if intent can be forwarded from the userId from to dest + */ + @Override + public boolean canForwardTo(Intent intent, String resolvedType, int userIdFrom, int userIdDest) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); + List<ForwardingIntentFilter> matches = + getMatchingForwardingIntentFilters(intent, resolvedType, userIdFrom); + if (matches != null) { + int size = matches.size(); + for (int i = 0; i < size; i++) { + if (matches.get(i).getUserIdDest() == userIdDest) return true; + } + } + return false; + } + + private List<ForwardingIntentFilter> getMatchingForwardingIntentFilters(Intent intent, + String resolvedType, int userId) { + ForwardingIntentResolver fir = mSettings.mForwardingIntentResolvers.get(userId); + if (fir != null) { + return fir.queryIntent(intent, resolvedType, false, userId); + } + return null; + } + @Override public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { @@ -3096,7 +3219,38 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { final String pkgName = intent.getPackage(); if (pkgName == null) { - return mActivities.queryIntent(intent, resolvedType, flags, userId); + List<ResolveInfo> result = + mActivities.queryIntent(intent, resolvedType, flags, userId); + // Checking if we can forward the intent to another user + List<ForwardingIntentFilter> fifs = + getMatchingForwardingIntentFilters(intent, resolvedType, userId); + if (fifs != null) { + ForwardingIntentFilter forwardingIntentFilterWithResult = null; + HashSet<Integer> alreadyTriedUserIds = new HashSet<Integer>(); + for (ForwardingIntentFilter fif : fifs) { + int userIdDest = fif.getUserIdDest(); + // Two {@link ForwardingIntentFilter}s can have the same userIdDest and + // match the same an intent. For performance reasons, it is better not to + // run queryIntent twice for the same userId + if (!alreadyTriedUserIds.contains(userIdDest)) { + List<ResolveInfo> resultUser = mActivities.queryIntent(intent, + resolvedType, flags, userIdDest); + if (resultUser != null) { + forwardingIntentFilterWithResult = fif; + // As soon as there is a match in another user, we add the + // intentForwarderActivity to the list of ResolveInfo. + break; + } + alreadyTriedUserIds.add(userIdDest); + } + } + if (forwardingIntentFilterWithResult != null) { + ResolveInfo forwardingResolveInfo = createForwardingResolveInfo( + forwardingIntentFilterWithResult, userId); + result.add(forwardingResolveInfo); + } + } + return result; } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { @@ -3107,6 +3261,28 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private ResolveInfo createForwardingResolveInfo(ForwardingIntentFilter fif, int userIdFrom) { + String className; + int userIdDest = fif.getUserIdDest(); + if (userIdDest == UserHandle.USER_OWNER) { + className = FORWARD_INTENT_TO_USER_OWNER; + } else { + className = FORWARD_INTENT_TO_MANAGED_PROFILE; + } + ComponentName forwardingActivityComponentName = new ComponentName( + mAndroidApplication.packageName, className); + ActivityInfo forwardingActivityInfo = getActivityInfo(forwardingActivityComponentName, 0, + userIdFrom); + ResolveInfo forwardingResolveInfo = new ResolveInfo(); + forwardingResolveInfo.activityInfo = forwardingActivityInfo; + forwardingResolveInfo.priority = 0; + forwardingResolveInfo.preferredOrder = 0; + forwardingResolveInfo.match = 0; + forwardingResolveInfo.isDefault = true; + forwardingResolveInfo.filter = fif; + return forwardingResolveInfo; + } + @Override public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, @@ -3801,7 +3977,8 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package pkg, File srcFile, int parseFlags) { if (ps != null && ps.codePath.equals(srcFile) - && ps.timeStamp == srcFile.lastModified()) { + && ps.timeStamp == srcFile.lastModified() + && !isCompatSignatureUpdateNeeded(pkg)) { if (ps.signatures.mSignatures != null && ps.signatures.mSignatures.length != 0) { // Optimization: reuse the existing cached certificates @@ -3912,7 +4089,8 @@ public class PackageManagerService extends IPackageManager.Stub { + " better than installed " + ps.versionCode); InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps), - ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString); + ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString, + getAppInstructionSetFromSettings(ps)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } @@ -3976,7 +4154,8 @@ public class PackageManagerService extends IPackageManager.Stub { + ps.codePathString + ": new version " + pkg.mVersionCode + " better than installed " + ps.versionCode); InstallArgs args = createInstallArgs(packageFlagsToInstallFlags(ps), - ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString); + ps.codePathString, ps.resourcePathString, ps.nativeLibraryPathString, + getAppInstructionSetFromSettings(ps)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } @@ -4010,8 +4189,6 @@ public class PackageManagerService extends IPackageManager.Stub { codePath = pkg.mScanPath; // Set application objects path explicitly. setApplicationInfoPaths(pkg, codePath, resPath); - // Applications can run with the primary Cpu Abi unless otherwise is specified - pkg.applicationInfo.requiredCpuAbi = null; // Note that we invoke the following method only if we are about to unpack an application PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user); @@ -4051,22 +4228,32 @@ public class PackageManagerService extends IPackageManager.Stub { return processName; } - private boolean verifySignaturesLP(PackageSetting pkgSetting, - PackageParser.Package pkg) { + private boolean verifySignaturesLP(PackageSetting pkgSetting, PackageParser.Package pkg) { if (pkgSetting.signatures.mSignatures != null) { // Already existing package. Make sure signatures match - if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures) != - PackageManager.SIGNATURE_MATCH) { - Slog.e(TAG, "Package " + pkg.packageName - + " signatures do not match the previously installed version; ignoring!"); - mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; - return false; - } + boolean match = compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures) + == PackageManager.SIGNATURE_MATCH; + if (!match) { + match = compareSignaturesCompat(pkgSetting.signatures, pkg) + == PackageManager.SIGNATURE_MATCH; + } + if (!match) { + Slog.e(TAG, "Package " + pkg.packageName + + " signatures do not match the previously installed version; ignoring!"); + mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; + return false; + } } // Check for shared user signatures if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) { - if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures, - pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { + // Already existing package. Make sure signatures match + boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures, + pkg.mSignatures) == PackageManager.SIGNATURE_MATCH; + if (!match) { + match = compareSignaturesCompat(pkgSetting.sharedUser.signatures, pkg) + == PackageManager.SIGNATURE_MATCH; + } + if (!match) { Slog.e(TAG, "Package " + pkg.packageName + " has no signatures that match those in shared user " + pkgSetting.sharedUser.name + "; ignoring!"); @@ -4091,12 +4278,16 @@ public class PackageManagerService extends IPackageManager.Stub { } } + @Override public void performBootDexOpt() { - HashSet<PackageParser.Package> pkgs = null; + enforceSystemOrRoot("Only the system can request dexopt be performed"); + + final HashSet<PackageParser.Package> pkgs; synchronized (mPackages) { pkgs = mDeferredDexOpt; mDeferredDexOpt = null; } + if (pkgs != null) { int i = 0; for (PackageParser.Package pkg : pkgs) { @@ -4113,16 +4304,17 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package p = pkg; synchronized (mInstallLock) { if (!p.mDidDexOpt) { - performDexOptLI(p, false, false, true); + performDexOptLI(p, false /* force dex */, false /* defer */, + true /* include dependencies */); } } } } } + @Override public boolean performDexOpt(String packageName) { enforceSystemOrRoot("Only the system can request dexopt be performed"); - if (!mNoDexOpt) { return false; } @@ -4135,12 +4327,13 @@ public class PackageManagerService extends IPackageManager.Stub { } } synchronized (mInstallLock) { - return performDexOptLI(p, false, false, true) == DEX_OPT_PERFORMED; + return performDexOptLI(p, false /* force dex */, false /* defer */, + true /* include dependencies */) == DEX_OPT_PERFORMED; } } - private void performDexOptLibsLI(ArrayList<String> libs, boolean forceDex, boolean defer, - HashSet<String> done) { + 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; @@ -4154,7 +4347,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } if (libPkg != null && !done.contains(libName)) { - performDexOptLI(libPkg, forceDex, defer, done); + performDexOptLI(libPkg, instructionSet, forceDex, defer, done); } } } @@ -4164,24 +4357,29 @@ public class PackageManagerService extends IPackageManager.Stub { static final int DEX_OPT_DEFERRED = 2; static final int DEX_OPT_FAILED = -1; - private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer, - HashSet<String> done) { - boolean performed = false; + private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride, + boolean forceDex, + boolean defer, HashSet<String> done) { + final String instructionSet = instructionSetOverride != null ? + instructionSetOverride : getAppInstructionSet(pkg.applicationInfo); + if (done != null) { done.add(pkg.packageName); if (pkg.usesLibraries != null) { - performDexOptLibsLI(pkg.usesLibraries, forceDex, defer, done); + performDexOptLibsLI(pkg.usesLibraries, instructionSet, forceDex, defer, done); } if (pkg.usesOptionalLibraries != null) { - performDexOptLibsLI(pkg.usesOptionalLibraries, forceDex, defer, done); + performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSet, forceDex, defer, done); } } + + 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, - defer)) { + if (forceDex || dalvik.system.DexFile.isDexOptNeededInternal(path, + pkg.packageName, instructionSet, defer)) { if (!forceDex && defer) { if (mDeferredDexOpt == null) { mDeferredDexOpt = new HashSet<PackageParser.Package>(); @@ -4189,10 +4387,12 @@ public class PackageManagerService extends IPackageManager.Stub { mDeferredDexOpt.add(pkg); return DEX_OPT_DEFERRED; } else { - Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName); + 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), - pkg.packageName); + pkg.packageName, instructionSet); pkg.mDidDexOpt = true; performed = true; } @@ -4219,17 +4419,58 @@ public class PackageManagerService extends IPackageManager.Stub { return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED; } + private String getAppInstructionSet(ApplicationInfo info) { + String instructionSet = getPreferredInstructionSet(); + + if (info.requiredCpuAbi != null) { + instructionSet = VMRuntime.getInstructionSet(info.requiredCpuAbi); + } + + return instructionSet; + } + + private String getAppInstructionSetFromSettings(PackageSetting ps) { + String instructionSet = getPreferredInstructionSet(); + + if (ps.requiredCpuAbiString != null) { + instructionSet = VMRuntime.getInstructionSet(ps.requiredCpuAbiString); + } + + return instructionSet; + } + + private static String getPreferredInstructionSet() { + if (sPreferredInstructionSet == null) { + sPreferredInstructionSet = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); + } + + return sPreferredInstructionSet; + } + + private static List<String> getAllInstructionSets() { + final String[] allAbis = Build.SUPPORTED_ABIS; + final List<String> allInstructionSets = new ArrayList<String>(allAbis.length); + + for (String abi : allAbis) { + final String instructionSet = VMRuntime.getInstructionSet(abi); + if (!allInstructionSets.contains(instructionSet)) { + allInstructionSets.add(instructionSet); + } + } + + return allInstructionSets; + } + private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer, boolean inclDependencies) { HashSet<String> done; - boolean performed = false; if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) { done = new HashSet<String>(); done.add(pkg.packageName); } else { done = null; } - return performDexOptLI(pkg, forceDex, defer, done); + return performDexOptLI(pkg, null /* instruction set override */, forceDex, defer, done); } private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) { @@ -4884,6 +5125,8 @@ public class PackageManagerService extends IPackageManager.Stub { Log.i(TAG, "removed obsolete native libraries for system package " + path); } + + setInternalAppAbi(pkg, pkgSetting); } else { if (!isForwardLocked(pkg) && !isExternal(pkg)) { /* @@ -4915,6 +5158,28 @@ public class PackageManagerService extends IPackageManager.Stub { mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; return null; } + } else { + // We don't have to copy the shared libraries if we're in the ASEC container + // but we still need to scan the file to figure out what ABI the app needs. + // + // TODO: This duplicates work done in the default container service. It's possible + // to clean this up but we'll need to change the interface between this service + // and IMediaContainerService (but doing so will spread this logic out, rather + // than centralizing it). + final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile); + final int abi = NativeLibraryHelper.findSupportedAbi(handle, Build.SUPPORTED_ABIS); + if (abi >= 0) { + pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_ABIS[abi]; + } else if (abi == PackageManager.NO_NATIVE_LIBRARIES) { + // Note that (non upgraded) system apps will not have any native + // libraries bundled in their APK, but we're guaranteed not to be + // such an app at this point. + pkg.applicationInfo.requiredCpuAbi = null; + } else { + mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; + return null; + } + handle.close(); } if (DEBUG_INSTALL) Slog.i(TAG, "Linking native library dir for " + path); @@ -4991,8 +5256,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (allowed) { if (!mSharedLibraries.containsKey(name)) { - mSharedLibraries.put(name, new SharedLibraryEntry(null, - pkg.packageName)); + mSharedLibraries.put(name, new SharedLibraryEntry(null, pkg.packageName)); } else if (!name.equals(pkg.packageName)) { Slog.w(TAG, "Package " + pkg.packageName + " library " + name + " already exists; skipping"); @@ -5065,6 +5329,12 @@ public class PackageManagerService extends IPackageManager.Stub { // writer synchronized (mPackages) { + if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) { + // We don't do this here during boot because we can do it all + // at once after scanning all existing packages. + adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, + true, forceDex, (scanMode & SCAN_DEFER_DEX) != 0); + } // We don't expect installation to fail beyond this point, if ((scanMode&SCAN_MONITOR) != 0) { mAppDirs.put(pkg.mPath, pkg); @@ -5409,6 +5679,55 @@ public class PackageManagerService extends IPackageManager.Stub { return pkg; } + public void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser, + boolean doDexOpt, boolean forceDexOpt, boolean deferDexOpt) { + String requiredInstructionSet = null; + PackageSetting requirer = null; + for (PackageSetting ps : packagesForUser) { + if (ps.requiredCpuAbiString != null) { + final String instructionSet = VMRuntime.getInstructionSet(ps.requiredCpuAbiString); + if (requiredInstructionSet != null) { + if (!instructionSet.equals(requiredInstructionSet)) { + // We have a mismatch between instruction sets (say arm vs arm64). + // + // TODO: We should rescan all the packages in a shared UID to check if + // they do contain shared libs for other ABIs in addition to the ones we've + // already extracted. For example, the package might contain both arm64-v8a + // and armeabi-v7a shared libs, and we'd have chosen arm64-v8a on 64 bit + // devices. + String errorMessage = "Instruction set mismatch, " + requirer.pkg.packageName + + " requires " + requiredInstructionSet + " whereas " + ps.pkg.packageName + + " requires " + instructionSet; + Slog.e(TAG, errorMessage); + + reportSettingsProblem(Log.WARN, errorMessage); + // Give up, don't bother making any other changes to the package settings. + return; + } + } else { + requiredInstructionSet = instructionSet; + requirer = ps; + } + } + } + + if (requiredInstructionSet != null) { + for (PackageSetting ps : packagesForUser) { + if (ps.requiredCpuAbiString == null) { + ps.requiredCpuAbiString = requirer.requiredCpuAbiString; + if (ps.pkg != null) { + ps.pkg.applicationInfo.requiredCpuAbi = requirer.requiredCpuAbiString; + Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + ps.requiredCpuAbiString); + if (doDexOpt) { + performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true); + mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet()); + } + } + } + } + } + } + private void setUpCustomResolverActivity(PackageParser.Package pkg) { synchronized (mPackages) { mResolverReplaced = true; @@ -5488,6 +5807,31 @@ public class PackageManagerService extends IPackageManager.Stub { pkgSetting.nativeLibraryPathString = nativeLibraryPath; } + // Deduces the required ABI of an upgraded system app. + private void setInternalAppAbi(PackageParser.Package pkg, PackageSetting pkgSetting) { + final String apkRoot = calculateApkRoot(pkg.applicationInfo.sourceDir); + final String apkName = getApkName(pkg.applicationInfo.sourceDir); + + // This is of the form "/system/lib64/<packagename>", "/vendor/lib64/<packagename>" + // or similar. + final File lib64 = new File(apkRoot, new File(LIB64_DIR_NAME, apkName).getPath()); + final File lib = new File(apkRoot, new File(LIB_DIR_NAME, apkName).getPath()); + + // Assume that the bundled native libraries always correspond to the + // most preferred 32 or 64 bit ABI. + if (lib64.exists()) { + pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_64_BIT_ABIS[0]; + pkgSetting.requiredCpuAbiString = Build.SUPPORTED_64_BIT_ABIS[0]; + } else if (lib.exists()) { + pkg.applicationInfo.requiredCpuAbi = Build.SUPPORTED_32_BIT_ABIS[0]; + pkgSetting.requiredCpuAbiString = Build.SUPPORTED_32_BIT_ABIS[0]; + } else { + // This is the case where the app has no native code. + pkg.applicationInfo.requiredCpuAbi = null; + pkgSetting.requiredCpuAbiString = null; + } + } + private static int copyNativeLibrariesForInternalApp(File scanFile, final File nativeLibraryDir) throws IOException { if (!nativeLibraryDir.isDirectory()) { @@ -8130,7 +8474,8 @@ public class PackageManagerService extends IPackageManager.Stub { int mRet; MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags, - String packageName, String dataDir, int uid, UserHandle user) { + String packageName, String dataDir, String instructionSet, + int uid, UserHandle user) { super(user); this.srcArgs = srcArgs; this.observer = observer; @@ -8139,7 +8484,7 @@ public class PackageManagerService extends IPackageManager.Stub { this.uid = uid; if (srcArgs != null) { Uri packageUri = Uri.fromFile(new File(srcArgs.getCodePath())); - targetArgs = createInstallArgs(packageUri, flags, packageName, dataDir); + targetArgs = createInstallArgs(packageUri, flags, packageName, dataDir, instructionSet); } else { targetArgs = null; } @@ -8248,7 +8593,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath, - String nativeLibraryPath) { + String nativeLibraryPath, String instructionSet) { final boolean isInAsec; if (installOnSd(flags)) { /* Apps on SD card are always in ASEC containers. */ @@ -8266,21 +8611,23 @@ public class PackageManagerService extends IPackageManager.Stub { if (isInAsec) { return new AsecInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath, - installOnSd(flags), installForwardLocked(flags)); + instructionSet, installOnSd(flags), installForwardLocked(flags)); } else { - return new FileInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath); + return new FileInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath, + instructionSet); } } // Used by package mover - private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName, String dataDir) { + private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName, String dataDir, + String instructionSet) { if (installOnSd(flags) || installForwardLocked(flags)) { String cid = getNextCodePath(packageURI.getPath(), pkgName, "/" + AsecInstallArgs.RES_FILE_NAME); - return new AsecInstallArgs(packageURI, cid, installOnSd(flags), + return new AsecInstallArgs(packageURI, cid, instructionSet, installOnSd(flags), installForwardLocked(flags)); } else { - return new FileInstallArgs(packageURI, pkgName, dataDir); + return new FileInstallArgs(packageURI, pkgName, dataDir, instructionSet); } } @@ -8293,11 +8640,12 @@ public class PackageManagerService extends IPackageManager.Stub { final String installerPackageName; final ManifestDigest manifestDigest; final UserHandle user; + final String instructionSet; InstallArgs(Uri packageURI, IPackageInstallObserver observer, IPackageInstallObserver2 observer2, int flags, String installerPackageName, ManifestDigest manifestDigest, - UserHandle user) { + UserHandle user, String instructionSet) { this.packageURI = packageURI; this.flags = flags; this.observer = observer; @@ -8305,6 +8653,7 @@ public class PackageManagerService extends IPackageManager.Stub { this.installerPackageName = installerPackageName; this.manifestDigest = manifestDigest; this.user = user; + this.instructionSet = instructionSet; } abstract void createCopyFile(); @@ -8360,11 +8709,12 @@ public class PackageManagerService extends IPackageManager.Stub { FileInstallArgs(InstallParams params) { super(params.getPackageUri(), params.observer, params.observer2, params.flags, params.installerPackageName, params.getManifestDigest(), - params.getUser()); + params.getUser(), null /* instruction set */); } - FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { - super(null, null, null, 0, null, null, null); + FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath, + String instructionSet) { + super(null, null, null, 0, null, null, null, instructionSet); File codeFile = new File(fullCodePath); installDir = codeFile.getParentFile(); codeFileName = fullCodePath; @@ -8372,8 +8722,8 @@ public class PackageManagerService extends IPackageManager.Stub { libraryPath = nativeLibraryPath; } - FileInstallArgs(Uri packageURI, String pkgName, String dataDir) { - super(packageURI, null, null, 0, null, null, null); + FileInstallArgs(Uri packageURI, String pkgName, String dataDir, String instructionSet) { + super(packageURI, null, null, 0, null, null, null, instructionSet); installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir; String apkName = getNextCodePath(null, pkgName, ".apk"); codeFileName = new File(installDir, apkName + ".apk").getPath(); @@ -8632,7 +8982,10 @@ public class PackageManagerService extends IPackageManager.Stub { void cleanUpResourcesLI() { String sourceDir = getCodePath(); if (cleanUp()) { - int retCode = mInstaller.rmdex(sourceDir); + if (instructionSet == null) { + throw new IllegalStateException("instructionSet == null"); + } + int retCode = mInstaller.rmdex(sourceDir, instructionSet); if (retCode < 0) { Slog.w(TAG, "Couldn't remove dex file for package: " + " at location " @@ -8696,14 +9049,14 @@ public class PackageManagerService extends IPackageManager.Stub { AsecInstallArgs(InstallParams params) { super(params.getPackageUri(), params.observer, params.observer2, params.flags, params.installerPackageName, params.getManifestDigest(), - params.getUser()); + params.getUser(), null /* instruction set */); } AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath, - boolean isExternal, boolean isForwardLocked) { + String instructionSet, boolean isExternal, boolean isForwardLocked) { super(null, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0) | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), - null, null, null); + null, null, null, instructionSet); // Extract cid from fullCodePath int eidx = fullCodePath.lastIndexOf("/"); String subStr1 = fullCodePath.substring(0, eidx); @@ -8712,18 +9065,19 @@ public class PackageManagerService extends IPackageManager.Stub { setCachePath(subStr1); } - AsecInstallArgs(String cid, boolean isForwardLocked) { + AsecInstallArgs(String cid, String instructionSet, boolean isForwardLocked) { super(null, null, null, (isAsecExternal(cid) ? PackageManager.INSTALL_EXTERNAL : 0) | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), - null, null, null); + null, null, null, instructionSet); this.cid = cid; setCachePath(PackageHelper.getSdDir(cid)); } - AsecInstallArgs(Uri packageURI, String cid, boolean isExternal, boolean isForwardLocked) { + AsecInstallArgs(Uri packageURI, String cid, String instructionSet, + boolean isExternal, boolean isForwardLocked) { super(packageURI, null, null, (isExternal ? PackageManager.INSTALL_EXTERNAL : 0) | (isForwardLocked ? PackageManager.INSTALL_FORWARD_LOCK : 0), - null, null, null); + null, null, null, instructionSet); this.cid = cid; } @@ -8904,7 +9258,10 @@ public class PackageManagerService extends IPackageManager.Stub { void cleanUpResourcesLI() { String sourceFile = getCodePath(); // Remove dex file - int retCode = mInstaller.rmdex(sourceFile); + if (instructionSet == null) { + throw new IllegalStateException("instructionSet == null"); + } + int retCode = mInstaller.rmdex(sourceFile, instructionSet); if (retCode < 0) { Slog.w(TAG, "Couldn't remove dex file for package: " + " at location " @@ -9289,7 +9646,8 @@ public class PackageManagerService extends IPackageManager.Stub { res.removedInfo.args = createInstallArgs(0, deletedPackage.applicationInfo.sourceDir, deletedPackage.applicationInfo.publicSourceDir, - deletedPackage.applicationInfo.nativeLibraryDir); + deletedPackage.applicationInfo.nativeLibraryDir, + getAppInstructionSet(deletedPackage.applicationInfo)); } else { res.removedInfo.args = null; } @@ -9349,7 +9707,8 @@ public class PackageManagerService extends IPackageManager.Stub { private int moveDexFilesLI(PackageParser.Package newPackage) { int retCode; if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { - retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath); + retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath, + getAppInstructionSet(newPackage.applicationInfo)); if (retCode != 0) { if (mNoDexOpt) { /* @@ -10035,7 +10394,8 @@ public class PackageManagerService extends IPackageManager.Stub { // Delete application code and resources if (deleteCodeAndResources && (outInfo != null)) { outInfo.args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString, - ps.resourcePathString, ps.nativeLibraryPathString); + ps.resourcePathString, ps.nativeLibraryPathString, + getAppInstructionSetFromSettings(ps)); } return true; } @@ -10405,9 +10765,10 @@ public class PackageManagerService extends IPackageManager.Stub { boolean dataOnly = false; String libDirPath = null; String asecPath = null; + PackageSetting ps = null; synchronized (mPackages) { p = mPackages.get(packageName); - PackageSetting ps = mSettings.mPackages.get(packageName); + ps = mSettings.mPackages.get(packageName); if(p == null) { dataOnly = true; if((ps == null) || (ps.pkg == null)) { @@ -10438,7 +10799,8 @@ public class PackageManagerService extends IPackageManager.Stub { } } int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, libDirPath, - publicSrcDir, asecPath, pStats); + publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps), + pStats); if (res < 0) { return false; } @@ -10750,6 +11112,47 @@ public class PackageManagerService extends IPackageManager.Stub { } } + /* + * 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"); + } + 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)); + 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"); + } + synchronized (mPackages) { + ForwardingIntentResolver fir = mSettings.editForwardingIntentResolverLPw(userIdOrig); + HashSet<ForwardingIntentFilter> set = + new HashSet<ForwardingIntentFilter>(fir.filterSet()); + for (ForwardingIntentFilter fif : set) { + fir.removeFilter(fif); + } + mSettings.writePackageRestrictionsLPr(userIdOrig); + } + } + @Override public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) { Intent intent = new Intent(Intent.ACTION_MAIN); @@ -11627,7 +12030,9 @@ public class PackageManagerService extends IPackageManager.Stub { continue; } - final AsecInstallArgs args = new AsecInstallArgs(cid, isForwardLocked(ps)); + final AsecInstallArgs args = new AsecInstallArgs(cid, + getAppInstructionSetFromSettings(ps), + isForwardLocked(ps)); // The package status is changed only if the code path // matches between settings and the container id. if (ps.codePathString != null && ps.codePathString.equals(args.getCodePath())) { @@ -11945,15 +12350,17 @@ public class PackageManagerService extends IPackageManager.Stub { * anyway. */ if (returnCode != PackageManager.MOVE_SUCCEEDED) { - processPendingMove(new MoveParams(null, observer, 0, packageName, + processPendingMove(new MoveParams(null, observer, 0, packageName, null, null, -1, user), returnCode); } else { Message msg = mHandler.obtainMessage(INIT_COPY); + final String instructionSet = getAppInstructionSet(pkg.applicationInfo); InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir, - pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir); + pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir, + instructionSet); MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName, - pkg.applicationInfo.dataDir, pkg.applicationInfo.uid, user); + pkg.applicationInfo.dataDir, instructionSet, pkg.applicationInfo.uid, user); msg.obj = mp; mHandler.sendMessage(msg); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index a69940f..599d2a7 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -36,6 +36,7 @@ import com.android.internal.util.JournaledFile; import com.android.internal.util.XmlUtils; import com.android.server.pm.PackageManagerService.DumpState; +import java.util.Collection; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -97,7 +98,7 @@ final class Settings { * Note that care should be taken to make sure all database upgrades are * idempotent. */ - private static final int CURRENT_DATABASE_VERSION = DatabaseVersion.FIRST_VERSION; + private static final int CURRENT_DATABASE_VERSION = DatabaseVersion.SIGNATURE_END_ENTITY; /** * This class contains constants that can be referred to from upgrade code. @@ -109,6 +110,12 @@ final class Settings { * The initial version of the database. */ public static final int FIRST_VERSION = 1; + + /** + * Migrating the Signature array from the entire certificate chain to + * just the signing certificate. + */ + public static final int SIGNATURE_END_ENTITY = 2; } private static final boolean DEBUG_STOPPED = false; @@ -124,6 +131,8 @@ final class Settings { private static final String TAG_PACKAGE = "pkg"; private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES = "persistent-preferred-activities"; + static final String TAG_FORWARDING_INTENT_FILTERS = + "forwarding-intent-filters"; private static final String ATTR_NAME = "name"; private static final String ATTR_USER = "user"; @@ -178,6 +187,10 @@ final class Settings { final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities = new SparseArray<PersistentPreferredIntentResolver>(); + // For every user, it is used to find to which other users the intent can be forwarded. + final SparseArray<ForwardingIntentResolver> mForwardingIntentResolvers = + new SparseArray<ForwardingIntentResolver>(); + final HashMap<String, SharedUserSetting> mSharedUsers = new HashMap<String, SharedUserSetting>(); private final ArrayList<Object> mUserIds = new ArrayList<Object>(); @@ -296,6 +309,11 @@ final class Settings { return s; } + Collection<SharedUserSetting> getAllSharedUsersLPw() { + return mSharedUsers.values(); + } + + boolean disableSystemPackageLPw(String name) { final PackageSetting p = mPackages.get(name); if(p == null) { @@ -825,6 +843,15 @@ final class Settings { return ppir; } + ForwardingIntentResolver editForwardingIntentResolverLPw(int userId) { + ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId); + if (fir == null) { + fir = new ForwardingIntentResolver(); + mForwardingIntentResolvers.put(userId, fir); + } + return fir; + } + private File getUserPackagesStateFile(int userId) { return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml"); } @@ -940,6 +967,28 @@ final class Settings { } } + private void readForwardingIntentFiltersLPw(XmlPullParser parser, int userId) + throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + String tagName = parser.getName(); + if (tagName.equals(TAG_ITEM)) { + ForwardingIntentFilter fif = new ForwardingIntentFilter(parser); + editForwardingIntentResolverLPw(userId).addFilter(fif); + } else { + String msg = "Unknown element under " + TAG_FORWARDING_INTENT_FILTERS + ": " + + parser.getName(); + PackageManagerService.reportSettingsProblem(Log.WARN, msg); + XmlUtils.skipCurrentTag(parser); + } + } + } + void readPackageRestrictionsLPr(int userId) { if (DEBUG_MU) { Log.i(TAG, "Reading package restrictions for user=" + userId); @@ -1068,6 +1117,8 @@ final class Settings { readPreferredActivitiesLPw(parser, userId); } else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) { readPersistentPreferredActivitiesLPw(parser, userId); + } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) { + readForwardingIntentFiltersLPw(parser, userId); } else { Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: " + parser.getName()); @@ -1145,6 +1196,20 @@ final class Settings { serializer.endTag(null, TAG_PERSISTENT_PREFERRED_ACTIVITIES); } + void writeForwardingIntentFiltersLPr(XmlSerializer serializer, int userId) + throws IllegalArgumentException, IllegalStateException, IOException { + serializer.startTag(null, TAG_FORWARDING_INTENT_FILTERS); + ForwardingIntentResolver fir = mForwardingIntentResolvers.get(userId); + if (fir != null) { + for (final ForwardingIntentFilter fif : fir.filterSet()) { + serializer.startTag(null, TAG_ITEM); + fif.writeToXml(serializer); + serializer.endTag(null, TAG_ITEM); + } + } + serializer.endTag(null, TAG_FORWARDING_INTENT_FILTERS); + } + void writePackageRestrictionsLPr(int userId) { if (DEBUG_MU) { Log.i(TAG, "Writing package restrictions for user=" + userId); @@ -1243,6 +1308,8 @@ final class Settings { writePersistentPreferredActivitiesLPr(serializer, userId); + writeForwardingIntentFiltersLPr(serializer, userId); + serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS); serializer.endDocument(); @@ -1860,6 +1927,10 @@ final class Settings { // TODO: check whether this is okay! as it is very // similar to how preferred-activities are treated readPersistentPreferredActivitiesLPw(parser, 0); + } else if (tagName.equals(TAG_FORWARDING_INTENT_FILTERS)) { + // TODO: check whether this is okay! as it is very + // similar to how preferred-activities are treated + readForwardingIntentFiltersLPw(parser, 0); } else if (tagName.equals("updated-package")) { readDisabledSysPackageLPw(parser); } else if (tagName.equals("cleaning-package")) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index f8103de..3239b46 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -23,7 +23,6 @@ import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.IStopUserCallback; -import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -274,16 +273,6 @@ public class UserManagerService extends IUserManager.Stub { /** Assume permissions already checked and caller's identity cleared */ private List<UserInfo> getProfilesLocked(int userId, boolean enabledOnly) { - // Getting the service here is not good for testing purposes. - // However, this service is not available when UserManagerService starts - // up so we need a lazy load. - - DevicePolicyManager dpm = null; - if (enabledOnly) { - dpm = (DevicePolicyManager) - mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - } - UserInfo user = getUserInfoLocked(userId); ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); for (int i = 0; i < mUsers.size(); i++) { @@ -291,23 +280,8 @@ public class UserManagerService extends IUserManager.Stub { if (!isProfileOf(user, profile)) { continue; } - - if (enabledOnly && profile.isManagedProfile()) { - if (dpm != null) { - if (!dpm.isProfileEnabled(profile.id)) { - continue; - } - } else { - Log.w(LOG_TAG, - "Attempting to reach DevicePolicyManager before it is started"); - // TODO: There might be system apps that need to call this. - // Make sure that DevicePolicyManagerService is ready at that - // time (otherwise, any default value is a bad one). - throw new IllegalArgumentException(String.format( - "Attempting to get enabled profiles for %d before " - + "DevicePolicyManagerService has been started.", - userId)); - } + if (enabledOnly && !profile.isEnabled()) { + continue; } users.add(profile); } @@ -321,6 +295,18 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public void setUserEnabled(int userId) { + checkManageUsersPermission("enable user"); + synchronized (mPackagesLock) { + UserInfo info = getUserInfoLocked(userId); + if (info != null && !info.isEnabled()) { + info.flags ^= UserInfo.FLAG_DISABLED; + writeUserLocked(info); + } + } + } + + @Override public UserInfo getUserInfo(int userId) { checkManageUsersPermission("query user"); synchronized (mPackagesLock) { @@ -1106,6 +1092,9 @@ public class UserManagerService extends IUserManager.Stub { // 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); @@ -1134,6 +1123,7 @@ public class UserManagerService extends IUserManager.Stub { // 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, @@ -1154,6 +1144,11 @@ public class UserManagerService extends IUserManager.Stub { removeUserStateLocked(userHandle); } } + // Send broadcast to notify system that the user removed was a + // managed user. + if (isManaged) { + sendProfileRemovedBroadcast(userHandle); + } } }.start(); } @@ -1205,6 +1200,13 @@ public class UserManagerService extends IUserManager.Stub { 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..d9e95c7 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -409,7 +409,7 @@ final class Notifier { EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0); - mPolicy.screenTurningOn(mScreenOnListener); + mPolicy.wakingUp(mScreenOnListener); mActivityManagerInternal.wakingUp(); if (ActivityManagerNative.isSystemReady()) { @@ -460,7 +460,7 @@ final class Notifier { 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..6d2e859 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 @@ public final class PowerManagerService extends com.android.server.SystemService 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/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 class SearchManagerService extends ISearchManager.Stub { */ 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/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index a2a49c9..9061f96 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -187,7 +187,7 @@ public class TrustManagerService extends SystemService { boolean trustMayHaveChanged = false; for (int i = 0; i < mObsoleteAgents.size(); i++) { - AgentInfo info = mActiveAgents.valueAt(i); + AgentInfo info = mObsoleteAgents.valueAt(i); if (info.agent.isTrusted()) { trustMayHaveChanged = true; } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 649f9dc..50dd27d 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -554,6 +554,10 @@ public final class TvInputManagerService extends SystemService { } } } finally { + if (surface != null) { + // surface is not used in TvInputManagerService. + surface.release(); + } Binder.restoreCallingIdentity(identity); } } diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp index f3e8f3c..527216d 100644 --- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp @@ -19,57 +19,173 @@ #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); private: + // 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); +} + +// 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 JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J", (void *) nativeInit }, + { "nativeSendCecCommand", "(JII[B)I", + (void *) nativeSendCecCommand }, }; #define CLASS_PATH "com/android/server/hdmi/HdmiCecController" diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp index 54c9755..6e03993 100644 --- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp +++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp @@ -67,10 +67,10 @@ public: cec_logical_address_t getLogicalAddress(cec_device_type_t deviceType); uint16_t getPhysicalAddress(); - int getDeviceType(cec_logical_address_t addr); + cec_device_type_t getDeviceType(cec_logical_address_t addr); void queueMessage(const MessageEntry& message); void queueOutgoingMessage(const cec_message_t& message); - void sendReportPhysicalAddress(); + void sendReportPhysicalAddress(cec_logical_address_t srcAddr); void sendActiveSource(cec_logical_address_t srcAddr); void sendFeatureAbort(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr, int opcode, int reason); @@ -93,15 +93,41 @@ private: EVENT_TYPE_STANDBY }; + /* + * logical address pool for each device type. + */ + static const cec_logical_address_t TV_ADDR_POOL[]; + static const cec_logical_address_t PLAYBACK_ADDR_POOL[]; + static const cec_logical_address_t RECORDER_ADDR_POOL[]; + static const cec_logical_address_t TUNER_ADDR_POOL[]; + static const unsigned int MAX_BUFFER_SIZE = 256; static const uint16_t INVALID_PHYSICAL_ADDRESS = 0xFFFF; - static const int INACTIVE_DEVICE_TYPE = -1; static void onReceived(const hdmi_event_t* event, void* arg); static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); void updatePhysicalAddress(); void updateLogicalAddress(); + + // Allocate logical address. The CEC standard recommends that we try to use the address + // we have ever used before, in case this is to allocate an address afte the cable is + // connected again. If preferredAddr is given a valid one (not CEC_ADDR_UNREGISTERED), then + // this method checks if the address is available first. If not, it tries other addresses + // int the address pool available for the given type. + cec_logical_address_t allocateLogicalAddress(cec_device_type_t type, + cec_logical_address_t preferredAddr); + + // Send a CEC ping message. Returns true if successful. + bool sendPing(cec_logical_address_t addr); + + // Return the pool of logical addresses that are used for a given device type. + // One of the addresses in the pool will be chosen in the allocation logic. + bool getLogicalAddressPool(cec_device_type_t type, const cec_logical_address_t** addrPool, + size_t* poolSize); + + // Handles the message retrieved from internal message queue. The message can be + // for either rx or tx. void dispatchMessage(const MessageEntry& message); void processIncomingMessage(const cec_message_t& msg); @@ -159,6 +185,29 @@ private: std::string mOsdName; }; + const cec_logical_address_t HdmiCecHandler::TV_ADDR_POOL[] = { + CEC_ADDR_TV, + CEC_ADDR_FREE_USE, + }; + + const cec_logical_address_t HdmiCecHandler::PLAYBACK_ADDR_POOL[] = { + CEC_ADDR_PLAYBACK_1, + CEC_ADDR_PLAYBACK_2, + CEC_ADDR_PLAYBACK_3 + }; + + const cec_logical_address_t HdmiCecHandler::RECORDER_ADDR_POOL[] = { + CEC_ADDR_RECORDER_1, + CEC_ADDR_RECORDER_2, + CEC_ADDR_RECORDER_3 + }; + + const cec_logical_address_t HdmiCecHandler::TUNER_ADDR_POOL[] = { + CEC_ADDR_TUNER_1, + CEC_ADDR_TUNER_2, + CEC_ADDR_TUNER_3, + CEC_ADDR_TUNER_4 + }; HdmiCecHandler::HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj) : mDevice(device), @@ -176,39 +225,15 @@ uint16_t HdmiCecHandler::getPhysicalAddress() { return mPhysicalAddress; } -void HdmiCecHandler::updatePhysicalAddress() { - uint16_t addr; - if (!mDevice->get_physical_address(mDevice, &addr)) { - mPhysicalAddress = addr; - } else { - mPhysicalAddress = INVALID_PHYSICAL_ADDRESS; - } -} - -void HdmiCecHandler::updateLogicalAddress() { - std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin(); - for (; it != mLogicalDevices.end(); ++it) { - cec_logical_address_t addr; - if (!mDevice->get_logical_address(mDevice, it->first, &addr)) { - it->second = addr; - } - } -} - cec_logical_address_t HdmiCecHandler::initLogicalDevice(cec_device_type_t type) { - cec_logical_address_t addr; - int res = mDevice->allocate_logical_address(mDevice, type, &addr); - - if (res != 0) { - ALOGE("Logical Address Allocation failed: %d", res); - } else { - ALOGV("Logical Address Allocation success: %d", addr); + cec_logical_address addr = allocateLogicalAddress(type, CEC_ADDR_UNREGISTERED); + if (addr != CEC_ADDR_UNREGISTERED && !mDevice->add_logical_address(mDevice, addr)) { mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr)); // Broadcast <Report Physical Address> when a new logical address was allocated to let // other devices discover the new logical device and its logical - physical address // association. - sendReportPhysicalAddress(); + sendReportPhysicalAddress(addr); } return addr; } @@ -229,14 +254,14 @@ cec_logical_address_t HdmiCecHandler::getLogicalAddress(cec_device_type_t type) return CEC_ADDR_UNREGISTERED; } -int HdmiCecHandler::getDeviceType(cec_logical_address_t addr) { +cec_device_type_t HdmiCecHandler::getDeviceType(cec_logical_address_t addr) { std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin(); for (; it != mLogicalDevices.end(); ++it) { if (it->second == addr) { return it->first; } } - return INACTIVE_DEVICE_TYPE; + return CEC_DEVICE_INACTIVE; } void HdmiCecHandler::queueMessage(const MessageEntry& entry) { @@ -256,26 +281,26 @@ void HdmiCecHandler::queueOutgoingMessage(const cec_message_t& message) { queueMessage(entry); } -void HdmiCecHandler::sendReportPhysicalAddress() { +void HdmiCecHandler::sendReportPhysicalAddress(cec_logical_address_t addr) { if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) { ALOGE("Invalid physical address."); return; } - - // Report physical address for each logical one hosted in it. - std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin(); - while (it != mLogicalDevices.end()) { - cec_message_t msg; - msg.initiator = it->second; // logical address - msg.destination = CEC_ADDR_BROADCAST; - msg.length = 4; - msg.body[0] = CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS; - msg.body[1] = (mPhysicalAddress >> 8) & 0xff; - msg.body[2] = mPhysicalAddress & 0xff; - msg.body[3] = it->first; // device type - queueOutgoingMessage(msg); - ++it; + cec_device_type_t deviceType = getDeviceType(addr); + if (deviceType == CEC_DEVICE_INACTIVE) { + ALOGE("Invalid logical address: %d", addr); + return; } + + cec_message_t msg; + msg.initiator = addr; + msg.destination = CEC_ADDR_BROADCAST; + msg.length = 4; + msg.body[0] = CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS; + msg.body[1] = (mPhysicalAddress >> 8) & 0xff; + msg.body[2] = mPhysicalAddress & 0xff; + msg.body[3] = deviceType; + queueOutgoingMessage(msg); } void HdmiCecHandler::sendActiveSource(cec_logical_address_t srcAddr) { @@ -410,6 +435,99 @@ void HdmiCecHandler::checkAndClearExceptionFromCallback(JNIEnv* env, const char* } } +void HdmiCecHandler::updatePhysicalAddress() { + uint16_t addr; + if (!mDevice->get_physical_address(mDevice, &addr)) { + mPhysicalAddress = addr; + } else { + mPhysicalAddress = INVALID_PHYSICAL_ADDRESS; + } +} + +void HdmiCecHandler::updateLogicalAddress() { + mDevice->clear_logical_address(mDevice); + std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin(); + for (; it != mLogicalDevices.end(); ++it) { + cec_logical_address_t addr; + cec_logical_address_t preferredAddr = it->second; + cec_device_type_t deviceType = it->first; + addr = allocateLogicalAddress(deviceType, preferredAddr); + if (!mDevice->add_logical_address(mDevice, addr)) { + it->second = addr; + } else { + it->second = CEC_ADDR_UNREGISTERED; + } + } +} + +cec_logical_address_t HdmiCecHandler::allocateLogicalAddress(cec_device_type_t type, + cec_logical_address_t preferredAddr) { + const cec_logical_address_t* addrPool; + size_t poolSize; + if (getLogicalAddressPool(type, &addrPool, &poolSize) < 0) { + return CEC_ADDR_UNREGISTERED; + } + unsigned start = 0; + + // Find the index of preferred address in the pool. If not found, the start + // position will be 0. This happens when the passed preferredAddr is set to + // CEC_ADDR_UNREGISTERED, meaning that no preferred address is given. + for (unsigned i = 0; i < poolSize; i++) { + if (addrPool[i] == preferredAddr) { + start = i; + break; + } + } + for (unsigned i = 0; i < poolSize; i++) { + cec_logical_address_t addr = addrPool[(start + i) % poolSize]; + if (!sendPing(addr)) { + // Failure in pinging means the address is available, not taken by any device. + ALOGV("Logical Address Allocation success: %d", addr); + return addr; + } + } + ALOGE("Logical Address Allocation failed"); + return CEC_ADDR_UNREGISTERED; +} + +bool HdmiCecHandler::sendPing(cec_logical_address addr) { + cec_message_t msg; + msg.initiator = msg.destination = addr; + msg.length = 0; + return !mDevice->send_message(mDevice, &msg); + +} + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +bool HdmiCecHandler::getLogicalAddressPool(cec_device_type_t deviceType, + const cec_logical_address_t** addrPool, size_t* poolSize) { + switch (deviceType) { + case CEC_DEVICE_TV: + *addrPool = TV_ADDR_POOL; + *poolSize = ARRAY_SIZE(TV_ADDR_POOL); + break; + case CEC_DEVICE_RECORDER: + *addrPool = RECORDER_ADDR_POOL; + *poolSize = ARRAY_SIZE(RECORDER_ADDR_POOL); + break; + case CEC_DEVICE_TUNER: + *addrPool = TUNER_ADDR_POOL; + *poolSize = ARRAY_SIZE(TUNER_ADDR_POOL); + break; + case CEC_DEVICE_PLAYBACK: + *addrPool = PLAYBACK_ADDR_POOL; + *poolSize = ARRAY_SIZE(PLAYBACK_ADDR_POOL); + break; + default: + ALOGE("Unsupported device type: %d", deviceType); + return false; + } + return true; +} + +#undef ARRAY_SIZE + void HdmiCecHandler::dispatchMessage(const MessageEntry& entry) { int type = entry.first; mMessageQueueLock.unlock(); @@ -434,7 +552,7 @@ void HdmiCecHandler::dispatchMessage(const MessageEntry& entry) { void HdmiCecHandler::processIncomingMessage(const cec_message_t& msg) { int opcode = msg.body[0]; if (opcode == CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS) { - sendReportPhysicalAddress(); + sendReportPhysicalAddress(msg.destination); } else if (opcode == CEC_MESSAGE_REQUEST_ACTIVE_SOURCE) { handleRequestActiveSource(); } else if (opcode == CEC_MESSAGE_GET_OSD_NAME) { @@ -507,7 +625,7 @@ void HdmiCecHandler::handleRequestActiveSource() { JNIEnv* env = AndroidRuntime::getJNIEnv(); jint activeDeviceType = env->CallIntMethod(mCallbacksObj, gHdmiCecServiceClassInfo.getActiveSource); - if (activeDeviceType != INACTIVE_DEVICE_TYPE) { + if (activeDeviceType != CEC_DEVICE_INACTIVE) { sendActiveSource(getLogicalAddress(static_cast<cec_device_type_t>(activeDeviceType))); } checkAndClearExceptionFromCallback(env, __FUNCTION__); diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 4085991..34ae8b4 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -870,7 +870,7 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) { if (policyFlags & POLICY_FLAG_INTERACTIVE) { policyFlags |= POLICY_FLAG_PASS_TO_USER; - } else if (policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED)) { + } else if (policyFlags & POLICY_FLAG_WAKE) { JNIEnv* env = jniEnv(); jint wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptWakeMotionBeforeQueueing, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java index 3c46e40..1647425 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java @@ -53,7 +53,6 @@ public class DeviceOwner { private static final String ATTR_NAME = "name"; private static final String ATTR_PACKAGE = "package"; private static final String ATTR_USERID = "userId"; - private static final String ATTR_ENABLED = "profileEnabled"; private AtomicFile fileForWriting; @@ -104,8 +103,7 @@ public class DeviceOwner { */ static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) { DeviceOwner owner = new DeviceOwner(); - owner.mProfileOwners.put( - userId, new OwnerInfo(ownerName, packageName, false /* disabled */)); + owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName)); return owner; } @@ -122,7 +120,7 @@ public class DeviceOwner { } void setProfileOwner(String packageName, String ownerName, int userId) { - mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName, false /* disabled */)); + mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName)); } void removeProfileOwner(int userId) { @@ -139,19 +137,6 @@ public class DeviceOwner { return profileOwner != null ? profileOwner.name : null; } - boolean isProfileEnabled(int userId) { - OwnerInfo profileOwner = mProfileOwners.get(userId); - return profileOwner != null ? profileOwner.enabled : true; - } - - void setProfileEnabled(int userId) { - OwnerInfo profileOwner = mProfileOwners.get(userId); - if (profileOwner == null) { - throw new IllegalArgumentException("No profile owner exists."); - } - profileOwner.enabled = true; - } - boolean hasDeviceOwner() { return mDeviceOwner != null; } @@ -203,12 +188,9 @@ public class DeviceOwner { } else if (tag.equals(TAG_PROFILE_OWNER)) { String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE); String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME); - Boolean profileEnabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_ENABLED)); int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID)); mProfileOwners.put(userId, - new OwnerInfo( - profileOwnerName, profileOwnerPackageName, profileEnabled)); + new OwnerInfo(profileOwnerName, profileOwnerPackageName)); } else { throw new XmlPullParserException( "Unexpected tag in device owner file: " + tag); @@ -251,7 +233,6 @@ public class DeviceOwner { out.startTag(null, TAG_PROFILE_OWNER); out.attribute(null, ATTR_PACKAGE, owner.getValue().packageName); out.attribute(null, ATTR_NAME, owner.getValue().name); - out.attribute(null, ATTR_ENABLED, String.valueOf(owner.getValue().enabled)); out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey())); out.endTag(null, TAG_PROFILE_OWNER); } @@ -292,12 +273,6 @@ public class DeviceOwner { static class OwnerInfo { public String name; public String packageName; - public boolean enabled = true; // only makes sense for managed profiles - - public OwnerInfo(String name, String packageName, boolean enabled) { - this(name, packageName); - this.enabled = enabled; - } public OwnerInfo(String name, String packageName) { this.name = name; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f1ee280..d0a6db1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -588,6 +588,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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); @@ -2903,11 +2904,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int userId = UserHandle.getCallingUserId(); Slog.d(LOG_TAG, "Enabling the profile for: " + userId); - mDeviceOwner.setProfileEnabled(userId); - mDeviceOwner.writeOwnerFile(); - + UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { + um.setUserEnabled(userId); Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED); intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId())); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | @@ -2948,23 +2948,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } - @Override - public boolean isProfileEnabled(int userHandle) { - if (!mHasFeature) { - // If device policy management is not enabled, then the userHandle cannot belong to a - // managed profile. All other profiles are considered enabled. - return true; - } - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); - - synchronized (this) { - if (mDeviceOwner != null) { - return mDeviceOwner.isProfileEnabled(userHandle); - } - } - return true; - } - private boolean isDeviceProvisioned() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) > 0; @@ -3099,6 +3082,51 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + public void forwardMatchingIntents(ComponentName who, IntentFilter filter, int flags) { + int callingUserId = UserHandle.getCallingUserId(); + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + IPackageManager pm = AppGlobals.getPackageManager(); + long id = Binder.clearCallingIdentity(); + try { + if ((flags & DevicePolicyManager.FLAG_TO_PRIMARY_USER) != 0) { + pm.addForwardingIntentFilter(filter, callingUserId, UserHandle.USER_OWNER); + } + if ((flags & DevicePolicyManager.FLAG_TO_MANAGED_PROFILE) != 0) { + pm.addForwardingIntentFilter(filter, UserHandle.USER_OWNER, callingUserId); + } + } catch (RemoteException re) { + // Shouldn't happen + } finally { + restoreCallingIdentity(id); + } + } + } + + public void clearForwardingIntentFilters(ComponentName who) { + int callingUserId = UserHandle.getCallingUserId(); + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + IPackageManager pm = AppGlobals.getPackageManager(); + long id = Binder.clearCallingIdentity(); + try { + pm.clearForwardingIntentFilters(callingUserId); + pm.clearForwardingIntentFilters(UserHandle.USER_OWNER); + } catch (RemoteException re) { + // Shouldn't happen + } finally { + restoreCallingIdentity(id); + } + } + } + @Override public Bundle getApplicationRestrictions(ComponentName who, String packageName) { final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3d82027..7c9f7a8 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -923,7 +923,6 @@ public final class SystemServer { } try { - Slog.i(TAG, "MediaSessionService"); mSystemServiceManager.startService(MediaSessionService.class); } catch (Throwable e) { reportWtf("starting MediaSessionService", e); 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 @@ public class UsbDeviceManager { 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/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 @@ public class ServiceState implements Parcelable { 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 class TelephonyManager { 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 class TelephonyManager { 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 @@ public class TelephonyManager { return "iDEN"; case NETWORK_TYPE_HSPAP: return "HSPA+"; + case NETWORK_TYPE_GSM: + return "GSM"; default: return "UNKNOWN"; } diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 5c2583b..af0d0ad 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -288,6 +288,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..f060bc8 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.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)); + + 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/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 @@ public class SmallCircleActivity extends Activity { 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..2e029f0 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java @@ -119,7 +119,9 @@ public class PlayerSession { } 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 +134,7 @@ public class PlayerSession { @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 +149,33 @@ public class PlayerSession { 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 +189,8 @@ public class PlayerSession { @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 @@ public class OneMediaRouteProvider extends RouteProviderService { 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 @@ public class OneMediaRouteProvider extends RouteProviderService { @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 09531fd..8f9cf58 100644 --- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java +++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java @@ -1,17 +1,13 @@ package com.example.renderthread; -import android.animation.TimeInterpolator; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; -import android.os.SystemClock; -import android.view.RenderNode; import android.view.HardwareRenderer; -import android.view.ThreadedRenderer; +import android.view.RenderNodeAnimator; import android.view.View; -import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; @@ -66,82 +62,21 @@ public class MainActivity extends Activity implements OnItemClickListener { } } - private static class DisplayListAnimator { - private static final TimeInterpolator sDefaultInterpolator = - new AccelerateDecelerateInterpolator(); - - RenderNode mDisplayList; - float mFromValue; - float mDelta; - long mDuration = DURATION * 2; - long mStartTime; - - DisplayListAnimator(View view, float translateXBy) { - mDelta = translateXBy; - mFromValue = view.getTranslationY(); - mDisplayList = view.getDisplayList(); - } - - boolean animate(long currentTime) { - if (mStartTime == 0) mStartTime = currentTime; - - float fraction = (float)(currentTime - mStartTime) / mDuration; - if (fraction > 1) { - return false; - } - fraction = sDefaultInterpolator.getInterpolation(fraction); - float translation = mFromValue + (mDelta * fraction); - mDisplayList.setTranslationY(translation); - return fraction < 1f; - } - } - - private static class AnimationExecutor implements Runnable { - DisplayListAnimator[] mAnimations; - ThreadedRenderer mRenderer; - - AnimationExecutor(ThreadedRenderer renderer, DisplayListAnimator[] animations) { - mRenderer = renderer; - mAnimations = animations; - ThreadedRenderer.postToRenderThread(this); - } - - @Override - public void run() { - boolean hasMore = false; - long now = SystemClock.uptimeMillis(); - for (DisplayListAnimator animator : mAnimations) { - hasMore |= animator.animate(now); - } - mRenderer.repeatLastDraw(); - if (hasMore) { - ThreadedRenderer.postToRenderThread(this); - } - } - - } - @Override public void onItemClick(final AdapterView<?> adapterView, View clickedView, int clickedPosition, long clickedId) { int topPosition = adapterView.getFirstVisiblePosition(); int dy = adapterView.getHeight(); - final DisplayListAnimator[] animators = new DisplayListAnimator[adapterView.getChildCount()]; for (int i = 0; i < adapterView.getChildCount(); i++) { int pos = topPosition + i; View child = adapterView.getChildAt(i); float delta = (pos - clickedPosition) * 1.1f; if (delta == 0) delta = -1; - animators[i] = new DisplayListAnimator(child, dy * delta); + RenderNodeAnimator animator = new RenderNodeAnimator( + RenderNodeAnimator.TRANSLATION_Y, RenderNodeAnimator.DELTA_TYPE_DELTA, dy * delta); + animator.setDuration(DURATION); + animator.start(child); } - adapterView.invalidate(); - adapterView.post(new Runnable() { - - @Override - public void run() { - new AnimationExecutor((ThreadedRenderer) adapterView.getHardwareRenderer(), animators); - } - }); //mHandler.postDelayed(mLaunchActivity, (long) (DURATION * .4)); mLaunchActivity.run(); } diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 25bb26e..b445b8a 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -1340,7 +1340,6 @@ status_t compileResourceFile(Bundle* bundle, name, locale, SourcePos(in->getPrintableSource(), block.getLineNumber())); - curIsPseudolocalizable = fileIsTranslatable; } if (formatted == false16) { @@ -1352,7 +1351,7 @@ status_t compileResourceFile(Bundle* bundle, curType = string16; curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING; curIsStyled = true; - curIsPseudolocalizable = (translatable != false16); + curIsPseudolocalizable = fileIsTranslatable && (translatable != false16); } else if (strcmp16(block.getElementName(&len), drawable16.string()) == 0) { curTag = &drawable16; curType = drawable16; 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..cdb839a 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 @@ public class BridgeMenuItemImpl extends MenuItemImpl { * at the time of rendering. */ private Object viewCookie; + private BridgeContext mContext; /** * Instantiates this menu item. @@ -34,14 +41,28 @@ public class BridgeMenuItemImpl extends MenuItemImpl { 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 49027c6..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 @@ -23,8 +23,10 @@ import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle; import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.ResourceValue; import com.android.ide.common.rendering.api.SessionParams; +import com.android.ide.common.rendering.api.SystemViewCookie; import com.android.internal.R; import com.android.internal.app.WindowDecorActionBar; +import com.android.internal.util.Predicate; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuItemImpl; import com.android.internal.widget.ActionBarAccessor; @@ -48,6 +50,7 @@ import android.view.LayoutInflater; 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; @@ -56,6 +59,8 @@ import android.widget.RelativeLayout; import java.util.ArrayList; +import static com.android.ide.common.rendering.api.SystemViewCookie.ACTION_BAR_OVERFLOW; + /** * A layout representing the action bar. */ @@ -164,10 +169,34 @@ public class ActionBarLayout extends LinearLayout { } // Set action bar to be split, if needed. - mActionBarView.setSplitView((ActionBarContainer) findViewById(R.id.split_action_bar)); + ActionBarContainer splitView = (ActionBarContainer) findViewById(R.id.split_action_bar); + mActionBarView.setSplitView(splitView); mActionBarView.setSplitActionBar(mSplit); inflateMenus(); + + // Find if the Overflow Menu Button (the three dots) exists. If yes, + // add the view cookie. + Predicate<View> overflowMenuButtonTest = new Predicate<View>() { + @Override + public boolean apply(View view) { + ViewGroup.LayoutParams lp = view.getLayoutParams(); + return lp instanceof ActionMenuView.LayoutParams && + ((ActionMenuView.LayoutParams) lp).isOverflowButton; + } + }; + View overflowMenu = null; + if (mSplit) { + if (splitView != null) { + overflowMenu = splitView.findViewByPredicate(overflowMenuButtonTest); + } + } + else { + overflowMenu = mActionBarView.findViewByPredicate(overflowMenuButtonTest); + } + if (overflowMenu != null) { + mBridgeContext.addViewKey(overflowMenu, new SystemViewCookie(ACTION_BAR_OVERFLOW)); + } } } |