Merge "Save OwnerInfo so CryptKeeper can display at boot time"
diff --git a/api/current.txt b/api/current.txt
index efadf77..a543cbf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -865,6 +865,7 @@
field public static final int permissionFlags = 16843719; // 0x10103c7
field public static final int permissionGroup = 16842762; // 0x101000a
field public static final int permissionGroupFlags = 16843717; // 0x10103c5
+ field public static final int persistable = 16843832; // 0x1010438
field public static final int persistent = 16842765; // 0x101000d
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
@@ -1821,46 +1822,50 @@
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 = 16974534; // 0x10302c6
- field public static final int TextAppearance_Quantum_Body2 = 16974533; // 0x10302c5
- field public static final int TextAppearance_Quantum_Button = 16974537; // 0x10302c9
- field public static final int TextAppearance_Quantum_Caption = 16974535; // 0x10302c7
+ 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 = 16974529; // 0x10302c1
- field public static final int TextAppearance_Quantum_Display2 = 16974528; // 0x10302c0
- field public static final int TextAppearance_Quantum_Display3 = 16974527; // 0x10302bf
- field public static final int TextAppearance_Quantum_Display4 = 16974526; // 0x10302be
- field public static final int TextAppearance_Quantum_Headline = 16974530; // 0x10302c2
+ 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 = 16974536; // 0x10302c8
+ 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 = 16974532; // 0x10302c4
- field public static final int TextAppearance_Quantum_Title = 16974531; // 0x10302c3
+ 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_Title = 16974361; // 0x1030219
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974362; // 0x103021a
- field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974363; // 0x103021b
- field public static final int TextAppearance_Quantum_Widget_Button = 16974364; // 0x103021c
- field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974365; // 0x103021d
- field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974366; // 0x103021e
- field public static final int TextAppearance_Quantum_Widget_EditText = 16974367; // 0x103021f
- field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974368; // 0x1030220
- field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974369; // 0x1030221
- field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974370; // 0x1030222
- field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974371; // 0x1030223
- field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974372; // 0x1030224
- field public static final int TextAppearance_Quantum_Widget_TextView = 16974373; // 0x1030225
- field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974374; // 0x1030226
- field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974375; // 0x1030227
+ 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_Small = 16973894; // 0x1030046
field public static final int TextAppearance_Small_Inverse = 16973895; // 0x1030047
@@ -1956,34 +1961,34 @@
field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
field public static final int Theme_Panel = 16973913; // 0x1030059
- field public static final int Theme_Quantum = 16974376; // 0x1030228
- field public static final int Theme_Quantum_Dialog = 16974377; // 0x1030229
- field public static final int Theme_Quantum_DialogWhenLarge = 16974381; // 0x103022d
- field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974382; // 0x103022e
- field public static final int Theme_Quantum_Dialog_MinWidth = 16974378; // 0x103022a
- field public static final int Theme_Quantum_Dialog_NoActionBar = 16974379; // 0x103022b
- field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974380; // 0x103022c
- field public static final int Theme_Quantum_InputMethod = 16974383; // 0x103022f
- field public static final int Theme_Quantum_Light = 16974391; // 0x1030237
- field public static final int Theme_Quantum_Light_DarkActionBar = 16974392; // 0x1030238
- field public static final int Theme_Quantum_Light_Dialog = 16974393; // 0x1030239
- field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974397; // 0x103023d
- field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974398; // 0x103023e
- field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974394; // 0x103023a
- field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974395; // 0x103023b
- field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974396; // 0x103023c
- field public static final int Theme_Quantum_Light_NoActionBar = 16974399; // 0x103023f
- field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974400; // 0x1030240
- field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974401; // 0x1030241
- field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974402; // 0x1030242
- field public static final int Theme_Quantum_Light_Panel = 16974403; // 0x1030243
- field public static final int Theme_Quantum_NoActionBar = 16974384; // 0x1030230
- field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974385; // 0x1030231
- field public static final int Theme_Quantum_NoActionBar_Overscan = 16974386; // 0x1030232
- field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974387; // 0x1030233
- field public static final int Theme_Quantum_Panel = 16974388; // 0x1030234
- field public static final int Theme_Quantum_Wallpaper = 16974389; // 0x1030235
- field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974390; // 0x1030236
+ 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_Translucent = 16973839; // 0x103000f
field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
field public static final int Theme_Translucent_NoTitleBar_Fullscreen = 16973841; // 0x1030011
@@ -2187,7 +2192,7 @@
field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
- field public static final int Widget_Holo_Light_Button_Borderless = 16974538; // 0x10302ca
+ field public static final int Widget_Holo_Light_Button_Borderless = 16974542; // 0x10302ce
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
@@ -2272,128 +2277,128 @@
field public static final int Widget_ProgressBar_Large_Inverse = 16973916; // 0x103005c
field public static final int Widget_ProgressBar_Small = 16973854; // 0x103001e
field public static final int Widget_ProgressBar_Small_Inverse = 16973917; // 0x103005d
- field public static final int Widget_Quantum = 16974404; // 0x1030244
- field public static final int Widget_Quantum_ActionBar = 16974405; // 0x1030245
- field public static final int Widget_Quantum_ActionBar_Solid = 16974406; // 0x1030246
- field public static final int Widget_Quantum_ActionBar_TabBar = 16974407; // 0x1030247
- field public static final int Widget_Quantum_ActionBar_TabText = 16974408; // 0x1030248
- field public static final int Widget_Quantum_ActionBar_TabView = 16974409; // 0x1030249
- field public static final int Widget_Quantum_ActionButton = 16974410; // 0x103024a
- field public static final int Widget_Quantum_ActionButton_CloseMode = 16974411; // 0x103024b
- field public static final int Widget_Quantum_ActionButton_Overflow = 16974412; // 0x103024c
- field public static final int Widget_Quantum_ActionButton_TextButton = 16974413; // 0x103024d
- field public static final int Widget_Quantum_ActionMode = 16974414; // 0x103024e
- field public static final int Widget_Quantum_AutoCompleteTextView = 16974415; // 0x103024f
- field public static final int Widget_Quantum_Button = 16974416; // 0x1030250
- field public static final int Widget_Quantum_ButtonBar = 16974422; // 0x1030256
- field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974423; // 0x1030257
- field public static final int Widget_Quantum_Button_Borderless = 16974417; // 0x1030251
- field public static final int Widget_Quantum_Button_Borderless_Small = 16974418; // 0x1030252
- field public static final int Widget_Quantum_Button_Inset = 16974419; // 0x1030253
- field public static final int Widget_Quantum_Button_Paper = 16974522; // 0x10302ba
- field public static final int Widget_Quantum_Button_Paper_Color = 16974523; // 0x10302bb
- field public static final int Widget_Quantum_Button_Small = 16974420; // 0x1030254
- field public static final int Widget_Quantum_Button_Toggle = 16974421; // 0x1030255
- field public static final int Widget_Quantum_CalendarView = 16974424; // 0x1030258
- field public static final int Widget_Quantum_CheckedTextView = 16974425; // 0x1030259
- field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974426; // 0x103025a
- field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974427; // 0x103025b
- field public static final int Widget_Quantum_CompoundButton_Star = 16974428; // 0x103025c
- field public static final int Widget_Quantum_DatePicker = 16974429; // 0x103025d
- field public static final int Widget_Quantum_DropDownItem = 16974430; // 0x103025e
- field public static final int Widget_Quantum_DropDownItem_Spinner = 16974431; // 0x103025f
- field public static final int Widget_Quantum_EditText = 16974432; // 0x1030260
- field public static final int Widget_Quantum_ExpandableListView = 16974433; // 0x1030261
- field public static final int Widget_Quantum_FastScroll = 16974434; // 0x1030262
- field public static final int Widget_Quantum_FragmentBreadCrumbs = 16974435; // 0x1030263
- field public static final int Widget_Quantum_GridView = 16974436; // 0x1030264
- field public static final int Widget_Quantum_HorizontalScrollView = 16974437; // 0x1030265
- field public static final int Widget_Quantum_ImageButton = 16974438; // 0x1030266
- field public static final int Widget_Quantum_Light = 16974463; // 0x103027f
- field public static final int Widget_Quantum_Light_ActionBar = 16974464; // 0x1030280
- field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974465; // 0x1030281
- field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974466; // 0x1030282
- field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974467; // 0x1030283
- field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974468; // 0x1030284
- field public static final int Widget_Quantum_Light_ActionButton = 16974469; // 0x1030285
- field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974470; // 0x1030286
- field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974471; // 0x1030287
- field public static final int Widget_Quantum_Light_ActionMode = 16974472; // 0x1030288
- field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974473; // 0x1030289
- field public static final int Widget_Quantum_Light_Button = 16974474; // 0x103028a
- field public static final int Widget_Quantum_Light_ButtonBar = 16974479; // 0x103028f
- field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974480; // 0x1030290
- field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974475; // 0x103028b
- field public static final int Widget_Quantum_Light_Button_Inset = 16974476; // 0x103028c
- field public static final int Widget_Quantum_Light_Button_Paper = 16974524; // 0x10302bc
- field public static final int Widget_Quantum_Light_Button_Paper_Color = 16974525; // 0x10302bd
- field public static final int Widget_Quantum_Light_Button_Small = 16974477; // 0x103028d
- field public static final int Widget_Quantum_Light_Button_Toggle = 16974478; // 0x103028e
- field public static final int Widget_Quantum_Light_CalendarView = 16974481; // 0x1030291
- field public static final int Widget_Quantum_Light_CheckedTextView = 16974482; // 0x1030292
- field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974483; // 0x1030293
- field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974484; // 0x1030294
- field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974485; // 0x1030295
- field public static final int Widget_Quantum_Light_DropDownItem = 16974486; // 0x1030296
- field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974487; // 0x1030297
- field public static final int Widget_Quantum_Light_EditText = 16974488; // 0x1030298
- field public static final int Widget_Quantum_Light_ExpandableListView = 16974489; // 0x1030299
- field public static final int Widget_Quantum_Light_FastScroll = 16974490; // 0x103029a
- field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974491; // 0x103029b
- field public static final int Widget_Quantum_Light_GridView = 16974492; // 0x103029c
- field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974493; // 0x103029d
- field public static final int Widget_Quantum_Light_ImageButton = 16974494; // 0x103029e
- field public static final int Widget_Quantum_Light_ListPopupWindow = 16974495; // 0x103029f
- field public static final int Widget_Quantum_Light_ListView = 16974496; // 0x10302a0
- field public static final int Widget_Quantum_Light_ListView_DropDown = 16974497; // 0x10302a1
- field public static final int Widget_Quantum_Light_MediaRouteButton = 16974498; // 0x10302a2
- field public static final int Widget_Quantum_Light_PopupMenu = 16974499; // 0x10302a3
- field public static final int Widget_Quantum_Light_PopupWindow = 16974500; // 0x10302a4
- field public static final int Widget_Quantum_Light_ProgressBar = 16974501; // 0x10302a5
- field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974502; // 0x10302a6
- field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974503; // 0x10302a7
- field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974504; // 0x10302a8
- field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974505; // 0x10302a9
- field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974506; // 0x10302aa
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974507; // 0x10302ab
- field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974508; // 0x10302ac
- field public static final int Widget_Quantum_Light_RatingBar = 16974509; // 0x10302ad
- field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974510; // 0x10302ae
- field public static final int Widget_Quantum_Light_RatingBar_Small = 16974511; // 0x10302af
- field public static final int Widget_Quantum_Light_ScrollView = 16974512; // 0x10302b0
- field public static final int Widget_Quantum_Light_SeekBar = 16974513; // 0x10302b1
- field public static final int Widget_Quantum_Light_SegmentedButton = 16974514; // 0x10302b2
- field public static final int Widget_Quantum_Light_Spinner = 16974515; // 0x10302b3
- field public static final int Widget_Quantum_Light_Tab = 16974516; // 0x10302b4
- field public static final int Widget_Quantum_Light_TabWidget = 16974517; // 0x10302b5
- field public static final int Widget_Quantum_Light_TextView = 16974518; // 0x10302b6
- field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974519; // 0x10302b7
- field public static final int Widget_Quantum_Light_WebTextView = 16974520; // 0x10302b8
- field public static final int Widget_Quantum_Light_WebView = 16974521; // 0x10302b9
- field public static final int Widget_Quantum_ListPopupWindow = 16974439; // 0x1030267
- field public static final int Widget_Quantum_ListView = 16974440; // 0x1030268
- field public static final int Widget_Quantum_ListView_DropDown = 16974441; // 0x1030269
- field public static final int Widget_Quantum_MediaRouteButton = 16974442; // 0x103026a
- field public static final int Widget_Quantum_PopupMenu = 16974443; // 0x103026b
- field public static final int Widget_Quantum_PopupWindow = 16974444; // 0x103026c
- field public static final int Widget_Quantum_ProgressBar = 16974445; // 0x103026d
- field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974446; // 0x103026e
- field public static final int Widget_Quantum_ProgressBar_Large = 16974447; // 0x103026f
- field public static final int Widget_Quantum_ProgressBar_Small = 16974448; // 0x1030270
- field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974449; // 0x1030271
- field public static final int Widget_Quantum_RatingBar = 16974450; // 0x1030272
- field public static final int Widget_Quantum_RatingBar_Indicator = 16974451; // 0x1030273
- field public static final int Widget_Quantum_RatingBar_Small = 16974452; // 0x1030274
- field public static final int Widget_Quantum_ScrollView = 16974453; // 0x1030275
- field public static final int Widget_Quantum_SeekBar = 16974454; // 0x1030276
- field public static final int Widget_Quantum_SegmentedButton = 16974455; // 0x1030277
- field public static final int Widget_Quantum_Spinner = 16974456; // 0x1030278
- field public static final int Widget_Quantum_Tab = 16974457; // 0x1030279
- field public static final int Widget_Quantum_TabWidget = 16974458; // 0x103027a
- field public static final int Widget_Quantum_TextView = 16974459; // 0x103027b
- field public static final int Widget_Quantum_TextView_SpinnerItem = 16974460; // 0x103027c
- field public static final int Widget_Quantum_WebTextView = 16974461; // 0x103027d
- field public static final int Widget_Quantum_WebView = 16974462; // 0x103027e
+ 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_RatingBar = 16973857; // 0x1030021
field public static final int Widget_ScrollView = 16973869; // 0x103002d
field public static final int Widget_SeekBar = 16973856; // 0x1030020
@@ -3258,6 +3263,7 @@
method public void reportFullyDrawn();
method public final boolean requestWindowFeature(int);
method public final void runOnUiThread(java.lang.Runnable);
+ method public void setActivityLabelAndIcon(java.lang.CharSequence, android.graphics.Bitmap);
method public void setContentTransitionManager(android.transition.TransitionManager);
method public void setContentView(int);
method public void setContentView(android.view.View);
@@ -3274,8 +3280,6 @@
method public final void setProgressBarIndeterminate(boolean);
method public final void setProgressBarIndeterminateVisibility(boolean);
method public final void setProgressBarVisibility(boolean);
- method public void setRecentsIcon(android.graphics.Bitmap);
- method public void setRecentsLabel(java.lang.CharSequence);
method public void setRequestedOrientation(int);
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
@@ -12083,11 +12087,16 @@
field public static final int MESSAGE_VENDOR_COMMAND_WITH_ID = 160; // 0xa0
field public static final int MESSAGE_VENDOR_REMOTE_BUTTON_DOWN = 138; // 0x8a
field public static final int MESSAGE_VENDOR_REMOTE_BUTTON_UP = 139; // 0x8b
+ field public static final int POWER_STATUS_ON = 0; // 0x0
+ field public static final int POWER_STATUS_STANDBY = 1; // 0x1
+ 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
}
public final class HdmiCecClient {
+ method public boolean isTvOn();
method public void sendActiveSource();
- method public void sendGiveDevicePowerStatus(int);
method public void sendImageViewOn();
method public void sendInactiveSource();
method public void sendTextViewOn();
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 8d2b739..bdbb08c 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -30,8 +30,9 @@
class AppRuntime : public AndroidRuntime
{
public:
- AppRuntime()
- : mParentDir(NULL)
+ AppRuntime(char* argBlockStart, const size_t argBlockLength)
+ : AndroidRuntime(argBlockStart, argBlockLength)
+ , mParentDir(NULL)
, mClassName(NULL)
, mClass(NULL)
, mArgC(0)
@@ -125,29 +126,30 @@
using namespace android;
-/*
- * sets argv0 to as much of newArgv0 as will fit
- */
-static void setArgv0(const char *argv0, const char *newArgv0)
-{
- strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
+static size_t computeArgBlockSize(int argc, char* const argv[]) {
+ // TODO: This assumes that all arguments are allocated in
+ // contiguous memory. There isn't any documented guarantee
+ // that this is the case, but this is how the kernel does it
+ // (see fs/exec.c).
+ //
+ // Also note that this is a constant for "normal" android apps.
+ // Since they're forked from zygote, the size of their command line
+ // is the size of the zygote command line.
+ //
+ // We change the process name of the process by over-writing
+ // the start of the argument block (argv[0]) with the new name of
+ // the process, so we'd mysteriously start getting truncated process
+ // names if the zygote command line decreases in size.
+ uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
+ uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
+ end += strlen(argv[argc - 1]);
+
+ return (end - start);
}
int main(int argc, char* const argv[])
{
- // These are global variables in ProcessState.cpp
- mArgC = argc;
- mArgV = argv;
-
- mArgLen = 0;
- for (int i=0; i<argc; i++) {
- mArgLen += strlen(argv[i]) + 1;
- }
- mArgLen--;
-
- AppRuntime runtime;
- const char* argv0 = argv[0];
-
+ AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
@@ -184,7 +186,7 @@
}
if (niceName && *niceName) {
- setArgv0(argv0, niceName);
+ runtime.setArgv0(niceName);
set_process_name(niceName);
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index f415c85..5454b46 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1033,18 +1033,18 @@
public void runCreateUser() {
String name;
- int relatedUserId = -1;
+ int userId = -1;
int flags = 0;
String opt;
while ((opt = nextOption()) != null) {
- if ("--relatedTo".equals(opt)) {
+ if ("--profileOf".equals(opt)) {
String optionData = nextOptionData();
if (optionData == null || !isNumber(optionData)) {
System.err.println("Error: no USER_ID specified");
showUsage();
return;
} else {
- relatedUserId = Integer.parseInt(optionData);
+ userId = Integer.parseInt(optionData);
}
} else if ("--managed".equals(opt)) {
flags |= UserInfo.FLAG_MANAGED_PROFILE;
@@ -1062,14 +1062,14 @@
name = arg;
try {
UserInfo info = null;
- if (relatedUserId < 0) {
+ if (userId < 0) {
info = mUm.createUser(name, flags);
} else {
if (Process.myUid() != 0) {
System.err.println("Error: not running as root.");
return;
}
- info = mUm.createRelatedUser(name, flags, relatedUserId);
+ info = mUm.createProfileForUser(name, flags, userId);
}
if (info != null) {
System.out.println("Success: created user id " + info.id);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e38bbb3..20e7311 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4701,42 +4701,31 @@
}
/**
- * Set a label to be used in the Recents task display. The activities of a task are traversed
- * in order from the topmost activity to the bottommost. As soon as one activity returns a
- * non-null Recents label the traversal is ended and that value will be used in
- * {@link ActivityManager.RecentTaskInfo#activityLabel}
+ * 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}.
*
* @see ActivityManager#getRecentTasks
+ * @see ActivityManager.RecentTaskInfo
*
- * @param recentsLabel The label to use in the RecentTaskInfo.
+ * @param activityLabel The label to use in the RecentTaskInfo.
+ * @param activityIcon The Bitmap to use in the RecentTaskInfo.
*/
- public void setRecentsLabel(CharSequence recentsLabel) {
- try {
- ActivityManagerNative.getDefault().setRecentsLabel(mToken, recentsLabel);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Set an icon to be used in the Recents task display. The activities of a task are traversed
- * in order from the topmost activity to the bottommost. As soon as one activity returns a
- * non-null Recents icon the traversal is ended and that value will be used in
- * {@link ActivityManager.RecentTaskInfo#activityIcon}.
- *
- * @see ActivityManager#getRecentTasks
- *
- * @param recentsIcon The Bitmap to use in the RecentTaskInfo.
- */
- public void setRecentsIcon(Bitmap recentsIcon) {
+ public void setActivityLabelAndIcon(CharSequence activityLabel, Bitmap activityIcon) {
final Bitmap scaledIcon;
- if (recentsIcon != null) {
+ if (activityIcon != null) {
final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
- scaledIcon = Bitmap.createScaledBitmap(recentsIcon, size, size, true);
+ scaledIcon = Bitmap.createScaledBitmap(activityIcon, size, size, true);
} else {
scaledIcon = null;
}
try {
- ActivityManagerNative.getDefault().setRecentsIcon(mToken, scaledIcon);
+ ActivityManagerNative.getDefault().setActivityLabelAndIcon(mToken, activityLabel,
+ scaledIcon);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d386eff..c027e99 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -516,14 +516,14 @@
public int userId;
/**
- * The label of the highest activity in the task stack to have set a label
- * {@link Activity#setRecentsLabel}.
+ * 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#setRecentsIcon}.
+ * {@link Activity#setActivityLabelAndIcon(CharSequence, android.graphics.Bitmap)}.
*/
public Bitmap activityIcon;
@@ -563,11 +563,7 @@
public void readFromParcel(Parcel source) {
id = source.readInt();
persistentId = source.readInt();
- if (source.readInt() != 0) {
- baseIntent = Intent.CREATOR.createFromParcel(source);
- } else {
- baseIntent = null;
- }
+ 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);
@@ -605,11 +601,11 @@
public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002;
/**
- * Provides a list that also contains recent tasks for user
- * and related users.
+ * Provides a list that contains recent tasks for all
+ * profiles of a user.
* @hide
*/
- public static final int RECENT_INCLUDE_RELATED = 0x0004;
+ public static final int RECENT_INCLUDE_PROFILES = 0x0004;
/**
* Return a list of the tasks that the user has recently launched, with
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 707a038..a37a35a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2129,21 +2129,13 @@
return true;
}
- case SET_RECENTS_LABEL_TRANSACTION: {
+ case SET_ACTIVITY_LABEL_ICON_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- CharSequence recentsLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
- setRecentsLabel(token, recentsLabel);
- reply.writeNoException();
- return true;
- }
-
- case SET_RECENTS_ICON_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- Bitmap recentsIcon = data.readInt() != 0
+ CharSequence activityLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
+ Bitmap activityIcon = data.readInt() > 0
? Bitmap.CREATOR.createFromParcel(data) : null;
- setRecentsIcon(token, recentsIcon);
+ setActivityLabelAndIcon(token, activityLabel, activityIcon);
reply.writeNoException();
return true;
}
@@ -4918,32 +4910,22 @@
return isInLockTaskMode;
}
- public void setRecentsLabel(IBinder token, CharSequence recentsLabel) throws RemoteException
+ @Override
+ public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
+ Bitmap activityIcon) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
- TextUtils.writeToParcel(recentsLabel, data, 0);
- mRemote.transact(SET_RECENTS_LABEL_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
-
- public void setRecentsIcon(IBinder token, Bitmap recentsBitmap) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- if (recentsBitmap != null) {
+ TextUtils.writeToParcel(activityLabel, data, 0);
+ if (activityIcon != null) {
data.writeInt(1);
- recentsBitmap.writeToParcel(data, 0);
+ activityIcon.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
- mRemote.transact(SET_RECENTS_ICON_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+ mRemote.transact(SET_ACTIVITY_LABEL_ICON_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
reply.recycle();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d1f94f0..7149ab9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -468,7 +468,8 @@
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_Dialog,
+ com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
ctx.mMainThread.getHandler());
}});
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3b56839..f7416d6 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -437,10 +437,8 @@
public boolean isInLockTaskMode() throws RemoteException;
/** @hide */
- public void setRecentsLabel(IBinder token, CharSequence recentsLabel) throws RemoteException;
-
- /** @hide */
- public void setRecentsIcon(IBinder token, Bitmap recentsBitmap) throws RemoteException;
+ public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
+ Bitmap activityBitmap) throws RemoteException;
/*
* Private non-Binder interfaces
@@ -741,6 +739,5 @@
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_RECENTS_LABEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
- int SET_RECENTS_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
+ int SET_ACTIVITY_LABEL_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
}
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index 4ca06ed..7036aea 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -124,4 +124,12 @@
int type, String domain, String path, long mode, long mtime,
int token, IBackupManager callbackBinder);
+ /**
+ * Out of band: instruct the agent to crash within the client process. This is used
+ * when the backup infrastructure detects a semantic error post-hoc and needs to
+ * pass the problem back to the app.
+ *
+ * @param message The message to be passed to the agent's application in an exception.
+ */
+ void fail(String message);
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 67c772b..3c31f8d 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -128,6 +128,13 @@
Handler mHandler = null;
+ Handler getHandler() {
+ if (mHandler == null) {
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+ return mHandler;
+ }
+
class SharedPrefsSynchronizer implements Runnable {
public final CountDownLatch mLatch = new CountDownLatch(1);
@@ -140,12 +147,9 @@
// Syncing shared preferences deferred writes needs to happen on the main looper thread
private void waitForSharedPrefs() {
- if (mHandler == null) {
- mHandler = new Handler(Looper.getMainLooper());
- }
-
+ Handler h = getHandler();
final SharedPrefsSynchronizer s = new SharedPrefsSynchronizer();
- mHandler.postAtFrontOfQueue(s);
+ h.postAtFrontOfQueue(s);
try {
s.mLatch.await();
} catch (InterruptedException e) { /* ignored */ }
@@ -680,5 +684,23 @@
}
}
}
+
+ @Override
+ public void fail(String message) {
+ getHandler().post(new FailRunnable(message));
+ }
+ }
+
+ static class FailRunnable implements Runnable {
+ private String mMessage;
+
+ FailRunnable(String message) {
+ mMessage = message;
+ }
+
+ @Override
+ public void run() {
+ throw new IllegalStateException(mMessage);
+ }
}
}
diff --git a/core/java/android/app/backup/BackupDataOutput.java b/core/java/android/app/backup/BackupDataOutput.java
index 845784f..fc5fb3d 100644
--- a/core/java/android/app/backup/BackupDataOutput.java
+++ b/core/java/android/app/backup/BackupDataOutput.java
@@ -85,11 +85,6 @@
* @throws IOException if the write failed
*/
public int writeEntityHeader(String key, int dataSize) throws IOException {
- if (key != null && key.charAt(0) >= 0xff00) {
- if (Process.myUid() != Process.SYSTEM_UID) {
- throw new IllegalArgumentException("Invalid key " + key);
- }
- }
int result = writeEntityHeader_native(mBackupWriter, key, dataSize);
if (result >= 0) {
return result;
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 40275d8..9916476 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -189,6 +189,13 @@
*/
public static final int FLAG_IMMERSIVE = 0x0800;
/**
+ * Bit in {@link #flags} indicating that this activity is to be persisted across
+ * reboots for display in the Recents list.
+ * {@link android.R.attr#persistable}
+ * @hide
+ */
+ public static final int FLAG_PERSISTABLE = 0x1000;
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the primary user. Only works with broadcast receivers. Set from the
* {@link android.R.attr#primaryUserOnly} attribute.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a89c507..4b5616f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -57,7 +57,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.jar.JarEntry;
import java.util.jar.StrictJarFile;
import java.util.zip.ZipEntry;
@@ -2448,6 +2447,11 @@
a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_persistable, false)) {
+ a.info.flags |= ActivityInfo.FLAG_PERSISTABLE;
+ }
+
if (!receiver) {
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 6f1d4f8..f53aa4c 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -71,7 +71,7 @@
public static final int FLAG_MANAGED_PROFILE = 0x00000020;
- public static final int NO_RELATED_GROUP_ID = -1;
+ public static final int NO_PROFILE_GROUP_ID = -1;
public int id;
public int serialNumber;
@@ -80,7 +80,7 @@
public int flags;
public long creationTime;
public long lastLoggedInTime;
- public int relatedGroupId;
+ public int profileGroupId;
/** User is only partially created. */
public boolean partial;
@@ -94,7 +94,7 @@
this.name = name;
this.flags = flags;
this.iconPath = iconPath;
- this.relatedGroupId = NO_RELATED_GROUP_ID;
+ this.profileGroupId = NO_PROFILE_GROUP_ID;
}
public boolean isPrimary() {
@@ -137,7 +137,7 @@
creationTime = orig.creationTime;
lastLoggedInTime = orig.lastLoggedInTime;
partial = orig.partial;
- relatedGroupId = orig.relatedGroupId;
+ profileGroupId = orig.profileGroupId;
}
public UserHandle getUserHandle() {
@@ -162,7 +162,7 @@
dest.writeLong(creationTime);
dest.writeLong(lastLoggedInTime);
dest.writeInt(partial ? 1 : 0);
- dest.writeInt(relatedGroupId);
+ dest.writeInt(profileGroupId);
}
public static final Parcelable.Creator<UserInfo> CREATOR
@@ -184,6 +184,6 @@
creationTime = source.readLong();
lastLoggedInTime = source.readLong();
partial = source.readInt() != 0;
- relatedGroupId = source.readInt();
+ profileGroupId = source.readInt();
}
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 1955be3..d6eafc6 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -135,17 +135,31 @@
sPreloadedDrawables[1] = new LongSparseArray<ConstantState>();
}
- /** @hide */
+ /**
+ * 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) {
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,
+ com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar);
}
-
+
/** @hide */
- public static int selectSystemTheme(int curTheme, int targetSdkVersion,
- int orig, int holo, int deviceDefault) {
+ public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
+ int dark, int deviceDefault) {
if (curTheme != 0) {
return curTheme;
}
@@ -155,9 +169,12 @@
if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return holo;
}
+ if (targetSdkVersion < Build.VERSION_CODES.CUR_DEVELOPMENT) {
+ return dark;
+ }
return deviceDefault;
}
-
+
/**
* This exception is thrown by the resource APIs when a requested resource
* can not be found.
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 38d9de4..8578a32 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -160,6 +160,12 @@
public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
public static final int MESSAGE_ABORT = 0xFF;
+ public static final int POWER_STATUS_UNKNOWN = -1;
+ public static final int POWER_STATUS_ON = 0;
+ public static final int POWER_STATUS_STANDBY = 1;
+ public static final int POWER_TRANSIENT_TO_ON = 2;
+ public static final int POWER_TRANSIENT_TO_STANDBY = 3;
+
private static final int[] ADDRESS_TO_TYPE = {
DEVICE_TV, // ADDR_TV
DEVICE_RECORDER, // ADDR_RECORDER_1
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
index d7f4a72..1f382e6 100644
--- a/core/java/android/hardware/hdmi/HdmiCecClient.java
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -110,16 +110,20 @@
}
/**
- * Send <GiveDevicePowerStatus> message.
+ * Returns true if the TV or attached display is powered on.
+ * <p>
+ * The result of this method is only meaningful on playback devices (where the device
+ * type is {@link HdmiCec#DEVICE_PLAYBACK}).
+ * </p>
*
- * @param address logical address of the device to send the message to, such as
- * {@link HdmiCec#ADDR_TV}.
+ * @return true if TV is on; otherwise false.
*/
- public void sendGiveDevicePowerStatus(int address) {
+ public boolean isTvOn() {
try {
- mService.sendGiveDevicePowerStatus(mBinder, address);
+ return mService.isTvOn(mBinder);
} catch (RemoteException e) {
- Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e);
+ Log.e(TAG, "isTvOn threw exception ", e);
}
+ return false;
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiCecManager.java b/core/java/android/hardware/hdmi/HdmiCecManager.java
index 575785d..10b058c 100644
--- a/core/java/android/hardware/hdmi/HdmiCecManager.java
+++ b/core/java/android/hardware/hdmi/HdmiCecManager.java
@@ -45,6 +45,9 @@
* @return {@link HdmiCecClient} instance. {@code null} on failure.
*/
public HdmiCecClient getClient(int type, HdmiCecClient.Listener listener) {
+ if (mService == null) {
+ return null;
+ }
try {
IBinder b = mService.allocateLogicalDevice(type, getListenerWrapper(listener));
return HdmiCecClient.create(mService, b);
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
index 6fefcf8..b5df131 100644
--- a/core/java/android/hardware/hdmi/IHdmiCecService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
@@ -29,12 +29,11 @@
interface IHdmiCecService {
IBinder allocateLogicalDevice(int type, IHdmiCecListener listener);
void removeServiceListener(IBinder b, IHdmiCecListener listener);
- void setOsdName(IBinder b, String name);
void sendActiveSource(IBinder b);
void sendInactiveSource(IBinder b);
void sendImageViewOn(IBinder b);
void sendTextViewOn(IBinder b);
- void sendGiveDevicePowerStatus(IBinder b, int address);
+ boolean isTvOn(IBinder b);
void sendMessage(IBinder b, in HdmiCecMessage message);
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 81ad28b..a355d1e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -647,6 +647,7 @@
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);
super.setTheme(mTheme);
super.onCreate();
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index d8e8e2c..377ed88 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -211,6 +211,7 @@
private Context mContext;
private static final int INVALID_LISTENER_KEY = 0;
+ private static final int BUSY_LISTENER_KEY = -1;
private int mListenerKey = 1;
private final SparseArray mListenerMap = new SparseArray();
private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<NsdServiceInfo>();
@@ -317,71 +318,74 @@
Log.d(TAG, "Stale key " + message.arg2);
return;
}
- boolean listenerRemove = true;
NsdServiceInfo ns = getNsdService(message.arg2);
switch (message.what) {
case DISCOVER_SERVICES_STARTED:
String s = getNsdServiceInfoType((NsdServiceInfo) message.obj);
((DiscoveryListener) listener).onDiscoveryStarted(s);
- // Keep listener until stop discovery
- listenerRemove = false;
break;
case DISCOVER_SERVICES_FAILED:
+ removeListener(message.arg2);
((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns),
message.arg1);
break;
case SERVICE_FOUND:
((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj);
- // Keep listener until stop discovery
- listenerRemove = false;
break;
case SERVICE_LOST:
((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj);
- // Keep listener until stop discovery
- listenerRemove = false;
break;
case STOP_DISCOVERY_FAILED:
+ removeListener(message.arg2);
((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns),
message.arg1);
break;
case STOP_DISCOVERY_SUCCEEDED:
+ removeListener(message.arg2);
((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns));
break;
case REGISTER_SERVICE_FAILED:
+ removeListener(message.arg2);
((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1);
break;
case REGISTER_SERVICE_SUCCEEDED:
((RegistrationListener) listener).onServiceRegistered(
(NsdServiceInfo) message.obj);
- // Keep listener until unregister
- listenerRemove = false;
break;
case UNREGISTER_SERVICE_FAILED:
+ removeListener(message.arg2);
((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1);
break;
case UNREGISTER_SERVICE_SUCCEEDED:
+ removeListener(message.arg2);
((RegistrationListener) listener).onServiceUnregistered(ns);
break;
case RESOLVE_SERVICE_FAILED:
+ removeListener(message.arg2);
((ResolveListener) listener).onResolveFailed(ns, message.arg1);
break;
case RESOLVE_SERVICE_SUCCEEDED:
+ removeListener(message.arg2);
((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj);
break;
default:
Log.d(TAG, "Ignored " + message);
break;
}
- if (listenerRemove) {
- removeListener(message.arg2);
- }
}
}
+ // if the listener is already in the map, reject it. Otherwise, add it and
+ // return its key.
+
private int putListener(Object listener, NsdServiceInfo s) {
if (listener == null) return INVALID_LISTENER_KEY;
int key;
synchronized (mMapLock) {
+ int valueIndex = mListenerMap.indexOfValue(listener);
+ if (valueIndex != -1) {
+ return BUSY_LISTENER_KEY;
+ }
do {
key = mListenerKey++;
} while (key == INVALID_LISTENER_KEY);
@@ -422,7 +426,6 @@
return INVALID_LISTENER_KEY;
}
-
private String getNsdServiceInfoType(NsdServiceInfo s) {
if (s == null) return "?";
return s.getServiceType();
@@ -449,14 +452,18 @@
* Register a service to be discovered by other services.
*
* <p> The function call immediately returns after sending a request to register service
- * to the framework. The application is notified of a success to initiate
- * discovery through the callback {@link RegistrationListener#onServiceRegistered} or a failure
+ * to the framework. The application is notified of a successful registration
+ * through the callback {@link RegistrationListener#onServiceRegistered} or a failure
* through {@link RegistrationListener#onRegistrationFailed}.
*
+ * <p> The application should call {@link #unregisterService} when the service
+ * registration is no longer required, and/or whenever the application is stopped.
+ *
* @param serviceInfo The service being registered
* @param protocolType The service discovery protocol
* @param listener The listener notifies of a successful registration and is used to
* unregister this service through a call on {@link #unregisterService}. Cannot be null.
+ * Cannot be in use for an active service registration.
*/
public void registerService(NsdServiceInfo serviceInfo, int protocolType,
RegistrationListener listener) {
@@ -473,8 +480,11 @@
if (protocolType != PROTOCOL_DNS_SD) {
throw new IllegalArgumentException("Unsupported protocol");
}
- mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, putListener(listener, serviceInfo),
- serviceInfo);
+ int key = putListener(listener, serviceInfo);
+ if (key == BUSY_LISTENER_KEY) {
+ throw new IllegalArgumentException("listener already in use");
+ }
+ mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo);
}
/**
@@ -484,7 +494,11 @@
*
* @param listener This should be the listener object that was passed to
* {@link #registerService}. It identifies the service that should be unregistered
- * and notifies of a successful unregistration.
+ * and notifies of a successful or unsuccessful unregistration via the listener
+ * callbacks. In API versions 20 and above, the listener object may be used for
+ * another service registration once the callback has been called. In API versions <= 19,
+ * there is no entirely reliable way to know when a listener may be re-used, and a new
+ * listener should be created for each service registration request.
*/
public void unregisterService(RegistrationListener listener) {
int id = getListenerKey(listener);
@@ -514,12 +528,16 @@
* <p> Upon failure to start, service discovery is not active and application does
* not need to invoke {@link #stopServiceDiscovery}
*
+ * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
+ * service type is no longer required, and/or whenever the application is paused or
+ * stopped.
+ *
* @param serviceType The service type being discovered. Examples include "_http._tcp" for
* http services or "_ipp._tcp" for printers
* @param protocolType The service discovery protocol
* @param listener The listener notifies of a successful discovery and is used
* to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
- * Cannot be null.
+ * Cannot be null. Cannot be in use for an active service discovery.
*/
public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
if (listener == null) {
@@ -535,11 +553,17 @@
NsdServiceInfo s = new NsdServiceInfo();
s.setServiceType(serviceType);
- mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, putListener(listener, s), s);
+
+ int key = putListener(listener, s);
+ if (key == BUSY_LISTENER_KEY) {
+ throw new IllegalArgumentException("listener already in use");
+ }
+
+ mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s);
}
/**
- * Stop service discovery initiated with {@link #discoverServices}. An active service
+ * Stop service discovery initiated with {@link #discoverServices}. An active service
* discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted}
* and it stays active until the application invokes a stop service discovery. A successful
* stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}.
@@ -548,7 +572,11 @@
* {@link DiscoveryListener#onStopDiscoveryFailed}.
*
* @param listener This should be the listener object that was passed to {@link #discoverServices}.
- * It identifies the discovery that should be stopped and notifies of a successful stop.
+ * It identifies the discovery that should be stopped and notifies of a successful or
+ * unsuccessful stop. In API versions 20 and above, the listener object may be used for
+ * another service discovery once the callback has been called. In API versions <= 19,
+ * there is no entirely reliable way to know when a listener may be re-used, and a new
+ * listener should be created for each service discovery request.
*/
public void stopServiceDiscovery(DiscoveryListener listener) {
int id = getListenerKey(listener);
@@ -568,6 +596,7 @@
*
* @param serviceInfo service to be resolved
* @param listener to receive callback upon success or failure. Cannot be null.
+ * Cannot be in use for an active service resolution.
*/
public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) {
if (TextUtils.isEmpty(serviceInfo.getServiceName()) ||
@@ -577,8 +606,13 @@
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
}
- mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, putListener(listener, serviceInfo),
- serviceInfo);
+
+ int key = putListener(listener, serviceInfo);
+
+ if (key == BUSY_LISTENER_KEY) {
+ throw new IllegalArgumentException("listener already in use");
+ }
+ mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo);
}
/** Internal use only @hide */
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 6e6c06d..1192a45 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -28,13 +28,13 @@
*/
interface IUserManager {
UserInfo createUser(in String name, int flags);
- UserInfo createRelatedUser(in String name, int flags, int relatedUserId);
+ UserInfo createProfileForUser(in String name, int flags, int userHandle);
boolean removeUser(int userHandle);
void setUserName(int userHandle, String name);
void setUserIcon(int userHandle, in Bitmap icon);
Bitmap getUserIcon(int userHandle);
List<UserInfo> getUsers(boolean excludeDying);
- List<UserInfo> getRelatedUsers(int userHandle);
+ List<UserInfo> getProfiles(int userHandle);
UserInfo getUserInfo(int userHandle);
boolean isRestricted();
void setGuestEnabled(boolean enable);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 057f516..3241693 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,10 +16,11 @@
package android.os;
-import android.net.LocalSocketAddress;
import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.util.Log;
-import dalvik.system.Zygote;
+
+import com.android.internal.os.Zygote;
import java.io.BufferedWriter;
import java.io.DataInputStream;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1ec5cd5..520a08c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -410,20 +410,29 @@
}
/**
- * Creates a user with the specified name and options.
+ * Renamed, just present to avoid multi project commit.
+ * TODO delete.
+ * @hide
+ */
+ public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+ return createProfileForUser(name, flags, relatedUserId);
+ }
+
+ /**
+ * Creates a user with the specified name and options as a profile of another user.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
* @param name the user's name
* @param flags flags that identify the type of user and other properties.
* @see UserInfo
- * @param relatedUserId new user will be related to this user id.
+ * @param userHandle new user will be a profile of this use.
*
* @return the UserInfo object for the created user, or null if the user could not be created.
* @hide
*/
- public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+ public UserInfo createProfileForUser(String name, int flags, int userHandle) {
try {
- return mService.createRelatedUser(name, flags, relatedUserId);
+ return mService.createProfileForUser(name, flags, userHandle);
} catch (RemoteException re) {
Log.w(TAG, "Could not create a user", re);
return null;
@@ -454,15 +463,26 @@
}
/**
- * Returns information for all users related to userId
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @param userHandle users related to this user id will be returned.
- * @return the list of related users.
+ * Renaming, left to avoid multi project commit.
+ * TODO Delete.
* @hide
*/
public List<UserInfo> getRelatedUsers(int userHandle) {
+ return getProfiles(userHandle);
+ }
+
+ /**
+ * Returns list of the profiles of userHandle including
+ * userHandle itself.
+ *
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ * @param userHandle profiles of this user will be returned.
+ * @return the list of profiles.
+ * @hide
+ */
+ public List<UserInfo> getProfiles(int userHandle) {
try {
- return mService.getRelatedUsers(userHandle);
+ return mService.getProfiles(userHandle);
} catch (RemoteException re) {
Log.w(TAG, "Could not get user list", re);
return null;
diff --git a/core/java/android/provider/SearchIndexablesContract.java b/core/java/android/provider/SearchIndexablesContract.java
index b8635b8..05f3a1c 100644
--- a/core/java/android/provider/SearchIndexablesContract.java
+++ b/core/java/android/provider/SearchIndexablesContract.java
@@ -73,7 +73,8 @@
public static final String[] INDEXABLES_RAW_COLUMNS = new String[] {
RawData.COLUMN_RANK,
RawData.COLUMN_TITLE,
- RawData.COLUMN_SUMMARY,
+ RawData.COLUMN_SUMMARY_ON,
+ RawData.COLUMN_SUMMARY_OFF,
RawData.COLUMN_KEYWORDS,
RawData.COLUMN_SCREEN_TITLE,
RawData.COLUMN_CLASS_NAME,
@@ -123,9 +124,14 @@
public static final String COLUMN_TITLE = "title";
/**
- * Summary's raw data.
+ * Summary's raw data when the data is "ON".
*/
- public static final String COLUMN_SUMMARY = "summary";
+ public static final String COLUMN_SUMMARY_ON = "summaryOn";
+
+ /**
+ * Summary's raw data when the data is "OFF".
+ */
+ public static final String COLUMN_SUMMARY_OFF = "summaryOff";
/**
* Keywords' raw data.
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7647c22..de9eeff 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -153,11 +153,11 @@
private final Handler mHandler = new Handler();
private IBinder mWindowToken;
private Window mWindow;
- private WindowManager mWindowManager;
- private boolean mInteractive = false;
+ private boolean mInteractive;
private boolean mLowProfile = true;
- private boolean mFullscreen = false;
+ private boolean mFullscreen;
private boolean mScreenBright = true;
+ private boolean mStarted;
private boolean mFinished;
private boolean mCanDoze;
private boolean mDozing;
@@ -340,7 +340,7 @@
* @return The current window manager, or null if the dream is not started.
*/
public WindowManager getWindowManager() {
- return mWindowManager;
+ return mWindow != null ? mWindow.getWindowManager() : null;
}
/**
@@ -623,7 +623,7 @@
* @hide experimental
*/
public DozeHardware getDozeHardware() {
- if (mCanDoze && mDozeHardware == null) {
+ if (mCanDoze && mDozeHardware == null && mWindowToken != null) {
try {
IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
if (hardware != null) {
@@ -701,24 +701,25 @@
* Must run on mHandler.
*/
private final void detach() {
- if (mWindow == null) {
- // already detached!
- return;
+ if (mStarted) {
+ if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+ mStarted = false;
+ onDreamingStopped();
}
- if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
- onDreamingStopped();
+ if (mWindow != null) {
+ // force our window to be removed synchronously
+ if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
+ mWindow.getWindowManager().removeViewImmediate(mWindow.getDecorView());
+ mWindow = null;
+ }
- if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
-
- // force our window to be removed synchronously
- mWindowManager.removeViewImmediate(mWindow.getDecorView());
- // the following will print a log message if it finds any other leaked windows
- WindowManagerGlobal.getInstance().closeAll(mWindowToken,
- this.getClass().getName(), "Dream");
-
- mWindow = null;
- mWindowToken = null;
+ if (mWindowToken != null) {
+ // the following will print a log message if it finds any other leaked windows
+ WindowManagerGlobal.getInstance().closeAll(mWindowToken,
+ this.getClass().getName(), "Dream");
+ mWindowToken = null;
+ }
}
/**
@@ -746,12 +747,13 @@
if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
mWindowToken = windowToken;
+ mCanDoze = canDoze;
+
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mWindow.setFormat(PixelFormat.OPAQUE);
- mCanDoze = canDoze;
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -769,26 +771,28 @@
| (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
);
mWindow.setAttributes(lp);
-
- if (mDebug) Slog.v(TAG, "Created and attached window: " + mWindow);
-
mWindow.setWindowManager(null, windowToken, "dream", true);
- mWindowManager = mWindow.getWindowManager();
- if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
applySystemUiVisibilityFlags(
(mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
View.SYSTEM_UI_FLAG_LOW_PROFILE);
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+
+ try {
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
+ } catch (WindowManager.BadTokenException ex) {
+ // This can happen because the dream manager service will remove the token
+ // immediately without necessarily waiting for the dream to start.
+ // We should receive a finish message soon.
+ Slog.i(TAG, "attach() called after window token already removed, dream will "
+ + "finish soon");
+ mWindow = null;
+ return;
+ }
// start it up
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
- onDreamingStarted();
- }
- });
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ mStarted = true;
+ onDreamingStarted();
}
private void safelyFinish() {
@@ -831,7 +835,7 @@
WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.flags = applyFlags(lp.flags, flags, mask);
mWindow.setAttributes(lp);
- mWindowManager.updateViewLayout(mWindow.getDecorView(), lp);
+ mWindow.getWindowManager().updateViewLayout(mWindow.getDecorView(), lp);
}
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index a92f89d..4f646e1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -182,7 +182,7 @@
public static boolean sSystemRendererDisabled = false;
/** @hide */
- public static boolean sUseRenderThread = true;
+ public static boolean sUseRenderThread = false;
private boolean mEnabled;
private boolean mRequested = true;
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index a27c313..26eaef8 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.graphics.Matrix;
import android.graphics.Outline;
@@ -196,18 +197,20 @@
}
/**
- * Starts recording the display list. All operations performed on the
- * returned canvas are recorded and stored in this display list.
+ * Starts recording a display list for the render node. All
+ * operations performed on the returned canvas are recorded and
+ * stored in this display list.
*
- * Calling this method will mark the display list invalid until
- * {@link #end()} is called. Only valid display lists can be replayed.
+ * Calling this method will mark the render node invalid until
+ * {@link #end(HardwareRenderer, HardwareCanvas)} is called.
+ * Only valid render nodes can be replayed.
*
- * @param width The width of the display list's viewport
- * @param height The height of the display list's viewport
+ * @param width The width of the recording viewport
+ * @param height The height of the recording viewport
*
* @return A canvas to record drawing operations.
*
- * @see #end()
+ * @see #end(HardwareRenderer, HardwareCanvas)
* @see #isValid()
*/
public HardwareCanvas start(int width, int height) {
@@ -284,7 +287,23 @@
}
///////////////////////////////////////////////////////////////////////////
- // DisplayList Property Setters
+ // Matrix manipulation
+ ///////////////////////////////////////////////////////////////////////////
+
+ public boolean hasIdentityMatrix() {
+ return nHasIdentityMatrix(mNativeDisplayList);
+ }
+
+ public void getMatrix(@NonNull Matrix outMatrix) {
+ nGetTransformMatrix(mNativeDisplayList, outMatrix.native_instance);
+ }
+
+ public void getInverseMatrix(@NonNull Matrix outMatrix) {
+ nGetInverseTransformMatrix(mNativeDisplayList, outMatrix.native_instance);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // RenderProperty Setters
///////////////////////////////////////////////////////////////////////////
/**
@@ -301,7 +320,7 @@
}
/**
- * Set whether the display list should clip itself to its bounds. This property is controlled by
+ * Set whether the Render node should clip itself to its bounds. This property is controlled by
* the view's parent.
*
* @param clipToBounds true if the display list should clip to its bounds
@@ -312,9 +331,7 @@
/**
* Sets whether the display list should be drawn immediately after the
- * closest ancestor display list where isolateZVolume is true. If the
- * display list itself satisfies this constraint, changing this attribute
- * has no effect on drawing order.
+ * closest ancestor display list containing a projection receiver.
*
* @param shouldProject true if the display list should be projected onto a
* containing volume.
@@ -373,9 +390,6 @@
* transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.)
*
* @param matrix A transform matrix to apply to this display list
- *
- * @see #getMatrix(android.graphics.Matrix)
- * @see #getMatrix()
*/
public void setStaticMatrix(Matrix matrix) {
nSetStaticMatrix(mNativeDisplayList, matrix.native_instance);
@@ -613,28 +627,6 @@
}
/**
- * Sets all of the transform-related values of the display list
- *
- * @param alpha The alpha value of the display list
- * @param translationX The translationX value of the display list
- * @param translationY The translationY value of the display list
- * @param rotation The rotation value of the display list
- * @param rotationX The rotationX value of the display list
- * @param rotationY The rotationY value of the display list
- * @param scaleX The scaleX value of the display list
- * @param scaleY The scaleY value of the display list
- *
- * @hide
- */
- public void setTransformationInfo(float alpha,
- float translationX, float translationY, float translationZ,
- float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
- nSetTransformationInfo(mNativeDisplayList, alpha,
- translationX, translationY, translationZ,
- rotation, rotationX, rotationY, scaleX, scaleY);
- }
-
- /**
* Sets the pivot value for the display list on the X axis
*
* @param pivotX The pivot value of the display list on the X axis, in pixels
@@ -676,6 +668,10 @@
return nGetPivotY(mNativeDisplayList);
}
+ public boolean isPivotExplicitlySet() {
+ return nIsPivotExplicitlySet(mNativeDisplayList);
+ }
+
/**
* Sets the camera distance for the display list. Refer to
* {@link View#setCameraDistance(float)} for more information on how to
@@ -842,6 +838,12 @@
private static native void nDestroyDisplayList(long displayList);
private static native void nSetDisplayListName(long displayList, String name);
+ // Matrix
+
+ private static native void nGetTransformMatrix(long displayList, long nativeMatrix);
+ private static native void nGetInverseTransformMatrix(long displayList, long nativeMatrix);
+ private static native boolean nHasIdentityMatrix(long displayList);
+
// Properties
private static native void nOffsetTopAndBottom(long displayList, float offset);
@@ -877,9 +879,6 @@
private static native void nSetRotationY(long displayList, float rotationY);
private static native void nSetScaleX(long displayList, float scaleX);
private static native void nSetScaleY(long displayList, float scaleY);
- private static native void nSetTransformationInfo(long displayList, float alpha,
- float translationX, float translationY, float translationZ,
- float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
private static native void nSetStaticMatrix(long displayList, long nativeMatrix);
private static native void nSetAnimationMatrix(long displayList, long animationMatrix);
@@ -898,6 +897,7 @@
private static native float nGetRotation(long displayList);
private static native float nGetRotationX(long displayList);
private static native float nGetRotationY(long displayList);
+ private static native boolean nIsPivotExplicitlySet(long displayList);
private static native float nGetPivotX(long displayList);
private static native float nGetPivotY(long displayList);
private static native void nOutput(long displayList);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5be4698..6c414f6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1792,12 +1792,9 @@
private static final int PFLAG_HOVERED = 0x10000000;
/**
- * Indicates that pivotX or pivotY were explicitly set and we should not assume the center
- * for transform operations
- *
- * @hide
+ * no longer needed, should be reused
*/
- private static final int PFLAG_PIVOT_EXPLICITLY_SET = 0x20000000;
+ private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000;
/** {@hide} */
static final int PFLAG_ACTIVATED = 0x40000000;
@@ -2930,123 +2927,23 @@
static class TransformationInfo {
/**
* The transform matrix for the View. This transform is calculated internally
- * based on the rotation, scaleX, and scaleY properties. The identity matrix
- * is used by default. Do *not* use this variable directly; instead call
- * getMatrix(), which will automatically recalculate the matrix if necessary
- * to get the correct matrix based on the latest rotation and scale properties.
+ * based on the translation, rotation, and scale properties.
+ *
+ * Do *not* use this variable directly; instead call getMatrix(), which will
+ * load the value from the View's RenderNode.
*/
private final Matrix mMatrix = new Matrix();
/**
- * The transform matrix for the View. This transform is calculated internally
- * based on the rotation, scaleX, and scaleY properties. The identity matrix
- * is used by default. Do *not* use this variable directly; instead call
- * getInverseMatrix(), which will automatically recalculate the matrix if necessary
- * to get the correct matrix based on the latest rotation and scale properties.
+ * The inverse transform matrix for the View. This transform is calculated
+ * internally based on the translation, rotation, and scale properties.
+ *
+ * Do *not* use this variable directly; instead call getInverseMatrix(),
+ * which will load the value from the View's RenderNode.
*/
private Matrix mInverseMatrix;
/**
- * An internal variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated.
- */
- boolean mMatrixDirty = false;
-
- /**
- * An internal variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated.
- */
- private boolean mInverseMatrixDirty = true;
-
- /**
- * A variable that tracks whether we need to recalculate the
- * transform matrix, based on whether the rotation or scaleX/Y properties
- * have changed since the matrix was last calculated. This variable
- * is only valid after a call to updateMatrix() or to a function that
- * calls it such as getMatrix(), hasIdentityMatrix() and getInverseMatrix().
- */
- private boolean mMatrixIsIdentity = true;
-
- /**
- * The Camera object is used to compute a 3D matrix when rotationX or rotationY are set.
- */
- private Camera mCamera = null;
-
- /**
- * This matrix is used when computing the matrix for 3D rotations.
- */
- private Matrix matrix3D = null;
-
- /**
- * These prev values are used to recalculate a centered pivot point when necessary. The
- * pivot point is only used in matrix operations (when rotation, scale, or translation are
- * set), so thes values are only used then as well.
- */
- private int mPrevWidth = -1;
- private int mPrevHeight = -1;
-
- /**
- * The degrees rotation around the vertical axis through the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotationY = 0f;
-
- /**
- * The degrees rotation around the horizontal axis through the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotationX = 0f;
-
- /**
- * The degrees rotation around the pivot point.
- */
- @ViewDebug.ExportedProperty
- float mRotation = 0f;
-
- /**
- * The amount of translation of the object away from its left property (post-layout).
- */
- @ViewDebug.ExportedProperty
- float mTranslationX = 0f;
-
- /**
- * The amount of translation of the object away from its top property (post-layout).
- */
- @ViewDebug.ExportedProperty
- float mTranslationY = 0f;
-
- @ViewDebug.ExportedProperty
- float mTranslationZ = 0f;
-
- /**
- * The amount of scale in the x direction around the pivot point. A
- * value of 1 means no scaling is applied.
- */
- @ViewDebug.ExportedProperty
- float mScaleX = 1f;
-
- /**
- * The amount of scale in the y direction around the pivot point. A
- * value of 1 means no scaling is applied.
- */
- @ViewDebug.ExportedProperty
- float mScaleY = 1f;
-
- /**
- * The x location of the point around which the view is rotated and scaled.
- */
- @ViewDebug.ExportedProperty
- float mPivotX = 0f;
-
- /**
- * The y location of the point around which the view is rotated and scaled.
- */
- @ViewDebug.ExportedProperty
- float mPivotY = 0f;
-
- /**
* The opacity of the View. This is a value from 0 to 1, where 0 means
* completely transparent and 1 means completely opaque.
*/
@@ -3557,7 +3454,7 @@
* of the View content. Its DisplayList content is cleared on temporary detach and reset on
* cleanup.
*/
- RenderNode mRenderNode;
+ final RenderNode mRenderNode;
/**
* Set to true when the view is sending hover accessibility events because it
@@ -3608,6 +3505,7 @@
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
mUserPaddingStart = UNDEFINED_PADDING;
mUserPaddingEnd = UNDEFINED_PADDING;
+ mRenderNode = RenderNode.create(getClass().getName());
if (!sCompatibilityDone && context != null) {
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
@@ -4172,6 +4070,7 @@
*/
View() {
mResources = null;
+ mRenderNode = RenderNode.create(getClass().getName());
}
public String toString() {
@@ -4847,10 +4746,10 @@
final float x = r.exactCenterX();
final float y = r.exactCenterY();
- mBackground.setHotspot(Drawable.HOTSPOT_FOCUS, x, y);
+ mBackground.setHotspot(R.attr.state_focused, x, y);
if (!focused) {
- mBackground.removeHotspot(Drawable.HOTSPOT_FOCUS);
+ mBackground.removeHotspot(R.attr.state_focused);
}
}
}
@@ -9092,6 +8991,8 @@
}
removeTapCallback();
+ } else {
+ clearHotspot(R.attr.state_pressed);
}
break;
@@ -9204,6 +9105,7 @@
*/
private void removeUnsetPressCallback() {
if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) {
+ clearHotspot(R.attr.state_pressed);
setPressed(false);
removeCallbacks(mUnsetPressedState);
}
@@ -9682,21 +9584,10 @@
* @return The current transform matrix for the view
*/
public Matrix getMatrix() {
- if (mTransformationInfo != null) {
- updateMatrix();
- return mTransformationInfo.mMatrix;
- }
- return Matrix.IDENTITY_MATRIX;
- }
-
- /**
- * Utility function to determine if the value is far enough away from zero to be
- * considered non-zero.
- * @param value A floating point value to check for zero-ness
- * @return whether the passed-in value is far enough away from zero to be considered non-zero
- */
- private static boolean nonzero(float value) {
- return (value < -NONZERO_EPSILON || value > NONZERO_EPSILON);
+ ensureTransformationInfo();
+ final Matrix matrix = mTransformationInfo.mMatrix;
+ mRenderNode.getMatrix(matrix);
+ return matrix;
}
/**
@@ -9706,11 +9597,7 @@
* @return True if the transform matrix is the identity matrix, false otherwise.
*/
final boolean hasIdentityMatrix() {
- if (mTransformationInfo != null) {
- updateMatrix();
- return mTransformationInfo.mMatrixIsIdentity;
- }
- return true;
+ return mRenderNode.hasIdentityMatrix();
}
void ensureTransformationInfo() {
@@ -9719,59 +9606,6 @@
}
}
- void ensureRenderNode() {
- if (mRenderNode == null) {
- mRenderNode = RenderNode.create(getClass().getName());
- }
- }
-
- /**
- * Recomputes the transform matrix if necessary.
- */
- private void updateMatrix() {
- final TransformationInfo info = mTransformationInfo;
- if (info == null) {
- return;
- }
- if (info.mMatrixDirty) {
- // transform-related properties have changed since the last time someone
- // asked for the matrix; recalculate it with the current values
-
- // Figure out if we need to update the pivot point
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- if ((mRight - mLeft) != info.mPrevWidth || (mBottom - mTop) != info.mPrevHeight) {
- info.mPrevWidth = mRight - mLeft;
- info.mPrevHeight = mBottom - mTop;
- info.mPivotX = info.mPrevWidth / 2f;
- info.mPivotY = info.mPrevHeight / 2f;
- }
- }
- info.mMatrix.reset();
- if (!nonzero(info.mRotationX) && !nonzero(info.mRotationY)) {
- info.mMatrix.setTranslate(info.mTranslationX, info.mTranslationY);
- info.mMatrix.preRotate(info.mRotation, info.mPivotX, info.mPivotY);
- info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY);
- } else {
- if (info.mCamera == null) {
- info.mCamera = new Camera();
- info.matrix3D = new Matrix();
- }
- info.mCamera.save();
- info.mMatrix.preScale(info.mScaleX, info.mScaleY, info.mPivotX, info.mPivotY);
- info.mCamera.rotate(info.mRotationX, info.mRotationY, -info.mRotation);
- info.mCamera.getMatrix(info.matrix3D);
- info.matrix3D.preTranslate(-info.mPivotX, -info.mPivotY);
- info.matrix3D.postTranslate(info.mPivotX + info.mTranslationX,
- info.mPivotY + info.mTranslationY);
- info.mMatrix.postConcat(info.matrix3D);
- info.mCamera.restore();
- }
- info.mMatrixDirty = false;
- info.mMatrixIsIdentity = info.mMatrix.isIdentity();
- info.mInverseMatrixDirty = true;
- }
- }
-
/**
* Utility method to retrieve the inverse of the current mMatrix property.
* We cache the matrix to avoid recalculating it when transform properties
@@ -9780,19 +9614,13 @@
* @return The inverse of the current matrix of this view.
*/
final Matrix getInverseMatrix() {
- final TransformationInfo info = mTransformationInfo;
- if (info != null) {
- updateMatrix();
- if (info.mInverseMatrixDirty) {
- if (info.mInverseMatrix == null) {
- info.mInverseMatrix = new Matrix();
- }
- info.mMatrix.invert(info.mInverseMatrix);
- info.mInverseMatrixDirty = false;
- }
- return info.mInverseMatrix;
+ ensureTransformationInfo();
+ if (mTransformationInfo.mInverseMatrix == null) {
+ mTransformationInfo.mInverseMatrix = new Matrix();
}
- return Matrix.IDENTITY_MATRIX;
+ final Matrix matrix = mTransformationInfo.mInverseMatrix;
+ mRenderNode.getInverseMatrix(matrix);
+ return matrix;
}
/**
@@ -9803,14 +9631,8 @@
* @return The distance along the Z axis.
*/
public float getCameraDistance() {
- ensureTransformationInfo();
final float dpi = mResources.getDisplayMetrics().densityDpi;
- final TransformationInfo info = mTransformationInfo;
- if (info.mCamera == null) {
- info.mCamera = new Camera();
- info.matrix3D = new Matrix();
- }
- return -(info.mCamera.getLocationZ() * dpi);
+ return -(mRenderNode.getCameraDistance() * dpi);
}
/**
@@ -9853,27 +9675,13 @@
* @see #setRotationY(float)
*/
public void setCameraDistance(float distance) {
- invalidateViewProperty(true, false);
-
- ensureTransformationInfo();
final float dpi = mResources.getDisplayMetrics().densityDpi;
- final TransformationInfo info = mTransformationInfo;
- if (info.mCamera == null) {
- info.mCamera = new Camera();
- info.matrix3D = new Matrix();
- }
- info.mCamera.setLocation(0.0f, 0.0f, -Math.abs(distance) / dpi);
- info.mMatrixDirty = true;
-
+ invalidateViewProperty(true, false);
+ mRenderNode.setCameraDistance(-Math.abs(distance) / dpi);
invalidateViewProperty(false, false);
- if (mRenderNode != null) {
- mRenderNode.setCameraDistance(-Math.abs(distance) / dpi);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
/**
@@ -9887,7 +9695,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getRotation() {
- return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
+ return mRenderNode.getRotation();
}
/**
@@ -9905,21 +9713,13 @@
* @attr ref android.R.styleable#View_rotation
*/
public void setRotation(float rotation) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mRotation != rotation) {
+ if (rotation != getRotation()) {
// Double-invalidation is necessary to capture view's old and new areas
invalidateViewProperty(true, false);
- info.mRotation = rotation;
- info.mMatrixDirty = true;
+ mRenderNode.setRotation(rotation);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setRotation(rotation);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -9934,7 +9734,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getRotationY() {
- return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
+ return mRenderNode.getRotationY();
}
/**
@@ -9957,20 +9757,12 @@
* @attr ref android.R.styleable#View_rotationY
*/
public void setRotationY(float rotationY) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mRotationY != rotationY) {
+ if (rotationY != getRotationY()) {
invalidateViewProperty(true, false);
- info.mRotationY = rotationY;
- info.mMatrixDirty = true;
+ mRenderNode.setRotationY(rotationY);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setRotationY(rotationY);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -9985,7 +9777,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getRotationX() {
- return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
+ return mRenderNode.getRotationX();
}
/**
@@ -10008,20 +9800,12 @@
* @attr ref android.R.styleable#View_rotationX
*/
public void setRotationX(float rotationX) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mRotationX != rotationX) {
+ if (rotationX != getRotationX()) {
invalidateViewProperty(true, false);
- info.mRotationX = rotationX;
- info.mMatrixDirty = true;
+ mRenderNode.setRotationX(rotationX);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setRotationX(rotationX);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10037,7 +9821,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getScaleX() {
- return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
+ return mRenderNode.getScaleX();
}
/**
@@ -10051,20 +9835,12 @@
* @attr ref android.R.styleable#View_scaleX
*/
public void setScaleX(float scaleX) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mScaleX != scaleX) {
+ if (scaleX != getScaleX()) {
invalidateViewProperty(true, false);
- info.mScaleX = scaleX;
- info.mMatrixDirty = true;
+ mRenderNode.setScaleX(scaleX);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setScaleX(scaleX);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10080,7 +9856,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getScaleY() {
- return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
+ return mRenderNode.getScaleY();
}
/**
@@ -10094,20 +9870,12 @@
* @attr ref android.R.styleable#View_scaleY
*/
public void setScaleY(float scaleY) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mScaleY != scaleY) {
+ if (scaleY != getScaleY()) {
invalidateViewProperty(true, false);
- info.mScaleY = scaleY;
- info.mMatrixDirty = true;
+ mRenderNode.setScaleY(scaleY);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setScaleY(scaleY);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10125,7 +9893,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getPivotX() {
- return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
+ return mRenderNode.getPivotX();
}
/**
@@ -10144,23 +9912,12 @@
* @attr ref android.R.styleable#View_transformPivotX
*/
public void setPivotX(float pivotX) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
- PFLAG_PIVOT_EXPLICITLY_SET;
- if (info.mPivotX != pivotX || !pivotSet) {
- mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
+ if (mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) {
invalidateViewProperty(true, false);
- info.mPivotX = pivotX;
- info.mMatrixDirty = true;
+ mRenderNode.setPivotX(pivotX);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setPivotX(pivotX);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10178,7 +9935,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getPivotY() {
- return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
+ return mRenderNode.getPivotY();
}
/**
@@ -10196,23 +9953,12 @@
* @attr ref android.R.styleable#View_transformPivotY
*/
public void setPivotY(float pivotY) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
- PFLAG_PIVOT_EXPLICITLY_SET;
- if (info.mPivotY != pivotY || !pivotSet) {
- mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
+ if (mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) {
invalidateViewProperty(true, false);
- info.mPivotY = pivotY;
- info.mMatrixDirty = true;
+ mRenderNode.setPivotY(pivotY);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setPivotY(pivotY);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10290,9 +10036,7 @@
} else {
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
- if (mRenderNode != null) {
- mRenderNode.setAlpha(getFinalAlpha());
- }
+ mRenderNode.setAlpha(getFinalAlpha());
}
}
}
@@ -10317,9 +10061,7 @@
return true;
} else {
mPrivateFlags &= ~PFLAG_ALPHA_SET;
- if (mRenderNode != null) {
- mRenderNode.setAlpha(getFinalAlpha());
- }
+ mRenderNode.setAlpha(getFinalAlpha());
}
}
return false;
@@ -10340,9 +10082,7 @@
mTransformationInfo.mTransitionAlpha = alpha;
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
- if (mRenderNode != null) {
- mRenderNode.setAlpha(getFinalAlpha());
- }
+ mRenderNode.setAlpha(getFinalAlpha());
}
}
@@ -10389,9 +10129,7 @@
*/
public final void setTop(int top) {
if (top != mTop) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
int minTop;
@@ -10414,17 +10152,11 @@
int oldHeight = mBottom - mTop;
mTop = top;
- if (mRenderNode != null) {
- mRenderNode.setTop(mTop);
- }
+ mRenderNode.setTop(mTop);
sizeChange(width, mBottom - mTop, width, oldHeight);
if (!matrixIsIdentity) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- mTransformationInfo.mMatrixDirty = true;
- }
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
invalidate(true);
}
@@ -10465,9 +10197,7 @@
*/
public final void setBottom(int bottom) {
if (bottom != mBottom) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
int maxBottom;
@@ -10487,17 +10217,11 @@
int oldHeight = mBottom - mTop;
mBottom = bottom;
- if (mRenderNode != null) {
- mRenderNode.setBottom(mBottom);
- }
+ mRenderNode.setBottom(mBottom);
sizeChange(width, mBottom - mTop, width, oldHeight);
if (!matrixIsIdentity) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- mTransformationInfo.mMatrixDirty = true;
- }
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
invalidate(true);
}
@@ -10529,9 +10253,7 @@
*/
public final void setLeft(int left) {
if (left != mLeft) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
int minLeft;
@@ -10554,17 +10276,11 @@
int height = mBottom - mTop;
mLeft = left;
- if (mRenderNode != null) {
- mRenderNode.setLeft(left);
- }
+ mRenderNode.setLeft(left);
sizeChange(mRight - mLeft, height, oldWidth, height);
if (!matrixIsIdentity) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- mTransformationInfo.mMatrixDirty = true;
- }
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
invalidate(true);
}
@@ -10596,9 +10312,7 @@
*/
public final void setRight(int right) {
if (right != mRight) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
if (mAttachInfo != null) {
int maxRight;
@@ -10618,17 +10332,11 @@
int height = mBottom - mTop;
mRight = right;
- if (mRenderNode != null) {
- mRenderNode.setRight(mRight);
- }
+ mRenderNode.setRight(mRight);
sizeChange(mRight - mLeft, height, oldWidth, height);
if (!matrixIsIdentity) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- mTransformationInfo.mMatrixDirty = true;
- }
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
invalidate(true);
}
@@ -10650,7 +10358,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getX() {
- return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
+ return mLeft + getTranslationX();
}
/**
@@ -10673,7 +10381,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getY() {
- return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
+ return mTop + getTranslationY();
}
/**
@@ -10697,7 +10405,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationX() {
- return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
+ return mRenderNode.getTranslationX();
}
/**
@@ -10711,21 +10419,12 @@
* @attr ref android.R.styleable#View_translationX
*/
public void setTranslationX(float translationX) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mTranslationX != translationX) {
- // Double-invalidation is necessary to capture view's old and new areas
+ if (translationX != getTranslationX()) {
invalidateViewProperty(true, false);
- info.mTranslationX = translationX;
- info.mMatrixDirty = true;
+ mRenderNode.setTranslationX(translationX);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setTranslationX(translationX);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10739,7 +10438,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationY() {
- return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
+ return mRenderNode.getTranslationY();
}
/**
@@ -10753,20 +10452,12 @@
* @attr ref android.R.styleable#View_translationY
*/
public void setTranslationY(float translationY) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mTranslationY != translationY) {
+ if (translationY != getTranslationY()) {
invalidateViewProperty(true, false);
- info.mTranslationY = translationY;
- info.mMatrixDirty = true;
+ mRenderNode.setTranslationY(translationY);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setTranslationY(translationY);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10777,7 +10468,7 @@
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationZ() {
- return mTransformationInfo != null ? mTransformationInfo.mTranslationZ : 0;
+ return mRenderNode.getTranslationZ();
}
/**
@@ -10786,20 +10477,12 @@
* @attr ref android.R.styleable#View_translationZ
*/
public void setTranslationZ(float translationZ) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- if (info.mTranslationZ != translationZ) {
+ if (translationZ != getTranslationZ()) {
invalidateViewProperty(true, false);
- info.mTranslationZ = translationZ;
- info.mMatrixDirty = true;
+ mRenderNode.setTranslationZ(translationZ);
invalidateViewProperty(false, true);
- if (mRenderNode != null) {
- mRenderNode.setTranslationZ(translationZ);
- }
- if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
- // View was rejected last time it was drawn by its parent; this may have changed
- invalidateParentIfNeeded();
- }
+
+ invalidateParentIfNeededAndWasQuickRejected();
}
}
@@ -10869,10 +10552,7 @@
}
mOutline.set(outline);
}
-
- if (mRenderNode != null) {
- mRenderNode.setOutline(mOutline);
- }
+ mRenderNode.setOutline(mOutline);
}
/**
@@ -10907,9 +10587,7 @@
} else {
mPrivateFlags3 &= ~PFLAG3_CLIP_TO_OUTLINE;
}
- if (mRenderNode != null) {
- mRenderNode.setClipToOutline(clipToOutline);
- }
+ mRenderNode.setClipToOutline(clipToOutline);
}
}
@@ -10920,11 +10598,9 @@
*/
public void setRevealClip(boolean shouldClip, boolean inverseClip,
float x, float y, float radius) {
- if (mRenderNode != null) {
- mRenderNode.setRevealClip(shouldClip, inverseClip, x, y, radius);
- // TODO: Handle this invalidate in a better way, or purely in native.
- invalidate();
- }
+ mRenderNode.setRevealClip(shouldClip, inverseClip, x, y, radius);
+ // TODO: Handle this invalidate in a better way, or purely in native.
+ invalidate();
}
/**
@@ -10933,14 +10609,12 @@
* @param outRect The hit rectangle of the view.
*/
public void getHitRect(Rect outRect) {
- updateMatrix();
- final TransformationInfo info = mTransformationInfo;
- if (info == null || info.mMatrixIsIdentity || mAttachInfo == null) {
+ if (hasIdentityMatrix() || mAttachInfo == null) {
outRect.set(mLeft, mTop, mRight, mBottom);
} else {
final RectF tmpRect = mAttachInfo.mTmpTransformRect;
tmpRect.set(0, 0, getWidth(), getHeight());
- info.mMatrix.mapRect(tmpRect);
+ getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect)
outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop,
(int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop);
}
@@ -11029,11 +10703,9 @@
*/
public void offsetTopAndBottom(int offset) {
if (offset != 0) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
- if (mRenderNode != null) {
+ if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
final ViewParent p = mParent;
@@ -11061,8 +10733,8 @@
mTop += offset;
mBottom += offset;
- if (mRenderNode != null) {
- mRenderNode.offsetTopAndBottom(offset);
+ mRenderNode.offsetTopAndBottom(offset);
+ if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
if (!matrixIsIdentity) {
@@ -11080,11 +10752,9 @@
*/
public void offsetLeftAndRight(int offset) {
if (offset != 0) {
- updateMatrix();
- final boolean matrixIsIdentity = mTransformationInfo == null
- || mTransformationInfo.mMatrixIsIdentity;
+ final boolean matrixIsIdentity = hasIdentityMatrix();
if (matrixIsIdentity) {
- if (mRenderNode != null) {
+ if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
final ViewParent p = mParent;
@@ -11109,8 +10779,8 @@
mLeft += offset;
mRight += offset;
- if (mRenderNode != null) {
- mRenderNode.offsetLeftAndRight(offset);
+ mRenderNode.offsetLeftAndRight(offset);
+ if (isHardwareAccelerated()) {
invalidateViewProperty(false, false);
} else {
if (!matrixIsIdentity) {
@@ -11490,7 +11160,7 @@
}
// Damage the entire IsolatedZVolume recieving this view's shadow.
- if (getTranslationZ() != 0) {
+ if (isHardwareAccelerated() && getTranslationZ() != 0) {
damageShadowReceiver();
}
}
@@ -11553,7 +11223,9 @@
* list properties are not being used in this view
*/
void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
- if (mRenderNode == null || (mPrivateFlags & PFLAG_DRAW_ANIMATION) == PFLAG_DRAW_ANIMATION) {
+ if (!isHardwareAccelerated()
+ || !mRenderNode.isValid()
+ || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {
if (invalidateParent) {
invalidateParentCaches();
}
@@ -11564,7 +11236,7 @@
} else {
damageInParent();
}
- if (invalidateParent && getTranslationZ() != 0) {
+ if (isHardwareAccelerated() && invalidateParent && getTranslationZ() != 0) {
damageShadowReceiver();
}
}
@@ -11581,7 +11253,7 @@
final Rect r = ai.mTmpInvalRect;
r.set(0, 0, mRight - mLeft, mBottom - mTop);
if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).invalidateChildFast(this, r);
+ ((ViewGroup) mParent).damageChild(this, r);
} else {
mParent.invalidateChild(this, r);
}
@@ -11634,6 +11306,16 @@
}
/**
+ * @hide
+ */
+ protected void invalidateParentIfNeededAndWasQuickRejected() {
+ if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) {
+ // View was rejected last time it was drawn by its parent; this may have changed
+ invalidateParentIfNeeded();
+ }
+ }
+
+ /**
* Indicates whether this View is opaque. An opaque View guarantees that it will
* draw all the pixels overlapping its bounds using a fully opaque color.
*
@@ -13976,13 +13658,12 @@
* @hide
*/
public RenderNode getDisplayList() {
- ensureRenderNode();
updateDisplayListIfDirty(mRenderNode, false);
return mRenderNode;
}
private void resetDisplayList() {
- if (mRenderNode != null && mRenderNode.isValid()) {
+ if (mRenderNode.isValid()) {
mRenderNode.destroyDisplayListData();
}
@@ -14577,21 +14258,16 @@
}
/**
- * This method is called by getDisplayList() when a display list is created or re-rendered.
- * It sets or resets the current value of all properties on that display list (resetting is
- * necessary when a display list is being re-created, because we need to make sure that
- * previously-set transform values
+ * This method is called by getDisplayList() when a display list is recorded for a View.
+ * It pushes any properties to the RenderNode that aren't managed by the RenderNode.
*/
- void setDisplayListProperties(RenderNode displayList) {
- if (displayList != null) {
- displayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
- displayList.setHasOverlappingRendering(hasOverlappingRendering());
+ void setDisplayListProperties(RenderNode renderNode) {
+ if (renderNode != null) {
+ renderNode.setHasOverlappingRendering(hasOverlappingRendering());
if (mParent instanceof ViewGroup) {
- displayList.setClipToBounds(
+ renderNode.setClipToBounds(
(((ViewGroup) mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
}
- displayList.setOutline(mOutline);
- displayList.setClipToOutline(getClipToOutline());
float alpha = 1;
if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
@@ -14604,7 +14280,7 @@
alpha = t.getAlpha();
}
if ((transformType & Transformation.TYPE_MATRIX) != 0) {
- displayList.setStaticMatrix(t.getMatrix());
+ renderNode.setStaticMatrix(t.getMatrix());
}
}
}
@@ -14617,23 +14293,9 @@
alpha = 1;
}
}
- displayList.setTransformationInfo(alpha,
- mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY,
- mTransformationInfo.mTranslationZ,
- mTransformationInfo.mRotation, mTransformationInfo.mRotationX,
- mTransformationInfo.mRotationY, mTransformationInfo.mScaleX,
- mTransformationInfo.mScaleY);
- if (mTransformationInfo.mCamera == null) {
- mTransformationInfo.mCamera = new Camera();
- mTransformationInfo.matrix3D = new Matrix();
- }
- displayList.setCameraDistance(mTransformationInfo.mCamera.getLocationZ());
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == PFLAG_PIVOT_EXPLICITLY_SET) {
- displayList.setPivotX(getPivotX());
- displayList.setPivotY(getPivotY());
- }
+ renderNode.setAlpha(alpha);
} else if (alpha < 1) {
- displayList.setAlpha(alpha);
+ renderNode.setAlpha(alpha);
}
}
}
@@ -14680,8 +14342,7 @@
}
transformToApply = parent.getChildTransformation();
} else {
- if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) ==
- PFLAG3_VIEW_IS_ANIMATING_TRANSFORM && mRenderNode != null) {
+ if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) {
// No longer animating: clear out old animation matrix
mRenderNode.setAnimationMatrix(null);
mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
@@ -15196,9 +14857,7 @@
if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
// Outline not currently define, query from background
mOutline = background.getOutline();
- if (mRenderNode != null) {
- mRenderNode.setOutline(mOutline);
- }
+ mRenderNode.setOutline(mOutline);
}
}
@@ -15533,20 +15192,12 @@
mTop = top;
mRight = right;
mBottom = bottom;
- if (mRenderNode != null) {
- mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
- }
+ mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
mPrivateFlags |= PFLAG_HAS_BOUNDS;
if (sizeChanged) {
- if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
- // A change in dimension means an auto-centered pivot point changes, too
- if (mTransformationInfo != null) {
- mTransformationInfo.mMatrixDirty = true;
- }
- }
sizeChange(newWidth, newHeight, oldWidth, oldHeight);
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index bcc82fb..d2c6302 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4449,7 +4449,7 @@
*
* @hide
*/
- public void invalidateChildFast(View child, final Rect dirty) {
+ public void damageChild(View child, final Rect dirty) {
ViewParent parent = this;
final AttachInfo attachInfo = mAttachInfo;
@@ -4472,7 +4472,7 @@
parentVG.invalidate();
parent = null;
} else {
- parent = parentVG.invalidateChildInParentFast(left, top, dirty);
+ parent = parentVG.damageChildInParent(left, top, dirty);
left = parentVG.mLeft;
top = parentVG.mTop;
}
@@ -4494,9 +4494,9 @@
*
* @hide
*/
- protected ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
- if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
- (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
+ protected ViewParent damageChildInParent(int left, int top, final Rect dirty) {
+ if ((mPrivateFlags & PFLAG_DRAWN) != 0
+ || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) != 0) {
dirty.offset(left - mScrollX, top - mScrollY);
if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
diff --git a/core/java/android/view/ViewOverlay.java b/core/java/android/view/ViewOverlay.java
index 47de780..0cf9ddd 100644
--- a/core/java/android/view/ViewOverlay.java
+++ b/core/java/android/view/ViewOverlay.java
@@ -290,7 +290,11 @@
}
}
- public void invalidateChildFast(View child, final Rect dirty) {
+ /**
+ * @hide
+ */
+ @Override
+ public void damageChild(View child, final Rect dirty) {
if (mHostView != null) {
// Note: This is not a "fast" invalidation. Would be nice to instead invalidate
// using DisplayList properties and a dirty rect instead of causing a real
@@ -309,9 +313,9 @@
* @hide
*/
@Override
- protected ViewParent invalidateChildInParentFast(int left, int top, Rect dirty) {
+ protected ViewParent damageChildInParent(int left, int top, Rect dirty) {
if (mHostView instanceof ViewGroup) {
- return ((ViewGroup) mHostView).invalidateChildInParentFast(left, top, dirty);
+ return ((ViewGroup) mHostView).damageChildInParent(left, top, dirty);
}
return null;
}
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index bbae0ca..6b21451 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -928,48 +928,38 @@
final RenderNode renderNode = mView.mRenderNode;
switch (propertyConstant) {
case TRANSLATION_X:
- info.mTranslationX = value;
- if (renderNode != null) renderNode.setTranslationX(value);
+ renderNode.setTranslationX(value);
break;
case TRANSLATION_Y:
- info.mTranslationY = value;
- if (renderNode != null) renderNode.setTranslationY(value);
+ renderNode.setTranslationY(value);
break;
case TRANSLATION_Z:
- info.mTranslationZ = value;
- if (renderNode != null) renderNode.setTranslationZ(value);
+ renderNode.setTranslationZ(value);
break;
case ROTATION:
- info.mRotation = value;
- if (renderNode != null) renderNode.setRotation(value);
+ renderNode.setRotation(value);
break;
case ROTATION_X:
- info.mRotationX = value;
- if (renderNode != null) renderNode.setRotationX(value);
+ renderNode.setRotationX(value);
break;
case ROTATION_Y:
- info.mRotationY = value;
- if (renderNode != null) renderNode.setRotationY(value);
+ renderNode.setRotationY(value);
break;
case SCALE_X:
- info.mScaleX = value;
- if (renderNode != null) renderNode.setScaleX(value);
+ renderNode.setScaleX(value);
break;
case SCALE_Y:
- info.mScaleY = value;
- if (renderNode != null) renderNode.setScaleY(value);
+ renderNode.setScaleY(value);
break;
case X:
- info.mTranslationX = value - mView.mLeft;
- if (renderNode != null) renderNode.setTranslationX(value - mView.mLeft);
+ renderNode.setTranslationX(value - mView.mLeft);
break;
case Y:
- info.mTranslationY = value - mView.mTop;
- if (renderNode != null) renderNode.setTranslationY(value - mView.mTop);
+ renderNode.setTranslationY(value - mView.mTop);
break;
case ALPHA:
info.mAlpha = value;
- if (renderNode != null) renderNode.setAlpha(value);
+ renderNode.setAlpha(value);
break;
}
}
@@ -981,30 +971,30 @@
* @return float The value of the named property
*/
private float getValue(int propertyConstant) {
- final View.TransformationInfo info = mView.mTransformationInfo;
+ final RenderNode node = mView.mRenderNode;
switch (propertyConstant) {
case TRANSLATION_X:
- return info.mTranslationX;
+ return node.getTranslationX();
case TRANSLATION_Y:
- return info.mTranslationY;
+ return node.getTranslationY();
case TRANSLATION_Z:
- return info.mTranslationZ;
+ return node.getTranslationZ();
case ROTATION:
- return info.mRotation;
+ return node.getRotation();
case ROTATION_X:
- return info.mRotationX;
+ return node.getRotationX();
case ROTATION_Y:
- return info.mRotationY;
+ return node.getRotationY();
case SCALE_X:
- return info.mScaleX;
+ return node.getScaleX();
case SCALE_Y:
- return info.mScaleY;
+ return node.getScaleY();
case X:
- return mView.mLeft + info.mTranslationX;
+ return mView.mLeft + node.getTranslationX();
case Y:
- return mView.mTop + info.mTranslationY;
+ return mView.mTop + node.getTranslationY();
case ALPHA:
- return info.mAlpha;
+ return mView.mTransformationInfo.mAlpha;
}
return 0;
}
@@ -1123,7 +1113,6 @@
}
}
if ((propertyMask & TRANSFORM_MASK) != 0) {
- mView.mTransformationInfo.mMatrixDirty = true;
if (!useRenderNodeProperties) {
mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b617f68..a35c28e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -678,13 +678,13 @@
mAttachInfo.mHardwareAccelerationRequested = false;
// Don't enable hardware acceleration when the application is in compatibility mode
- if (false && mTranslator != null) return;
+ if (mTranslator != null) return;
// Try to enable hardware acceleration if requested
final boolean hardwareAccelerated =
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
- if (true || hardwareAccelerated) {
+ if (hardwareAccelerated) {
if (!HardwareRenderer.isAvailable()) {
return;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 687036c..5e4c143 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5163,12 +5163,12 @@
final int width = mRight - mLeft;
final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
final float dx = mLayout.getLineRight(0) - (width - padding);
- canvas.translate(isLayoutRtl ? -dx : +dx, 0.0f);
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
}
if (mMarquee != null && mMarquee.isRunning()) {
final float dx = -mMarquee.getScroll();
- canvas.translate(isLayoutRtl ? -dx : +dx, 0.0f);
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
}
}
@@ -5182,8 +5182,8 @@
}
if (mMarquee != null && mMarquee.shouldDrawGhost()) {
- final int dx = (int) mMarquee.getGhostOffset();
- canvas.translate(isLayoutRtl ? -dx : dx, 0.0f);
+ final float dx = mMarquee.getGhostOffset();
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
}
diff --git a/core/java/android/widget/TimePickerDelegate.java b/core/java/android/widget/TimePickerDelegate.java
index c9a9894..79256e5 100644
--- a/core/java/android/widget/TimePickerDelegate.java
+++ b/core/java/android/widget/TimePickerDelegate.java
@@ -152,11 +152,11 @@
final int headerBackgroundColor = a.getColor(
R.styleable.TimePicker_headerBackgroundColor, 0);
- a.recycle();
-
final int layoutResourceId = a.getResourceId(
R.styleable.TimePicker_internalLayout, R.layout.time_picker_holo);
+ a.recycle();
+
final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index cc51a8b..80e1caa 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -174,7 +174,6 @@
}
private void init(View decor) {
- mContext = decor.getContext();
mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
com.android.internal.R.id.action_bar_overlay_layout);
if (mOverlayLayout != null) {
@@ -193,6 +192,7 @@
"with a compatible window decor layout");
}
+ mContext = mActionView.getContext();
mActionView.setContextView(mContextView);
mContextDisplayMode = mActionView.isSplitActionBar() ?
CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 03a053c..ac3274d 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -504,7 +504,7 @@
private String mEnabledInputMethodsStrCache;
private int mCurrentUserId;
- private int[] mRelatedUserIds = new int[0];
+ private int[] mCurrentProfileIds = new int[0];
private static void buildEnabledInputMethodsSettingString(
StringBuilder builder, Pair<String, ArrayList<String>> pair) {
@@ -537,17 +537,17 @@
mCurrentUserId = userId;
}
- public void setRelatedUserIds(int[] relatedUserIds) {
+ public void setCurrentProfileIds(int[] currentProfileIds) {
synchronized (this) {
- mRelatedUserIds = relatedUserIds;
+ mCurrentProfileIds = currentProfileIds;
}
}
- public boolean isRelatedToOrCurrentUser(int userId) {
+ public boolean isCurrentProfile(int userId) {
synchronized (this) {
if (userId == mCurrentUserId) return true;
- for (int i = 0; i < mRelatedUserIds.length; i++) {
- if (userId == mRelatedUserIds[i]) return true;
+ for (int i = 0; i < mCurrentProfileIds.length; i++) {
+ if (userId == mCurrentProfileIds[i]) return true;
}
return false;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 39636fe..4c11fa9 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -574,6 +574,7 @@
mUptime = in.readLong();
mPastUptime = in.readLong();
mUptimeStart = in.readLong();
+ mRealtime = in.readLong();
mPastRealtime = in.readLong();
mRealtimeStart = in.readLong();
mUnpluggedUptime = in.readLong();
@@ -586,6 +587,7 @@
out.writeLong(mUptime);
out.writeLong(runningUptime);
out.writeLong(mUptimeStart);
+ out.writeLong(mRealtime);
out.writeLong(runningRealtime);
out.writeLong(mRealtimeStart);
out.writeLong(mUnpluggedUptime);
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 1766f7b..3301cbe 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -26,8 +26,6 @@
import libcore.io.IoUtils;
-import dalvik.system.Zygote;
-
/**
* Startup class for the wrapper process.
* @hide
@@ -94,7 +92,7 @@
* @param niceName The nice name for the application, or null if none.
* @param targetSdkVersion The target SDK version for the app.
* @param pipeFd The pipe to which the application's pid should be written, or null if none.
- * @param args Arguments for {@link RuntimeInit.main}.
+ * @param args Arguments for {@link RuntimeInit#main}.
*/
public static void execApplication(String invokeWith, String niceName,
int targetSdkVersion, FileDescriptor pipeFd, String[] args) {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
new file mode 100644
index 0000000..c5fa0a1
--- /dev/null
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.os;
+
+
+import dalvik.system.ZygoteHooks;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+
+/** @hide */
+public final class Zygote {
+ /*
+ * Bit values for "debugFlags" argument. The definitions are duplicated
+ * in the native code.
+ */
+
+ /** enable debugging over JDWP */
+ public static final int DEBUG_ENABLE_DEBUGGER = 1;
+ /** enable JNI checks */
+ public static final int DEBUG_ENABLE_CHECKJNI = 1 << 1;
+ /** enable Java programming language "assert" statements */
+ public static final int DEBUG_ENABLE_ASSERT = 1 << 2;
+ /** disable the JIT compiler */
+ public static final int DEBUG_ENABLE_SAFEMODE = 1 << 3;
+ /** Enable logging of third-party JNI activity. */
+ public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
+
+ /** No external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_NONE = 0;
+ /** Single-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_SINGLEUSER = 1;
+ /** Multi-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_MULTIUSER = 2;
+ /** All multi-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_MULTIUSER_ALL = 3;
+
+ private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
+
+ private Zygote() {}
+
+ /**
+ * Forks a new VM instance. The current VM must have been started
+ * with the -Xzygote flag. <b>NOTE: new instance keeps all
+ * root capabilities. The new process is expected to call capset()</b>.
+ *
+ * @param uid the UNIX uid that the new process should setuid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gid the UNIX gid that the new process should setgid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gids null-ok; a list of UNIX gids that the new process should
+ * setgroups() to after fork and before spawning any threads.
+ * @param debugFlags bit flags that enable debugging features.
+ * @param rlimits null-ok an array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ * @param seInfo null-ok a string specifying SELinux information for
+ * the new process.
+ * @param niceName null-ok a string specifying the process name.
+ * @param fdsToClose an array of ints, holding one or more POSIX
+ * file descriptor numbers that are to be closed by the child
+ * (and replaced by /dev/null) after forking. An integer value
+ * of -1 in any entry in the array means "ignore this one".
+ *
+ * @return 0 if this is the child, pid of the child
+ * if this is the parent, or -1 on error.
+ */
+ public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose) {
+ VM_HOOKS.preFork();
+ int pid = nativeForkAndSpecialize(
+ uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose);
+ VM_HOOKS.postForkCommon();
+ return pid;
+ }
+
+ native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
+ int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose);
+
+ /**
+ * Special method to start the system server process. In addition to the
+ * common actions performed in forkAndSpecialize, the pid of the child
+ * process is recorded such that the death of the child process will cause
+ * zygote to exit.
+ *
+ * @param uid the UNIX uid that the new process should setuid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gid the UNIX gid that the new process should setgid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gids null-ok; a list of UNIX gids that the new process should
+ * setgroups() to after fork and before spawning any threads.
+ * @param debugFlags bit flags that enable debugging features.
+ * @param rlimits null-ok an array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ * @param permittedCapabilities argument for setcap()
+ * @param effectiveCapabilities argument for setcap()
+ *
+ * @return 0 if this is the child, pid of the child
+ * if this is the parent, or -1 on error.
+ */
+ public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
+ VM_HOOKS.preFork();
+ int pid = nativeForkSystemServer(
+ uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
+ VM_HOOKS.postForkCommon();
+ return pid;
+ }
+
+ native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
+
+ private static void callPostForkChildHooks(int debugFlags) {
+ VM_HOOKS.postForkChild(debugFlags);
+ }
+
+
+ /**
+ * Executes "/system/bin/sh -c <command>" using the exec() system call.
+ * This method throws a runtime exception if exec() failed, otherwise, this
+ * method never returns.
+ *
+ * @param command The shell command to execute.
+ */
+ public static void execShell(String command) {
+ String[] args = { "/system/bin/sh", "-c", command };
+ try {
+ Libcore.os.execv(args[0], args);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Appends quotes shell arguments to the specified string builder.
+ * The arguments are quoted using single-quotes, escaped if necessary,
+ * prefixed with a space, and appended to the command.
+ *
+ * @param command A string builder for the shell command being constructed.
+ * @param args An array of argument strings to be quoted and appended to the command.
+ * @see #execShell(String)
+ */
+ public static void appendQuotedShellArgs(StringBuilder command, String[] args) {
+ for (String arg : args) {
+ command.append(" '").append(arg.replace("'", "'\\''")).append("'");
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index f9a1f89..aad534c 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -24,7 +24,6 @@
import android.util.Log;
import dalvik.system.PathClassLoader;
-import dalvik.system.Zygote;
import java.io.BufferedReader;
import java.io.DataInputStream;
@@ -807,7 +806,7 @@
/**
* Applies invoke-with system properties to the zygote arguments.
*
- * @param parsedArgs non-null; zygote args
+ * @param args non-null; zygote args
*/
public static void applyInvokeWithSystemProperty(Arguments args) {
if (args.invokeWith == null && args.niceName != null) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 05c57e8..66cc120 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -32,7 +32,6 @@
import android.util.Log;
import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
import libcore.io.IoUtils;
import libcore.io.Libcore;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 52c463d..711f28a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -151,7 +151,8 @@
android_content_res_ObbScanner.cpp \
android_content_res_Configuration.cpp \
android_animation_PropertyValuesHolder.cpp \
- com_android_internal_net_NetworkStatsFactory.cpp
+ com_android_internal_net_NetworkStatsFactory.cpp \
+ com_android_internal_os_Zygote.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9a7a5f9..4759451 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -178,6 +178,7 @@
extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_Zygote(JNIEnv *env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -228,9 +229,10 @@
/*static*/ JavaVM* AndroidRuntime::mJavaVM = NULL;
-
-AndroidRuntime::AndroidRuntime() :
- mExitWithoutCleanup(false)
+AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
+ mExitWithoutCleanup(false),
+ mArgBlockStart(argBlockStart),
+ mArgBlockLength(argBlockLength)
{
SkGraphics::Init();
// this sets our preference for 16bit images during decode
@@ -265,6 +267,10 @@
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}
+void AndroidRuntime::setArgv0(const char* argv0) {
+ strlcpy(mArgBlockStart, argv0, mArgBlockLength);
+}
+
status_t AndroidRuntime::callMain(const char* className,
jclass clazz, int argc, const char* const argv[])
{
@@ -1244,6 +1250,7 @@
REG_JNI(register_android_net_TrafficStats),
REG_JNI(register_android_os_MemoryFile),
REG_JNI(register_com_android_internal_os_ZygoteInit),
+ REG_JNI(register_com_android_internal_os_Zygote),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
REG_JNI(register_android_hardware_SensorManager),
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index cbed99f..a4efed7 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -19,8 +19,8 @@
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+#include <cutils/process_name.h>
#include <cutils/sched_policy.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -385,7 +385,9 @@
}
if (name8.size() > 0) {
- ProcessState::self()->setArgV0(name8.string());
+ const char* procName = name8.string();
+ set_process_name(procName);
+ AndroidRuntime::getRuntime()->setArgv0(procName);
}
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 3e359d4..d079349 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -69,7 +69,7 @@
}
// ----------------------------------------------------------------------------
-// RenderProperties
+// RenderProperties - setters
// ----------------------------------------------------------------------------
static void android_view_RenderNode_setCaching(JNIEnv* env,
@@ -209,22 +209,6 @@
displayList->mutateStagingProperties().setScaleY(sy);
}
-static void android_view_RenderNode_setTransformationInfo(JNIEnv* env,
- jobject clazz, jlong displayListPtr, float alpha,
- float translationX, float translationY, float translationZ,
- float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
- RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
- displayList->mutateStagingProperties().setAlpha(alpha);
- displayList->mutateStagingProperties().setTranslationX(translationX);
- displayList->mutateStagingProperties().setTranslationY(translationY);
- displayList->mutateStagingProperties().setTranslationZ(translationZ);
- displayList->mutateStagingProperties().setRotation(rotation);
- displayList->mutateStagingProperties().setRotationX(rotationX);
- displayList->mutateStagingProperties().setRotationY(rotationY);
- displayList->mutateStagingProperties().setScaleX(scaleX);
- displayList->mutateStagingProperties().setScaleY(scaleY);
-}
-
static void android_view_RenderNode_setPivotX(JNIEnv* env,
jobject clazz, jlong displayListPtr, float px) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
@@ -286,6 +270,10 @@
displayList->mutateStagingProperties().offsetTopBottom(offset);
}
+// ----------------------------------------------------------------------------
+// RenderProperties - getters
+// ----------------------------------------------------------------------------
+
static jboolean android_view_RenderNode_hasOverlappingRendering(JNIEnv* env,
jobject clazz, jlong displayListPtr) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
@@ -352,6 +340,12 @@
return displayList->stagingProperties().getTranslationY();
}
+static jfloat android_view_RenderNode_getTranslationZ(JNIEnv* env,
+ jobject clazz, jlong displayListPtr) {
+ RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+ return displayList->stagingProperties().getTranslationZ();
+}
+
static jfloat android_view_RenderNode_getRotation(JNIEnv* env,
jobject clazz, jlong displayListPtr) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
@@ -370,6 +364,53 @@
return displayList->stagingProperties().getRotationY();
}
+static jboolean android_view_RenderNode_isPivotExplicitlySet(JNIEnv* env,
+ jobject clazz, jlong displayListPtr) {
+ RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+ return displayList->stagingProperties().isPivotExplicitlySet();
+}
+
+static jboolean android_view_RenderNode_hasIdentityMatrix(JNIEnv* env,
+ jobject clazz, jlong displayListPtr) {
+ RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+ return displayList->stagingProperties().getMatrixFlags() == 0;
+}
+
+// ----------------------------------------------------------------------------
+// RenderProperties - computed getters
+// ----------------------------------------------------------------------------
+
+static void android_view_RenderNode_getTransformMatrix(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jlong outMatrixPtr) {
+ RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
+ SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
+
+ displayList->mutateStagingProperties().updateMatrix();
+ const SkMatrix* transformMatrix = displayList->stagingProperties().getTransformMatrix();
+
+ if (displayList->stagingProperties().getMatrixFlags() == TRANSLATION) {
+ outMatrix->setTranslate(displayList->stagingProperties().getTranslationX(),
+ displayList->stagingProperties().getTranslationY());
+ } else if (transformMatrix) {
+ *outMatrix = *transformMatrix;
+ } else {
+ outMatrix->setIdentity();
+ }
+}
+
+static void android_view_RenderNode_getInverseTransformMatrix(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jlong outMatrixPtr) {
+ // load transform matrix
+ android_view_RenderNode_getTransformMatrix(env, clazz, displayListPtr, outMatrixPtr);
+ SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
+
+ // return it inverted
+ if (!outMatrix->invert(outMatrix)) {
+ // failed to load inverse, pass back identity
+ outMatrix->setIdentity();
+ }
+}
+
static jfloat android_view_RenderNode_getPivotX(JNIEnv* env,
jobject clazz, jlong displayListPtr) {
RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
@@ -424,8 +465,6 @@
{ "nSetRotationY", "(JF)V", (void*) android_view_RenderNode_setRotationY },
{ "nSetScaleX", "(JF)V", (void*) android_view_RenderNode_setScaleX },
{ "nSetScaleY", "(JF)V", (void*) android_view_RenderNode_setScaleY },
- { "nSetTransformationInfo","(JFFFFFFFFF)V",
- (void*) android_view_RenderNode_setTransformationInfo },
{ "nSetPivotX", "(JF)V", (void*) android_view_RenderNode_setPivotX },
{ "nSetPivotY", "(JF)V", (void*) android_view_RenderNode_setPivotY },
{ "nSetCameraDistance", "(JF)V", (void*) android_view_RenderNode_setCameraDistance },
@@ -448,11 +487,18 @@
{ "nGetScaleY", "(J)F", (void*) android_view_RenderNode_getScaleY },
{ "nGetTranslationX", "(J)F", (void*) android_view_RenderNode_getTranslationX },
{ "nGetTranslationY", "(J)F", (void*) android_view_RenderNode_getTranslationY },
+ { "nGetTranslationZ", "(J)F", (void*) android_view_RenderNode_getTranslationZ },
{ "nGetRotation", "(J)F", (void*) android_view_RenderNode_getRotation },
{ "nGetRotationX", "(J)F", (void*) android_view_RenderNode_getRotationX },
{ "nGetRotationY", "(J)F", (void*) android_view_RenderNode_getRotationY },
- { "nGetPivotX", "(J)F", (void*) android_view_RenderNode_getPivotX },
- { "nGetPivotY", "(J)F", (void*) android_view_RenderNode_getPivotY },
+ { "nIsPivotExplicitlySet", "(J)Z", (void*) android_view_RenderNode_isPivotExplicitlySet },
+ { "nHasIdentityMatrix", "(J)Z", (void*) android_view_RenderNode_hasIdentityMatrix },
+
+ { "nGetTransformMatrix", "(JJ)V", (void*) android_view_RenderNode_getTransformMatrix },
+ { "nGetInverseTransformMatrix","(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix },
+
+ { "nGetPivotX", "(J)F", (void*) android_view_RenderNode_getPivotX },
+ { "nGetPivotY", "(J)F", (void*) android_view_RenderNode_getPivotY },
#endif
};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
new file mode 100644
index 0000000..a61fa87
--- /dev/null
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android_runtime/AndroidRuntime.h"
+
+// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
+#include <sys/mount.h>
+#include <linux/fs.h>
+
+#include <grp.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "cutils/fs.h"
+#include "cutils/multiuser.h"
+#include "cutils/sched_policy.h"
+#include "utils/String8.h"
+#include "JNIHelp.h"
+#include "ScopedLocalRef.h"
+#include "ScopedPrimitiveArray.h"
+#include "ScopedUtfChars.h"
+
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+
+#include <selinux/android.h>
+
+#if defined(__linux__)
+#include <sys/personality.h>
+#include <sys/utsname.h>
+#if defined(HAVE_ANDROID_OS)
+#include <sys/capability.h>
+#endif
+#endif
+
+namespace {
+
+using android::String8;
+
+static pid_t gSystemServerPid = 0;
+
+static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
+static jclass gZygoteClass;
+static jmethodID gCallPostForkChildHooks;
+
+// Must match values in com.android.internal.os.Zygote.
+enum MountExternalKind {
+ MOUNT_EXTERNAL_NONE = 0,
+ MOUNT_EXTERNAL_SINGLEUSER = 1,
+ MOUNT_EXTERNAL_MULTIUSER = 2,
+ MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
+};
+
+static void RuntimeAbort(JNIEnv* env) {
+ env->FatalError("RuntimeAbort");
+}
+
+// This signal handler is for zygote mode, since the zygote must reap its children
+static void SigChldHandler(int /*signal_number*/) {
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ // Log process-death status that we care about. In general it is
+ // not safe to call LOG(...) from a signal handler because of
+ // possible reentrancy. However, we know a priori that the
+ // current implementation of LOG() is safe to call from a SIGCHLD
+ // handler in the zygote process. If the LOG() implementation
+ // changes its locking strategy or its use of syscalls within the
+ // lazy-init critical section, its use here may become unsafe.
+ 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));
+ }
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status)) {
+ ALOGI("Process %d dumped core.", pid);
+ }
+#endif /* ifdef WCOREDUMP */
+ }
+
+ // If the just-crashed process is the system_server, bring down zygote
+ // so that it is restarted by init and system server will be restarted
+ // from there.
+ if (pid == gSystemServerPid) {
+ ALOGE("Exit zygote because system server (%d) has terminated");
+ kill(getpid(), SIGKILL);
+ }
+ }
+
+ if (pid < 0) {
+ ALOGW("Zygote SIGCHLD error in waitpid: %d", errno);
+ }
+}
+
+// Configures the SIGCHLD handler for the zygote process. This is configured
+// very late, because earlier in the runtime we may fork() and exec()
+// other processes, and we want to waitpid() for those rather than
+// have them be harvested immediately.
+//
+// This ends up being called repeatedly before each fork(), but there's
+// no real harm in that.
+static void SetSigChldHandler() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SigChldHandler;
+
+ int err = sigaction(SIGCHLD, &sa, NULL);
+ if (err < 0) {
+ ALOGW("Error setting SIGCHLD handler: %d", errno);
+ }
+}
+
+// Sets the SIGCHLD handler back to default behavior in zygote children.
+static void UnsetSigChldHandler() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+
+ int err = sigaction(SIGCHLD, &sa, NULL);
+ if (err < 0) {
+ ALOGW("Error unsetting SIGCHLD handler: %d", errno);
+ }
+}
+
+// Calls POSIX setgroups() using the int[] object as an argument.
+// A NULL argument is tolerated.
+static void SetGids(JNIEnv* env, jintArray javaGids) {
+ if (javaGids == NULL) {
+ return;
+ }
+
+ ScopedIntArrayRO gids(env, javaGids);
+ if (gids.get() == NULL) {
+ RuntimeAbort(env);
+ }
+ int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
+ if (rc == -1) {
+ ALOGE("setgroups failed");
+ RuntimeAbort(env);
+ }
+}
+
+// Sets the resource limits via setrlimit(2) for the values in the
+// two-dimensional array of integers that's passed in. The second dimension
+// contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
+// treated as an empty array.
+static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
+ if (javaRlimits == NULL) {
+ return;
+ }
+
+ rlimit rlim;
+ memset(&rlim, 0, sizeof(rlim));
+
+ for (int i = 0; i < env->GetArrayLength(javaRlimits); ++i) {
+ ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
+ ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
+ if (javaRlimit.size() != 3) {
+ ALOGE("rlimits array must have a second dimension of size 3");
+ RuntimeAbort(env);
+ }
+
+ rlim.rlim_cur = javaRlimit[1];
+ rlim.rlim_max = javaRlimit[2];
+
+ int rc = setrlimit(javaRlimit[0], &rlim);
+ if (rc == -1) {
+ ALOGE("setrlimit(%d, {%d, %d}) failed", javaRlimit[0], rlim.rlim_cur, rlim.rlim_max);
+ RuntimeAbort(env);
+ }
+ }
+}
+
+#if defined(HAVE_ANDROID_OS)
+
+// The debug malloc library needs to know whether it's the zygote or a child.
+extern "C" int gMallocLeakZygoteChild;
+
+static void EnableKeepCapabilities(JNIEnv* env) {
+ int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+ if (rc == -1) {
+ ALOGE("prctl(PR_SET_KEEPCAPS) failed");
+ RuntimeAbort(env);
+ }
+}
+
+static void DropCapabilitiesBoundingSet(JNIEnv* env) {
+ for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+ int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+ if (rc == -1) {
+ if (errno == EINVAL) {
+ ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
+ "your kernel is compiled with file capabilities support");
+ } else {
+ ALOGE("prctl(PR_CAPBSET_DROP) failed");
+ RuntimeAbort(env);
+ }
+ }
+ }
+}
+
+static void SetCapabilities(JNIEnv* env, int64_t permitted, int64_t effective) {
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ __user_cap_data_struct capdata[2];
+ memset(&capdata, 0, sizeof(capdata));
+ capdata[0].effective = effective;
+ capdata[1].effective = effective >> 32;
+ capdata[0].permitted = permitted;
+ capdata[1].permitted = permitted >> 32;
+
+ if (capset(&capheader, &capdata[0]) == -1) {
+ ALOGE("capset(%lld, %lld) failed", permitted, effective);
+ RuntimeAbort(env);
+ }
+}
+
+static void SetSchedulerPolicy(JNIEnv* env) {
+ errno = -set_sched_policy(0, SP_DEFAULT);
+ if (errno != 0) {
+ ALOGE("set_sched_policy(0, SP_DEFAULT) failed");
+ RuntimeAbort(env);
+ }
+}
+
+#else
+
+static int gMallocLeakZygoteChild = 0;
+
+static void EnableKeepCapabilities(JNIEnv*) {}
+static void DropCapabilitiesBoundingSet(JNIEnv*) {}
+static void SetCapabilities(JNIEnv*, int64_t, int64_t) {}
+static void SetSchedulerPolicy(JNIEnv*) {}
+
+#endif
+
+// Create a private mount namespace and bind mount appropriate emulated
+// storage for the given user.
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
+ if (mount_mode == MOUNT_EXTERNAL_NONE) {
+ return true;
+ }
+
+ // See storage config details at http://source.android.com/tech/storage/
+ userid_t user_id = multiuser_get_user_id(uid);
+
+ // Create a second private mount namespace for our process
+ if (unshare(CLONE_NEWNS) == -1) {
+ ALOGW("Failed to unshare(): %d", errno);
+ return false;
+ }
+
+ // Create bind mounts to expose external storage
+ if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+ // These paths must already be created by init.rc
+ const char* source = getenv("EMULATED_STORAGE_SOURCE");
+ const char* target = getenv("EMULATED_STORAGE_TARGET");
+ const char* legacy = getenv("EXTERNAL_STORAGE");
+ if (source == NULL || target == NULL || legacy == NULL) {
+ ALOGW("Storage environment undefined; unable to provide external storage");
+ return false;
+ }
+
+ // Prepare source paths
+
+ // /mnt/shell/emulated/0
+ const String8 source_user(String8::format("%s/%d", source, user_id));
+ // /storage/emulated/0
+ const String8 target_user(String8::format("%s/%d", target, user_id));
+
+ if (fs_prepare_dir(source_user.string(), 0000, 0, 0) == -1
+ || fs_prepare_dir(target_user.string(), 0000, 0, 0) == -1) {
+ return false;
+ }
+
+ if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+ // Mount entire external storage tree for all users
+ if (TEMP_FAILURE_RETRY(mount(source, target, NULL, MS_BIND, NULL)) == -1) {
+ ALOGW("Failed to mount %s to %s :%d", source, target, errno);
+ return false;
+ }
+ } else {
+ // Only mount user-specific external storage
+ if (TEMP_FAILURE_RETRY(
+ mount(source_user.string(), target_user.string(), NULL, MS_BIND, NULL)) == -1) {
+ ALOGW("Failed to mount %s to %s: %d", source_user.string(), target_user.string(), errno);
+ return false;
+ }
+ }
+
+ if (fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+ return false;
+ }
+
+ // Finally, mount user-specific path into place for legacy users
+ if (TEMP_FAILURE_RETRY(
+ mount(target_user.string(), legacy, NULL, MS_BIND | MS_REC, NULL)) == -1) {
+ ALOGW("Failed to mount %s to %s: %d", target_user.string(), legacy, errno);
+ return false;
+ }
+ } else {
+ ALOGW("Mount mode %d unsupported", mount_mode);
+ return false;
+ }
+
+ return true;
+}
+
+#if defined(__linux__)
+static bool NeedsNoRandomizeWorkaround() {
+#if !defined(__arm__)
+ return false;
+#else
+ int major;
+ int minor;
+ struct utsname uts;
+ if (uname(&uts) == -1) {
+ return false;
+ }
+
+ if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+ return false;
+ }
+
+ // Kernels before 3.4.* need the workaround.
+ return (major < 3) || ((major == 3) && (minor < 4));
+#endif
+}
+#endif
+
+// Utility to close down the Zygote socket file descriptors while
+// the child is still running as root with Zygote's privileges. Each
+// descriptor (if any) is closed via dup2(), replacing it with a valid
+// (open) descriptor to /dev/null.
+
+static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) {
+ if (!fdsToClose) {
+ return;
+ }
+ jsize count = env->GetArrayLength(fdsToClose);
+ jint *ar = env->GetIntArrayElements(fdsToClose, 0);
+ if (!ar) {
+ ALOGE("Bad fd array");
+ RuntimeAbort(env);
+ }
+ jsize i;
+ int devnull;
+ for (i = 0; i < count; i++) {
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ ALOGE("Failed to open /dev/null");
+ RuntimeAbort(env);
+ continue;
+ }
+ ALOGV("Switching descriptor %d to /dev/null: %d", ar[i], errno);
+ if (dup2(devnull, ar[i]) < 0) {
+ ALOGE("Failed dup2() on descriptor %d", ar[i]);
+ RuntimeAbort(env);
+ }
+ close(devnull);
+ }
+}
+
+void SetThreadName(const char* thread_name) {
+ bool hasAt = false;
+ bool hasDot = false;
+ const char* s = thread_name;
+ while (*s) {
+ if (*s == '.') {
+ hasDot = true;
+ } else if (*s == '@') {
+ hasAt = true;
+ }
+ s++;
+ }
+ const int len = s - thread_name;
+ if (len < 15 || hasAt || !hasDot) {
+ s = thread_name;
+ } else {
+ s = thread_name + len - 15;
+ }
+ // pthread_setname_np fails rather than truncating long strings.
+ char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
+ strlcpy(buf, s, sizeof(buf)-1);
+ errno = pthread_setname_np(pthread_self(), buf);
+ if (errno != 0) {
+ ALOGW("Unable to set the name of current thread to '%s'", buf);
+ }
+}
+
+// Utility routine to fork zygote and specialize the child process.
+static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
+ jint debug_flags, jobjectArray javaRlimits,
+ jlong permittedCapabilities, jlong effectiveCapabilities,
+ jint mount_external,
+ jstring java_se_info, jstring java_se_name,
+ bool is_system_server, jintArray fdsToClose) {
+ SetSigChldHandler();
+
+ pid_t pid = fork();
+
+ if (pid == 0) {
+ // The child process.
+ gMallocLeakZygoteChild = 1;
+
+ // Clean up any descriptors which must be closed immediately
+ DetachDescriptors(env, fdsToClose);
+
+ // Keep capabilities across UID change, unless we're staying root.
+ if (uid != 0) {
+ EnableKeepCapabilities(env);
+ }
+
+ DropCapabilitiesBoundingSet(env);
+
+ if (!MountEmulatedStorage(uid, mount_external)) {
+ ALOGW("Failed to mount emulated storage: %d", errno);
+ if (errno == ENOTCONN || errno == EROFS) {
+ // When device is actively encrypting, we get ENOTCONN here
+ // since FUSE was mounted before the framework restarted.
+ // When encrypted device is booting, we get EROFS since
+ // FUSE hasn't been created yet by init.
+ // In either case, continue without external storage.
+ } else {
+ ALOGE("Cannot continue without emulated storage");
+ RuntimeAbort(env);
+ }
+ }
+
+ SetGids(env, javaGids);
+
+ SetRLimits(env, javaRlimits);
+
+ int rc = setresgid(gid, gid, gid);
+ if (rc == -1) {
+ ALOGE("setresgid(%d) failed", gid);
+ RuntimeAbort(env);
+ }
+
+ rc = setresuid(uid, uid, uid);
+ if (rc == -1) {
+ ALOGE("setresuid(%d) failed", uid);
+ RuntimeAbort(env);
+ }
+
+#if defined(__linux__)
+ if (NeedsNoRandomizeWorkaround()) {
+ // Work around ARM kernel ASLR lossage (http://b/5817320).
+ int old_personality = personality(0xffffffff);
+ int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE);
+ if (new_personality == -1) {
+ ALOGW("personality(%d) failed", new_personality);
+ }
+ }
+#endif
+
+ SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
+
+ SetSchedulerPolicy(env);
+
+#if defined(HAVE_ANDROID_OS)
+ { // NOLINT(whitespace/braces)
+ const char* se_info_c_str = NULL;
+ ScopedUtfChars* se_info = NULL;
+ if (java_se_info != NULL) {
+ se_info = new ScopedUtfChars(env, java_se_info);
+ se_info_c_str = se_info->c_str();
+ if (se_info_c_str == NULL) {
+ ALOGE("se_info_c_str == NULL");
+ RuntimeAbort(env);
+ }
+ }
+ const char* se_name_c_str = NULL;
+ ScopedUtfChars* se_name = NULL;
+ if (java_se_name != NULL) {
+ se_name = new ScopedUtfChars(env, java_se_name);
+ se_name_c_str = se_name->c_str();
+ if (se_name_c_str == NULL) {
+ ALOGE("se_name_c_str == NULL");
+ RuntimeAbort(env);
+ }
+ }
+ rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+ if (rc == -1) {
+ ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+ is_system_server, se_info_c_str, se_name_c_str);
+ RuntimeAbort(env);
+ }
+
+ // Make it easier to debug audit logs by setting the main thread's name to the
+ // nice name rather than "app_process".
+ if (se_info_c_str == NULL && is_system_server) {
+ se_name_c_str = "system_server";
+ }
+ if (se_info_c_str != NULL) {
+ SetThreadName(se_name_c_str);
+ }
+
+ delete se_info;
+ delete se_name;
+ }
+#else
+ UNUSED(is_system_server);
+ UNUSED(java_se_info);
+ UNUSED(java_se_name);
+#endif
+
+ UnsetSigChldHandler();
+
+ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags);
+ if (env->ExceptionCheck()) {
+ ALOGE("Error calling post fork hooks.");
+ RuntimeAbort(env);
+ }
+ } else if (pid > 0) {
+ // the parent process
+ }
+ return pid;
+}
+} // anonymous namespace
+
+namespace android {
+
+static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
+ JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
+ jint debug_flags, jobjectArray rlimits,
+ jint mount_external, jstring se_info, jstring se_name,
+ jintArray fdsToClose) {
+ return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
+ rlimits, 0, 0, mount_external, se_info, se_name, false, fdsToClose);
+}
+
+static jint com_android_internal_os_Zygote_nativeForkSystemServer(
+ JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
+ jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
+ jlong effectiveCapabilities) {
+ pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
+ debug_flags, rlimits,
+ permittedCapabilities, effectiveCapabilities,
+ MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL);
+ if (pid > 0) {
+ // The zygote process checks whether the child process has died or not.
+ ALOGI("System server process %d has been created", pid);
+ gSystemServerPid = pid;
+ // There is a slight window that the system server process has crashed
+ // but it went unnoticed because we haven't published its pid yet. So
+ // we recheck here just to make sure that all is well.
+ int status;
+ if (waitpid(pid, &status, WNOHANG) == pid) {
+ ALOGE("System server process %d has died. Restarting Zygote!", pid);
+ RuntimeAbort(env);
+ }
+ }
+ return pid;
+}
+
+static JNINativeMethod gMethods[] = {
+ { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I",
+ (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
+ { "nativeForkSystemServer", "(II[II[[IJJ)I",
+ (void *) com_android_internal_os_Zygote_nativeForkSystemServer }
+};
+
+int register_com_android_internal_os_Zygote(JNIEnv* env) {
+ gZygoteClass = (jclass) env->NewGlobalRef(env->FindClass(kZygoteClassName));
+ if (gZygoteClass == NULL) {
+ RuntimeAbort(env);
+ }
+ gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks", "(I)V");
+
+ return AndroidRuntime::registerNativeMethods(env, "com/android/internal/os/Zygote",
+ gMethods, NELEM(gMethods));
+}
+} // namespace android
+
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2a4d872..3857cd1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2585,6 +2585,13 @@
android:description="@string/permdesc_accessNetworkConditions"
android:protectionLevel="signature|system" />
+ <!-- Allows an application to provision and access DRM certificates
+ @hide This is not a third-party API (intended for system apps). -->
+ <permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
+ android:label="@string/permlab_accessDrmCertificates"
+ android:description="@string/permdesc_accessDrmCertificates"
+ android:protectionLevel="signature|system" />
+
<!-- The system process is explicitly the only one allowed to launch the
confirmation UI for full backup/restore -->
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..51a895d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..2f59488
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..d38aed2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..87dade3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..33ec44c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..0166d70
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png
new file mode 100644
index 0000000..4b49faf
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_off_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png
new file mode 100644
index 0000000..561d9ef
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_rating_star_on_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable/item_background_quantum.xml b/core/res/res/drawable/item_background_quantum.xml
index f668ca0..11e1f67 100644
--- a/core/res/res/drawable/item_background_quantum.xml
+++ b/core/res/res/drawable/item_background_quantum.xml
@@ -15,4 +15,5 @@
-->
<touch-feedback xmlns:android="http://schemas.android.com/apk/res/android"
- android:tint="?attr/colorButtonPressed" />
+ android:tint="?attr/colorButtonPressed"
+ android:pinned="true" />
diff --git a/core/res/res/drawable/ratingbar_full_empty_quantum.xml b/core/res/res/drawable/ratingbar_full_empty_quantum.xml
new file mode 100644
index 0000000..e5e4315
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_empty_quantum.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <bitmap android:src="@drawable/btn_rating_star_off_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item>
+ <bitmap android:src="@drawable/btn_rating_star_off_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_full_filled_quantum.xml b/core/res/res/drawable/ratingbar_full_filled_quantum.xml
new file mode 100644
index 0000000..ad3aa5d
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_filled_quantum.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true">
+ <bitmap android:src="@drawable/btn_rating_star_on_qntm_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item>
+ <bitmap android:src="@drawable/btn_rating_star_on_qntm_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_full_quantum.xml b/core/res/res/drawable/ratingbar_full_quantum.xml
new file mode 100644
index 0000000..143e7c2
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_full_quantum.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@id/background"
+ android:drawable="@drawable/ratingbar_full_empty_quantum" />
+ <item android:id="@id/secondaryProgress"
+ android:drawable="@drawable/ratingbar_full_empty_quantum" />
+ <item android:id="@id/progress"
+ android:drawable="@drawable/ratingbar_full_filled_quantum" />
+</layer-list>
diff --git a/core/res/res/layout/alert_dialog_progress_quantum.xml b/core/res/res/layout/alert_dialog_progress_quantum.xml
new file mode 100644
index 0000000..b9d0814
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_progress_quantum.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+ <ProgressBar android:id="@+id/progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dip"
+ android:layout_marginBottom="1dip"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:layout_centerHorizontal="true" />
+ <TextView
+ android:id="@+id/progress_percent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dip"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/progress" />
+ <TextView
+ android:id="@+id/progress_number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dip"
+ android:layout_marginStart="16dip"
+ android:layout_marginEnd="16dip"
+ android:layout_alignParentEnd="true"
+ android:layout_below="@id/progress" />
+</RelativeLayout>
diff --git a/core/res/res/layout/alert_dialog_quantum.xml b/core/res/res/layout/alert_dialog_quantum.xml
new file mode 100644
index 0000000..59dba08
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_quantum.xml
@@ -0,0 +1,125 @@
+<?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="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout android:id="@+id/topPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <LinearLayout android:id="@+id/title_template"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical|start"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:paddingTop="16dip">
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="8dip"
+ android:src="@null" />
+ <TextView android:id="@+id/alertTitle"
+ style="?android:attr/windowTitleStyle"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAlignment="viewStart" />
+ </LinearLayout>
+ <!-- If the client uses a customTitle, it will be added here. -->
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/contentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:minHeight="64dp">
+ <ScrollView android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipToPadding="false">
+ <TextView android:id="@+id/message"
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:paddingTop="16dip" />
+ </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:padding="16dip">
+ <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/button3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:layout_marginRight="8dip"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?android:attr/buttonBarButtonStyle" />
+ <View android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="invisible" />
+ <Button android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:layout_marginRight="8dip"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?android:attr/buttonBarButtonStyle" />
+ <Button android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
+ style="?android:attr/buttonBarButtonStyle" />
+ </LinearLayout>
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/dialog_custom_title_quantum.xml b/core/res/res/layout/dialog_custom_title_quantum.xml
new file mode 100644
index 0000000..f8a2bf7
--- /dev/null
+++ b/core/res/res/layout/dialog_custom_title_quantum.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+This is a custom layout for a dialog.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+ <FrameLayout android:id="@android:id/title_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/alert_dialog_title_height"
+ android:layout_weight="0"
+ android:gravity="center_vertical|start"
+ style="?android:attr/windowTitleBackgroundStyle">
+ </FrameLayout>
+ <View android:id="@+id/titleDivider"
+ android:layout_width="match_parent"
+ android:layout_height="2dip"
+ android:background="@android:color/holo_blue_light" />
+ <FrameLayout
+ android:layout_width="match_parent" android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:foreground="?android:attr/windowContentOverlay">
+ <FrameLayout android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </FrameLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/dialog_title_icons_quantum.xml b/core/res/res/layout/dialog_title_icons_quantum.xml
new file mode 100644
index 0000000..e3d771c
--- /dev/null
+++ b/core/res/res/layout/dialog_title_icons_quantum.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+This is an optimized layout for a screen, with the minimum set of features
+enabled.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+
+ <LinearLayout android:id="@+id/title_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:minHeight="@android:dimen/alert_dialog_title_height"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip">
+ <ImageView android:id="@+id/left_icon"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:scaleType="fitCenter"
+ android:layout_marginEnd="8dip" />
+ <TextView android:id="@android:id/title"
+ style="?android:attr/windowTitleStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0" />
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:scaleType="fitCenter"
+ android:layout_marginStart="8dip" />
+ </LinearLayout>
+
+ <View android:id="@+id/titleDivider"
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="@android:color/holo_blue_light" />
+
+ <FrameLayout
+ android:layout_width="match_parent" android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:foreground="?android:attr/windowContentOverlay">
+ <FrameLayout android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </FrameLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/dialog_title_quantum.xml b/core/res/res/layout/dialog_title_quantum.xml
new file mode 100644
index 0000000..0a692ee
--- /dev/null
+++ b/core/res/res/layout/dialog_title_quantum.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+
+This is an optimized layout for a screen, with the minimum set of features
+enabled.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:fitsSystemWindows="true">
+ <TextView android:id="@android:id/title" style="?android:attr/windowTitleStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@android:dimen/alert_dialog_title_height"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:gravity="center_vertical|start" />
+ <View android:id="@+id/titleDivider"
+ android:layout_width="match_parent"
+ android:layout_height="2dip"
+ android:background="@android:color/holo_blue_light" />
+ <FrameLayout
+ android:layout_width="match_parent" android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:foreground="?android:attr/windowContentOverlay">
+ <FrameLayout android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </FrameLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/progress_dialog_quantum.xml b/core/res/res/layout/progress_dialog_quantum.xml
new file mode 100644
index 0000000..84d06b5
--- /dev/null
+++ b/core/res/res/layout/progress_dialog_quantum.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout android:id="@+id/body"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:baselineAligned="false"
+ android:padding="16dip">
+
+ <ProgressBar android:id="@android:id/progress"
+ style="?android:attr/progressBarStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:max="10000"
+ android:layout_marginEnd="16dip" />
+
+ <TextView android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical" />
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 3265736..b1afec1 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -24,7 +24,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:splitMotionEvents="false"
- android:theme="?attr/actionBarTheme">
+ android:theme="?attr/actionBarWidgetTheme">
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
diff --git a/core/res/res/layout/select_dialog_item_quantum.xml b/core/res/res/layout/select_dialog_item_quantum.xml
new file mode 100644
index 0000000..59b432e
--- /dev/null
+++ b/core/res/res/layout/select_dialog_item_quantum.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<!--
+ This layout file is used by the AlertDialog when displaying a list of items.
+ This layout file is inflated and used as the TextView to display individual
+ items.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:ellipsize="marquee" />
diff --git a/core/res/res/layout/select_dialog_multichoice_quantum.xml b/core/res/res/layout/select_dialog_multichoice_quantum.xml
new file mode 100644
index 0000000..8b4c59d
--- /dev/null
+++ b/core/res/res/layout/select_dialog_multichoice_quantum.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:checkMark="?android:attr/listChoiceIndicatorMultiple"
+ android:ellipsize="marquee" />
diff --git a/core/res/res/layout/select_dialog_quantum.xml b/core/res/res/layout/select_dialog_quantum.xml
new file mode 100644
index 0000000..ee04039
--- /dev/null
+++ b/core/res/res/layout/select_dialog_quantum.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<!--
+ This layout file is used by the AlertDialog when displaying a list of items.
+ This layout file is inflated and used as the ListView to display the items.
+ Assign an ID so its state will be saved/restored.
+-->
+<view class="com.android.internal.app.AlertController$RecycleListView"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+android:id/select_dialog_listview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:cacheColorHint="@null"
+ android:divider="?android:attr/listDividerAlertDialog"
+ android:scrollbars="vertical"
+ android:overScrollMode="ifContentScrolls"
+ android:textAlignment="viewStart" />
diff --git a/core/res/res/layout/select_dialog_singlechoice_quantum.xml b/core/res/res/layout/select_dialog_singlechoice_quantum.xml
new file mode 100644
index 0000000..27a6648
--- /dev/null
+++ b/core/res/res/layout/select_dialog_singlechoice_quantum.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingStart="16dip"
+ android:paddingEnd="16dip"
+ android:checkMark="?android:attr/listChoiceIndicatorSingle"
+ android:ellipsize="marquee" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 369dda1..aa5005f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -677,8 +677,6 @@
<!-- Action bar styles -->
<!-- =================== -->
<eat-comment />
- <!-- Theme override for the Action Bar -->
- <attr name="actionBarTheme" format="reference" />
<!-- Default style for tabs within an action bar -->
<attr name="actionBarTabStyle" format="reference" />
<attr name="actionBarTabBarStyle" format="reference" />
@@ -1677,6 +1675,7 @@
that is, when in portrait. Can be either an absolute dimension
or a fraction of the screen size in that dimension. -->
<attr name="windowFixedHeightMajor" format="dimension|fraction" />
+ <attr name="windowOutsetBottom" format="dimension" />
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -4555,6 +4554,7 @@
<enum name="state_activated" value="8" />
<enum name="state_window_focused" value="9" />
</attr>
+ <attr name="versionCode" />
</declare-styleable>
<!-- Define the virtual size of the drawing surface paths will draw to. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 39b8a6b..b14453a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -866,6 +866,18 @@
<!-- The name of the logical parent of the activity as it appears in the manifest. -->
<attr name="parentActivityName" format="string" />
+ <!-- Define an activity that will persist across reboots. If such an activity is in the
+ Recents list when the device is shut off it will appear in the Recents list when
+ the device is next powered on. To be persisted all activities in the task from the
+ root activity up to the last activity before a <em>break</em> must be declared with
+ the persistable attribute. A <em>break</em> is the first activity after the root
+ started with Intent.FLAG_CLEAR_TASK_WHEN_RESET.
+
+ <p>Activities that are declared with the persistable attribute will be provided with a
+ forced-persistable Bundle in onCreate() and onSavedInstanceState(), and must only
+ be passed a persistable Bundle in their Intent.extras. -->
+ <attr name="persistable" format="boolean" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1528,6 +1540,7 @@
<!-- @hide This broacast receiver will only receive broadcasts for the
primary user. Can only be used with receivers. -->
<attr name="primaryUserOnly" format="boolean" />
+ <attr name="persistable" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d4692f1..667adde 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2142,6 +2142,7 @@
<public type="attr" name="colorButtonPressed" />
<public type="attr" name="colorButtonNormalColored" />
<public type="attr" name="colorButtonPressedColored" />
+ <public type="attr" name="persistable" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
@@ -2181,9 +2182,13 @@
<public type="style" name="TextAppearance.Quantum.Widget" />
<public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Menu" />
<public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Subtitle" />
+ <public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse" />
<public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Title" />
+ <public type="style" name="TextAppearance.Quantum.Widget.ActionBar.Title.Inverse" />
<public type="style" name="TextAppearance.Quantum.Widget.ActionMode.Subtitle" />
+ <public type="style" name="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse" />
<public type="style" name="TextAppearance.Quantum.Widget.ActionMode.Title" />
+ <public type="style" name="TextAppearance.Quantum.Widget.ActionMode.Title.Inverse" />
<public type="style" name="TextAppearance.Quantum.Widget.Button" />
<public type="style" name="TextAppearance.Quantum.Widget.DropDownHint" />
<public type="style" name="TextAppearance.Quantum.Widget.DropDownItem" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3a4f059..902aea8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2002,6 +2002,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_setInputCalibration">Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_accessDrmCertificates">access DRM certificates</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_accessDrmCertificates">Allows an application to provision and use DRM certficates. Should never be needed for normal apps.</string>
+
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 2bbc2e4..85d8761 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -394,6 +394,7 @@
<style name="Widget.Quantum.Button" parent="Widget.Button">
<item name="background">@drawable/btn_default_quantum</item>
<item name="textAppearance">?attr/textAppearanceButton</item>
+ <item name="textColor">?attr/textColorPrimary</item>
<item name="minHeight">48dip</item>
<item name="minWidth">96dip</item>
</style>
@@ -443,23 +444,13 @@
</style>
<style name="Widget.Quantum.ButtonBar">
- <item name="paddingTop">0dip</item>
- <item name="paddingStart">0dip</item>
- <item name="paddingEnd">0dip</item>
- <item name="paddingBottom">0dip</item>
- <item name="divider">?attr/dividerVertical</item>
- <item name="showDividers">middle</item>
- <item name="dividerPadding">12dip</item>
<item name="background">@null</item>
</style>
<style name="Widget.Quantum.ButtonBar.AlertDialog">
<item name="background">@null</item>
- <item name="dividerPadding">0dp</item>
</style>
- <style name="Widget.Quantum.ButtonBar.Button"/>
-
<style name="Widget.Quantum.SegmentedButton" parent="SegmentedButton">
<item name="background">@drawable/btn_group_holo_dark</item>
</style>
@@ -630,8 +621,8 @@
</style>
<style name="Widget.Quantum.RatingBar" parent="Widget.RatingBar">
- <item name="progressDrawable">@drawable/ratingbar_full_holo_dark</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_full_holo_dark</item>
+ <item name="progressDrawable">@drawable/ratingbar_full_quantum</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_full_quantum</item>
</style>
<style name="Widget.Quantum.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
@@ -740,7 +731,7 @@
<item name="contentDescription">@string/action_menu_overflow_description</item>
</style>
- <style name="Widget.Quantum.ActionButton.TextButton" parent="Widget.Quantum.ButtonBar.Button"/>
+ <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>
@@ -919,10 +910,7 @@
<style name="Widget.Quantum.Light.ProgressBar.Large.Inverse" parent="Widget.Quantum.ProgressBar.Large.Inverse"/>
<style name="Widget.Quantum.Light.SeekBar" parent="Widget.Quantum.SeekBar"/>
- <style name="Widget.Quantum.Light.RatingBar" parent="Widget.RatingBar">
- <item name="progressDrawable">@drawable/ratingbar_full_holo_light</item>
- <item name="indeterminateDrawable">@drawable/ratingbar_full_holo_light</item>
- </style>
+ <style name="Widget.Quantum.Light.RatingBar" parent="Widget.Quantum.RatingBar" />
<style name="Widget.Quantum.Light.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
<item name="progressDrawable">@drawable/ratingbar_holo_light</item>
@@ -1047,13 +1035,13 @@
<item name="bottomBright">?attr/colorBackground</item>
<item name="bottomMedium">?attr/colorBackground</item>
<item name="centerMedium">?attr/colorBackground</item>
- <item name="layout">@layout/alert_dialog_holo</item>
- <item name="listLayout">@layout/select_dialog_holo</item>
- <item name="progressLayout">@layout/progress_dialog_holo</item>
- <item name="horizontalProgressLayout">@layout/alert_dialog_progress_holo</item>
- <item name="listItemLayout">@layout/select_dialog_item_holo</item>
- <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_holo</item>
- <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_holo</item>
+ <item name="layout">@layout/alert_dialog_quantum</item>
+ <item name="listLayout">@layout/select_dialog_quantum</item>
+ <item name="progressLayout">@layout/progress_dialog_quantum</item>
+ <item name="horizontalProgressLayout">@layout/alert_dialog_progress_quantum</item>
+ <item name="listItemLayout">@layout/select_dialog_item_quantum</item>
+ <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_quantum</item>
+ <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_quantum</item>
</style>
<style name="AlertDialog.Quantum.Light"/>
@@ -1066,8 +1054,7 @@
<style name="WindowTitle.Quantum">
<item name="singleLine">true</item>
<item name="textAppearance">@style/TextAppearance.Quantum.WindowTitle</item>
- <item name="shadowColor">#BB000000</item>
- <item name="shadowRadius">2.75</item>
+ <item name="shadowRadius">0</item>
</style>
<style name="DialogWindowTitle.Quantum">
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index d39a1f8..50f1ca6 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -154,7 +154,7 @@
<item name="windowTitleStyle">@style/WindowTitle.Quantum</item>
<item name="windowTitleSize">25dip</item>
<item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Quantum</item>
- <item name="windowContentTransitions">true</item>
+ <item name="windowContentTransitions">false</item>
<item name="windowAnimationStyle">@style/Animation.Quantum.Activity</item>
<item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">true</item>
@@ -162,9 +162,9 @@
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.Quantum.Dialog</item>
- <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item>
- <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item>
- <item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item>
+ <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_quantum</item>
+ <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_quantum</item>
+ <item name="dialogTitleDecorLayout">@layout/dialog_title_quantum</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.Quantum.Dialog.Alert</item>
@@ -488,9 +488,9 @@
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.Quantum.Light.Dialog</item>
- <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item>
- <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item>
- <item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item>
+ <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_quantum</item>
+ <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_quantum</item>
+ <item name="dialogTitleDecorLayout">@layout/dialog_title_quantum</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.Quantum.Light.Dialog.Alert</item>
@@ -694,7 +694,7 @@
with an inverse color profile. The dark action bar sharply stands out against
the light content. -->
<style name="Theme.Quantum.Light.DarkActionBar">
- <item name="actionBarTheme">@style/Theme.Quantum</item>
+ <item name="actionBarWidgetTheme">@style/Theme.Quantum</item>
</style>
<!-- Variant of the quantum (dark) theme with no action bar. -->
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 6d29c69..92ecd24 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -61,7 +61,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
<br/>Any versions with less than 0.1% distribution are not shown.</em>
</p>
@@ -92,7 +92,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014.
<br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
@@ -133,17 +133,17 @@
</tr>
<tr>
<td>2.0</th>
-<td>91.1%</td>
+<td>89.4%</td>
</tr>
<tr>
<td>3.0</th>
-<td>8.8%</td>
+<td>10.5%</td>
</tr>
</table>
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 1, 2014</em></p>
@@ -161,17 +161,17 @@
var VERSION_DATA =
[
{
- "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chd=t%3A1.2%2C19.0%2C0.1%2C15.2%2C62.0%2C2.5&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=500x250&cht=p",
+ "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",
"data": [
{
"api": 8,
"name": "Froyo",
- "perc": "1.2"
+ "perc": "1.1"
},
{
"api": 10,
"name": "Gingerbread",
- "perc": "19.0"
+ "perc": "17.8"
},
{
"api": 13,
@@ -181,27 +181,27 @@
{
"api": 15,
"name": "Ice Cream Sandwich",
- "perc": "15.2"
+ "perc": "14.3"
},
{
"api": 16,
"name": "Jelly Bean",
- "perc": "35.3"
+ "perc": "34.4"
},
{
"api": 17,
"name": "Jelly Bean",
- "perc": "17.1"
+ "perc": "18.1"
},
{
"api": 18,
"name": "Jelly Bean",
- "perc": "9.6"
+ "perc": "8.9"
},
{
"api": 19,
"name": "KitKat",
- "perc": "2.5"
+ "perc": "5.3"
}
]
}
@@ -218,16 +218,15 @@
"Large": {
"hdpi": "0.6",
"ldpi": "0.7",
- "mdpi": "4.3",
+ "mdpi": "4.4",
"tvdpi": "1.5",
"xhdpi": "0.6"
},
"Normal": {
"hdpi": "33.7",
- "ldpi": "0.2",
- "mdpi": "13.6",
- "xhdpi": "19.9",
- "xxhdpi": "11.9"
+ "mdpi": "13.2",
+ "xhdpi": "19.8",
+ "xxhdpi": "12.5"
},
"Small": {
"ldpi": "8.1"
@@ -235,12 +234,12 @@
"Xlarge": {
"hdpi": "0.3",
"ldpi": "0.1",
- "mdpi": "4.3",
- "xhdpi": "0.2"
+ "mdpi": "4.2",
+ "xhdpi": "0.3"
}
},
- "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A9.1%2C22.2%2C1.5%2C34.6%2C20.7%2C11.9&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
- "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.9%2C7.7%2C79.3%2C8.1&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=400x250&cht=p"
+ "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"
}
];
diff --git a/docs/html/google/index.jd b/docs/html/google/index.jd
index b743b66..2e97d62 100644
--- a/docs/html/google/index.jd
+++ b/docs/html/google/index.jd
@@ -125,7 +125,7 @@
<img src="{@docRoot}images/google/analytics.png" width="40" />
</div>
<h4><a class="external-link"
-href="https://developers.google.com/analytics/devguides/collection/android/v2/"
+href="https://developers.google.com/analytics/devguides/collection/android/v4/"
>Google Analytics</a></h4>
<p>Measure your success and gain insights into how users engage with your app content
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 73d5b74..0a234aa 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -368,7 +368,10 @@
<span class="en">Media Playback</span></a>
</li>
<li><a href="<?cs var:toroot ?>guide/topics/media/mediarouter.html">
- <span class="en">MediaRouter</span></a>
+ <span class="en">Media Router</span></a>
+ </li>
+ <li><a href="<?cs var:toroot ?>guide/topics/media/mediarouteprovider.html">
+ <span class="en">Media Route Provider</span></a>
</li>
<li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
<span class="en">Supported Media Formats</span></a>
diff --git a/docs/html/guide/topics/media/mediarouteprovider.jd b/docs/html/guide/topics/media/mediarouteprovider.jd
new file mode 100644
index 0000000..389fbfb
--- /dev/null
+++ b/docs/html/guide/topics/media/mediarouteprovider.jd
@@ -0,0 +1,453 @@
+page.title=Media Route Provider
+page.tags="mediarouteprovider","mediacontrolintent"
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#overview">Overview</a>
+ <ol>
+ <li><a href="#dist">Distribution of route providers</a></li>
+ <li><a href="#playback-types">Types of playback</a></li>
+ <li><a href="#mr-packages">Media router packages</a></li>
+ </ol>
+ </li>
+ <li><a href="#provider-service">Creating a Provider Service</a></li>
+ <li><a href="#route-caps">Specifying Route Capabilities</a>
+ <ol>
+ <li><a href="#route-cat">Route categories</a></li>
+ <li><a href="#media-types">Media types and protocols</a></li>
+ <li><a href="#playback-ctrls">Playback controls</a></li>
+ <li><a href="#mrpd">MediaRouteProviderDescriptor</a></li>
+ </ol>
+ </li>
+ <li><a href="#ctrl-routes">Controlling Routes</a></li>
+ </ol>
+ <h2>Key Classes</h2>
+ <ol>
+ <li>{@link android.support.v7.media.MediaRouteProvider}</li>
+ <li>{@link android.support.v7.media.MediaRouteProviderDescriptor}</li>
+ <li>{@link android.support.v7.media.MediaRouteProvider.RouteController RouteController}</li>
+ </ol>
+ <h2>Related Samples</h2>
+ <ol>
+ <li><a href="{@docRoot}samples/MediaRouter/index.html">MediaRouter</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>Users want to play media content from their Android devices bigger, brighter, and louder on
+ connected playback devices such as televisions, stereos,
+ and home theater equipment. As a manufacturer of these devices, allowing Android users to
+ instantly show a picture, play a song, or share a video for friends and family using your product
+ can make it much more compelling and engaging.</p>
+
+<p>The Android media router framework allows manufacturers to enable playback on their devices
+ through a standardized interface called a {@link android.support.v7.media.MediaRouteProvider}.
+ A route provider defines a common interface for playing media on a receiver device, making it
+ possible to play media on your equipment from any Android application that supports media
+ routes.</p>
+
+<p>This guide discusses how to create a media route provider for a receiver device and make it
+ available to other media playback applications that run on Android.</p>
+
+<h2 id="overview">Overview</h2>
+
+<p>The Android media router framework enables media app developers and media playback device
+ manufacturers to connect through a common API and common user interface. App developers that
+ implement a {@link android.support.v7.media.MediaRouter} interface can then connect to the
+ framework and play content to devices that participate in the media router framework. Media
+ playback device manufacturers can participate in the framework by publishing a {@link
+ android.support.v7.media.MediaRouteProvider} that allows other applications to connect to and
+ play media on the receiver devices. Figure 1 illustrates how an app connects to a receiving
+ device through the media router framework.</p>
+
+<img src="{@docRoot}images/mediarouter/media-route-provider-framework.png" alt="" id="figure1"/>
+<p class="img-caption">
+ <strong>Figure 1.</strong> Overview of how media route provider classes provide communication
+ from a media app to a receiver device.
+</p>
+
+<p>When you build a media route provider for your receiver device, the provider serves the
+following purposes:</p>
+
+<ul>
+ <li>Describe and publish the capabilities of the receiver device so other apps can discover it
+ and use its playback features.</li>
+ <li>Wrap the programming interface of the receiver device and its communication
+ transport mechanisms to make the device compatible with the media router framework.</li>
+</ul>
+
+
+<h3 id="dist">Distribution of route providers</h3>
+
+<p>A media route provider is distributed as part of an Android app. Your route provider can be
+ made available to other apps by extending
+ {@link android.support.v7.media.MediaRouteProviderService} or wrapping your implementation of
+ {@link android.support.v7.media.MediaRouteProvider} with your own service and declaring an intent
+ filter for the media route provider. These steps allow other apps to discover and make use of
+ your media route.</p>
+
+<p>
+ <strong>Note:</strong> The app containing the media route provider can also include a
+ <a href="{@docRoot}guide/topics/media/mediarouter.html">MediaRouter</a> interface to the
+ route provider, but this is not required.
+</p>
+
+
+<h3 id="playback-types">Types of playback</h3>
+
+<p>There are two main types of playback supported by the media router framework. A media route
+ provider can support one or both types of playback, depending on the capabilities of your playback
+ equipment and the functionality you want to support:</p>
+
+<ul>
+ <li><strong>Remote Playback</strong> — This approach uses the receiver device to handle the
+ content data retrieval, decoding, and playback, while an Android device in the user's hand is
+ used as a remote control. This approach is used by Android apps that support
+ <a href="https://developers.google.com/cast/">Google Cast</a>.</li>
+ <li><strong>Secondary Output</strong> — With this approach, the Android media application
+ retrieves, renders and streams video or music directly to the receiver device. This approach is
+ used to support Wireless Display output on Android.</li>
+</ul>
+
+
+<h3 id="mr-packages">Media router packages</h3>
+
+<p>
+ The media router APIs are provided as part of the Android Support Library version 18 and higher,
+ in the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter</a>
+ support library. You should use the classes in the
+ {@link android.support.v7.media} package for media route provider functions.
+ These APIs are compatible with devices running Android 2.1 (API level 7) and higher.
+</p>
+
+<p class="caution">
+ <strong>Caution:</strong> There is another set of media router APIs provided in the
+ {@link android.media} class package that have been superseded by the
+ <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter</a>
+ support library. You <em>should not</em> use the {@link android.media} classes for
+ implementing media route provider functions.
+</p>
+
+<p>In order to use the {@link android.support.v7.media} media router classes, you
+ must add the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter"
+ >v7-mediarouter support library package</a> to your app development project. For more
+ information on adding support libraries to your app development project, see
+ <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a>.
+</p>
+
+
+<h2 id="provider-service">Creating a Provider Service</h2>
+
+<p>The media router framework must be able to discover and connect to your media route provider
+ to allow other applications to use your route. In order to do this, the media router framework
+ looks for apps that declare a media route provider intent action. When another app wants to
+ connect to your provider, the framework must be able to invoke and connect to it, so your provider
+ must be encapsulated in a {@link android.app.Service}.</p>
+
+<p>The following example code shows the declaration of a media route provider service and the
+ intent filter in a manifest, which allows it to be discovered and used by the media router
+ framework:</p>
+
+<pre>
+<service android:name=".provider.SampleMediaRouteProviderService"
+ android:label="@string/sample_media_route_provider_service"
+ android:process=":mrp">
+ <intent-filter>
+ <action android:name="android.media.MediaRouteProviderService" />
+ </intent-filter>
+</service>
+</pre>
+
+<p>This manifest example declares a service that wraps the actual media route provider classes.
+ The Android media router framework provides the
+ {@link android.support.v7.media.MediaRouteProviderService} class for use as a service wrapper for
+ media route providers. The following example code demonstrates how to use this wrapper
+ class:</p>
+
+<pre>
+public class SampleMediaRouteProviderService extends MediaRouteProviderService {
+
+ @Override
+ public MediaRouteProvider onCreateMediaRouteProvider() {
+ return new SampleMediaRouteProvider(this);
+ }
+}
+</pre>
+
+
+<h2 id="route-caps">Specifying Route Capabilities</h2>
+
+<p>Apps connecting to the media router framework can discover your media route through your
+ app's manifest declarations, but they also need to know the capabilities of the media routes you
+ are providing. Media routes can be of different types and have different features, and other apps
+ need to be able to discover these details to determine if they are compatible with your route.</p>
+
+<p>The media router framework allows you to define and publish the capabilities of your media
+ route through {@link android.content.IntentFilter} objects, {@link
+ android.support.v7.media.MediaRouteDescriptor} objects and a {@link
+ android.support.v7.media.MediaRouteProviderDescriptor}. This section explains how to use these
+ classes to publish the details of your media route for other apps.</p>
+
+
+<h3 id="route-cat">Route categories</h3>
+
+<p>As part of the programmatic description of your media route provider, you must specify
+ whether your provider supports remote playback, secondary output, or both. These are the route
+ categories provided by the media router framework:</p>
+
+<ul>
+ <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_AUDIO CATEGORY_LIVE_AUDIO}
+ — Output of audio to a secondary output device, such as a wireless-enabled music system.
+ </li>
+ <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_VIDEO CATEGORY_LIVE_VIDEO}
+ — Output of video to a secondary output device, such as Wireless Display devices.</li>
+ <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
+ CATEGORY_REMOTE_PLAYBACK} — Play video or audio on a separate device which handles media
+ retrieval, decoding, and playback, such as
+ <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a> devices.
+ </li>
+</ul>
+
+<p>In order to include these settings in a description of your media route, you insert them into
+ an {@link android.content.IntentFilter} object, which you later add to a
+ {@link android.support.v7.media.MediaRouteDescriptor} object:</p>
+
+<pre>
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+ private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
+ static {
+ IntentFilter videoPlayback = new IntentFilter();
+ <strong>videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);</strong>
+ CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
+ CONTROL_FILTERS_BASIC.add(videoPlayback);
+ }
+}
+
+</pre>
+
+<p>If you specify the {@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
+ CATEGORY_REMOTE_PLAYBACK} intent, you must also define what media types and
+ playback controls are supported by your media route provider. The next section describes how to
+ specify these settings for your device.</p>
+
+
+<h3 id="media-types">Media types and protocols</h3>
+
+<p>A media route provider for a remote playback device must specify the media types and transfer
+ protocols it supports. You specify these settings using the {@link android.content.IntentFilter}
+ class and the {@link android.content.IntentFilter#addDataScheme addDataScheme()} and
+ {@link android.content.IntentFilter#addDataType addDataType()} methods of that object. The
+ following code snippet demonstrates how to define an intent filter for supporting remote video
+ playback using http, https, and Real Time Streaming Protocol (RTSP):</p>
+
+<pre>
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+
+ private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
+
+ static {
+ IntentFilter videoPlayback = new IntentFilter();
+ videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+ videoPlayback.addAction(MediaControlIntent.ACTION_PLAY);
+ videoPlayback.addDataScheme("http");
+ videoPlayback.addDataScheme("https");
+ videoPlayback.addDataScheme("rtsp");
+ addDataTypeUnchecked(videoPlayback, "video/*");
+ CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
+ CONTROL_FILTERS_BASIC.add(videoPlayback);
+ }
+ ...
+
+ private static void addDataTypeUnchecked(IntentFilter filter, String type) {
+ try {
+ filter.addDataType(type);
+ } catch (MalformedMimeTypeException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
+
+</pre>
+
+
+<h3 id="playback-ctrls">Playback controls</h3>
+
+<p>A media route provider that offers remote playback must specify the types of media controls
+ it supports. These are the general types of control that media routes can provide:</p>
+
+<ul>
+ <li><strong>Playback controls</strong>, such as play, pause, rewind, and fast-forward.</li>
+ <li><strong>Queuing features</strong>, which allow the sending app to add and remove items
+ from a playlist which is maintained by the receiver device.</li>
+ <li><strong>Session features</strong>, which prevent sending apps from interfering with each
+ other by having the receiver device provide a session id to the requesting app and then checking
+ that id with each subsequent playback control request.</li>
+</ul>
+
+<p>The following code example demonstrates how to construct an intent filter for supporting
+ basic media route playback controls:</p>
+
+<pre>
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+ private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
+ static {
+ ...
+ IntentFilter playControls = new IntentFilter();
+ playControls.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+ playControls.addAction(MediaControlIntent.ACTION_SEEK);
+ playControls.addAction(MediaControlIntent.ACTION_GET_STATUS);
+ playControls.addAction(MediaControlIntent.ACTION_PAUSE);
+ playControls.addAction(MediaControlIntent.ACTION_RESUME);
+ playControls.addAction(MediaControlIntent.ACTION_STOP);
+ CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
+ CONTROL_FILTERS_BASIC.add(videoPlayback);
+ CONTROL_FILTERS_BASIC.add(playControls);
+ }
+ ...
+}
+</pre>
+
+<p>For more information about the available playback control intents, see the
+ {@link android.support.v7.media.MediaControlIntent} class.</p>
+
+
+<h3 id="mrpd">MediaRouteProviderDescriptor</h3>
+
+<p>After defining the capabilities of your media route using {@link
+ android.content.IntentFilter} objects, you can then create a descriptor object for publishing to
+ the Android media router framework. This descriptor object contains the specifics of your media
+ route's capabilities so that other applications can determine how to interact with your media
+ route.</p>
+
+<p>The following example code demonstrates how to add the previously created intent filters to a
+ {@link android.support.v7.media.MediaRouteProviderDescriptor} and set the descriptor for use by
+ the media router framework:</p>
+
+<pre>
+public SampleMediaRouteProvider(Context context) {
+ super(context);
+ publishRoutes();
+}
+
+private void publishRoutes() {
+ Resources r = getContext().getResources();
+ // Create a route descriptor using previously created IntentFilters
+ MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder(
+ VARIABLE_VOLUME_BASIC_ROUTE_ID,
+ r.getString(R.string.variable_volume_basic_route_name))
+ .setDescription(r.getString(R.string.sample_route_description))
+ .addControlFilters(CONTROL_FILTERS_BASIC)
+ .setPlaybackStream(AudioManager.STREAM_MUSIC)
+ .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+ .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
+ .setVolumeMax(VOLUME_MAX)
+ .setVolume(mVolume)
+ .build();
+ // Add the route descriptor to the provider descriptor
+ MediaRouteProviderDescriptor providerDescriptor =
+ new MediaRouteProviderDescriptor.Builder()
+ .addRoute(routeDescriptor)
+ .build();
+
+ // Publish the descriptor to the framework
+ setDescriptor(providerDescriptor);
+}
+</pre>
+
+<p>For more information on the available descriptor settings, see the reference documentation
+ for {@link android.support.v7.media.MediaRouteDescriptor} and {@link
+ android.support.v7.media.MediaRouteProviderDescriptor}.</p>
+
+
+<h2 id="ctrl-routes">Controlling Routes</h2>
+
+<p>When an application connects to your media route provider, the provider receives playback
+ commands through the media router framework sent to your route by other apps. To handle these
+ requests, you must provide an implementation of a {@link
+ android.support.v7.media.MediaRouteProvider.RouteController} class, which processes the commands
+ and handles the actual communication to your receiver device.</p>
+
+<p>The media router framework calls the {@link
+ android.support.v7.media.MediaRouteProvider#onCreateRouteController onCreateRouteController()}
+ method of your route provider to obtain an instance of this class and then routes requests to it.
+ These are the key methods of the {@link
+ android.support.v7.media.MediaRouteProvider.RouteController} class, which you must implement for
+ your media route provider:</p>
+
+<ul>
+ <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onSelect onSelect()}
+ — Called when an application selects your route for playback. You use this method to do
+ any preparation work that may be required before media playback begins.</li>
+ <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onControlRequest
+ onControlRequest()} — Sends specific playback commands to the receiving device.</li>
+ <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onSetVolume
+ onSetVolume()} — Sends a request to the receiving device to set the playback volume to a
+ specific value.</li>
+ <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onUpdateVolume
+ onUpdateVolume()} — Sends a request to the receiving device to modify the playback
+ volume by a specified amount.</li>
+ <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect
+ onUnselect()} — Called when an application unselects a route.</li>
+ <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onRelease onRelease()}
+ — Called when the route is no longer needed by the framework, allowing it to free its
+ resources.</li>
+</ul>
+
+<p>All playback control requests, except for volume changes, are directed to the {@link
+ android.support.v7.media.MediaRouteProvider.RouteController#onControlRequest onControlRequest()}
+ method. Your implementation of this method must parse the control requests and respond to them
+ appropriately. Here is an example implementation of this method which processes commands for a
+ remote playback media route:</p>
+
+<pre>
+private final class SampleRouteController extends
+ MediaRouteProvider.RouteController {
+ ...
+
+ @Override
+ public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
+
+ String action = intent.getAction();
+
+ if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
+ boolean success = false;
+ if (action.equals(MediaControlIntent.ACTION_PLAY)) {
+ success = handlePlay(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
+ success = handleEnqueue(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
+ success = handleRemove(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
+ success = handleSeek(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
+ success = handleGetStatus(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
+ success = handlePause(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
+ success = handleResume(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
+ success = handleStop(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) {
+ success = handleStartSession(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) {
+ success = handleGetSessionStatus(intent, callback);
+ } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) {
+ success = handleEndSession(intent, callback);
+ }
+
+ Log.d(TAG, mSessionManager.toString());
+ return success;
+ }
+ return false;
+ }
+ ...
+}
+</pre>
+
+<p>It is important to understand that the {@link
+ android.support.v7.media.MediaRouteProvider.RouteController} class is intended to act as a wrapper
+ for the API to your media playback equipment. The implementation of the methods in this class is
+ entirely dependent on the programmatic interface provided by your receiving device.</p>
diff --git a/docs/html/guide/topics/media/mediarouter.jd b/docs/html/guide/topics/media/mediarouter.jd
index 1b10265..e0bf889 100644
--- a/docs/html/guide/topics/media/mediarouter.jd
+++ b/docs/html/guide/topics/media/mediarouter.jd
@@ -1,5 +1,5 @@
-page.title=MediaRouter
-page.tags="cast","chromecast","wireless display","miracast"
+page.title=Media Router
+page.tags="mediarouter","cast","chromecast","wireless display","miracast"
@jd:body
<div id="qv-wrapper">
@@ -36,6 +36,10 @@
<li>{@link android.support.v7.media.MediaRouter.Callback}</li>
<li>{@link android.support.v7.media.MediaRouteProvider}</li>
</ol>
+ <h2>Related Samples</h2>
+ <ol>
+ <li><a href="{@docRoot}guide/topics/media/mediarouter.html">MediaRouter</a></li>
+ </ol>
</div>
</div>
@@ -105,15 +109,17 @@
(API level 7) and higher.
</p>
-<p class="note">
- <strong>Note:</strong> There is another set of media router APIs provided in the
+<p class="caution">
+ <strong>Caution:</strong> There is another set of media router APIs provided in the
{@link android.media} that have been superseded by the v7-mediarouter support library.
You <em>should not</em> use the {@link android.media} classes for media router functions.
</p>
<p>In order to use the {@link android.support.v7.media} media router classes, you must add
the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter
- support library package</a> to your app development project.
+ support library package</a> to your app development project. For more
+ information on adding support libraries to your app development project, see
+ <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a>.
</p>
@@ -211,9 +217,9 @@
CATEGORY_LIVE_VIDEO} — Output of video to a secondary output device, such as Wireless
Display devices.</li>
<li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
- CATEGORY_REMOTE_PLAYBACK} — Play video or audio on a separate device that supports the
- <a href="https://developers.google.com/cast/">Google Cast</a> remote control protocol, such
- as <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a>.
+ CATEGORY_REMOTE_PLAYBACK} — Play video or audio on a separate device that handles media
+ retrieval, decoding, and playback, such as
+ <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a> devices.
</li>
</ul>
@@ -279,7 +285,7 @@
<p>In order to connect to a media route selected by the user, your app must obtain the {@link
android.support.v7.media.MediaRouter} framework object and then attach a {@link
android.support.v7.media.MediaRouter.Callback} object. The callback object receives messages
- from the media router framework when a route selected, changed or disconnected by the user.</p>
+ from the media router framework when a route is selected, changed, or disconnected by the user.</p>
<p>To obtain an instance of the {@link android.support.v7.media.MediaRouter} framework object,
call {@link android.support.v7.media.MediaRouter#getInstance MediaRouter.getInstance()}
@@ -299,11 +305,11 @@
<p>The media router framework communicates with an app through a callback object that
you attach to the {@link android.support.v7.media.MediaRouter} framework object. An app
that uses the media router framework must extend the {@link
- android.support.v7.media.MediaRouter.Callback} object to receive messages when a media route is
- connected and provide content to the connected device through that route.</p>
+ android.support.v7.media.MediaRouter.Callback} object in order to receive messages when a
+ media route is connected.</p>
-<p>There are several methods in the callback that can be overwritten to receive messages about
- media router events. At the minimum, your implementation of the {@link
+<p>There are several methods in the callback that you can override to receive information about
+ media router events. At minimum, your implementation of the {@link
android.support.v7.media.MediaRouter.Callback} class should override the following
methods:</p>
@@ -440,12 +446,12 @@
<p class="note">
<strong>Note:</strong> The media route framework also provides a
- {@link android.support.v7.app.MediaRouteDiscoveryFragment} class which takes care of adding and
- removing the call back for an activity.
+ {@link android.support.v7.app.MediaRouteDiscoveryFragment} class, which takes care of adding and
+ removing the callback for an activity.
</p>
<p>Now when you run your application, you should see a Cast button appear in your activity.
- When you press the button the media router framework, a route selection dialog appears as shown
+ When you touch the button, a route selection dialog appears as shown
in figure 3, allowing your user to select an available media route. Make sure you have a
supported device available on your local network when testing this interface.</p>
diff --git a/docs/html/images/mediarouter/media-route-provider-framework.png b/docs/html/images/mediarouter/media-route-provider-framework.png
new file mode 100644
index 0000000..60cc29a
--- /dev/null
+++ b/docs/html/images/mediarouter/media-route-provider-framework.png
Binary files differ
diff --git a/docs/html/sdk/installing/studio-build.jd b/docs/html/sdk/installing/studio-build.jd
index 41ad5de..8674134 100644
--- a/docs/html/sdk/installing/studio-build.jd
+++ b/docs/html/sdk/installing/studio-build.jd
@@ -1,4 +1,4 @@
-page.title=Building your Project
+page.title=Building Your Project with Gradle
@jd:body
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 0e543e4..c281644 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -37,7 +37,7 @@
<li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
Using the Layout Editor</a></li>
<li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
- Building your Project</a></li>
+ Building Your Project with Gradle</a></li>
</ul>
</li>
<li><a href="<?cs var:toroot ?>sdk/exploring.html">
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index 50485db..c4cb362 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -10,9 +10,9 @@
<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
+<div id="tb-wrapper">
+<div id="tb">
+
<h2>This lesson teaches you to</h2>
<ol>
@@ -27,10 +27,10 @@
SDK</a></li>
<li><a href="{@docRoot}tools/projects/index.html">Managing Projects</a></li>
</ul>
-
-
-</div>
-</div>
+
+
+</div>
+</div>
<p>An Android project contains all the files that comprise the source code for your Android
app. The Android SDK tools make it easy to start a new Android project with a set of
@@ -42,7 +42,7 @@
<p class="note"><strong>Note:</strong> You should already have the Android SDK installed, and if
you're using Eclipse, you should also have the <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT
-plugin</a> installed (version 21.0.0 or higher). If you don't have these, follow the guide to <a
+plugin</a> installed (version 22.6.2 or higher). If you don't have these, follow the guide to <a
href="{@docRoot}sdk/installing/index.html">Installing the Android SDK</a> before you start this
lesson.</p>
@@ -50,7 +50,7 @@
<h2 id="Eclipse">Create a Project with Eclipse</h2>
<ol>
- <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
+ <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
style="vertical-align:baseline;margin:0" /> in the toolbar.</li>
<li>In the window that appears, open the <strong>Android</strong> folder,
select <strong>Android Application Project</strong>, and click <strong>Next</strong>.</li>
@@ -116,11 +116,11 @@
<li>Now you can select an activity template from which to begin building your app.
<p>For this project, select <strong>BlankActivity</strong> and click <strong>Next</strong>.</p>
</li>
- <li>Leave all the details for the activity in their default state and click
+ <li>Leave all the details for the activity in their default state and click
<strong>Finish</strong>.</li>
</ol>
-<p>Your Android project is now a basic "Hello World" app that contains some default files.
+<p>Your Android project is now a basic "Hello World" app that contains some default files.
To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
@@ -155,7 +155,7 @@
projects.</p></li>
</ol>
-<p>Your Android project is now a basic "Hello World" app that contains some default files.
+<p>Your Android project is now a basic "Hello World" app that contains some default files.
To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
<p class="note"><strong>Tip:</strong> Add the <code>platform-tools/</code> as well as the
diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd
index 4c1a0dc..1b49096 100644
--- a/docs/html/training/basics/firstapp/index.jd
+++ b/docs/html/training/basics/firstapp/index.jd
@@ -8,21 +8,21 @@
@jd:body
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>Dependencies and prerequisites</h2>
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
<ul>
<li><a href="http://developer.android.com/sdk/index.html">Android SDK</a></li>
- <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> 20.0.0 or higher
+ <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> 22.6.2 or higher
(if you're using Eclipse)</li>
</ul>
-
-</div>
-</div>
-
-<p>Welcome to Android application development!</p>
+
+</div>
+</div>
+
+<p>Welcome to Android application development!</p>
<p>This class teaches you how to build your first Android app. You’ll learn how to create an Android
project and run a debuggable version of the app. You'll also learn some fundamentals of Android app
@@ -36,6 +36,10 @@
<li>Download the latest SDK tools and platforms using the SDK Manager.</li>
</ol>
+<p class="note"><strong>Note:</strong> Make sure you install the most recent versions of the ADT
+plugin and the Android SDK before you start this class. The procedures described in this class may
+not apply to earlier versions.</p>
+
<p>If you haven't already done these tasks, start by downloading the
<a href="{@docRoot}sdk/index.html">Android SDK</a> and following the install steps.
Once you've finished the setup, you're ready to begin this class.</p>
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 9aa25a3..27d2c10 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -10,9 +10,9 @@
<!-- This is the training bar -->
-<div id="tb-wrapper">
-<div id="tb">
-
+<div id="tb-wrapper">
+<div id="tb">
+
<h2>This lesson teaches you to</h2>
<ol>
@@ -30,10 +30,10 @@
<li><a href="{@docRoot}sdk/installing/index.html">Installing the
SDK</a></li>
</ul>
-
-
-</div>
-</div>
+
+
+</div>
+</div>
@@ -151,7 +151,7 @@
</pre>
<p class="note"><strong>Note:</strong>
-You now need an import statement for <code>android.widget.EditText</code>.
+You now need an import statement for <code>android.widget.EditText</code>.
You'll define the <code>EXTRA_MESSAGE</code> constant in a moment.</p>
<p>An {@link android.content.Intent} can carry a collection of various data types as key-value
@@ -212,7 +212,7 @@
<p>To create a new activity using Eclipse:</p>
<ol>
- <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
+ <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
style="vertical-align:baseline;margin:0" /> in the toolbar.</li>
<li>In the window that appears, open the <strong>Android</strong> folder
and select <strong>Android Activity</strong>. Click <strong>Next</strong>.</li>
@@ -247,15 +247,19 @@
<li>There's also an implementation of {@link android.app.Activity#onOptionsItemSelected
onOptionsItemSelected()} which handles the behavior for the action bar's <em>Up</em> behavior.
Keep this one the way it is.</li>
- <li>There's also a <code>PlaceholderFragment</code> class that extends
+ <li>There's also a <code>PlaceholderFragment</code> class that extends
{@link android.app.Fragment}. You will not need this class in the final version of this
activity.</li>
</ul>
-<p>Fragments decompose application functionality and UI into reusable modules. For more
-information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments
+<p>Fragments decompose application functionality and UI into reusable modules. For more
+information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments
API Guide</a>. The final version of this activity does not use fragments.</p>
+<p class="note"><strong>Note:</strong> Your activity may look different if you did not use
+the latest version of the ADT plugin. Make sure you install the latest version of the
+<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT plugin</a> to complete this tutorial.</p>
+
<p>The {@code DisplayMessageActivity} class should now look like this:</p>
<pre>
diff --git a/docs/html/wear/images/laptop-bridge.png b/docs/html/wear/images/laptop-bridge.png
index b481224..083b82b 100644
--- a/docs/html/wear/images/laptop-bridge.png
+++ b/docs/html/wear/images/laptop-bridge.png
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist
new file mode 100644
index 0000000..d82ea05
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png
new file mode 100644
index 0000000..3435e35
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist
new file mode 100644
index 0000000..07791df
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png
new file mode 100644
index 0000000..d6e3e95
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist b/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist
new file mode 100644
index 0000000..ffd8212
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png b/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png
new file mode 100644
index 0000000..d6e3e95
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png
Binary files differ
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index e320c67..1760458 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -121,20 +121,6 @@
* document.</p></div>
*/
public abstract class Drawable {
- /**
- * Hotspot identifier mask for tracking touch points.
- *
- * @hide until hotspot APIs are finalized
- */
- public static final int HOTSPOT_TOUCH_MASK = 0xFF;
-
- /**
- * Hotspot identifier for tracking keyboard focus.
- *
- * @hide until hotspot APIs are finalized
- */
- public static final int HOTSPOT_FOCUS = 0x100;
-
private static final Rect ZERO_BOUNDS_RECT = new Rect();
private int[] mStateSet = StateSet.WILD_CARD;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index f3dd2fc..33683ab 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -60,9 +60,11 @@
* The vector drawable has 6 elements:
* <p/>
* <dl>
- * <dt><code><vector></code></dt><dd>
- * The attribute <code>android:trigger</code> which defines a state change that
+ * <dt><code><vector></code></dt>
+ * <dd>The attribute <code>android:trigger</code> defines a state change that
* will drive the animation </dd>
+ * <dd>The attribute <code>android:versionCode</code> defines the version of
+ * VectorDrawable </dd>
* <dt><code><size></code></dt>
* <dd>Used to defined the intrinsic Width Height size of the drawable using
* <code>android:width</code> and <code>android:height</code> </dd>
@@ -494,6 +496,16 @@
} else if (SHAPE_VECTOR.equals(tagName)) {
TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
+
+ // Parsing the version information.
+ // Right now, we only support version "1".
+ // If the xml didn't specify the version number, the default version is "1".
+ int versionCode = a.getInt(R.styleable.VectorDrawable_versionCode, 1);
+ if (versionCode != 1) {
+ throw new IllegalArgumentException(
+ "So far, VectorDrawable only support version 1");
+ }
+
a.recycle();
}
}
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 649f4c3..6f2af90 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -34,7 +34,7 @@
class AndroidRuntime
{
public:
- AndroidRuntime();
+ AndroidRuntime(char* argBlockStart, size_t argBlockSize);
virtual ~AndroidRuntime();
enum StartMode {
@@ -44,6 +44,8 @@
Tool,
};
+ void setArgv0(const char* argv0);
+
/**
* Register a set of methods in the specified class.
*/
@@ -120,6 +122,8 @@
Vector<JavaVMOption> mOptions;
bool mExitWithoutCleanup;
+ char* const mArgBlockStart;
+ const size_t mArgBlockLength;
/* JNI JavaVM pointer */
static JavaVM* mJavaVM;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 34d98a1..663b67e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -61,8 +61,12 @@
void RenderNode::destroyDisplayListDeferred(RenderNode* displayList) {
if (displayList) {
- DISPLAY_LIST_LOGD("Deferring display list destruction");
- Caches::getInstance().deleteDisplayListDeferred(displayList);
+ if (Caches::hasInstance()) {
+ DISPLAY_LIST_LOGD("Deferring display list destruction");
+ Caches::getInstance().deleteDisplayListDeferred(displayList);
+ } else {
+ delete displayList;
+ }
}
}
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 3975a76..e7e7768 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -45,28 +45,24 @@
, mPrevWidth(-1), mPrevHeight(-1)
, mPivotExplicitlySet(false)
, mMatrixDirty(false)
- , mMatrixIsIdentity(true)
, mMatrixFlags(0)
, mCaching(false) {
}
RenderProperties::ComputedFields::ComputedFields()
: mTransformMatrix(NULL)
- , mTransformCamera(NULL)
, mTransformMatrix3D(NULL)
, mClipPath(NULL) {
}
RenderProperties::ComputedFields::~ComputedFields() {
delete mTransformMatrix;
- delete mTransformCamera;
delete mTransformMatrix3D;
delete mClipPath;
}
RenderProperties::RenderProperties()
- : mCameraDistance(0)
- , mStaticMatrix(NULL)
+ : mStaticMatrix(NULL)
, mAnimationMatrix(NULL) {
}
@@ -82,9 +78,12 @@
setAnimationMatrix(other.getAnimationMatrix());
setCameraDistance(other.getCameraDistance());
- // Update the computed fields
- updateMatrix();
+ // Update the computed clip path
updateClipPath();
+
+ // Force recalculation of the matrix, since other's dirty bit may be clear
+ mPrimitiveFields.mMatrixDirty = true;
+ updateMatrix();
}
return *this;
}
@@ -106,8 +105,8 @@
ALOGD("%*sTranslate %.2f, %.2f, %.2f",
level * 2, "", mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY, mPrimitiveFields.mTranslationZ);
} else {
- ALOGD("%*sConcatMatrix %p: " MATRIX_4_STRING,
- level * 2, "", mComputedFields.mTransformMatrix, MATRIX_4_ARGS(mComputedFields.mTransformMatrix));
+ ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
+ level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
}
}
@@ -141,7 +140,7 @@
if (mPrimitiveFields.mMatrixFlags && mPrimitiveFields.mMatrixFlags != TRANSLATION) {
if (!mComputedFields.mTransformMatrix) {
// only allocate a mPrimitiveFields.matrix if we have a complex transform
- mComputedFields.mTransformMatrix = new Matrix4();
+ mComputedFields.mTransformMatrix = new SkMatrix();
}
if (!mPrimitiveFields.mPivotExplicitlySet) {
if (mPrimitiveFields.mWidth != mPrimitiveFields.mPrevWidth || mPrimitiveFields.mHeight != mPrimitiveFields.mPrevHeight) {
@@ -153,33 +152,31 @@
}
if ((mPrimitiveFields.mMatrixFlags & ROTATION_3D) == 0) {
- mComputedFields.mTransformMatrix->loadTranslate(
- mPrimitiveFields.mPivotX + mPrimitiveFields.mTranslationX,
- mPrimitiveFields.mPivotY + mPrimitiveFields.mTranslationY,
- 0);
- mComputedFields.mTransformMatrix->rotate(mPrimitiveFields.mRotation, 0, 0, 1);
- mComputedFields.mTransformMatrix->scale(mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY, 1);
- mComputedFields.mTransformMatrix->translate(-mPrimitiveFields.mPivotX, -mPrimitiveFields.mPivotY);
+ mComputedFields.mTransformMatrix->setTranslate(
+ mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY);
+ mComputedFields.mTransformMatrix->preRotate(mPrimitiveFields.mRotation,
+ mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
+ mComputedFields.mTransformMatrix->preScale(
+ mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
+ mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
} else {
- if (!mComputedFields.mTransformCamera) {
- mComputedFields.mTransformCamera = new Sk3DView();
+ if (!mComputedFields.mTransformMatrix3D) {
mComputedFields.mTransformMatrix3D = new SkMatrix();
}
- SkMatrix transformMatrix;
- transformMatrix.reset();
- mComputedFields.mTransformCamera->save();
- transformMatrix.preScale(mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY, mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
- mComputedFields.mTransformCamera->rotateX(mPrimitiveFields.mRotationX);
- mComputedFields.mTransformCamera->rotateY(mPrimitiveFields.mRotationY);
- mComputedFields.mTransformCamera->rotateZ(-mPrimitiveFields.mRotation);
- mComputedFields.mTransformCamera->getMatrix(mComputedFields.mTransformMatrix3D);
+ mComputedFields.mTransformMatrix->reset();
+ mComputedFields.mTransformCamera.save();
+ mComputedFields.mTransformMatrix->preScale(
+ mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
+ mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
+ mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
+ mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
+ mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
+ mComputedFields.mTransformCamera.getMatrix(mComputedFields.mTransformMatrix3D);
mComputedFields.mTransformMatrix3D->preTranslate(-mPrimitiveFields.mPivotX, -mPrimitiveFields.mPivotY);
mComputedFields.mTransformMatrix3D->postTranslate(mPrimitiveFields.mPivotX + mPrimitiveFields.mTranslationX,
mPrimitiveFields.mPivotY + mPrimitiveFields.mTranslationY);
- transformMatrix.postConcat(*mComputedFields.mTransformMatrix3D);
- mComputedFields.mTransformCamera->restore();
-
- mComputedFields.mTransformMatrix->load(transformMatrix);
+ mComputedFields.mTransformMatrix->postConcat(*mComputedFields.mTransformMatrix3D);
+ mComputedFields.mTransformCamera.restore();
}
}
mPrimitiveFields.mMatrixDirty = false;
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 061e469..dd68210 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -258,20 +258,20 @@
return mPrimitiveFields.mPivotY;
}
+ bool isPivotExplicitlySet() const {
+ return mPrimitiveFields.mPivotExplicitlySet;
+ }
+
void setCameraDistance(float distance) {
- if (distance != mCameraDistance) {
- mCameraDistance = distance;
+ if (distance != getCameraDistance()) {
mPrimitiveFields.mMatrixDirty = true;
- if (!mComputedFields.mTransformCamera) {
- mComputedFields.mTransformCamera = new Sk3DView();
- mComputedFields.mTransformMatrix3D = new SkMatrix();
- }
- mComputedFields.mTransformCamera->setCameraLocation(0, 0, distance);
+ mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance);
}
}
float getCameraDistance() const {
- return mCameraDistance;
+ // TODO: update getCameraLocationZ() to be const
+ return const_cast<Sk3DView*>(&mComputedFields.mTransformCamera)->getCameraLocationZ();
}
void setLeft(int left) {
@@ -396,7 +396,7 @@
return mPrimitiveFields.mMatrixFlags;
}
- const Matrix4* getTransformMatrix() const {
+ const SkMatrix* getTransformMatrix() const {
return mComputedFields.mTransformMatrix;
}
@@ -481,13 +481,11 @@
int mPrevWidth, mPrevHeight;
bool mPivotExplicitlySet;
bool mMatrixDirty;
- bool mMatrixIsIdentity;
uint32_t mMatrixFlags;
bool mCaching;
} mPrimitiveFields;
// mCameraDistance isn't in mPrimitiveFields as it has a complex setter
- float mCameraDistance;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
@@ -502,11 +500,12 @@
* Stores the total transformation of the DisplayList based upon its scalar
* translate/rotate/scale properties.
*
- * In the common translation-only case, the matrix isn't allocated and the mTranslation
- * properties are used directly.
+ * In the common translation-only case, the matrix isn't necessarily allocated,
+ * and the mTranslation properties are used directly.
*/
- Matrix4* mTransformMatrix;
- Sk3DView* mTransformCamera;
+ SkMatrix* mTransformMatrix;
+
+ Sk3DView mTransformCamera;
SkMatrix* mTransformMatrix3D;
SkPath* mClipPath; // TODO: remove this, create new ops for efficient/special case clipping
SkRegion::Op mClipPathOp;
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index cc6d0cd..5bdb18a 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -108,7 +108,7 @@
* Returns the current clip in local coordinates. The clip rect is
* transformed by the inverse transform matrix.
*/
- const Rect& getLocalClip();
+ ANDROID_API const Rect& getLocalClip();
/**
* Resets the clip to the specified rect.
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 7170ffb..440653a 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -20,6 +20,8 @@
import java.util.UUID;
import java.util.HashMap;
import java.util.List;
+import android.os.Binder;
+import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -95,12 +97,28 @@
private final static String TAG = "MediaDrm";
+ private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
+
private EventHandler mEventHandler;
private OnEventListener mOnEventListener;
private long mNativeContext;
/**
+ * Specify no certificate type
+ *
+ * @hide - not part of the public API at this time
+ */
+ public static final int CERTIFICATE_TYPE_NONE = 0;
+
+ /**
+ * Specify X.509 certificate type
+ *
+ * @hide - not part of the public API at this time
+ */
+ public static final int CERTIFICATE_TYPE_X509 = 1;
+
+ /**
* Query if the given scheme identified by its UUID is supported on
* this device.
* @param uuid The UUID of the crypto scheme.
@@ -135,7 +153,7 @@
}
private static final native boolean isCryptoSchemeSupportedNative(byte[] uuid,
- String mimeType);
+ String mimeType);
/**
* Instantiate a MediaDrm object
@@ -159,7 +177,7 @@
* It's easier to create it here than in C++.
*/
native_setup(new WeakReference<MediaDrm>(this),
- getByteArrayFromUUID(uuid));
+ getByteArrayFromUUID(uuid));
}
/**
@@ -268,7 +286,7 @@
* the cookie passed to native_setup().)
*/
private static void postEventFromNative(Object mediadrm_ref,
- int eventType, int extra, Object obj)
+ int eventType, int extra, Object obj)
{
MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
if (md == null) {
@@ -316,6 +334,9 @@
* Contains the opaque data an app uses to request keys from a license server
*/
public final static class KeyRequest {
+ private byte[] mData;
+ private String mDefaultUrl;
+
KeyRequest() {}
/**
@@ -329,9 +350,6 @@
* server URL from other sources.
*/
public String getDefaultUrl() { return mDefaultUrl; }
-
- private byte[] mData;
- private String mDefaultUrl;
};
/**
@@ -368,9 +386,8 @@
* problem with the certifcate
*/
public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
- String mimeType, int keyType,
- HashMap<String, String> optionalParameters)
- throws NotProvisionedException;
+ String mimeType, int keyType, HashMap<String, String> optionalParameters)
+ throws NotProvisionedException;
/**
@@ -394,7 +411,7 @@
* @throws ResourceBusyException if required resources are in use
*/
public native byte[] provideKeyResponse(byte[] scope, byte[] response)
- throws NotProvisionedException, DeniedByServerException;
+ throws NotProvisionedException, DeniedByServerException;
/**
@@ -456,7 +473,12 @@
* is returned in ProvisionRequest.data. The recommended URL to deliver the provision
* request to is returned in ProvisionRequest.defaultUrl.
*/
- public native ProvisionRequest getProvisionRequest();
+ public ProvisionRequest getProvisionRequest() {
+ return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, "");
+ }
+
+ private native ProvisionRequest getProvisionRequestNative(int certType,
+ String certAuthority);
/**
* After a provision response is received by the app, it is provided to the DRM
@@ -468,8 +490,13 @@
* @throws DeniedByServerException if the response indicates that the
* server rejected the request
*/
- public native void provideProvisionResponse(byte[] response)
- throws DeniedByServerException;
+ public void provideProvisionResponse(byte[] response)
+ throws DeniedByServerException {
+ provideProvisionResponseNative(response);
+ }
+
+ private native Certificate provideProvisionResponseNative(byte[] response)
+ throws DeniedByServerException;
/**
* A means of enforcing limits on the number of concurrent streams per subscriber
@@ -556,23 +583,22 @@
private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
- String algorithm);
+ String algorithm);
private static final native void setMacAlgorithmNative(MediaDrm drm, byte[] sessionId,
- String algorithm);
+ String algorithm);
private static final native byte[] encryptNative(MediaDrm drm, byte[] sessionId,
- byte[] keyId, byte[] input, byte[] iv);
+ byte[] keyId, byte[] input, byte[] iv);
private static final native byte[] decryptNative(MediaDrm drm, byte[] sessionId,
- byte[] keyId, byte[] input, byte[] iv);
+ byte[] keyId, byte[] input, byte[] iv);
private static final native byte[] signNative(MediaDrm drm, byte[] sessionId,
- byte[] keyId, byte[] message);
+ byte[] keyId, byte[] message);
private static final native boolean verifyNative(MediaDrm drm, byte[] sessionId,
- byte[] keyId, byte[] message,
- byte[] signature);
+ byte[] keyId, byte[] message, byte[] signature);
/**
* In addition to supporting decryption of DASH Common Encrypted Media, the
@@ -602,7 +628,7 @@
private byte[] mSessionId;
CryptoSession(MediaDrm drm, byte[] sessionId,
- String cipherAlgorithm, String macAlgorithm)
+ String cipherAlgorithm, String macAlgorithm)
{
mSessionId = sessionId;
mDrm = drm;
@@ -677,12 +703,124 @@
* "algorithms".
*/
public CryptoSession getCryptoSession(byte[] sessionId,
- String cipherAlgorithm,
- String macAlgorithm)
+ String cipherAlgorithm, String macAlgorithm)
{
return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
}
+ /**
+ * Contains the opaque data an app uses to request a certificate from a provisioning
+ * server
+ *
+ * @hide - not part of the public API at this time
+ */
+ public final static class CertificateRequest {
+ private byte[] mData;
+ private String mDefaultUrl;
+
+ CertificateRequest(byte[] data, String defaultUrl) {
+ mData = data;
+ mDefaultUrl = defaultUrl;
+ }
+
+ /**
+ * Get the opaque message data
+ */
+ public byte[] getData() { return mData; }
+
+ /**
+ * Get the default URL to use when sending the certificate request
+ * message to a server, if known. The app may prefer to use a different
+ * certificate server URL obtained from other sources.
+ */
+ public String getDefaultUrl() { return mDefaultUrl; }
+ }
+
+ /**
+ * Generate a certificate request, specifying the certificate type
+ * and authority. The response received should be passed to
+ * provideCertificateResponse.
+ *
+ * @param certType Specifies the certificate type.
+ *
+ * @param certAuthority is passed to the certificate server to specify
+ * the chain of authority.
+ *
+ * @hide - not part of the public API at this time
+ */
+ public CertificateRequest getCertificateRequest(int certType,
+ String certAuthority)
+ {
+ ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority);
+ return new CertificateRequest(provisionRequest.getData(),
+ provisionRequest.getDefaultUrl());
+ }
+
+ /**
+ * Contains the wrapped private key and public certificate data associated
+ * with a certificate.
+ *
+ * @hide - not part of the public API at this time
+ */
+ public final static class Certificate {
+ Certificate() {}
+
+ /**
+ * Get the wrapped private key data
+ */
+ public byte[] getWrappedPrivateKey() { return mWrappedKey; }
+
+ /**
+ * Get the PEM-encoded certificate chain
+ */
+ public byte[] getContent() { return mCertificateData; }
+
+ private byte[] mWrappedKey;
+ private byte[] mCertificateData;
+ }
+
+
+ /**
+ * Process a response from the certificate server. The response
+ * is obtained from an HTTP Post to the url provided by getCertificateRequest.
+ * <p>
+ * The public X509 certificate chain and wrapped private key are returned
+ * in the returned Certificate objec. The certificate chain is in PEM format.
+ * The wrapped private key should be stored in application private
+ * storage, and used when invoking the signRSA method.
+ *
+ * @param response the opaque certificate response byte array to provide to the
+ * DRM engine plugin.
+ *
+ * @throws DeniedByServerException if the response indicates that the
+ * server rejected the request
+ *
+ * @hide - not part of the public API at this time
+ */
+ public Certificate provideCertificateResponse(byte[] response)
+ throws DeniedByServerException {
+ return provideProvisionResponseNative(response);
+ }
+
+ private static final native byte[] signRSANative(MediaDrm drm, byte[] sessionId,
+ String algorithm, byte[] wrappedKey, byte[] message);
+
+ /**
+ * Sign data using an RSA key
+ *
+ * @param sessionId a sessionId obtained from openSession on the MediaDrm object
+ * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
+ * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
+ * from provideCertificateResponse
+ * @param message the data for which a signature is to be computed
+ *
+ * @hide - not part of the public API at this time
+ */
+ public byte[] signRSA(byte[] sessionId, String algorithm,
+ byte[] wrappedKey, byte[] message) {
+ return signRSANative(this, sessionId, algorithm, wrappedKey, message);
+ }
+
@Override
protected void finalize() {
native_finalize();
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 052d97d..7c45682 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -100,6 +100,16 @@
jint kKeyTypeRelease;
} gKeyTypes;
+struct CertificateTypes {
+ jint kCertificateTypeNone;
+ jint kCertificateTypeX509;
+} gCertificateTypes;
+
+struct CertificateFields {
+ jfieldID wrappedPrivateKey;
+ jfieldID certificateData;
+};
+
struct fields_t {
jfieldID context;
jmethodID post_event;
@@ -110,6 +120,11 @@
SetFields set;
IteratorFields iterator;
EntryFields entry;
+ CertificateFields certificate;
+ jclass certificateClassId;
+ jclass hashmapClassId;
+ jclass arraylistClassId;
+ jclass stringClassId;
};
static fields_t gFields;
@@ -406,8 +421,7 @@
*/
static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
- jclass clazz;
- FIND_CLASS(clazz, "java/lang/String");
+ jclass clazz = gFields.stringClassId;
KeyedVector<String8, String8> keyedVector;
jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
@@ -450,8 +464,7 @@
}
static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
- jclass clazz;
- FIND_CLASS(clazz, "java/util/HashMap");
+ jclass clazz = gFields.hashmapClassId;
jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
for (size_t i = 0; i < map.size(); ++i) {
jstring jkey = env->NewStringUTF(map.keyAt(i).string());
@@ -465,8 +478,7 @@
static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
List<Vector<uint8_t> > list) {
- jclass clazz;
- FIND_CLASS(clazz, "java/util/ArrayList");
+ jclass clazz = gFields.arraylistClassId;
jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
List<Vector<uint8_t> >::iterator iter = list.begin();
while (iter != list.end()) {
@@ -542,6 +554,11 @@
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
+ gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
+ gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
+
FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
@@ -550,6 +567,11 @@
GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
+ FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
+ GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
+ GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
+ gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
FIND_CLASS(clazz, "java/util/ArrayList");
GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
@@ -571,6 +593,15 @@
FIND_CLASS(clazz, "java/util/Map$Entry");
GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
+
+ FIND_CLASS(clazz, "java/util/HashMap");
+ gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ FIND_CLASS(clazz, "java/lang/String");
+ gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ FIND_CLASS(clazz, "java/util/ArrayList");
+ gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
}
static void android_media_MediaDrm_native_setup(
@@ -826,8 +857,8 @@
return KeyedVectorToHashMap(env, infoMap);
}
-static jobject android_media_MediaDrm_getProvisionRequest(
- JNIEnv *env, jobject thiz) {
+static jobject android_media_MediaDrm_getProvisionRequestNative(
+ JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
@@ -839,7 +870,17 @@
Vector<uint8_t> request;
String8 defaultUrl;
- status_t err = drm->getProvisionRequest(request, defaultUrl);
+ String8 certType;
+ if (jcertType == gCertificateTypes.kCertificateTypeX509) {
+ certType = "X.509";
+ } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
+ certType = "none";
+ } else {
+ certType = "invalid";
+ }
+
+ String8 certAuthority = JStringToString8(env, jcertAuthority);
+ status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
return NULL;
@@ -863,27 +904,43 @@
return provisionObj;
}
-static void android_media_MediaDrm_provideProvisionResponse(
+static jobject android_media_MediaDrm_provideProvisionResponseNative(
JNIEnv *env, jobject thiz, jbyteArray jresponse) {
sp<IDrm> drm = GetDrm(env, thiz);
if (drm == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"MediaDrm obj is null");
- return;
+ return NULL;
}
if (jresponse == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"provision response is null");
- return;
+ return NULL;
}
Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+ Vector<uint8_t> certificate, wrappedKey;
- status_t err = drm->provideProvisionResponse(response);
+ status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
+
+ // Fill out return obj
+ jclass clazz = gFields.certificateClassId;
+
+ jobject certificateObj = NULL;
+
+ if (clazz && certificate.size() && wrappedKey.size()) {
+ certificateObj = env->AllocObject(clazz);
+ jbyteArray jcertificate = VectorToJByteArray(env, certificate);
+ env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
+
+ jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
+ env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
+ }
throwExceptionAsNecessary(env, err, "Failed to handle provision response");
+ return certificateObj;
}
static jobject android_media_MediaDrm_getSecureStops(
@@ -1209,6 +1266,38 @@
}
+static jbyteArray android_media_MediaDrm_signRSANative(
+ JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+ jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
+
+ sp<IDrm> drm = GetDrm(env, jdrm);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return NULL;
+ }
+
+ if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "required argument is null");
+ return NULL;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+ String8 algorithm = JStringToString8(env, jalgorithm);
+ Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
+ Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
+ Vector<uint8_t> signature;
+
+ status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
+ return NULL;
+ }
+
+ return VectorToJByteArray(env, signature);
+}
+
+
static JNINativeMethod gMethods[] = {
{ "release", "()V", (void *)android_media_MediaDrm_release },
{ "native_init", "()V", (void *)android_media_MediaDrm_native_init },
@@ -1244,11 +1333,11 @@
{ "queryKeyStatus", "([B)Ljava/util/HashMap;",
(void *)android_media_MediaDrm_queryKeyStatus },
- { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
- (void *)android_media_MediaDrm_getProvisionRequest },
+ { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
+ (void *)android_media_MediaDrm_getProvisionRequestNative },
- { "provideProvisionResponse", "([B)V",
- (void *)android_media_MediaDrm_provideProvisionResponse },
+ { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
+ (void *)android_media_MediaDrm_provideProvisionResponseNative },
{ "getSecureStops", "()Ljava/util/List;",
(void *)android_media_MediaDrm_getSecureStops },
@@ -1287,6 +1376,9 @@
{ "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
(void *)android_media_MediaDrm_verifyNative },
+
+ { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
+ (void *)android_media_MediaDrm_signRSANative },
};
int register_android_media_Drm(JNIEnv *env) {
diff --git a/media/lib/Android.mk b/media/lib/remotedisplay/Android.mk
similarity index 93%
rename from media/lib/Android.mk
rename to media/lib/remotedisplay/Android.mk
index 50799a6..ea1ac2b 100644
--- a/media/lib/Android.mk
+++ b/media/lib/remotedisplay/Android.mk
@@ -15,7 +15,7 @@
#
LOCAL_PATH := $(call my-dir)
-# the library
+# the remotedisplay library
# ============================================================
include $(CLEAR_VARS)
@@ -23,7 +23,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
- $(call all-subdir-java-files) \
+ $(call all-java-files-under, java) \
$(call all-aidl-files-under, java)
include $(BUILD_JAVA_LIBRARY)
diff --git a/media/lib/README.txt b/media/lib/remotedisplay/README.txt
similarity index 99%
rename from media/lib/README.txt
rename to media/lib/remotedisplay/README.txt
index cade3df..5738dbe 100644
--- a/media/lib/README.txt
+++ b/media/lib/remotedisplay/README.txt
@@ -25,4 +25,3 @@
library is a compromise to make new capabilities available to the system
without exposing the full surface area of the support library media
route provider protocol.
-
diff --git a/media/lib/com.android.media.remotedisplay.xml b/media/lib/remotedisplay/com.android.media.remotedisplay.xml
similarity index 100%
rename from media/lib/com.android.media.remotedisplay.xml
rename to media/lib/remotedisplay/com.android.media.remotedisplay.xml
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
similarity index 100%
rename from media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
rename to media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
similarity index 100%
rename from media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
rename to media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
diff --git a/media/lib/Android.mk b/media/lib/signer/Android.mk
similarity index 76%
copy from media/lib/Android.mk
copy to media/lib/signer/Android.mk
index 50799a6..4c3772f 100644
--- a/media/lib/Android.mk
+++ b/media/lib/signer/Android.mk
@@ -15,24 +15,23 @@
#
LOCAL_PATH := $(call my-dir)
-# the library
+# the mediadrm signer library
# ============================================================
include $(CLEAR_VARS)
-LOCAL_MODULE:= com.android.media.remotedisplay
+LOCAL_MODULE:= com.android.mediadrm.signer
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
- $(call all-subdir-java-files) \
- $(call all-aidl-files-under, java)
+ $(call all-java-files-under, java)
-include $(BUILD_JAVA_LIBRARY)
+include $(BUILD_STATIC_JAVA_LIBRARY)
-# ==== com.android.media.remotedisplay.xml lib def ========================
+# ==== com.android.mediadrm.signer.xml lib def ========================
include $(CLEAR_VARS)
-LOCAL_MODULE := com.android.media.remotedisplay.xml
+LOCAL_MODULE := com.android.mediadrm.signer.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
diff --git a/media/lib/signer/README.txt b/media/lib/signer/README.txt
new file mode 100644
index 0000000..362ab8e
--- /dev/null
+++ b/media/lib/signer/README.txt
@@ -0,0 +1,28 @@
+This library (com.android.mediadrm.signer.jar) is a shared java library
+containing classes required by unbundled apps running on devices that use
+the certficate provisioning and private key signing capabilities provided
+by the MediaDrm API.
+
+--- Rules of this library ---
+o This library is effectively a PUBLIC API for unbundled CAST receivers
+ that may be distributed outside the system image. So it MUST BE API STABLE.
+ You can add but not remove. The rules are the same as for the
+ public platform SDK API.
+o This library can see and instantiate internal platform classes, but it must not
+ expose them in any public method (or by extending them via inheritance). This would
+ break clients of the library because they cannot see the internal platform classes.
+
+This library is distributed in the system image, and loaded as
+a shared library. So you can change the implementation, but not
+the interface. In this way it is like framework.jar.
+
+--- Why does this library exist? ---
+
+Unbundled apps cannot use internal platform classes.
+
+This library will eventually be replaced when the provisioned certificate-
+based signing infrastructure that is currently defined in the support library
+is reintegrated with the framework in a new API. That API isn't ready yet so
+this library is a compromise to make new capabilities available to the system
+without exposing the full surface area of the support library.
+
diff --git a/media/lib/signer/com.android.mediadrm.signer.xml b/media/lib/signer/com.android.mediadrm.signer.xml
new file mode 100644
index 0000000..b5b1f09
--- /dev/null
+++ b/media/lib/signer/com.android.mediadrm.signer.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<permissions>
+ <library name="com.android.media.drm.signer"
+ file="/system/framework/com.android.media.drm.signer.jar" />
+</permissions>
diff --git a/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java
new file mode 100644
index 0000000..0a2897f
--- /dev/null
+++ b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediadrm.signer;
+
+import android.media.MediaDrm;
+import android.media.DeniedByServerException;
+
+/**
+ * Provides certificate request generation, response handling and
+ * signing APIs
+ */
+public final class MediaDrmSigner {
+ private MediaDrmSigner() {}
+
+ /**
+ * Specify X.509 certificate type
+ */
+ public static final int CERTIFICATE_TYPE_X509 = MediaDrm.CERTIFICATE_TYPE_X509;
+
+ /**
+ * Contains the opaque data an app uses to request a certificate from a provisioning
+ * server
+ */
+ public final static class CertificateRequest {
+ private final MediaDrm.CertificateRequest mCertRequest;
+
+ CertificateRequest(MediaDrm.CertificateRequest certRequest) {
+ mCertRequest = certRequest;
+ }
+
+ /**
+ * Get the opaque message data
+ */
+ public byte[] getData() {
+ return mCertRequest.getData();
+ }
+
+ /**
+ * Get the default URL to use when sending the certificate request
+ * message to a server, if known. The app may prefer to use a different
+ * certificate server URL obtained from other sources.
+ */
+ public String getDefaultUrl() {
+ return mCertRequest.getDefaultUrl();
+ }
+ }
+
+ /**
+ * Contains the wrapped private key and public certificate data associated
+ * with a certificate.
+ */
+ public final static class Certificate {
+ private final MediaDrm.Certificate mCertificate;
+
+ Certificate(MediaDrm.Certificate certificate) {
+ mCertificate = certificate;
+ }
+
+ /**
+ * Get the wrapped private key data
+ */
+ public byte[] getWrappedPrivateKey() {
+ return mCertificate.getWrappedPrivateKey();
+ }
+
+ /**
+ * Get the PEM-encoded public certificate chain
+ */
+ public byte[] getContent() {
+ return mCertificate.getContent();
+ }
+ }
+
+ /**
+ * Generate a certificate request, specifying the certificate type
+ * and authority. The response received should be passed to
+ * provideCertificateResponse.
+ *
+ * @param drm the MediaDrm object
+ * @param certType Specifies the certificate type.
+ * @param certAuthority is passed to the certificate server to specify
+ * the chain of authority.
+ */
+ public static CertificateRequest getCertificateRequest(MediaDrm drm, int certType,
+ String certAuthority) {
+ return new CertificateRequest(drm.getCertificateRequest(certType, certAuthority));
+ }
+
+ /**
+ * Process a response from the provisioning server. The response
+ * is obtained from an HTTP Post to the url provided by getCertificateRequest.
+ *
+ * The public X509 certificate chain and wrapped private key are returned
+ * in the returned Certificate objec. The certificate chain is in BIO serialized
+ * PEM format. The wrapped private key should be stored in application private
+ * storage, and used when invoking the signRSA method.
+ *
+ * @param drm the MediaDrm object
+ * @param response the opaque certificate response byte array to provide to the
+ * DRM engine plugin.
+ * @throws android.media.DeniedByServerException if the response indicates that the
+ * server rejected the request
+ */
+ public static Certificate provideCertificateResponse(MediaDrm drm, byte[] response)
+ throws DeniedByServerException {
+ return new Certificate(drm.provideCertificateResponse(response));
+ }
+
+ /**
+ * Sign data using an RSA key
+ *
+ * @param drm the MediaDrm object
+ * @param sessionId a sessionId obtained from openSession on the MediaDrm object
+ * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
+ * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
+ * from provideCertificateResponse
+ * @param message the data for which a signature is to be computed
+ */
+ public static byte[] signRSA(MediaDrm drm, byte[] sessionId,
+ String algorithm, byte[] wrappedKey, byte[] message) {
+ return drm.signRSA(sessionId, algorithm, wrappedKey, message);
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 43ebef4..5f3ba74 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -140,7 +140,9 @@
private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
int requestId = mCameraUser.submitRequest(request, streaming);
- assertTrue("Request IDs should be non-negative", requestId >= 0);
+ assertTrue(
+ "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
+ requestId >= 0);
return requestId;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 3f17aa9..26498ca 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -309,7 +309,7 @@
});
// rational (n) -- in particular rational x 9
- checkKeyGetAndSetArray("android.sensor.calibrationTransform1", Rational[].class,
+ checkKeyGetAndSetArray("android.sensor.calibrationTransform", Rational[].class,
new Rational[] {
new Rational(1, 2), new Rational(3, 4), new Rational(5, 6),
new Rational(7, 8), new Rational(9, 10), new Rational(10, 11),
diff --git a/packages/BackupRestoreConfirmation/AndroidManifest.xml b/packages/BackupRestoreConfirmation/AndroidManifest.xml
index 4fb26ae..8141fa7 100644
--- a/packages/BackupRestoreConfirmation/AndroidManifest.xml
+++ b/packages/BackupRestoreConfirmation/AndroidManifest.xml
@@ -1,20 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-** Copyright 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.
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
-->
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.backupconfirm" >
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 179bcd1..6b77a7c 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -42,7 +42,7 @@
<activity
android:name=".SettingsActivity"
android:label="@string/menu_settings"
- android:theme="@android:style/Theme.Holo.Light.DialogWhenLarge"
+ android:theme="@android:style/Theme.DeviceDefault.Light.DialogWhenLarge"
android:exported="false" />
<provider
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
index 19d2ebe..8d31444 100644
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/styles.xml
@@ -15,11 +15,11 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="Theme" parent="@android:style/Theme.Holo.Light">
+ <style name="Theme" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionOverflowButtonStyle">@style/DarkerOverflow</item>
<item name="android:windowBackground">@*android:drawable/dialog_full_holo_light</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
- <item name="android:windowAnimationStyle">@*android:style/Animation.Holo.Dialog</item>
+ <item name="android:windowAnimationStyle">@*android:style/Animation.DeviceDefault.Dialog</item>
</style>
</resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 0c8f712..a416eb4 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -29,11 +29,11 @@
<!-- Normally just a redirection, but this is used to make ourselves a
dialog on large tablets -->
- <style name="Theme" parent="@android:style/Theme.Holo.Light">
+ <style name="Theme" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionOverflowButtonStyle">@style/DarkerOverflow</item>
</style>
- <style name="DarkerOverflow" parent="@android:style/Widget.Holo.Light.ActionButton.Overflow">
+ <style name="DarkerOverflow" parent="@android:style/Widget.DeviceDefault.Light.ActionButton.Overflow">
<item name="android:src">@drawable/ic_menu_overflow</item>
</style>
diff --git a/packages/Keyguard/res/values/styles.xml b/packages/Keyguard/res/values/styles.xml
index d4f98af..80fcf75 100644
--- a/packages/Keyguard/res/values/styles.xml
+++ b/packages/Keyguard/res/values/styles.xml
@@ -68,7 +68,7 @@
<item name="android:textSize">@dimen/widget_big_font_size</item>
</style>
- <style name="Widget.TransportControl.SeekBar" parent="@android:style/Widget.Holo.SeekBar">
+ <style name="Widget.TransportControl.SeekBar" parent="@android:style/Widget.DeviceDefault.Light.SeekBar">
<item name="android:indeterminateOnly">false</item>
<item name="android:progressDrawable">@drawable/scrubber_progress_horizontal_holo_light</item>
<item name="android:indeterminateDrawable">@drawable/scrubber_progress_horizontal_holo_light</item>
diff --git a/packages/Keyguard/test/AndroidManifest.xml b/packages/Keyguard/test/AndroidManifest.xml
index b801e4b..1638127 100644
--- a/packages/Keyguard/test/AndroidManifest.xml
+++ b/packages/Keyguard/test/AndroidManifest.xml
@@ -23,7 +23,7 @@
<application android:label="@string/app_name" android:icon="@drawable/app_icon">
<activity android:name=".KeyguardTestActivity"
android:label="@string/app_name"
- android:theme="@android:style/Theme.Holo">
+ android:theme="@android:style/Theme.DeviceDefault.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/packages/PrintSpooler/res/layout/select_printer_activity.xml b/packages/PrintSpooler/res/layout/select_printer_activity.xml
index 6fc77df..4488b6a 100644
--- a/packages/PrintSpooler/res/layout/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/layout/select_printer_activity.xml
@@ -61,7 +61,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
- style="@android:style/Widget.Holo.ProgressBar.Horizontal">
+ style="@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal">
</ProgressBar>
</LinearLayout>
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index 86f4a37..94ab895 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -16,7 +16,7 @@
<resources>
- <style name="PrintJobConfigActivityTheme" parent="@android:style/Theme.Holo.Light.NoActionBar">
+ <style name="PrintJobConfigActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowSoftInputMode">stateAlwaysHidden|adjustResize</item>
<item name="android:windowIsTranslucent">true</item>
@@ -25,11 +25,11 @@
<item name="android:windowIsFloating">true</item>
</style>
- <style name="SelectPrinterActivityTheme" parent="@android:style/Theme.Holo.Light">
+ <style name="SelectPrinterActivityTheme" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionBarStyle">@style/SelectPrinterActivityActionBarStyle</item>
</style>
- <style name="SelectPrinterActivityActionBarStyle" parent="@android:style/Widget.Holo.ActionBar">
+ <style name="SelectPrinterActivityActionBarStyle" parent="@android:style/Widget.DeviceDefault.Light.ActionBar">
<item name="android:displayOptions">showTitle</item>
</style>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 29e8d1d..19286c8 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -1,3 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.shell"
coreApp="true"
@@ -83,7 +101,7 @@
<activity
android:name=".BugreportWarningActivity"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:exported="false" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index b09cc1d..3424eed 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -1,3 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.systemui"
@@ -157,7 +175,7 @@
<activity android:name=".usb.UsbConfirmActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -166,7 +184,7 @@
<activity android:name=".usb.UsbPermissionActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -175,7 +193,7 @@
<activity android:name=".usb.UsbResolverActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -184,7 +202,7 @@
<activity android:name=".usb.UsbAccessoryUriActivity"
android:exported="true"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -192,7 +210,7 @@
<!-- started from UsbDebuggingManager -->
<activity android:name=".usb.UsbDebuggingActivity"
android:permission="android.permission.MANAGE_USB"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true">
</activity>
@@ -202,7 +220,7 @@
android:name=".net.NetworkOverLimitActivity"
android:exported="true"
android:permission="android.permission.MANAGE_NETWORK_POLICY"
- android:theme="@android:style/Theme.Holo.Panel"
+ android:theme="@android:style/Theme.DeviceDefault.Light.Panel"
android:finishOnCloseSystemDialogs="true"
android:launchMode="singleTop"
android:taskAffinity="com.android.systemui.net"
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f6e875c..96da21f 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -26,23 +26,31 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
- android:background="#88000000">
+ android:background="#e6444444">
<ImageView
- android:id="@+id/activity_icon"
- android:layout_width="@dimen/recents_task_view_icon_size"
- android:layout_height="@dimen/recents_task_view_icon_size"
- android:layout_gravity="top|left"
+ android:id="@+id/application_icon"
+ android:layout_width="@dimen/recents_task_view_application_icon_size"
+ android:layout_height="@dimen/recents_task_view_application_icon_size"
+ android:layout_gravity="center_vertical|left"
android:padding="8dp" />
<TextView
android:id="@+id/activity_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|left"
- android:layout_marginLeft="@dimen/recents_task_view_icon_size"
+ android:layout_marginLeft="@dimen/recents_task_view_application_icon_size"
+ android:layout_marginRight="@dimen/recents_task_view_activity_icon_size"
android:textSize="24sp"
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
android:fontFamily="sans-serif-thin" />
+ <ImageView
+ android:id="@+id/activity_icon"
+ android:layout_width="@dimen/recents_task_view_activity_icon_size"
+ android:layout_height="@dimen/recents_task_view_activity_icon_size"
+ android:layout_gravity="center_vertical|right"
+ android:padding="12dp"
+ android:visibility="invisible" />
</com.android.systemui.recents.views.TaskBarView>
</com.android.systemui.recents.views.TaskView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1da66bb..a7ec064 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -24,19 +24,10 @@
android:id="@+id/notification_panel"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:background="@drawable/notification_panel_bg"
android:paddingTop="@dimen/notification_panel_padding_top"
android:layout_marginStart="@dimen/notification_panel_margin_left"
>
- <View
- android:id="@+id/handle"
- android:layout_width="match_parent"
- android:layout_height="@dimen/close_handle_height"
- android:background="@drawable/status_bar_close"
- android:visibility="invisible"
- />
-
<include
layout="@layout/carrier_label"
android:layout_height="@dimen/carrier_label_height"
@@ -69,6 +60,7 @@
/>
<FrameLayout
+ android:id="@+id/notification_container_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
@@ -77,21 +69,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
-
- <ScrollView
- android:id="@+id/scroll"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:fadingEdge="none"
- android:overScrollMode="ifContentScrolls"
- >
- <com.android.systemui.statusbar.policy.NotificationRowLayout
- android:id="@+id/latestItems"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- systemui:rowHeight="@dimen/notification_row_min_height"
- />
- </ScrollView>
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a9b6985..1c6d5ad 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -230,8 +230,11 @@
<!-- Default distance from each snap target that GlowPadView considers a "hit" -->
<dimen name="glowpadview_inner_radius">15dip</dimen>
- <!-- The size of the icon in the recents task view. -->
- <dimen name="recents_task_view_icon_size">60dp</dimen>
+ <!-- The size of the application icon in the recents task view. -->
+ <dimen name="recents_task_view_application_icon_size">60dp</dimen>
+
+ <!-- The size of the activity icon in the recents task view. -->
+ <dimen name="recents_task_view_activity_icon_size">60dp</dimen>
<!-- Space below the notification stack -->
<dimen name="notification_stack_margin_bottom">0dp</dimen>
@@ -248,6 +251,6 @@
<!-- Z distance between notifications if they are in the stack -->
<dimen name="z_distance_between_notifications">2dp</dimen>
- <!-- Width of the zen mode interstitial dialog. Defaults to MATCH_PARENT. -->
- <dimen name="zen_mode_dialog_width">-1px</dimen>
+ <!-- Width of the zen mode interstitial dialog. -->
+ <dimen name="zen_mode_dialog_width">320dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 14af020..76cadd7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,12 +16,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="RecentsStyle" parent="@android:style/Theme.Holo.Wallpaper.NoTitleBar">
+ <style name="RecentsStyle" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
<item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
</style>
<!-- Alternate Recents theme -->
- <style name="RecentsTheme" parent="@android:style/Theme.Holo.Wallpaper.NoTitleBar">
+ <style name="RecentsTheme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 90b0c49..1832d37 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -34,6 +34,8 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import com.android.systemui.statusbar.policy.ScrollAdapter;
+
public class ExpandHelper implements Gefingerpoken, OnClickListener {
public interface Callback {
View getChildAtRawPosition(float x, float y);
@@ -609,19 +611,5 @@
}
mVibrator.vibrate(duration, AudioManager.STREAM_SYSTEM);
}
-
- public interface ScrollAdapter {
-
- /**
- * @return Whether the view returned by {@link #getHostView()} is scrolled to the top
- * and can therefore be expanded by a single finger drag
- */
- public boolean isScrolledToTop();
-
- /**
- * @return The view in which the scrolling is performed
- */
- public View getHostView();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 9d2d6ee..ab2ad96 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -368,7 +368,7 @@
final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(1,
- ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_RELATED,
+ ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES,
UserHandle.CURRENT.getIdentifier());
TaskDescription item = null;
if (recentTasks.size() > 0) {
@@ -441,7 +441,7 @@
final List<ActivityManager.RecentTaskInfo> recentTasks =
am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
- | ActivityManager.RECENT_INCLUDE_RELATED);
+ | ActivityManager.RECENT_INCLUDE_PROFILES);
int numTasks = recentTasks.size();
ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index f75ea92..7ab40b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -165,7 +165,7 @@
am.getRecentTasks(2,
ActivityManager.RECENT_WITH_EXCLUDED |
ActivityManager.RECENT_IGNORE_UNAVAILABLE |
- ActivityManager.RECENT_INCLUDE_RELATED);
+ ActivityManager.RECENT_INCLUDE_PROFILES);
if (recentTasks.size() > 1 &&
mRecentsPanel.simulateClick(recentTasks.get(1).persistentId)) {
// recents panel will take care of calling show(false) through simulateClick
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 1a616a0..8543b97 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -23,35 +23,26 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
-import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
import com.android.systemui.R;
-import com.android.systemui.RecentsComponent;
-import com.android.systemui.SystemUI;
import java.util.List;
@@ -113,6 +104,7 @@
final static String sRecentsService = "com.android.systemui.recents.RecentsService";
Context mContext;
+ SystemServicesProxy mSystemServicesProxy;
// Recents service binding
Messenger mService = null;
@@ -127,6 +119,7 @@
public AlternateRecentsComponent(Context context) {
mContext = context;
+ mSystemServicesProxy = new SystemServicesProxy(context);
mMessenger = new Messenger(new RecentsMessageHandler());
}
@@ -219,17 +212,16 @@
/** Loads the first task thumbnail */
Bitmap loadFirstTaskThumbnail() {
- ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1,
- ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_RELATED,
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
UserHandle.CURRENT.getIdentifier());
for (ActivityManager.RecentTaskInfo t : tasks) {
// Skip tasks in the home stack
- if (am.isInHomeStack(t.persistentId)) {
+ if (ssp.isInHomeStack(t.persistentId)) {
return null;
}
- Bitmap thumbnail = am.getTaskTopThumbnail(t.persistentId);
+ Bitmap thumbnail = ssp.getTaskThumbnail(t.persistentId);
return thumbnail;
}
return null;
@@ -237,13 +229,12 @@
/** Returns whether there is a first task */
boolean hasFirstTask() {
- ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(1,
- ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_RELATED,
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
UserHandle.CURRENT.getIdentifier());
for (ActivityManager.RecentTaskInfo t : tasks) {
// Skip tasks in the home stack
- if (am.isInHomeStack(t.persistentId)) {
+ if (ssp.isInHomeStack(t.persistentId)) {
continue;
}
@@ -294,8 +285,8 @@
// If Recents is the front most activity, then we should just communicate with it directly
// to launch the first task or dismiss itself
- ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index b5950e9..8c5c8fa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -26,11 +26,17 @@
public static final boolean Verbose = false;
public static class App {
- public static final boolean EnableTaskFiltering = false;
+ public static final boolean EnableTaskFiltering = true;
public static final boolean EnableTaskStackClipping = false;
public static final boolean EnableToggleNewRecentsActivity = false;
// This disables the bitmap and icon caches to
public static final boolean DisableBackgroundCache = false;
+ // For debugging, this enables us to create mock recents tasks
+ public static final boolean EnableSystemServicesProxy = false;
+ // For debugging, this defines the number of mock recents packages to create
+ public static final int SystemServicesProxyMockPackageCount = 12;
+ // For debugging, this defines the number of mock recents tasks to create
+ public static final int SystemServicesProxyMockTaskCount = 75;
// Timing certain paths
public static final String TimeRecentsStartupKey = "startup";
@@ -73,14 +79,16 @@
public static class RecentsTaskLoader {
// XXX: This should be calculated on the first load
public static final int PreloadFirstTasksCount = 5;
- // For debugging, this allows us to multiply the number of cards for each task
- public static final int TaskEntryMultiplier = 1;
}
public static class TaskStackView {
public static class Animation {
public static final int TaskRemovedReshuffleDuration = 200;
public static final int SnapScrollBackDuration = 650;
+ public static final int FilteredCurrentViewsDuration = 150;
+ public static final int FilteredNewViewsDuration = 200;
+ public static final int UnfilteredCurrentViewsDuration = 150;
+ public static final int UnfilteredNewViewsDuration = 200;
}
public static final int TaskStackOverscrollRange = 150;
@@ -107,7 +115,7 @@
public static final boolean AnimateFrontTaskIconOnEnterRecents = true;
public static final boolean AnimateFrontTaskIconOnLeavingRecents = true;
- public static final boolean UseRoundedCorners = true;
+ public static final boolean UseRoundedCorners = false;
public static final float RoundedCornerRadiusDps = 3;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b65b864..dd75921 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -54,8 +54,11 @@
finish();
}
} else if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
- // Dismiss recents and launch the first task if possible
- dismissRecentsIfVisible();
+ // Try and unfilter and filtered stacks
+ if (!mRecentsView.unfilterFilteredStacks()) {
+ // If there are no filtered stacks, dismiss recents and launch the first task
+ dismissRecentsIfVisible();
+ }
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 515cec1..22363bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -66,7 +66,7 @@
// in a bottom inset
tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top, 0);
tsv.boundScroll();
- TaskViewTransform transform = tsv.getStackTransform(0);
+ TaskViewTransform transform = tsv.getStackTransform(0, tsv.getStackScroll());
Rect taskRect = new Rect(transform.rect);
data.putParcelable("taskRect", taskRect);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index b497b69..e193a95 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -20,7 +20,6 @@
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -109,18 +108,20 @@
Handler mLoadThreadHandler;
Handler mMainThreadHandler;
+ SystemServicesProxy mSystemServicesProxy;
TaskResourceLoadQueue mLoadQueue;
- DrawableLruCache mIconCache;
+ DrawableLruCache mApplicationIconCache;
BitmapLruCache mThumbnailCache;
boolean mCancelled;
boolean mWaitingOnLoadQueue;
/** Constructor, creates a new loading thread that loads task resources in the background */
- public TaskResourceLoader(TaskResourceLoadQueue loadQueue, DrawableLruCache iconCache,
+ public TaskResourceLoader(TaskResourceLoadQueue loadQueue,
+ DrawableLruCache applicationIconCache,
BitmapLruCache thumbnailCache) {
mLoadQueue = loadQueue;
- mIconCache = iconCache;
+ mApplicationIconCache = applicationIconCache;
mThumbnailCache = thumbnailCache;
mMainThreadHandler = new Handler();
mLoadThread = new HandlerThread("Recents-TaskResourceLoader");
@@ -135,6 +136,7 @@
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|start]");
mContext = context;
mCancelled = false;
+ mSystemServicesProxy = new SystemServicesProxy(context);
// Notify the load thread to start loading
synchronized(mLoadThread) {
mLoadThread.notifyAll();
@@ -146,6 +148,7 @@
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]");
// Mark as cancelled for the thread to pick up
mCancelled = true;
+ mSystemServicesProxy = null;
// If we are waiting for the load queue for more tasks, then we can just reset the
// Context now, since nothing is using it
if (mWaitingOnLoadQueue) {
@@ -175,66 +178,60 @@
}
}
} else {
+ SystemServicesProxy ssp = mSystemServicesProxy;
+
// Load the next item from the queue
Pair<Task, Boolean> nextTaskData = mLoadQueue.nextTask();
final Task t = nextTaskData.first;
final boolean forceLoadTask = nextTaskData.second;
if (t != null) {
- try {
- Drawable loadIcon = mIconCache.get(t.key);
- Bitmap loadThumbnail = mThumbnailCache.get(t.key);
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [TaskResourceLoader|load]",
- t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
- " forceLoad: " + forceLoadTask);
- // Load the icon
- if (loadIcon == null || forceLoadTask) {
- PackageManager pm = mContext.getPackageManager();
- ActivityInfo info = pm.getActivityInfo(t.key.intent.getComponent(),
- PackageManager.GET_META_DATA);
- Drawable icon = info.loadIcon(pm);
- if (!mCancelled) {
- if (icon != null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [TaskResourceLoader|loadIcon]",
- icon);
- loadIcon = icon;
- mIconCache.put(t.key, icon);
- }
- }
- }
- // Load the thumbnail
- if (loadThumbnail == null || forceLoadTask) {
- ActivityManager am = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
- Bitmap thumbnail = am.getTaskTopThumbnail(t.key.id);
- if (!mCancelled) {
- if (thumbnail != null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [TaskResourceLoader|loadThumbnail]",
- thumbnail);
- loadThumbnail = thumbnail;
- mThumbnailCache.put(t.key, thumbnail);
- } else {
- Console.logError(mContext,
- "Failed to load task top thumbnail for: " +
- t.key.intent.getComponent().getPackageName());
- }
- }
- }
+ Drawable loadIcon = mApplicationIconCache.get(t.key);
+ Bitmap loadThumbnail = mThumbnailCache.get(t.key);
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [TaskResourceLoader|load]",
+ t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
+ " forceLoad: " + forceLoadTask);
+ // Load the application icon
+ if (loadIcon == null || forceLoadTask) {
+ ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent());
+ Drawable icon = ssp.getActivityIcon(info);
if (!mCancelled) {
- // Notify that the task data has changed
- final Drawable newIcon = loadIcon;
- final Bitmap newThumbnail = loadThumbnail;
- mMainThreadHandler.post(new Runnable() {
- @Override
- public void run() {
- t.notifyTaskDataLoaded(newThumbnail, newIcon, forceLoadTask);
- }
- });
+ if (icon != null) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [TaskResourceLoader|loadIcon]",
+ icon);
+ loadIcon = icon;
+ mApplicationIconCache.put(t.key, icon);
+ }
}
- } catch (PackageManager.NameNotFoundException ne) {
- ne.printStackTrace();
+ }
+ // Load the thumbnail
+ if (loadThumbnail == null || forceLoadTask) {
+ Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id);
+ if (!mCancelled) {
+ if (thumbnail != null) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [TaskResourceLoader|loadThumbnail]",
+ thumbnail);
+ loadThumbnail = thumbnail;
+ mThumbnailCache.put(t.key, thumbnail);
+ } else {
+ Console.logError(mContext,
+ "Failed to load task top thumbnail for: " +
+ t.key.baseIntent.getComponent().getPackageName());
+ }
+ }
+ }
+ if (!mCancelled) {
+ // Notify that the task data has changed
+ final Drawable newIcon = loadIcon;
+ final Bitmap newThumbnail = loadThumbnail;
+ mMainThreadHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ t.notifyTaskDataLoaded(newThumbnail, newIcon, forceLoadTask);
+ }
+ });
}
}
@@ -296,7 +293,8 @@
public class RecentsTaskLoader {
static RecentsTaskLoader sInstance;
- DrawableLruCache mIconCache;
+ SystemServicesProxy mSystemServicesProxy;
+ DrawableLruCache mApplicationIconCache;
BitmapLruCache mThumbnailCache;
TaskResourceLoadQueue mLoadQueue;
TaskResourceLoader mLoader;
@@ -304,7 +302,7 @@
int mMaxThumbnailCacheSize;
int mMaxIconCacheSize;
- BitmapDrawable mDefaultIcon;
+ BitmapDrawable mDefaultApplicationIcon;
Bitmap mDefaultThumbnail;
/** Private Constructor */
@@ -324,11 +322,12 @@
"[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
" iconCache: " + iconCacheSize);
- // Initialize the cache and loaders
+ // Initialize the proxy, cache and loaders
+ mSystemServicesProxy = new SystemServicesProxy(context);
mLoadQueue = new TaskResourceLoadQueue();
- mIconCache = new DrawableLruCache(iconCacheSize);
+ mApplicationIconCache = new DrawableLruCache(iconCacheSize);
mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
- mLoader = new TaskResourceLoader(mLoadQueue, mIconCache, mThumbnailCache);
+ mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache);
// Create the default assets
Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
@@ -339,10 +338,10 @@
c.setBitmap(mDefaultThumbnail);
c.drawColor(0x00000000);
c.setBitmap(null);
- mDefaultIcon = new BitmapDrawable(context.getResources(), icon);
+ mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
Console.log(Constants.DebugFlags.App.TaskDataLoader,
"[RecentsTaskLoader|defaultBitmaps]",
- "icon: " + mDefaultIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
+ "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
}
/** Initializes the recents task loader */
@@ -358,6 +357,11 @@
return sInstance;
}
+ /** Returns the system services proxy */
+ public SystemServicesProxy getSystemServicesProxy() {
+ return mSystemServicesProxy;
+ }
+
/** Reload the set of recent tasks */
SpaceNode reload(Context context, int preloadCount) {
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
@@ -367,142 +371,119 @@
SpaceNode root = new SpaceNode(context);
root.setStack(stack);
- try {
- long t1 = System.currentTimeMillis();
+ long t1 = System.currentTimeMillis();
- PackageManager pm = context.getPackageManager();
- ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ // Get the recent tasks
+ SystemServicesProxy ssp = mSystemServicesProxy;
+ List<ActivityManager.RecentTaskInfo> tasks =
+ ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
+ Collections.reverse(tasks);
+ Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+ "[RecentsTaskLoader|getRecentTasks]",
+ "" + (System.currentTimeMillis() - t1) + "ms");
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ "[RecentsTaskLoader|tasks]", "" + tasks.size());
- // Get the recent tasks
- List<ActivityManager.RecentTaskInfo> tasks = am.getRecentTasksForUser(25,
- ActivityManager.RECENT_IGNORE_UNAVAILABLE |
- ActivityManager.RECENT_INCLUDE_RELATED, UserHandle.CURRENT.getIdentifier());
- Collections.reverse(tasks);
- Console.log(Constants.DebugFlags.App.TimeSystemCalls,
- "[RecentsTaskLoader|getRecentTasks]",
- "" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- "[RecentsTaskLoader|tasks]", "" + tasks.size());
+ // Remove home/recents tasks
+ Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
+ while (iter.hasNext()) {
+ ActivityManager.RecentTaskInfo t = iter.next();
- // Remove home/recents tasks
- Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
- while (iter.hasNext()) {
- ActivityManager.RecentTaskInfo t = iter.next();
-
- // Skip tasks in the home stack
- if (am.isInHomeStack(t.persistentId)) {
- iter.remove();
- continue;
- }
- // Skip tasks from this Recents package
- if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) {
- iter.remove();
- continue;
- }
+ // Skip tasks in the home stack
+ if (ssp.isInHomeStack(t.persistentId)) {
+ iter.remove();
+ continue;
}
-
- // Add each task to the task stack
- t1 = System.currentTimeMillis();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- ActivityManager.RecentTaskInfo t = tasks.get(i);
- ActivityInfo info = pm.getActivityInfo(t.baseIntent.getComponent(),
- PackageManager.GET_META_DATA);
- String title = info.loadLabel(pm).toString();
- boolean isForemostTask = (i == (taskCount - 1));
-
- // Preload the specified number of apps
- if (i >= (taskCount - preloadCount)) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- "[RecentsTaskLoader|preloadTask]",
- "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
-
- String label = (t.activityLabel == null ? title : t.activityLabel.toString());
- BitmapDrawable bd = null;
- if (t.activityIcon != null) {
- bd = new BitmapDrawable(res, t.activityIcon);
- }
- Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, label, bd);
-
- // Load the icon (if possible and not the foremost task, from the cache)
- if (task.icon != null) {
- mIconCache.put(task.key, task.icon);
- } else {
- if (!isForemostTask) {
- task.icon = mIconCache.get(task.key);
- if (task.icon != null) {
- // Even though we get things from the cache, we should update them
- // if they've changed in the bg
- tasksToForceLoad.add(task);
- }
- }
- if (task.icon == null) {
- task.icon = info.loadIcon(pm);
- if (task.icon != null) {
- mIconCache.put(task.key, task.icon);
- } else {
- task.icon = mDefaultIcon;
- }
- }
- }
-
- // Load the thumbnail (if possible and not the foremost task, from the cache)
- if (!isForemostTask) {
- task.thumbnail = mThumbnailCache.get(task.key);
- if (task.thumbnail != null) {
- // Even though we get things from the cache, we should update them if
- // they've changed in the bg
- tasksToForceLoad.add(task);
- }
- }
- if (task.thumbnail == null) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- "[RecentsTaskLoader|loadingTaskThumbnail]");
- task.thumbnail = am.getTaskTopThumbnail(t.id);
- if (task.thumbnail != null) {
- mThumbnailCache.put(task.key, task.thumbnail);
- } else {
- task.thumbnail = mDefaultThumbnail;
- }
- }
-
- // Create as many tasks a we want to multiply by
- for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
- stack.addTask(task);
- }
- } else {
- // Create as many tasks a we want to multiply by
- for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader,
- " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
- stack.addTask(new Task(t.persistentId, (t.id > -1), t.baseIntent, title,
- null, null));
- }
- }
+ // Skip tasks from this Recents package
+ if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) {
+ iter.remove();
+ continue;
}
- Console.log(Constants.DebugFlags.App.TimeSystemCalls,
- "[RecentsTaskLoader|getAllTaskTopThumbnail]",
- "" + (System.currentTimeMillis() - t1) + "ms");
-
- /*
- // Get all the stacks
- t1 = System.currentTimeMillis();
- List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
- Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
- Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
- for (ActivityManager.StackInfo s : stackInfos) {
- Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
- if (stacks.containsKey(s.stackId)) {
- stacks.get(s.stackId).setRect(s.bounds);
- }
- }
- */
- } catch (Exception e) {
- e.printStackTrace();
}
+ // Add each task to the task stack
+ t1 = System.currentTimeMillis();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ ActivityManager.RecentTaskInfo t = tasks.get(i);
+ ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent());
+ String activityLabel = (t.activityLabel == null ? ssp.getActivityLabel(info) :
+ t.activityLabel.toString());
+ Bitmap activityIcon = t.activityIcon;
+ boolean isForemostTask = (i == (taskCount - 1));
+
+ // Create a new task
+ Task task = new Task(t.persistentId, (t.id > -1), t.baseIntent, activityLabel,
+ activityIcon);
+
+ // Preload the specified number of apps
+ if (i >= (taskCount - preloadCount)) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ "[RecentsTaskLoader|preloadTask]",
+ "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
+
+ // Load the icon (if possible and not the foremost task, from the cache)
+ if (!isForemostTask) {
+ task.applicationIcon = mApplicationIconCache.get(task.key);
+ if (task.applicationIcon != null) {
+ // Even though we get things from the cache, we should update them
+ // if they've changed in the bg
+ tasksToForceLoad.add(task);
+ }
+ }
+ if (task.applicationIcon == null) {
+ task.applicationIcon = ssp.getActivityIcon(info);
+ if (task.applicationIcon != null) {
+ mApplicationIconCache.put(task.key, task.applicationIcon);
+ } else {
+ task.applicationIcon = mDefaultApplicationIcon;
+ }
+ }
+
+ // Load the thumbnail (if possible and not the foremost task, from the cache)
+ if (!isForemostTask) {
+ task.thumbnail = mThumbnailCache.get(task.key);
+ if (task.thumbnail != null) {
+ // Even though we get things from the cache, we should update them if
+ // they've changed in the bg
+ tasksToForceLoad.add(task);
+ }
+ }
+ if (task.thumbnail == null) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ "[RecentsTaskLoader|loadingTaskThumbnail]");
+ task.thumbnail = ssp.getTaskThumbnail(task.key.id);
+ if (task.thumbnail != null) {
+ mThumbnailCache.put(task.key, task.thumbnail);
+ } else {
+ task.thumbnail = mDefaultThumbnail;
+ }
+ }
+ }
+
+ // Add the task to the stack
+ Console.log(Constants.DebugFlags.App.TaskDataLoader,
+ " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
+ stack.addTask(task);
+ }
+ Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+ "[RecentsTaskLoader|getAllTaskTopThumbnail]",
+ "" + (System.currentTimeMillis() - t1) + "ms");
+
+ /*
+ // Get all the stacks
+ t1 = System.currentTimeMillis();
+ List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
+ Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
+ Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
+ for (ActivityManager.StackInfo s : stackInfos) {
+ Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString());
+ if (stacks.containsKey(s.stackId)) {
+ stacks.get(s.stackId).setRect(s.bounds);
+ }
+ }
+ */
+
// Start the task loader
mLoader.start(context);
@@ -516,16 +497,16 @@
/** Acquires the task resource data from the pool. */
public void loadTaskData(Task t) {
- Drawable icon = mIconCache.get(t.key);
+ Drawable applicationIcon = mApplicationIconCache.get(t.key);
Bitmap thumbnail = mThumbnailCache.get(t.key);
Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
- t + " icon: " + icon + " thumbnail: " + thumbnail +
+ t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
" thumbnailCacheSize: " + mThumbnailCache.size());
boolean requiresLoad = false;
- if (icon == null) {
- icon = mDefaultIcon;
+ if (applicationIcon == null) {
+ applicationIcon = mDefaultApplicationIcon;
requiresLoad = true;
}
if (thumbnail == null) {
@@ -535,7 +516,7 @@
if (requiresLoad) {
mLoadQueue.addTask(t, false);
}
- t.notifyTaskDataLoaded(thumbnail, icon, false);
+ t.notifyTaskDataLoaded(thumbnail, applicationIcon, false);
}
/** Releases the task resource data back into the pool. */
@@ -545,7 +526,7 @@
" thumbnailCacheSize: " + mThumbnailCache.size());
mLoadQueue.removeTask(t);
- t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultIcon);
+ t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
}
/** Completely removes the resource data from the pool. */
@@ -555,8 +536,8 @@
mLoadQueue.removeTask(t);
mThumbnailCache.remove(t.key);
- mIconCache.remove(t.key);
- t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultIcon);
+ mApplicationIconCache.remove(t.key);
+ t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
}
/** Stops the task loader and clears all pending tasks */
@@ -579,19 +560,19 @@
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
// We are leaving recents, so trim the data a bit
mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 2);
- mIconCache.trimToSize(mMaxIconCacheSize / 2);
+ mApplicationIconCache.trimToSize(mMaxIconCacheSize / 2);
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
// We are going to be low on memory
mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 4);
- mIconCache.trimToSize(mMaxIconCacheSize / 4);
+ mApplicationIconCache.trimToSize(mMaxIconCacheSize / 4);
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
// We are low on memory, so release everything
mThumbnailCache.evictAll();
- mIconCache.evictAll();
+ mApplicationIconCache.evictAll();
break;
default:
break;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
new file mode 100644
index 0000000..f147fbc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Acts as a shim around the real system services that we need to access data from, and provides
+ * a point of injection when testing UI.
+ */
+public class SystemServicesProxy {
+ ActivityManager mAm;
+ PackageManager mPm;
+ String mPackage;
+
+ Bitmap mDummyIcon;
+
+ /** Private constructor */
+ public SystemServicesProxy(Context context) {
+ mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mPm = context.getPackageManager();
+ mPackage = context.getPackageName();
+
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ // Create a dummy icon
+ mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+ Canvas c = new Canvas(mDummyIcon);
+ c.drawColor(0xFFFF0000);
+ c.setBitmap(null);
+ }
+ }
+
+ /** Returns a list of the recents tasks */
+ public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+ if (mAm == null) return null;
+
+ // If we are mocking, then create some recent tasks
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ ArrayList<ActivityManager.RecentTaskInfo> tasks =
+ new ArrayList<ActivityManager.RecentTaskInfo>();
+ int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
+ for (int i = 0; i < count; i++) {
+ // Create a dummy component name
+ int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
+ ComponentName cn = new ComponentName("com.android.test" + packageIndex,
+ "com.android.test" + i + ".Activity");
+ // Create the recent task info
+ ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
+ rti.id = rti.persistentId = i;
+ rti.baseIntent = new Intent();
+ rti.baseIntent.setComponent(cn);
+ rti.description = rti.activityLabel =
+ Long.toString(Math.abs(new Random().nextLong()), 36);
+ if (i % 2 == 0) {
+ rti.activityIcon = Bitmap.createBitmap(mDummyIcon);
+ }
+ tasks.add(rti);
+ }
+ return tasks;
+ }
+
+ return mAm.getRecentTasksForUser(numTasks,
+ ActivityManager.RECENT_IGNORE_UNAVAILABLE |
+ ActivityManager.RECENT_INCLUDE_PROFILES, userId);
+ }
+
+ /** Returns a list of the running tasks */
+ public List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
+ if (mAm == null) return null;
+ return mAm.getRunningTasks(numTasks);
+ }
+
+ /** Returns whether the specified task is in the home stack */
+ public boolean isInHomeStack(int taskId) {
+ if (mAm == null) return false;
+
+ // If we are mocking, then just return false
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ return false;
+ }
+
+ return mAm.isInHomeStack(taskId);
+ }
+
+ /** Returns the top task thumbnail for the given task id */
+ public Bitmap getTaskThumbnail(int taskId) {
+ if (mAm == null) return null;
+
+ // If we are mocking, then just return a dummy thumbnail
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(thumbnail);
+ c.drawColor(0xFF00ff00);
+ c.setBitmap(null);
+ return thumbnail;
+ }
+
+ return mAm.getTaskTopThumbnail(taskId);
+ }
+
+ /** Moves a task to the front with the specified activity options */
+ public void moveTaskToFront(int taskId, ActivityOptions opts) {
+ if (mAm == null) return;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
+
+ if (opts != null) {
+ mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME,
+ opts.toBundle());
+ } else {
+ mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME);
+ }
+ }
+
+ /** Removes the task and kills the process */
+ public void removeTask(int taskId) {
+ if (mAm == null) return;
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
+
+ mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ }
+
+ /** Returns the activity info for a given component name */
+ 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;
+
+ // If we are mocking, then return a mock label
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ return "Recent Task";
+ }
+
+ return info.loadLabel(mPm).toString();
+ }
+
+ /** Returns the activity icon */
+ public Drawable getActivityIcon(ActivityInfo info) {
+ if (mPm == null) return null;
+
+ // If we are mocking, then return a mock label
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ return new ColorDrawable(0xFFff0000);
+ }
+
+ return info.loadIcon(mPm);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index 33e4246..9048cba 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -20,9 +20,6 @@
/* Common code */
public class Utilities {
- public static final Rect tmpRect = new Rect();
- public static final Rect tmpRect2 = new Rect();
-
/** Scales a rect about its centroid */
public static void scaleRectAboutCenter(Rect r, float scale) {
if (scale != 1.0f) {
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 cda4ab2..ed2ab2a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -19,7 +19,6 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import com.android.systemui.recents.Constants;
/**
@@ -37,11 +36,11 @@
/* The Task Key represents the unique primary key for the task */
public static class TaskKey {
public final int id;
- public final Intent intent;
+ public final Intent baseIntent;
public TaskKey(int id, Intent intent) {
this.id = id;
- this.intent = intent;
+ this.baseIntent = intent;
}
@Override
@@ -56,28 +55,24 @@
@Override
public String toString() {
- return "Task.Key: " + id + ", " + intent.getComponent().getPackageName();
+ return "Task.Key: " + id + ", " + baseIntent.getComponent().getPackageName();
}
}
public TaskKey key;
- public String title;
- public Drawable icon;
+ public Drawable applicationIcon;
+ public String activityLabel;
+ public Bitmap activityIcon;
public Bitmap thumbnail;
public boolean isActive;
TaskCallbacks mCb;
- public Task(int id, boolean isActive, Intent intent, String activityTitle, Drawable icon) {
- this(id, isActive, intent, activityTitle, icon, null);
- }
-
- public Task(int id, boolean isActive, Intent intent, String activityTitle, Drawable icon,
- Bitmap thumbnail) {
+ public Task(int id, boolean isActive, Intent intent, String activityTitle,
+ Bitmap activityIcon) {
this.key = new TaskKey(id, intent);
- this.title = activityTitle;
- this.icon = icon;
- this.thumbnail = thumbnail;
+ this.activityLabel = activityTitle;
+ this.activityIcon = activityIcon;
this.isActive = isActive;
}
@@ -87,8 +82,9 @@
}
/** Notifies the callback listeners that this task has been loaded */
- public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable icon, boolean reloadingTaskData) {
- this.icon = icon;
+ public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon,
+ boolean reloadingTaskData) {
+ this.applicationIcon = applicationIcon;
this.thumbnail = thumbnail;
if (mCb != null) {
mCb.onTaskDataLoaded(reloadingTaskData);
@@ -96,8 +92,8 @@
}
/** Notifies the callback listeners that this task has been unloaded */
- public void notifyTaskDataUnloaded(Bitmap defaultThumbnail, Drawable defaultIcon) {
- icon = defaultIcon;
+ public void notifyTaskDataUnloaded(Bitmap defaultThumbnail, Drawable defaultApplicationIcon) {
+ applicationIcon = defaultApplicationIcon;
thumbnail = defaultThumbnail;
if (mCb != null) {
mCb.onTaskDataUnloaded();
@@ -106,20 +102,13 @@
@Override
public boolean equals(Object o) {
- // If we have multiple task entries for the same task, then we do the simple object
- // equality check
- if (Constants.Values.RecentsTaskLoader.TaskEntryMultiplier > 1) {
- return super.equals(o);
- }
-
- // Otherwise, check that the id and intent match (the other fields can be asynchronously
- // loaded and is unsuitable to testing the identity of this Task)
+ // Check that the id matches
Task t = (Task) o;
return key.equals(t.key);
}
@Override
public String toString() {
- return "Task: " + key.intent.getComponent().getPackageName() + " [" + super.toString() + "]";
+ return "Task: " + key.baseIntent.getComponent().getPackageName() + " [" + super.toString() + "]";
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index f2f89ae..a0e5b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -39,9 +39,11 @@
TaskFilter mFilter;
/** Sets the task filter, saving the current touch state */
- void setFilter(TaskFilter filter) {
+ boolean setFilter(TaskFilter filter) {
+ ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
mFilter = filter;
updateFilteredTasks();
+ return !prevFilteredTasks.equals(mFilteredTasks);
}
/** Removes the task filter and returns the previous touch state */
@@ -126,9 +128,9 @@
/* Notifies when a task has been removed from the stack */
public void onStackTaskRemoved(TaskStack stack, Task t);
/** Notifies when the stack was filtered */
- public void onStackFiltered(TaskStack stack);
+ public void onStackFiltered(TaskStack newStack, ArrayList<Task> curStack, Task t);
/** Notifies when the stack was un-filtered */
- public void onStackUnfiltered(TaskStack stack);
+ public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curStack);
}
Context mContext;
@@ -201,29 +203,30 @@
}
/** Filters the stack into tasks similar to the one specified */
- public void filterTasks(Task t) {
+ public void filterTasks(final Task t) {
+ ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
+
// Set the task list filter
- // XXX: This is a dummy filter that currently just accepts every other task.
- mTaskList.setFilter(new TaskFilter() {
+ boolean filtered = mTaskList.setFilter(new TaskFilter() {
@Override
- public boolean acceptTask(Task t, int i) {
- if (i % 2 == 0) {
- return true;
- }
- return false;
+ public boolean acceptTask(Task at, int i) {
+ return t.key.baseIntent.getComponent().getPackageName().equals(
+ at.key.baseIntent.getComponent().getPackageName());
}
});
- if (mCb != null) {
- mCb.onStackFiltered(this);
+ if (filtered && mCb != null) {
+ mCb.onStackFiltered(this, oldStack, t);
}
}
/** Unfilters the current stack */
public void unfilterTasks() {
+ ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
+
// Unset the filter, then update the virtual scroll
mTaskList.removeFilter();
if (mCb != null) {
- mCb.onStackUnfiltered(this);
+ mCb.onStackUnfiltered(this, oldStack);
}
}
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 cc85439..cb52794 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents.views;
-import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -30,6 +29,7 @@
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
+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;
@@ -211,17 +211,18 @@
View sourceView = tv;
int offsetX = 0;
int offsetY = 0;
+ int stackScroll = stackView.getStackScroll();
if (tv == null) {
// If there is no actual task view, then use the stack view as the source view
// and then offset to the expected transform rect, but bound this to just
// outside the display rect (to ensure we don't animate from too far away)
RecentsConfiguration config = RecentsConfiguration.getInstance();
sourceView = stackView;
- transform = stackView.getStackTransform(stack.indexOfTask(task));
+ transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
offsetX = transform.rect.left;
offsetY = Math.min(transform.rect.top, config.displayRect.height());
} else {
- transform = stackView.getStackTransform(stack.indexOfTask(task));
+ transform = stackView.getStackTransform(stack.indexOfTask(task), stackScroll);
}
// Compute the thumbnail to scale up from
@@ -245,17 +246,11 @@
if (task.isActive) {
// Bring an active task to the foreground
- ActivityManager am = (ActivityManager)
- stackView.getContext().getSystemService(Context.ACTIVITY_SERVICE);
- if (opts != null) {
- am.moveTaskToFront(task.key.id, ActivityManager.MOVE_TASK_WITH_HOME,
- opts.toBundle());
- } else {
- am.moveTaskToFront(task.key.id, ActivityManager.MOVE_TASK_WITH_HOME);
- }
+ RecentsTaskLoader.getInstance().getSystemServicesProxy()
+ .moveTaskToFront(task.key.id, opts);
} else {
// Launch the activity with the desired animation
- Intent i = new Intent(task.key.intent);
+ Intent i = new Intent(task.key.baseIntent);
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
| Intent.FLAG_ACTIVITY_NEW_TASK);
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 235c6cc..c9a6d67 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -17,21 +17,12 @@
package com.android.systemui.recents.views;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
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.model.Task;
@@ -39,6 +30,7 @@
class TaskBarView extends FrameLayout {
Task mTask;
+ ImageView mApplicationIcon;
ImageView mActivityIcon;
TextView mActivityDescription;
@@ -61,6 +53,7 @@
@Override
protected void onFinishInflate() {
// Initialize the icon and description views
+ mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
mActivityIcon = (ImageView) findViewById(R.id.activity_icon);
mActivityDescription = (TextView) findViewById(R.id.activity_description);
}
@@ -68,9 +61,13 @@
/** Binds the bar view to the task */
void rebindToTask(Task t, boolean animate) {
mTask = t;
- if (t.icon != null) {
- mActivityIcon.setImageDrawable(t.icon);
- mActivityDescription.setText(t.title);
+ if (t.applicationIcon != null) {
+ mApplicationIcon.setImageDrawable(t.applicationIcon);
+ mActivityDescription.setText(t.activityLabel);
+ if (t.activityIcon != null) {
+ mActivityIcon.setImageBitmap(t.activityIcon);
+ mActivityIcon.setVisibility(View.VISIBLE);
+ }
if (animate) {
// XXX: Investigate how expensive it will be to create a second bitmap and crossfade
}
@@ -80,7 +77,9 @@
/** Unbinds the bar view from the task */
void unbindFromTask() {
mTask = null;
- mActivityIcon.setImageDrawable(null);
+ mApplicationIcon.setImageDrawable(null);
+ mActivityIcon.setImageBitmap(null);
+ mActivityIcon.setVisibility(View.INVISIBLE);
mActivityDescription.setText("");
}
}
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 e7f517f..dfd608c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -18,10 +18,10 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
-import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -34,14 +34,15 @@
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.OverScroller;
+import com.android.systemui.R;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsTaskLoader;
+import com.android.systemui.recents.SystemServicesProxy;
import com.android.systemui.recents.Utilities;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.R;
import java.util.ArrayList;
@@ -71,6 +72,7 @@
int mStackScroll;
int mMinScroll;
int mMaxScroll;
+ int mStashedScroll;
OverScroller mScroller;
ObjectAnimator mScrollAnimator;
@@ -79,6 +81,9 @@
int mStackViewsAnimationDuration;
boolean mStackViewsDirty = true;
boolean mAwaitingFirstLayout = true;
+ int[] mTmpVisibleRange = new int[2];
+ Rect mTmpRect = new Rect();
+ Rect mTmpRect2 = new Rect();
LayoutInflater mInflater;
public TaskStackView(Context context, TaskStack stack) {
@@ -102,7 +107,7 @@
}
void requestSynchronizeStackViewsWithModel(int duration) {
Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
- "[TaskStackView|requestSynchronize]", "", Console.AnsiYellow);
+ "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
if (!mStackViewsDirty) {
invalidate();
}
@@ -128,14 +133,17 @@
}
/** Update/get the transform */
- public TaskViewTransform getStackTransform(int indexInStack) {
+ public TaskViewTransform getStackTransform(int indexInStack, int stackScroll) {
TaskViewTransform transform = new TaskViewTransform();
- // Map the items to an continuous position relative to the current scroll
+ // Return early if we have an invalid index
+ if (indexInStack < 0) return transform;
+
+ // Map the items to an continuous position relative to the specified scroll
int numPeekCards = Constants.Values.TaskStackView.StackPeekNumCards;
float overlapHeight = Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height();
float peekHeight = Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height();
- float t = ((indexInStack * overlapHeight) - getStackScroll()) / overlapHeight;
+ float t = ((indexInStack * overlapHeight) - stackScroll) / overlapHeight;
float boundedT = Math.max(t, -(numPeekCards + 1));
// Set the scale relative to its position
@@ -167,25 +175,57 @@
return transform;
}
+ /**
+ * Gets the stack transforms of a list of tasks, and returns the visible range of tasks.
+ */
+ private ArrayList<TaskViewTransform> getStackTransforms(ArrayList<Task> tasks,
+ int stackScroll,
+ int[] visibleRangeOut) {
+ // XXX: Optimization: Use binary search to find the visible range
+
+ ArrayList<TaskViewTransform> taskTransforms = new ArrayList<TaskViewTransform>();
+ int taskCount = tasks.size();
+ int firstVisibleIndex = -1;
+ int lastVisibleIndex = -1;
+ for (int i = 0; i < taskCount; i++) {
+ TaskViewTransform transform = getStackTransform(i, stackScroll);
+ taskTransforms.add(transform);
+ if (transform.visible) {
+ if (firstVisibleIndex < 0) {
+ firstVisibleIndex = i;
+ }
+ lastVisibleIndex = i;
+ }
+ }
+ if (visibleRangeOut != null) {
+ visibleRangeOut[0] = firstVisibleIndex;
+ visibleRangeOut[1] = lastVisibleIndex;
+ }
+ return taskTransforms;
+ }
+
/** Synchronizes the views with the model */
void synchronizeStackViewsWithModel() {
Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
"[TaskStackView|synchronizeViewsWithModel]",
"mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
if (mStackViewsDirty) {
-
- // XXX: Optimization: Use binary search to find the visible range
- // XXX: Optimize to not call getStackTransform() so many times
// XXX: Consider using TaskViewTransform pool to prevent allocations
// XXX: Iterate children views, update transforms and remove all that are not visible
// For all remaining tasks, update transforms and if visible add the view
- // Update the visible state of all the tasks
+ // Get all the task transforms
+ int[] visibleRange = mTmpVisibleRange;
+ int stackScroll = getStackScroll();
ArrayList<Task> tasks = mStack.getTasks();
+ ArrayList<TaskViewTransform> taskTransforms = getStackTransforms(tasks, stackScroll,
+ visibleRange);
+
+ // Update the visible state of all the tasks
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
- TaskViewTransform transform = getStackTransform(i);
+ TaskViewTransform transform = taskTransforms.get(i);
TaskView tv = getChildViewForTask(task);
if (transform.visible) {
@@ -194,11 +234,10 @@
// When we are picking up a new view from the view pool, prepare it for any
// following animation by putting it in a reasonable place
if (mStackViewsAnimationDuration > 0 && i != 0) {
- // XXX: We have to animate when filtering, etc. Maybe we should have a
- // runnable that ensures that tasks are animated in a special way
- // when they are entering the scene?
- int fromIndex = (transform.t < 0) ? (i - 1) : (i + 1);
- tv.updateViewPropertiesFromTask(null, getStackTransform(fromIndex), 0);
+ int fromIndex = (transform.t < 0) ? (visibleRange[0] - 1) :
+ (visibleRange[1] + 1);
+ tv.updateViewPropertiesToTaskTransform(null,
+ getStackTransform(fromIndex, stackScroll), 0);
}
}
} else {
@@ -208,17 +247,18 @@
}
}
- // Update all the current view children
+ // Update all the remaining view children
// NOTE: We have to iterate in reverse where because we are removing views directly
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
TaskView tv = (TaskView) getChildAt(i);
Task task = tv.getTask();
- TaskViewTransform transform = getStackTransform(mStack.indexOfTask(task));
- if (!transform.visible) {
+ int taskIndex = mStack.indexOfTask(task);
+ if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
mViewPool.returnViewToPool(tv);
} else {
- tv.updateViewPropertiesFromTask(null, transform, mStackViewsAnimationDuration);
+ tv.updateViewPropertiesToTaskTransform(null, taskTransforms.get(taskIndex),
+ mStackViewsAnimationDuration);
}
}
@@ -235,6 +275,10 @@
mStackScroll = value;
requestSynchronizeStackViewsWithModel();
}
+ /** Sets the current stack scroll without synchronizing the stack view with the model */
+ public void setStackScrollRaw(int value) {
+ mStackScroll = value;
+ }
/** Gets the current stack scroll */
public int getStackScroll() {
@@ -251,36 +295,39 @@
// Abort any current animations
abortScroller();
- if (mScrollAnimator != null) {
- mScrollAnimator.cancel();
- mScrollAnimator.removeAllListeners();
- }
+ abortBoundScrollAnimation();
// Start a new scroll animation
- mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
- mScrollAnimator.setDuration(duration);
- mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- setStackScroll((Integer) animation.getAnimatedValue());
- }
- });
- mScrollAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // Disable hw layers on the stack
- decHwLayersRefCount("animateBoundScroll");
- }
- });
+ animateScroll(curScroll, newScroll, duration);
mScrollAnimator.start();
}
return mScrollAnimator;
}
+ /** Animates the stack scroll */
+ void animateScroll(int curScroll, int newScroll, int duration) {
+ mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
+ mScrollAnimator.setDuration(duration);
+ mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setStackScroll((Integer) animation.getAnimatedValue());
+ }
+ });
+ mScrollAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Disable hw layers on the stack
+ decHwLayersRefCount("animateBoundScroll");
+ }
+ });
+ }
+
/** Aborts any current stack scrolls */
void abortBoundScrollAnimation() {
if (mScrollAnimator != null) {
mScrollAnimator.cancel();
+ mScrollAnimator.removeAllListeners();
}
}
@@ -304,6 +351,20 @@
return false;
}
+ /**
+ * Bounds the current scroll if necessary, but does not synchronize the stack view with the
+ * model.
+ */
+ public boolean boundScrollRaw() {
+ int curScroll = getStackScroll();
+ int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll, curScroll));
+ if (newScroll != curScroll) {
+ setStackScrollRaw(newScroll);
+ return true;
+ }
+ return false;
+ }
+
/** Returns whether the current scroll is out of bounds */
boolean isScrollOutOfBounds() {
return (getStackScroll() < 0) || (getStackScroll() > mMaxScroll);
@@ -404,12 +465,12 @@
TaskView tv = (TaskView) child;
TaskView nextTv = null;
int curIndex = indexOfChild(tv);
- if (curIndex < (getChildCount() - 1)) {
+ if ((curIndex > -1) && (curIndex < (getChildCount() - 1))) {
// Clip against the next view (if we aren't animating its alpha)
nextTv = (TaskView) getChildAt(curIndex + 1);
if (nextTv.getAlpha() == 1f) {
- Rect curRect = tv.getClippingRect(Utilities.tmpRect, false);
- Rect nextRect = nextTv.getClippingRect(Utilities.tmpRect2, true);
+ Rect curRect = tv.getClippingRect(mTmpRect, false);
+ Rect nextRect = nextTv.getClippingRect(mTmpRect2, true);
RecentsConfiguration config = RecentsConfiguration.getInstance();
// The hit rects are relative to the task view, which needs to be offset by the
// system bar height
@@ -528,9 +589,7 @@
mTaskRect.right, mStackRectSansPeek.top + mTaskRect.height());
}
- if (!mAwaitingFirstLayout) {
- requestSynchronizeStackViewsWithModel();
- } else {
+ if (mAwaitingFirstLayout) {
mAwaitingFirstLayout = false;
}
}
@@ -570,13 +629,185 @@
}
@Override
- public void onStackFiltered(TaskStack stack) {
- requestSynchronizeStackViewsWithModel();
+ public void onStackFiltered(TaskStack newStack, final ArrayList<Task> curStack,
+ Task filteredTask) {
+ // NOTE: This code assumes that the current (unfiltered) stack is a superset of the new
+ // (filtered) stack
+ // XXX: Use HW Layers
+
+ // Stash the scroll for us to restore to when we unfilter
+ mStashedScroll = getStackScroll();
+
+ // Compute the transforms of the items in the current stack
+ final ArrayList<TaskViewTransform> curTaskTransforms =
+ getStackTransforms(curStack, mStashedScroll, null);
+
+ // Bound the new stack scroll
+ updateMinMaxScroll(false);
+ boundScrollRaw();
+
+ // Compute the transforms of the items in the new stack
+ final ArrayList<TaskViewTransform> taskTransforms =
+ getStackTransforms(mStack.getTasks(), getStackScroll(), null);
+
+ // Animate all of the existing views on screen either out of view (if they are not visible
+ // in the new stack) or to their final positions in the new stack
+ final ArrayList<TaskView> childrenToReturnToPool = new ArrayList<TaskView>();
+ final ArrayList<Task> tasks = mStack.getTasks();
+ ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ Task task = tv.getTask();
+ TaskViewTransform toTransform;
+ int taskIndex = tasks.indexOf(task);
+ if ((taskIndex < 0) || !taskTransforms.get(taskIndex).visible) {
+ // Compose a new transform that animates the task view out of view
+ TaskViewTransform fromTransform = curTaskTransforms.get(curStack.indexOf(task));
+ toTransform = new TaskViewTransform(fromTransform);
+ tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+ tv.prepareTaskTransformForFilterTaskHidden(toTransform);
+
+ childrenToReturnToPool.add(tv);
+ } else {
+ toTransform = taskTransforms.get(taskIndex);
+ }
+ childViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
+ }
+
+ AnimatorSet childViewAnimSet = new AnimatorSet();
+ childViewAnimSet.setDuration(
+ Constants.Values.TaskStackView.Animation.FilteredCurrentViewsDuration);
+ childViewAnimSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Return all the removed children to the view pool
+ for (TaskView tv : childrenToReturnToPool) {
+ mViewPool.returnViewToPool(tv);
+ }
+
+ // For views that are not already visible, animate them in
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ TaskViewTransform toTransform = taskTransforms.get(i);
+ if (toTransform.visible) {
+ TaskViewTransform fromTransform =
+ curTaskTransforms.get(curStack.indexOf(task));
+ TaskView tv = getChildViewForTask(task);
+ if (tv == null) {
+ tv = mViewPool.pickUpViewFromPool(task, task);
+
+ // Animate from the current position to the new position
+ tv.prepareTaskTransformForFilterTaskVisible(fromTransform);
+ tv.updateViewPropertiesToTaskTransform(fromTransform,
+ toTransform,
+ Constants.Values.TaskStackView.Animation.FilteredNewViewsDuration);
+ }
+ }
+ }
+ invalidate();
+ }
+ });
+ childViewAnimSet.playTogether(childViewAnims);
+ childViewAnimSet.start();
}
@Override
- public void onStackUnfiltered(TaskStack stack) {
- requestSynchronizeStackViewsWithModel();
+ public void onStackUnfiltered(TaskStack newStack, final ArrayList<Task> curStack) {
+ // Compute the transforms of the items in the current stack
+ final int curScroll = getStackScroll();
+ final ArrayList<TaskViewTransform> curTaskTransforms =
+ getStackTransforms(curStack, curScroll, null);
+
+ // Restore the stashed scroll
+ updateMinMaxScroll(false);
+ setStackScrollRaw(mStashedScroll);
+ boundScrollRaw();
+
+ // Compute the transforms of the items in the new stack
+ final ArrayList<TaskViewTransform> taskTransforms =
+ getStackTransforms(mStack.getTasks(), getStackScroll(), null);
+
+ // Animate all of the existing views out of view (if they are not in the visible range in
+ // the new stack) or to their final positions in the new stack
+ final ArrayList<TaskView> childrenToRemove = new ArrayList<TaskView>();
+ final ArrayList<Task> tasks = mStack.getTasks();
+ ArrayList<Animator> childViewAnims = new ArrayList<Animator>();
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ TaskView tv = (TaskView) getChildAt(i);
+ Task task = tv.getTask();
+ int taskIndex = tasks.indexOf(task);
+ TaskViewTransform transform;
+
+ // If the view is no longer visible, then we should just animate it out
+ if (taskIndex < 0 || !taskTransforms.get(taskIndex).visible) {
+ transform = new TaskViewTransform(curTaskTransforms.get(curStack.indexOf(task)));
+ tv.prepareTaskTransformForFilterTaskVisible(transform);
+ childrenToRemove.add(tv);
+ } else {
+ transform = taskTransforms.get(taskIndex);
+ }
+ childViewAnims.add(tv.getAnimatorToTaskTransform(transform));
+ }
+
+ AnimatorSet childViewAnimSet = new AnimatorSet();
+ childViewAnimSet.setDuration(
+ Constants.Values.TaskStackView.Animation.UnfilteredCurrentViewsDuration);
+ childViewAnimSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Return all the removed children to the view pool
+ for (TaskView tv : childrenToRemove) {
+ mViewPool.returnViewToPool(tv);
+ }
+
+ // Increment the hw layers ref count
+ addHwLayersRefCount("unfilteredNewViews");
+
+ // For views that are not already visible, animate them in
+ ArrayList<Animator> newViewAnims = new ArrayList<Animator>();
+ AnimatorSet newViewAnimSet = new AnimatorSet();
+ int taskCount = tasks.size();
+ int offset = 0;
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ TaskViewTransform toTransform = taskTransforms.get(i);
+ if (toTransform.visible) {
+ TaskView tv = getChildViewForTask(task);
+ if (tv == null) {
+ // For views that are not already visible, animate them in
+ tv = mViewPool.pickUpViewFromPool(task, task);
+
+ // Animate in this new view
+ TaskViewTransform fromTransform = new TaskViewTransform(toTransform);
+ tv.prepareTaskTransformForFilterTaskHidden(fromTransform);
+ tv.updateViewPropertiesToTaskTransform(null, fromTransform, 0);
+ newViewAnims.add(tv.getAnimatorToTaskTransform(toTransform));
+ offset++;
+ }
+ }
+ }
+
+ // Run the animation
+ newViewAnimSet.setDuration(
+ Constants.Values.TaskStackView.Animation.UnfilteredNewViewsDuration);
+ newViewAnimSet.playTogether(newViewAnims);
+ newViewAnimSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Decrement the hw layers ref count
+ decHwLayersRefCount("unfilteredNewViews");
+ }
+ });
+ newViewAnimSet.start();
+
+ invalidate();
+ }
+ });
+ childViewAnimSet.playTogether(childViewAnims);
+ childViewAnimSet.start();
}
/**** ViewPoolConsumer Implementation ****/
@@ -845,7 +1076,7 @@
/** Handles touch events once we have intercepted them */
public boolean onTouchEvent(MotionEvent ev) {
- Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+ Console.log(Constants.DebugFlags.UI.TouchEvents,
"[TaskStackViewTouchHandler|touchEvent]",
Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
@@ -1038,16 +1269,19 @@
loader.deleteTaskData(task);
// Remove the task from activity manager
- final ActivityManager am = (ActivityManager)
- activity.getSystemService(Context.ACTIVITY_SERVICE);
- if (am != null) {
- am.removeTask(tv.getTask().key.id,
- ActivityManager.REMOVE_TASK_KILL_PROCESS);
- }
+ RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(tv.getTask().key.id);
- // If there are no remaining tasks, then just close the activity
+ // If there are no remaining tasks, then either unfilter the current stack, or just close
+ // the activity if there are no filtered stacks
if (mSv.mStack.getTaskCount() == 0) {
- activity.finish();
+ boolean shouldFinishActivity = true;
+ if (mSv.mStack.hasFilteredTasks()) {
+ mSv.mStack.unfilterTasks();
+ shouldFinishActivity = (mSv.mStack.getTaskCount() == 0);
+ }
+ if (shouldFinishActivity) {
+ activity.finish();
+ }
}
// Disable HW layers
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 c86b0e1..2c27d44 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -16,6 +16,9 @@
package com.android.systemui.recents.views;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path;
@@ -72,6 +75,7 @@
// Bind the views
mThumbnailView = (TaskThumbnailView) findViewById(R.id.task_view_thumbnail);
mBarView = (TaskBarView) findViewById(R.id.task_view_bar);
+ mBarView.mApplicationIcon.setOnClickListener(this);
if (mTaskDataLoaded) {
onTaskDataLoaded(false);
}
@@ -90,12 +94,16 @@
}
@Override
- protected void onDraw(Canvas canvas) {
+ protected void dispatchDraw(Canvas canvas) {
+ int restoreCount = 0;
if (Constants.Values.TaskView.UseRoundedCorners) {
+ restoreCount = canvas.save();
canvas.clipPath(mRoundedRectClipPath);
}
-
- super.onDraw(canvas);
+ super.dispatchDraw(canvas);
+ if (Constants.Values.TaskView.UseRoundedCorners) {
+ canvas.restoreToCount(restoreCount);
+ }
}
/** Set callback */
@@ -109,27 +117,43 @@
}
/** Synchronizes this view's properties with the task's transform */
- void updateViewPropertiesFromTask(TaskViewTransform animateFromTransform,
- TaskViewTransform transform, int duration) {
+ void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
+ TaskViewTransform toTransform, int duration) {
if (duration > 0) {
if (animateFromTransform != null) {
setTranslationY(animateFromTransform.translationY);
setScaleX(animateFromTransform.scale);
setScaleY(animateFromTransform.scale);
+ setAlpha(animateFromTransform.alpha);
}
- animate().translationY(transform.translationY)
- .scaleX(transform.scale)
- .scaleY(transform.scale)
+ animate().translationY(toTransform.translationY)
+ .scaleX(toTransform.scale)
+ .scaleY(toTransform.scale)
+ .alpha(toTransform.alpha)
.setDuration(duration)
.setInterpolator(new AccelerateDecelerateInterpolator())
+ .withLayer()
.start();
} else {
- setTranslationY(transform.translationY);
- setScaleX(transform.scale);
- setScaleY(transform.scale);
+ setTranslationY(toTransform.translationY);
+ setScaleX(toTransform.scale);
+ setScaleY(toTransform.scale);
+ setAlpha(toTransform.alpha);
}
}
+ /** Returns an animator to animate this task to the specified transform */
+ Animator getAnimatorToTaskTransform(TaskViewTransform toTransform) {
+ AnimatorSet anims = new AnimatorSet();
+ anims.playTogether(
+ ObjectAnimator.ofFloat(this, "translationY", toTransform.translationY),
+ ObjectAnimator.ofFloat(this, "scaleX", toTransform.scale),
+ ObjectAnimator.ofFloat(this, "scaleY", toTransform.scale),
+ ObjectAnimator.ofFloat(this, "alpha", toTransform.alpha)
+ );
+ return anims;
+ }
+
/** Resets this view's properties */
void resetViewProperties() {
setTranslationX(0f);
@@ -139,6 +163,17 @@
setAlpha(1f);
}
+ void prepareTaskTransformForFilterTaskHidden(TaskViewTransform toTransform) {
+ // Fade the view out and slide it away
+ toTransform.alpha = 0f;
+ toTransform.translationY += 200;
+ }
+
+ void prepareTaskTransformForFilterTaskVisible(TaskViewTransform fromTransform) {
+ // Fade the view in
+ fromTransform.alpha = 0f;
+ }
+
/** Animates this task view as it enters recents */
public void animateOnEnterRecents() {
RecentsConfiguration config = RecentsConfiguration.getInstance();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 66c52a0..0748bbb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -23,13 +23,27 @@
public class TaskViewTransform {
public int translationY = 0;
public float scale = 1f;
- public boolean visible = true;
+ public float alpha = 1f;
+ public boolean visible = false;
public Rect rect = new Rect();
float t;
+ public TaskViewTransform() {
+ // Do nothing
+ }
+
+ public TaskViewTransform(TaskViewTransform o) {
+ translationY = o.translationY;
+ scale = o.scale;
+ alpha = o.alpha;
+ visible = o.visible;
+ rect.set(o.rect);
+ t = o.t;
+ }
+
@Override
public String toString() {
- return "TaskViewTransform y: " + translationY + " scale: " + scale +
+ return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
" visible: " + visible + " rect: " + rect;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index d584043..c99f691 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -83,22 +83,7 @@
}
public void onCheckedChanged(CompoundButton toggle, boolean checked) {
- Drawable thumb;
- Drawable slider;
- final Resources res = getContext().getResources();
- if (checked) {
- thumb = res.getDrawable(
- com.android.internal.R.drawable.scrubber_control_disabled_holo);
- slider = res.getDrawable(
- R.drawable.status_bar_settings_slider_disabled);
- } else {
- thumb = res.getDrawable(
- com.android.internal.R.drawable.scrubber_control_selector_holo);
- slider = res.getDrawable(
- com.android.internal.R.drawable.scrubber_progress_horizontal_holo_dark);
- }
- mSlider.setThumb(thumb);
- mSlider.setProgressDrawable(slider);
+ mSlider.setEnabled(checked);
if (mListener != null) {
mListener.onChanged(this, mTracking, checked, mSlider.getProgress());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index bad5641..f349036 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -41,7 +41,6 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -78,6 +77,7 @@
import com.android.systemui.SearchPanelView;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
import java.util.Locale;
@@ -98,8 +98,6 @@
protected static final int MSG_HIDE_HEADS_UP = 1027;
protected static final int MSG_ESCALATE_HEADS_UP = 1028;
- public static final boolean ENABLE_NOTIFICATION_STACK = SystemProperties
- .getBoolean("persist.notifications.use_stack", false);
protected static final boolean ENABLE_HEADS_UP = true;
// scores above this threshold should be displayed in heads up mode.
protected static final int INTERRUPTION_THRESHOLD = 10;
@@ -120,7 +118,7 @@
// all notifications
protected NotificationData mNotificationData = new NotificationData();
- protected ViewGroup mPile;
+ protected NotificationStackScrollLayout mStackScroller;
protected NotificationData.Entry mInterruptingNotificationEntry;
protected long mInterruptingNotificationTime;
@@ -134,7 +132,7 @@
protected PopupMenu mNotificationBlamePopup;
protected int mCurrentUserId = 0;
- final protected SparseArray<UserInfo> mRelatedUsers = new SparseArray<UserInfo>();
+ final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
protected int mLayoutDirection = -1; // invalid
private Locale mLocale;
@@ -244,21 +242,21 @@
String action = intent.getAction();
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- updateRelatedUserCache();
+ updateCurrentProfilesCache();
if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
userSwitched(mCurrentUserId);
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
- updateRelatedUserCache();
+ updateCurrentProfilesCache();
}
}
};
- private void updateRelatedUserCache() {
- synchronized (mRelatedUsers) {
- mRelatedUsers.clear();
+ private void updateCurrentProfilesCache() {
+ synchronized (mCurrentProfiles) {
+ mCurrentProfiles.clear();
if (mUserManager != null) {
- for (UserInfo related : mUserManager.getRelatedUsers(mCurrentUserId)) {
- mRelatedUsers.put(related.id, related);
+ for (UserInfo user : mUserManager.getProfiles(mCurrentUserId)) {
+ mCurrentProfiles.put(user.id, user);
}
}
}
@@ -361,24 +359,23 @@
filter.addAction(Intent.ACTION_USER_ADDED);
mContext.registerReceiver(mBroadcastReceiver, filter);
- updateRelatedUserCache();
+ updateCurrentProfilesCache();
}
public void userSwitched(int newUserId) {
// should be overridden
}
- public boolean notificationIsForCurrentOrRelatedUser(StatusBarNotification n) {
+ public boolean notificationIsForCurrentProfiles(StatusBarNotification n) {
final int thisUserId = mCurrentUserId;
final int notificationUserId = n.getUserId();
if (DEBUG && MULTIUSER_DEBUG) {
Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
n, thisUserId, notificationUserId));
}
- synchronized (mRelatedUsers) {
+ synchronized (mCurrentProfiles) {
return notificationUserId == UserHandle.USER_ALL
- || thisUserId == notificationUserId
- || mRelatedUsers.get(notificationUserId) != null;
+ || mCurrentProfiles.get(notificationUserId) != null;
}
}
@@ -1034,7 +1031,7 @@
}
// Construct the expanded view.
NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
- if (!inflateViews(entry, mPile)) {
+ if (!inflateViews(entry, mStackScroller)) {
handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+ notification);
return null;
@@ -1258,7 +1255,7 @@
updateNotificationVetoButton(oldEntry.row, notification);
// Is this for you?
- boolean isForCurrentUser = notificationIsForCurrentOrRelatedUser(notification);
+ boolean isForCurrentUser = notificationIsForCurrentProfiles(notification);
if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
// Restart the ticker if it's still running
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 6be6d4d..2d2f2f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -17,45 +17,51 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.util.EventLog;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
public class NotificationPanelView extends PanelView {
public static final boolean DEBUG_GESTURES = true;
- Drawable mHandleBar;
- int mHandleBarHeight;
- View mHandleView;
- int mFingers;
PhoneStatusBar mStatusBar;
- boolean mOkToFlip;
+ private NotificationStackScrollLayout mNotificationStackScroller;
+ private int[] mTempLocation = new int[2];
+ private int[] mTempChildLocation = new int[2];
+ private View mNotificationParent;
+
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setStatusBar(PhoneStatusBar bar) {
+ if (mStatusBar != null) {
+ mStatusBar.setOnFlipRunnable(null);
+ }
mStatusBar = bar;
+ if (bar != null) {
+ mStatusBar.setOnFlipRunnable(new Runnable() {
+ @Override
+ public void run() {
+ requestPanelHeightUpdate();
+ }
+ });
+ }
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- Resources resources = getContext().getResources();
- mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
- mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height);
- mHandleView = findViewById(R.id.handle);
+ mNotificationStackScroller = (NotificationStackScrollLayout)
+ findViewById(R.id.notification_stack_scroller);
+ mNotificationParent = findViewById(R.id.notification_container_parent);
}
@Override
@@ -80,61 +86,86 @@
return super.dispatchPopulateAccessibilityEvent(event);
}
- // We draw the handle ourselves so that it's always glued to the bottom of the window.
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (changed) {
- final int pl = getPaddingLeft();
- final int pr = getPaddingRight();
- mHandleBar.setBounds(pl, 0, getWidth() - pr, (int) mHandleBarHeight);
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
- final int off = (int) (getHeight() - mHandleBarHeight - getPaddingBottom());
- canvas.translate(0, off);
- mHandleBar.setState(mHandleView.getDrawableState());
- mHandleBar.draw(canvas);
- canvas.translate(0, -off);
+ /**
+ * 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 onTouchEvent(MotionEvent event) {
- if (DEBUG_GESTURES) {
- if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
- EventLog.writeEvent(EventLogTags.SYSUI_NOTIFICATIONPANEL_TOUCH,
- event.getActionMasked(), (int) event.getX(), (int) event.getY());
- }
+ // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
+ // implementation.
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ protected boolean isScrolledToBottom() {
+ if (!isInSettings()) {
+ return mNotificationStackScroller.isScrolledToBottom();
}
- if (PhoneStatusBar.SETTINGS_DRAG_SHORTCUT && mStatusBar.mHasFlipSettings) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- mOkToFlip = getExpandedHeight() == 0;
- break;
- case MotionEvent.ACTION_POINTER_DOWN:
- if (mOkToFlip) {
- float miny = event.getY(0);
- float maxy = miny;
- for (int i=1; i<event.getPointerCount(); i++) {
- final float y = event.getY(i);
- if (y < miny) miny = y;
- if (y > maxy) maxy = y;
- }
- if (maxy - miny < mHandleBarHeight) {
- if (getMeasuredHeight() < mHandleBarHeight) {
- mStatusBar.switchToSettings();
- } else {
- mStatusBar.flipToSettings();
- }
- mOkToFlip = false;
- }
- }
- break;
- }
+ return super.isScrolledToBottom();
+ }
+
+ @Override
+ protected int getMaxPanelHeight() {
+ if (!isInSettings()) {
+ int maxPanelHeight = super.getMaxPanelHeight();
+ int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
+ return maxPanelHeight - emptyBottomMargin;
}
- return mHandleView.dispatchTouchEvent(event);
+ return super.getMaxPanelHeight();
+ }
+
+ private boolean isInSettings() {
+ return mStatusBar != null && mStatusBar.isFlippedToSettings();
+ }
+
+ @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) {
+ 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)));
+ }
+ }
+
+ @Override
+ protected int getDesiredMeasureHeight() {
+ return mMaxPanelHeight;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 4b2c3e1..3c8af30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -25,6 +25,7 @@
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.widget.FrameLayout;
import com.android.systemui.R;
@@ -69,7 +70,7 @@
private View mHandleView;
private float mPeekHeight;
- private float mTouchOffset;
+ private float mInitialOffsetOnTouch;
private float mExpandedFraction = 0;
private float mExpandedHeight = 0;
private boolean mJustPeeked;
@@ -77,6 +78,7 @@
private boolean mRubberbanding;
private boolean mTracking;
private int mTrackingPointer;
+ private int mTouchSlop;
private TimeAnimator mTimeAnimator;
private ObjectAnimator mPeekAnimator;
@@ -198,7 +200,6 @@
}
}
- private int[] mAbsPos = new int[2];
PanelBar mBar;
private final TimeListener mAnimationCallback = new TimeListener() {
@@ -220,7 +221,7 @@
};
private float mVel, mAccel;
- private int mFullHeight = 0;
+ protected int mMaxPanelHeight = 0;
private String mViewName;
protected float mInitialTouchY;
protected float mFinalTouchY;
@@ -253,13 +254,13 @@
mTimeAnimator.start();
mRubberbanding = mRubberbandingEnabled // is it enabled at all?
- && mExpandedHeight > getFullHeight() // are we past the end?
+ && mExpandedHeight > getMaxPanelHeight() // are we past the end?
&& mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture?
if (mRubberbanding) {
mClosing = true;
} else if (mVel == 0) {
// if the panel is less than halfway open, close it
- mClosing = (mFinalTouchY / getFullHeight()) < 0.5f;
+ mClosing = (mFinalTouchY / getMaxPanelHeight()) < 0.5f;
} else {
mClosing = mExpandedHeight > 0 && mVel < 0;
}
@@ -268,7 +269,7 @@
if (DEBUG) logf("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
if (DEBUG) logf("tick: before: h=%d", (int) mExpandedHeight);
- final float fh = getFullHeight();
+ final float fh = getMaxPanelHeight();
boolean braking = false;
if (BRAKES) {
if (mClosing) {
@@ -351,6 +352,9 @@
mPeekHeight = res.getDimension(R.dimen.peek_height)
+ getPaddingBottom() // our window might have a dropshadow
- (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow
+
+ final ViewConfiguration configuration = ViewConfiguration.get(getContext());
+ mTouchSlop = configuration.getScaledTouchSlop();
}
private void trackMovement(MotionEvent event) {
@@ -363,10 +367,221 @@
event.offsetLocation(-deltaX, -deltaY);
}
- // Pass all touches along to the handle, allowing the user to drag the panel closed from its interior
@Override
public boolean onTouchEvent(MotionEvent event) {
- return mHandleView.dispatchTouchEvent(event);
+
+ /*
+ * We capture touch events here and update the expand height here in case according to
+ * the users fingers. This also handles multi-touch.
+ *
+ * If the user just clicks shortly, we give him a quick peek of the shade.
+ *
+ * Flinging is also enabled in order to open or close the shade.
+ */
+
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
+ }
+ final float y = event.getY(pointerIndex);
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mTracking = true;
+ if (mHandleView != null) {
+ mHandleView.setPressed(true);
+ postInvalidate(); // catch the press state change
+ }
+
+ mInitialTouchY = y;
+ initVelocityTracker();
+ trackMovement(event);
+ mTimeAnimator.cancel(); // end any outstanding animations
+ mBar.onTrackingStarted(PanelView.this);
+ mInitialOffsetOnTouch = mExpandedHeight;
+ if (mExpandedHeight == 0) {
+ mJustPeeked = true;
+ runPeekAnimation();
+ }
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ final float newY = event.getY(newIndex);
+ mTrackingPointer = event.getPointerId(newIndex);
+ mInitialOffsetOnTouch = mExpandedHeight;
+ mInitialTouchY = newY;
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY + mInitialOffsetOnTouch;
+ if (h > mPeekHeight) {
+ if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
+ mPeekAnimator.cancel();
+ }
+ mJustPeeked = false;
+ }
+ if (!mJustPeeked) {
+ setExpandedHeightInternal(h);
+ mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
+ }
+
+ trackMovement(event);
+ break;
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mFinalTouchY = y;
+ mTracking = false;
+ mTrackingPointer = -1;
+ if (mHandleView != null) {
+ mHandleView.setPressed(false);
+ postInvalidate(); // catch the press state change
+ }
+ mBar.onTrackingStopped(PanelView.this);
+ trackMovement(event);
+
+ float vel = getCurrentVelocity();
+ fling(vel, true);
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ break;
+ }
+ return true;
+ }
+
+ private float getCurrentVelocity() {
+ float vel = 0;
+ float yVel = 0, xVel = 0;
+ boolean negative = false;
+
+ // the velocitytracker might be null if we got a bad input stream
+ if (mVelocityTracker == null) {
+ return 0;
+ }
+
+ mVelocityTracker.computeCurrentVelocity(1000);
+
+ yVel = mVelocityTracker.getYVelocity();
+ negative = yVel < 0;
+
+ xVel = mVelocityTracker.getXVelocity();
+ if (xVel < 0) {
+ xVel = -xVel;
+ }
+ if (xVel > mFlingGestureMaxXVelocityPx) {
+ xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
+ }
+
+ vel = (float) Math.hypot(yVel, xVel);
+ if (vel > mFlingGestureMaxOutputVelocityPx) {
+ vel = mFlingGestureMaxOutputVelocityPx;
+ }
+
+ // if you've barely moved your finger, we treat the velocity as 0
+ // preventing spurious flings due to touch screen jitter
+ final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
+ if (deltaY < mFlingGestureMinDistPx
+ || vel < mFlingExpandMinVelocityPx
+ ) {
+ vel = 0;
+ }
+
+ if (negative) {
+ vel = -vel;
+ }
+
+ if (DEBUG) {
+ logf("gesture: dy=%f vel=(%f,%f) vlinear=%f",
+ deltaY,
+ xVel, yVel,
+ vel);
+ }
+ return vel;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+
+ /*
+ * If the user drags anywhere inside the panel we intercept it if he moves his finger
+ * upwards. This allows closing the shade from anywhere inside the panel.
+ *
+ * We only do this if the current content is scrolled to the bottom,
+ * i.e isScrolledToBottom() is true and therefore there is no conflicting scrolling gesture
+ * possible.
+ */
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
+ }
+ final float y = event.getY(pointerIndex);
+ boolean scrolledToBottom = isScrolledToBottom();
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mTracking = true;
+ if (mHandleView != null) {
+ mHandleView.setPressed(true);
+ // catch the press state change
+ postInvalidate();
+ }
+ mInitialTouchY = y;
+ initVelocityTracker();
+ trackMovement(event);
+ mTimeAnimator.cancel(); // end any outstanding animations
+ if (mExpandedHeight == 0 || y > getContentHeight()) {
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ mTrackingPointer = event.getPointerId(newIndex);
+ final float newY = event.getY(newIndex);
+ mInitialTouchY = newY;
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float h = y - mInitialTouchY;
+ trackMovement(event);
+ if (scrolledToBottom) {
+ if (h < -mTouchSlop) {
+ mInitialOffsetOnTouch = mExpandedHeight;
+ mInitialTouchY = y;
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+ }
+
+ private void initVelocityTracker() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ }
+ mVelocityTracker = FlingTracker.obtain();
+ }
+
+ protected boolean isScrolledToBottom() {
+ return false;
+ }
+
+ protected float getContentHeight() {
+ return mExpandedHeight;
}
@Override
@@ -375,134 +590,6 @@
mHandleView = findViewById(R.id.handle);
loadDimens();
-
- if (DEBUG) logf("handle view: " + mHandleView);
- if (mHandleView != null) {
- mHandleView.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- int pointerIndex = event.findPointerIndex(mTrackingPointer);
- if (pointerIndex < 0) {
- pointerIndex = 0;
- mTrackingPointer = event.getPointerId(pointerIndex);
- }
- final float y = event.getY(pointerIndex);
- final float rawDelta = event.getRawY() - event.getY();
- final float rawY = y + rawDelta;
- if (DEBUG) logf("handle.onTouch: a=%s p=[%d,%d] y=%.1f rawY=%.1f off=%.1f",
- MotionEvent.actionToString(event.getAction()),
- mTrackingPointer, pointerIndex,
- y, rawY, mTouchOffset);
- PanelView.this.getLocationOnScreen(mAbsPos);
-
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- mTracking = true;
- mHandleView.setPressed(true);
- postInvalidate(); // catch the press state change
- mInitialTouchY = y;
- mVelocityTracker = FlingTracker.obtain();
- trackMovement(event);
- mTimeAnimator.cancel(); // end any outstanding animations
- mBar.onTrackingStarted(PanelView.this);
- mTouchOffset = (rawY - mAbsPos[1]) - mExpandedHeight;
- if (mExpandedHeight == 0) {
- mJustPeeked = true;
- runPeekAnimation();
- }
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- final int upPointer = event.getPointerId(event.getActionIndex());
- if (mTrackingPointer == upPointer) {
- // gesture is ongoing, find a new pointer to track
- final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
- final float newY = event.getY(newIndex);
- final float newRawY = newY + rawDelta;
- mTrackingPointer = event.getPointerId(newIndex);
- mTouchOffset = (newRawY - mAbsPos[1]) - mExpandedHeight;
- mInitialTouchY = newY;
- }
- break;
-
- case MotionEvent.ACTION_MOVE:
- final float h = rawY - mAbsPos[1] - mTouchOffset;
- if (h > mPeekHeight) {
- if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
- mPeekAnimator.cancel();
- }
- mJustPeeked = false;
- }
- if (!mJustPeeked) {
- PanelView.this.setExpandedHeightInternal(h);
- mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
- }
-
- trackMovement(event);
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mFinalTouchY = y;
- mTracking = false;
- mTrackingPointer = -1;
- mHandleView.setPressed(false);
- postInvalidate(); // catch the press state change
- mBar.onTrackingStopped(PanelView.this);
- trackMovement(event);
-
- float vel = 0, yVel = 0, xVel = 0;
- boolean negative = false;
-
- if (mVelocityTracker != null) {
- // the velocitytracker might be null if we got a bad input stream
- mVelocityTracker.computeCurrentVelocity(1000);
-
- yVel = mVelocityTracker.getYVelocity();
- negative = yVel < 0;
-
- xVel = mVelocityTracker.getXVelocity();
- if (xVel < 0) {
- xVel = -xVel;
- }
- if (xVel > mFlingGestureMaxXVelocityPx) {
- xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
- }
-
- vel = (float)Math.hypot(yVel, xVel);
- if (vel > mFlingGestureMaxOutputVelocityPx) {
- vel = mFlingGestureMaxOutputVelocityPx;
- }
-
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
-
- // if you've barely moved your finger, we treat the velocity as 0
- // preventing spurious flings due to touch screen jitter
- final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
- if (deltaY < mFlingGestureMinDistPx
- || vel < mFlingExpandMinVelocityPx
- ) {
- vel = 0;
- }
-
- if (negative) {
- vel = -vel;
- }
-
- if (DEBUG) logf("gesture: dy=%f vel=(%f,%f) vlinear=%f",
- deltaY,
- xVel, yVel,
- vel);
-
- fling(vel, true);
-
- break;
- }
- return true;
- }});
- }
}
public void fling(float vel, boolean always) {
@@ -543,19 +630,18 @@
// Did one of our children change size?
int newHeight = getMeasuredHeight();
- if (newHeight != mFullHeight) {
- mFullHeight = newHeight;
- // If the user isn't actively poking us, let's rubberband to the content
- if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
- && mExpandedHeight > 0 && mExpandedHeight != mFullHeight) {
- mExpandedHeight = mFullHeight;
- }
+ if (newHeight != mMaxPanelHeight) {
+ mMaxPanelHeight = newHeight;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- (int) mExpandedHeight, MeasureSpec.AT_MOST); // MeasureSpec.getMode(heightMeasureSpec));
+ getDesiredMeasureHeight(), MeasureSpec.AT_MOST);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
+ protected int getDesiredMeasureHeight() {
+ return (int) mExpandedHeight;
+ }
+
public void setExpandedHeight(float height) {
if (DEBUG) logf("setExpandedHeight(%.1f)", height);
@@ -569,8 +655,20 @@
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
- if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, mFullHeight);
+ if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom,
+ (int)mExpandedHeight, mMaxPanelHeight);
super.onLayout(changed, left, top, right, bottom);
+ requestPanelHeightUpdate();
+ }
+
+ protected void requestPanelHeightUpdate() {
+ float currentMaxPanelHeight = getMaxPanelHeight();
+
+ // If the user isn't actively poking us, let's update the height
+ if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
+ && mExpandedHeight > 0 && currentMaxPanelHeight != mExpandedHeight) {
+ setExpandedHeightInternal(currentMaxPanelHeight);
+ }
}
public void setExpandedHeightInternal(float h) {
@@ -583,7 +681,7 @@
h = 0;
}
- float fh = getFullHeight();
+ float fh = getMaxPanelHeight();
if (fh == 0) {
// Hmm, full height hasn't been computed yet
}
@@ -593,9 +691,13 @@
mExpandedHeight = h;
- if (DEBUG) logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
+ if (DEBUG) {
+ logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh,
+ mTracking ? "T" : "f", mRubberbanding ? "T" : "f");
+ }
- requestLayout();
+ onHeightUpdated(mExpandedHeight);
+
// FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
// lp.height = (int) mExpandedHeight;
// setLayoutParams(lp);
@@ -603,13 +705,23 @@
mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh);
}
- private float getFullHeight() {
- if (mFullHeight <= 0) {
- if (DEBUG) logf("Forcing measure() since fullHeight=" + mFullHeight);
+ protected void onHeightUpdated(float expandedHeight) {
+ requestLayout();
+ }
+
+ /**
+ * This returns the maximum height of the panel. Children should override this if their
+ * desired height is not the full height.
+ *
+ * @return the default implementation simply returns the maximum height.
+ */
+ protected int getMaxPanelHeight() {
+ if (mMaxPanelHeight <= 0) {
+ if (DEBUG) logf("Forcing measure() since mMaxPanelHeight=" + mMaxPanelHeight);
measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
}
- return mFullHeight;
+ return mMaxPanelHeight;
}
public void setExpandedFraction(float frac) {
@@ -621,7 +733,7 @@
}
frac = 0;
}
- setExpandedHeight(getFullHeight() * frac);
+ setExpandedHeight(getMaxPanelHeight() * frac);
}
public float getExpandedHeight() {
@@ -633,7 +745,7 @@
}
public boolean isFullyExpanded() {
- return mExpandedHeight >= getFullHeight();
+ return mExpandedHeight >= getMaxPanelHeight();
}
public boolean isFullyCollapsed() {
@@ -681,12 +793,12 @@
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(String.format("[PanelView(%s): expandedHeight=%f fullHeight=%f closing=%s"
+ pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%f closing=%s"
+ " tracking=%s rubberbanding=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s"
+ "]",
this.getClass().getSimpleName(),
getExpandedHeight(),
- getFullHeight(),
+ getMaxPanelHeight(),
mClosing?"T":"f",
mTracking?"T":"f",
mRubberbanding?"T":"f",
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 e7f96dc..4730f2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -86,7 +86,6 @@
import com.android.systemui.DemoMode;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
@@ -101,8 +100,6 @@
import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.NotificationRowLayout;
-import com.android.systemui.statusbar.policy.OnSizeChangedListener;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -172,7 +169,7 @@
Display mDisplay;
Point mCurrentDisplaySize = new Point();
private float mHeadsUpVerticalOffset;
- private int[] mPilePosition = new int[2];
+ private int[] mStackScrollerPosition = new int[2];
StatusBarWindowView mStatusBarWindow;
PhoneStatusBarView mStatusBarView;
@@ -198,7 +195,6 @@
// expanded notifications
NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
- View mNotificationScroller;
View mExpandedContents;
int mNotificationPanelGravity;
int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
@@ -350,6 +346,12 @@
}
}};
+ private Runnable mOnFlipRunnable;
+
+ public void setOnFlipRunnable(Runnable onFlipRunnable) {
+ mOnFlipRunnable = onFlipRunnable;
+ }
+
@Override
public void setZenMode(int mode) {
super.setZenMode(mode);
@@ -417,7 +419,8 @@
PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
mStatusBarView.setPanelHolder(holder);
- mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
+ mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
+ R.id.notification_panel);
mNotificationPanel.setStatusBar(this);
mNotificationPanelIsFullScreenWidth =
(mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
@@ -443,7 +446,8 @@
mHeadsUpNotificationView.setBar(this);
}
if (MULTIUSER_DEBUG) {
- mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(R.id.header_debug_info);
+ mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
+ R.id.header_debug_info);
mNotificationPanelDebugText.setVisibility(View.VISIBLE);
}
@@ -482,33 +486,11 @@
mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
mTickerView = mStatusBarView.findViewById(R.id.ticker);
- View legacyScrollView = mStatusBarWindow.findViewById(R.id.scroll);
- NotificationStackScrollLayout notificationStack
- = (NotificationStackScrollLayout) mStatusBarWindow
- .findViewById(R.id.notification_stack_scroller);
- if (ENABLE_NOTIFICATION_STACK) {
- notificationStack.setLongPressListener(getNotificationLongClicker());
- mPile = notificationStack;
- legacyScrollView.setVisibility(View.GONE);
+ mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
+ R.id.notification_stack_scroller);
+ mStackScroller.setLongPressListener(getNotificationLongClicker());
- // The scrollview and the notification container are unified now!
- // TODO: remove mNotificationScroller entirely once we fully switch to the new Layout
- mNotificationScroller = notificationStack;
- } else {
- mNotificationScroller = legacyScrollView;
- // less drawing during pulldowns
- mNotificationScroller.setVerticalScrollBarEnabled(false);
- NotificationRowLayout rowLayout
- = (NotificationRowLayout) mStatusBarWindow.findViewById(R.id.latestItems);
- rowLayout.setLayoutTransitionsEnabled(false);
- rowLayout.setLongPressListener(getNotificationLongClicker());
- mPile = rowLayout;
- notificationStack.setVisibility(View.GONE);
- }
-
- mExpandedContents = mPile; // was: expanded.findViewById(R.id.notificationLinearLayout);
-
-
+ mExpandedContents = mStackScroller;
mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
@@ -551,7 +533,8 @@
}
}
if (mHasFlipSettings) {
- mNotificationButton = (ImageView) mStatusBarWindow.findViewById(R.id.notification_button);
+ mNotificationButton = (ImageView) mStatusBarWindow.findViewById(
+ R.id.notification_button);
if (mNotificationButton != null) {
mNotificationButton.setOnClickListener(mNotificationButtonListener);
}
@@ -593,17 +576,18 @@
if (isAPhone) {
mEmergencyCallLabel =
(TextView) mStatusBarWindow.findViewById(R.id.emergency_calls_only);
- if (mEmergencyCallLabel != null) {
- mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
- mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) { }});
- mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- updateCarrierLabelVisibility(false);
- }});
- }
+ // TODO: Uncomment when correctly positioned
+// if (mEmergencyCallLabel != null) {
+// mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
+// mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
+// public void onClick(View v) { }});
+// mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+// @Override
+// public void onLayoutChange(View v, int left, int top, int right, int bottom,
+// int oldLeft, int oldTop, int oldRight, int oldBottom) {
+// updateCarrierLabelVisibility(false);
+// }});
+// }
}
mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
@@ -621,13 +605,12 @@
}
// set up the dynamic hide/show of the label
- if (!ENABLE_NOTIFICATION_STACK)
- ((NotificationRowLayout) mPile).setOnSizeChangedListener(new OnSizeChangedListener() {
- @Override
- public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
- updateCarrierLabelVisibility(false);
- }
- });
+ // TODO: uncomment, handle this for the Stack scroller aswell
+// ((NotificationRowLayout) mStackScroller)
+// .setOnSizeChangedListener(new OnSizeChangedListener() {
+// @Override
+// public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
+// updateCarrierLabelVisibility(false);
}
// Quick Settings (where available, some restrictions apply)
@@ -1066,7 +1049,7 @@
}
private void loadNotificationShade() {
- if (mPile == null) return;
+ if (mStackScroller == null) return;
int N = mNotificationData.size();
@@ -1078,8 +1061,8 @@
Entry ent = mNotificationData.get(N-i-1);
if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
- // TODO How do we want to badge notifcations from related users.
- if (!notificationIsForCurrentOrRelatedUser(ent.notification)) continue;
+ // TODO How do we want to badge notifcations from profiles.
+ if (!notificationIsForCurrentProfiles(ent.notification)) continue;
final int vis = ent.notification.getNotification().visibility;
if (vis != Notification.VISIBILITY_SECRET) {
@@ -1092,21 +1075,21 @@
}
ArrayList<View> toRemove = new ArrayList<View>();
- for (int i=0; i<mPile.getChildCount(); i++) {
- View child = mPile.getChildAt(i);
+ for (int i=0; i< mStackScroller.getChildCount(); i++) {
+ View child = mStackScroller.getChildAt(i);
if (!toShow.contains(child)) {
toRemove.add(child);
}
}
for (View remove : toRemove) {
- mPile.removeView(remove);
+ mStackScroller.removeView(remove);
}
for (int i=0; i<toShow.size(); i++) {
View v = toShow.get(i);
if (v.getParent() == null) {
- mPile.addView(v, i);
+ mStackScroller.addView(v, i);
}
}
@@ -1138,7 +1121,7 @@
Entry ent = mNotificationData.get(N-i-1);
if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
|| showNotificationEvenIfUnprovisioned(ent.notification))) continue;
- if (!notificationIsForCurrentOrRelatedUser(ent.notification)) continue;
+ if (!notificationIsForCurrentProfiles(ent.notification)) continue;
if (isLockscreenPublicMode()
&& ent.notification.getNotification().visibility
== Notification.VISIBILITY_SECRET
@@ -1178,15 +1161,17 @@
// The idea here is to only show the carrier label when there is enough room to see it,
// i.e. when there aren't enough notifications to fill the panel.
if (SPEW) {
- Log.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d",
- mPile.getHeight(), mNotificationScroller.getHeight(), mCarrierLabelHeight));
+ Log.d(TAG, String.format("stackScrollerh=%d scrollh=%d carrierh=%d",
+ mStackScroller.getHeight(), mStackScroller.getHeight(),
+ mCarrierLabelHeight));
}
final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null;
final boolean makeVisible =
!(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
- && mPile.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight)
- && mNotificationScroller.getVisibility() == View.VISIBLE;
+ && mStackScroller.getHeight() < (mNotificationPanel.getHeight()
+ - mCarrierLabelHeight - mNotificationHeaderHeight)
+ && mStackScroller.getVisibility() == View.VISIBLE;
if (force || mCarrierLabelVisible != makeVisible) {
mCarrierLabelVisible = makeVisible;
@@ -1229,7 +1214,7 @@
if (mHasFlipSettings
&& mFlipSettingsView != null
&& mFlipSettingsView.getVisibility() == View.VISIBLE
- && mNotificationScroller.getVisibility() != View.VISIBLE) {
+ && mStackScroller.getVisibility() != View.VISIBLE) {
// the flip settings panel is unequivocally showing; we should not be shown
mClearButton.setVisibility(View.INVISIBLE);
} else if (mClearButton.isShown()) {
@@ -1483,9 +1468,6 @@
}
mExpandedVisible = true;
- if (!ENABLE_NOTIFICATION_STACK) {
- ((NotificationRowLayout) mPile).setLayoutTransitionsEnabled(true);
- }
if (mNavigationBarView != null)
mNavigationBarView.setSlippery(true);
@@ -1600,7 +1582,7 @@
}
mNotificationPanel.expand();
- if (mHasFlipSettings && mNotificationScroller.getVisibility() != View.VISIBLE) {
+ if (mHasFlipSettings && mStackScroller.getVisibility() != View.VISIBLE) {
flipToNotifications();
}
@@ -1614,11 +1596,11 @@
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
- mNotificationScroller.setVisibility(View.VISIBLE);
+ mStackScroller.setVisibility(View.VISIBLE);
mScrollViewAnim = start(
startDelay(FLIP_DURATION_OUT,
interpolator(mDecelerateInterpolator,
- ObjectAnimator.ofFloat(mNotificationScroller, View.SCALE_X, 0f, 1f)
+ ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 0f, 1f)
.setDuration(FLIP_DURATION_IN)
)));
mFlipSettingsViewAnim = start(
@@ -1645,6 +1627,9 @@
updateCarrierLabelVisibility(false);
}
}, FLIP_DURATION - 150);
+ if (mOnFlipRunnable != null) {
+ mOnFlipRunnable.run();
+ }
}
@Override
@@ -1676,11 +1661,21 @@
mFlipSettingsView.setScaleX(1f);
mFlipSettingsView.setVisibility(View.VISIBLE);
mSettingsButton.setVisibility(View.GONE);
- mNotificationScroller.setVisibility(View.GONE);
- mNotificationScroller.setScaleX(0f);
+ mStackScroller.setVisibility(View.GONE);
+ mStackScroller.setScaleX(0f);
mNotificationButton.setVisibility(View.VISIBLE);
mNotificationButton.setAlpha(1f);
mClearButton.setVisibility(View.GONE);
+ if (mOnFlipRunnable != null) {
+ mOnFlipRunnable.run();
+ }
+ }
+
+ public boolean isFlippedToSettings() {
+ if (mFlipSettingsView != null) {
+ return mFlipSettingsView.getVisibility() == View.VISIBLE;
+ }
+ return false;
}
public void flipToSettings() {
@@ -1704,15 +1699,15 @@
mScrollViewAnim = start(
setVisibilityWhenDone(
interpolator(mAccelerateInterpolator,
- ObjectAnimator.ofFloat(mNotificationScroller, View.SCALE_X, 1f, 0f)
+ ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 1f, 0f)
)
.setDuration(FLIP_DURATION_OUT),
- mNotificationScroller, View.INVISIBLE));
+ mStackScroller, View.INVISIBLE));
mSettingsButtonAnim = start(
setVisibilityWhenDone(
ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
.setDuration(FLIP_DURATION),
- mNotificationScroller, View.INVISIBLE));
+ mStackScroller, View.INVISIBLE));
mNotificationButton.setVisibility(View.VISIBLE);
mNotificationButtonAnim = start(
ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
@@ -1727,6 +1722,9 @@
updateCarrierLabelVisibility(false);
}
}, FLIP_DURATION - 150);
+ if (mOnFlipRunnable != null) {
+ mOnFlipRunnable.run();
+ }
}
public void flipPanels() {
@@ -1766,8 +1764,8 @@
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
- mNotificationScroller.setScaleX(1f);
- mNotificationScroller.setVisibility(View.VISIBLE);
+ mStackScroller.setScaleX(1f);
+ mStackScroller.setVisibility(View.VISIBLE);
mSettingsButton.setAlpha(1f);
mSettingsButton.setVisibility(View.VISIBLE);
mNotificationPanel.setVisibility(View.GONE);
@@ -1777,9 +1775,6 @@
}
mExpandedVisible = false;
- if (!ENABLE_NOTIFICATION_STACK) {
- ((NotificationRowLayout) mPile).setLayoutTransitionsEnabled(false);
- }
if (mNavigationBarView != null)
mNavigationBarView.setSlippery(false);
visibilityChanged(false);
@@ -1806,53 +1801,6 @@
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
}
- /**
- * Enables or disables layers on the children of the notifications pile.
- *
- * When layers are enabled, this method attempts to enable layers for the minimal
- * number of children. Only children visible when the notification area is fully
- * expanded will receive a layer. The technique used in this method might cause
- * more children than necessary to get a layer (at most one extra child with the
- * current UI.)
- *
- * @param layerType {@link View#LAYER_TYPE_NONE} or {@link View#LAYER_TYPE_HARDWARE}
- */
- private void setPileLayers(int layerType) {
- final int count = mPile.getChildCount();
-
- switch (layerType) {
- case View.LAYER_TYPE_NONE:
- for (int i = 0; i < count; i++) {
- mPile.getChildAt(i).setLayerType(layerType, null);
- }
- break;
- case View.LAYER_TYPE_HARDWARE:
- final int[] location = new int[2];
- mNotificationPanel.getLocationInWindow(location);
-
- final int left = location[0];
- final int top = location[1];
- final int right = left + mNotificationPanel.getWidth();
- final int bottom = top + getExpandedViewMaxHeight();
-
- final Rect childBounds = new Rect();
-
- for (int i = 0; i < count; i++) {
- final View view = mPile.getChildAt(i);
- view.getLocationInWindow(location);
-
- childBounds.set(location[0], location[1],
- location[0] + view.getWidth(), location[1] + view.getHeight());
-
- if (childBounds.intersects(left, top, right, bottom)) {
- view.setLayerType(layerType, null);
- }
- }
-
- break;
- }
- }
-
public boolean interceptTouchEvent(MotionEvent event) {
if (DEBUG_GESTURES) {
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
@@ -2150,7 +2098,7 @@
if (!isDeviceProvisioned()) return;
// not for you
- if (!notificationIsForCurrentOrRelatedUser(n)) return;
+ if (!notificationIsForCurrentProfiles(n)) return;
// Show the ticker if one is requested. Also don't do this
// until status bar window is attached to the window manager,
@@ -2230,11 +2178,11 @@
pw.println(" mTicking=" + mTicking);
pw.println(" mTracking=" + mTracking);
pw.println(" mDisplayMetrics=" + mDisplayMetrics);
- pw.println(" mPile: " + viewInfo(mPile));
+ pw.println(" mStackScroller: " + viewInfo(mStackScroller));
pw.println(" mTickerView: " + viewInfo(mTickerView));
- pw.println(" mNotificationScroller: " + viewInfo(mNotificationScroller)
- + " scroll " + mNotificationScroller.getScrollX()
- + "," + mNotificationScroller.getScrollY());
+ pw.println(" mStackScroller: " + viewInfo(mStackScroller)
+ + " scroll " + mStackScroller.getScrollX()
+ + "," + mStackScroller.getScrollY());
}
pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
@@ -2409,8 +2357,8 @@
if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
- mPile.getLocationOnScreen(mPilePosition);
- mHeadsUpVerticalOffset = mPilePosition[1] - mNaturalBarHeight;
+ mStackScroller.getLocationOnScreen(mStackScrollerPosition);
+ mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight;
}
updateCarrierLabelVisibility(false);
@@ -2428,7 +2376,6 @@
private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
public void onClick(View v) {
- // TODO: Handle this better with notification stack scroller
synchronized (mNotificationData) {
mPostCollapseCleanup = new Runnable() {
@Override
@@ -2437,86 +2384,14 @@
Log.v(TAG, "running post-collapse cleanup");
}
try {
- if (!ENABLE_NOTIFICATION_STACK) {
- ((NotificationRowLayout) mPile).setViewRemoval(true);
- }
mBarService.onClearAllNotifications(mCurrentUserId);
} catch (Exception ex) { }
}
};
- if(ENABLE_NOTIFICATION_STACK) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- return;
- }
-
- // animate-swipe all dismissable notifications, then animate the shade closed
- int numChildren = mPile.getChildCount();
-
- int scrollTop = mNotificationScroller.getScrollY();
- int scrollBottom = scrollTop + mNotificationScroller.getHeight();
- final ArrayList<View> snapshot = new ArrayList<View>(numChildren);
- for (int i=0; i<numChildren; i++) {
- final View child = mPile.getChildAt(i);
- if (((SwipeHelper.Callback) mPile).canChildBeDismissed(child)
- && child.getBottom() > scrollTop && child.getTop() < scrollBottom) {
- snapshot.add(child);
- }
- }
- if (snapshot.isEmpty()) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- return;
- }
- new Thread(new Runnable() {
- @Override
- public void run() {
- // Decrease the delay for every row we animate to give the sense of
- // accelerating the swipes
- final int ROW_DELAY_DECREMENT = 10;
- int currentDelay = 140;
- int totalDelay = 0;
-
-
- if (!ENABLE_NOTIFICATION_STACK) {
- // Set the shade-animating state to avoid doing other work during
- // all of these animations. In particular, avoid layout and
- // redrawing when collapsing the shade.
- ((NotificationRowLayout) mPile).setViewRemoval(false);
- }
-
- View sampleView = snapshot.get(0);
- int width = sampleView.getWidth();
- final int dir = sampleView.isLayoutRtl() ? -1 : +1;
- final int velocity = dir * width * 8; // 1000/8 = 125 ms duration
- for (final View _v : snapshot) {
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (!ENABLE_NOTIFICATION_STACK) {
- ((NotificationRowLayout) mPile).dismissRowAnimated(
- _v, velocity);
- } else {
- ((NotificationStackScrollLayout) mPile).dismissRowAnimated(
- _v, velocity);
- }
- }
- }, totalDelay);
- currentDelay = Math.max(50, currentDelay - ROW_DELAY_DECREMENT);
- totalDelay += currentDelay;
- }
- // Delay the collapse animation until after all swipe animations have
- // finished. Provide some buffer because there may be some extra delay
- // before actually starting each swipe animation. Ideally, we'd
- // synchronize the end of those animations with the start of the collaps
- // exactly.
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- }
- }, totalDelay + 225);
- }
- }).start();
+ animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ return;
+ // TODO: Handle this better with notification stack scroller
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index aed9a71..d67f7cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -911,6 +911,7 @@
d.getWindow().setAttributes(lp);
}
};
+ v.setAutoActivate(true);
v.setAdapter(new ZenModeViewAdapter(mContext) {
@Override
public void configure() {
@@ -928,7 +929,6 @@
d.create();
d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
WindowManager.LayoutParams lp = d.getWindow().getAttributes();
- lp.horizontalMargin = 0;
lp.width = mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_dialog_width);
d.getWindow().setAttributes(lp);
d.show();
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 eeae081..a7121c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -24,13 +24,13 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewRootImpl;
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.stack.NotificationStackScrollLayout;
@@ -40,9 +40,8 @@
public static final boolean DEBUG = BaseStatusBar.DEBUG;
private ExpandHelper mExpandHelper;
- private ViewGroup latestItems;
+ private NotificationStackScrollLayout mStackScrollLayout;
private NotificationPanelView mNotificationPanel;
- private View mNotificationScroller;
PhoneStatusBar mService;
@@ -56,37 +55,15 @@
protected void onAttachedToWindow () {
super.onAttachedToWindow();
- ExpandHelper.ScrollAdapter scrollAdapter;
- if (BaseStatusBar.ENABLE_NOTIFICATION_STACK) {
- NotificationStackScrollLayout stackScrollLayout =
- (NotificationStackScrollLayout) findViewById(R.id.notification_stack_scroller);
-
- // ScrollView and notification container are unified in a single view now.
- latestItems = stackScrollLayout;
- scrollAdapter = stackScrollLayout;
- mNotificationScroller = stackScrollLayout;
- } else {
- latestItems = (ViewGroup) findViewById(R.id.latestItems);
- mNotificationScroller = findViewById(R.id.scroll);
- scrollAdapter = new ExpandHelper.ScrollAdapter() {
- @Override
- public boolean isScrolledToTop() {
- return mNotificationScroller.getScrollY() == 0;
- }
-
- @Override
- public View getHostView() {
- return mNotificationScroller;
- }
- };
- }
+ mStackScrollLayout = (NotificationStackScrollLayout) findViewById(
+ R.id.notification_stack_scroller);
mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel);
int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
- mExpandHelper = new ExpandHelper(getContext(), (ExpandHelper.Callback) latestItems,
+ mExpandHelper = new ExpandHelper(getContext(), mStackScrollLayout,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
- mExpandHelper.setScrollAdapter(scrollAdapter);
+ mExpandHelper.setScrollAdapter(mStackScrollLayout);
// We really need to be able to animate while window animations are going on
// so that activities may be started asynchronously from panel animations
@@ -113,7 +90,7 @@
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercept = false;
if (mNotificationPanel.isFullyExpanded()
- && mNotificationScroller.getVisibility() == View.VISIBLE) {
+ && mStackScrollLayout.getVisibility() == View.VISIBLE) {
intercept = mExpandHelper.onInterceptTouchEvent(ev);
}
if (!intercept) {
@@ -122,7 +99,7 @@
if (intercept) {
MotionEvent cancellation = MotionEvent.obtain(ev);
cancellation.setAction(MotionEvent.ACTION_CANCEL);
- latestItems.onInterceptTouchEvent(cancellation);
+ mStackScrollLayout.onInterceptTouchEvent(cancellation);
cancellation.recycle();
}
return intercept;
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 d1a9d57..49cf78b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -16,11 +16,8 @@
package com.android.systemui.statusbar.phone;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
@@ -39,14 +36,12 @@
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
-import com.android.systemui.R;
import com.android.systemui.statusbar.phone.ZenModeView.Adapter.ExitCondition;
public class ZenModeView extends RelativeLayout {
@@ -63,20 +58,21 @@
private static final long DURATION = new ValueAnimator().getDuration();
private static final long PAGER_DURATION = DURATION / 2;
- private static final float BOUNCE_SCALE = 0.8f;
private static final long CLOSE_DELAY = 600;
+ private static final long AUTO_ACTIVATE_DELAY = 100;
private final Context mContext;
- private final Paint mPathPaint;
- private final ImageView mSettingsButton;
private final TextView mModeText;
private final Switch mModeSwitch;
private final View mDivider;
private final UntilPager mUntilPager;
private final ProgressDots mProgressDots;
+ private final View mDivider2;
+ private final TextView mSettingsButton;
private Adapter mAdapter;
private boolean mInit;
+ private boolean mAutoActivate;
public ZenModeView(Context context) {
this(context, null);
@@ -90,29 +86,9 @@
final int iconSize = mContext.getResources()
.getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width);
final int topRowSize = iconSize * 2 / 3;
- final int p = topRowSize / 7;
+ final int p = topRowSize / 3;
- mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPathPaint.setStyle(Paint.Style.STROKE);
- mPathPaint.setColor(GRAY);
- mPathPaint.setStrokeWidth(p / 2);
-
- mSettingsButton = new ImageView(mContext);
- mSettingsButton.setPadding(p, p, p, p);
- mSettingsButton.setImageResource(R.drawable.ic_notify_settings_normal);
- LayoutParams lp = new LayoutParams(topRowSize, topRowSize);
- lp.topMargin = p;
- lp.leftMargin = p;
- addView(mSettingsButton, lp);
- mSettingsButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mAdapter != null) {
- mAdapter.configure();
- }
- bounce(mSettingsButton, null);
- }
- });
+ LayoutParams lp = null;
mModeText = new TextView(mContext);
mModeText.setText(MODE_LABEL);
@@ -120,11 +96,10 @@
mModeText.setTextColor(GRAY);
mModeText.setTypeface(CONDENSED);
mModeText.setAllCaps(true);
- mModeText.setGravity(Gravity.CENTER);
- mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.1f);
+ mModeText.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
+ mModeText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mModeText.getTextSize() * 1.5f);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
- lp.topMargin = p;
- lp.addRule(CENTER_HORIZONTAL);
+ lp.leftMargin = p;
addView(mModeText, lp);
mModeSwitch = new Switch(mContext);
@@ -132,6 +107,7 @@
mModeSwitch.setSwitchTypeface(CONDENSED);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize);
lp.topMargin = p;
+ lp.rightMargin = p;
lp.addRule(ALIGN_PARENT_RIGHT);
lp.addRule(ALIGN_BASELINE, mModeText.getId());
addView(mModeSwitch, lp);
@@ -154,11 +130,10 @@
mDivider.setBackgroundColor(GRAY);
lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
lp.addRule(BELOW, mModeText.getId());
- lp.topMargin = p;
- lp.bottomMargin = p * 2;
+ lp.bottomMargin = p;
addView(mDivider, lp);
- mUntilPager = new UntilPager(mContext, mPathPaint, iconSize * 3 / 4);
+ mUntilPager = new UntilPager(mContext, iconSize * 3 / 4);
mUntilPager.setId(android.R.id.tabhost);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.leftMargin = lp.rightMargin = iconSize / 2;
@@ -167,10 +142,41 @@
addView(mUntilPager, lp);
mProgressDots = new ProgressDots(mContext, iconSize / 5);
+ mProgressDots.setId(android.R.id.progress);
lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.addRule(CENTER_HORIZONTAL);
lp.addRule(BELOW, mUntilPager.getId());
addView(mProgressDots, lp);
+
+ mDivider2 = new View(mContext);
+ mDivider2.setId(android.R.id.widget_frame);
+ mDivider2.setBackgroundColor(GRAY);
+ lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2);
+ lp.addRule(BELOW, mProgressDots.getId());
+ addView(mDivider2, lp);
+
+ mSettingsButton = new TextView(mContext);
+ mSettingsButton.setTypeface(CONDENSED);
+ mSettingsButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSettingsButton.getTextSize() * 1.3f);
+ mSettingsButton.setPadding(p, p, p, p);
+ mSettingsButton.setText("More settings...");
+ lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ lp.addRule(BELOW, mDivider2.getId());
+ addView(mSettingsButton, lp);
+ mSettingsButton.setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ mSettingsButton.setBackgroundColor(DARK_GRAY);
+ } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ mSettingsButton.setBackground(null);
+ if (mAdapter != null) {
+ mAdapter.configure();
+ }
+ }
+ return true;
+ }
+ });
}
public void setAdapter(Adapter adapter) {
@@ -189,6 +195,27 @@
updateState(false);
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mAutoActivate) {
+ mAutoActivate = false;
+ postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (!mModeSwitch.isChecked()) {
+ mInit = false;
+ mModeSwitch.setChecked(true);
+ }
+ }
+ }, AUTO_ACTIVATE_DELAY);
+ }
+ }
+
+ public void setAutoActivate(boolean value) {
+ mAutoActivate = value;
+ }
+
private void updateState(boolean animate) {
mUntilPager.updateState();
mModeSwitch.setChecked(mAdapter.getMode());
@@ -199,23 +226,6 @@
Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
}
- private static void bounce(final View v, final Runnable midBounce) {
- v.animate().scaleX(BOUNCE_SCALE).scaleY(BOUNCE_SCALE).setDuration(DURATION / 3)
- .setListener(new AnimatorListenerAdapter() {
- private boolean mFired;
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mFired) {
- mFired = true;
- if (midBounce != null) {
- midBounce.run();
- }
- v.animate().scaleX(1).scaleY(1).setListener(null).start();
- }
- }
- }).start();
- }
-
private final class UntilView extends FrameLayout {
private static final boolean SUPPORT_LINKS = false;
@@ -223,7 +233,7 @@
public UntilView(Context context) {
super(context);
mText = new TextView(mContext);
- mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.2f);
+ mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText.getTextSize() * 1.3f);
mText.setTypeface(CONDENSED);
mText.setTextColor(GRAY);
mText.setGravity(Gravity.CENTER);
@@ -284,7 +294,7 @@
private int mCurrent;
private float mDownX;
- public UntilPager(Context context, Paint pathPaint, int iconSize) {
+ public UntilPager(Context context, int iconSize) {
super(context);
mViews = new UntilView[3];
for (int i = 0; i < mViews.length; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ScrollAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ScrollAdapter.java
new file mode 100644
index 0000000..f35e22d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ScrollAdapter.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.policy;
+
+import android.view.View;
+
+/**
+ * A scroll adapter which can be queried for meta information about the scroll state
+ */
+public interface ScrollAdapter {
+
+ /**
+ * @return Whether the view returned by {@link #getHostView()} is scrolled to the top
+ */
+ public boolean isScrolledToTop();
+
+ /**
+ * @return Whether the view returned by {@link #getHostView()} is scrolled to the bottom
+ */
+ public boolean isScrolledToBottom();
+
+ /**
+ * @return The view in which the scrolling is performed
+ */
+ public View getHostView();
+}
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 ff8ea405..04b7f53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -22,6 +22,7 @@
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Paint;
+
import android.util.AttributeSet;
import android.util.Log;
@@ -37,12 +38,14 @@
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
+import com.android.systemui.statusbar.policy.ScrollAdapter;
/**
* 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, ExpandHelper.ScrollAdapter {
+ implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter {
private static final String TAG = "NotificationStackScrollLayout";
private static final boolean DEBUG = false;
@@ -53,7 +56,7 @@
private static final int INVALID_POINTER = -1;
private SwipeHelper mSwipeHelper;
- private boolean mAllowScrolling = true;
+ private boolean mSwipingInProgress = true;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private int mOwnScrollY;
private int mMaxLayoutHeight;
@@ -86,7 +89,9 @@
/**
* The current State this Layout is in
*/
- private StackScrollState mCurrentStackScrollState;
+ private final StackScrollState mCurrentStackScrollState = new StackScrollState(this);
+
+ private OnChildLocationsChangedListener mListener;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -153,7 +158,6 @@
// currently the padding is in the elements themself
mPaddingBetweenElements = 0;
mStackScrollAlgorithm = new StackScrollAlgorithm(context);
- mCurrentStackScrollState = null;
}
@Override
@@ -188,6 +192,24 @@
updateContentHeight();
}
+ public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Returns the location the given child is currently rendered at.
+ *
+ * @param child the child to get the location for
+ * @return one of {@link ViewState}'s <code>LOCATION_*</code> constants
+ */
+ public int getChildLocation(View child) {
+ ViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
+ if (childViewState == null) {
+ return ViewState.LOCATION_UNKNOWN;
+ }
+ return childViewState.location;
+ }
+
private void setMaxLayoutHeight(int maxLayoutHeight) {
mMaxLayoutHeight = maxLayoutHeight;
updateAlgorithmHeight();
@@ -203,13 +225,13 @@
*/
private void updateChildren() {
if (!isCurrentlyAnimating()) {
- if (mCurrentStackScrollState == null) {
- mCurrentStackScrollState = new StackScrollState(this);
- }
mCurrentStackScrollState.setScrollY(mOwnScrollY);
mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
mCurrentStackScrollState.apply();
mOwnScrollY = mCurrentStackScrollState.getScrollY();
+ if (mListener != null) {
+ mListener.onChildLocationsChanged(this);
+ }
} else {
// TODO: handle animation
}
@@ -258,7 +280,7 @@
}
/**
- * Get the current height of the view. This is at most the size of the view given by a the
+ * Get the current height of the view. This is at most the msize of the view given by a the
* layout but it can also be made smaller by setting {@link #mCurrentStackHeight}
*
* @return either the layout height or the externally defined height, whichever is smaller
@@ -267,6 +289,14 @@
return Math.min(mMaxLayoutHeight, mCurrentStackHeight);
}
+ public int getItemHeight() {
+ return mCollapsedSize;
+ }
+
+ public int getBottomStackPeekSize() {
+ return mBottomStackPeekSize;
+ }
+
public void setLongPressListener(View.OnLongClickListener listener) {
mSwipeHelper.setLongPressListener(listener);
}
@@ -277,15 +307,15 @@
if (veto != null && veto.getVisibility() != View.GONE) {
veto.performClick();
}
- allowScrolling(true);
+ setSwipingInProgress(false);
}
public void onBeginDrag(View v) {
- allowScrolling(false);
+ setSwipingInProgress(true);
}
public void onDragCancelled(View v) {
- allowScrolling(true);
+ setSwipingInProgress(false);
}
public View getChildAtPosition(MotionEvent ev) {
@@ -344,8 +374,11 @@
return (veto != null && veto.getVisibility() != View.GONE);
}
- private void allowScrolling(boolean allow) {
- mAllowScrolling = allow;
+ private void setSwipingInProgress(boolean isSwiped) {
+ mSwipingInProgress = isSwiped;
+ if(isSwiped) {
+ requestDisallowInterceptTouchEvent(true);
+ }
}
@Override
@@ -365,7 +398,7 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean scrollerWantsIt = false;
- if (mAllowScrolling) {
+ if (!mSwipingInProgress) {
scrollerWantsIt = onScrollTouch(ev);
}
boolean horizontalSwipeWantsIt = false;
@@ -388,12 +421,6 @@
}
boolean isBeingDragged = !mScroller.isFinished();
setIsBeingDragged(isBeingDragged);
- if (isBeingDragged) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- }
/*
* If being flinged and user touches, stop the fling. isFinished
@@ -418,10 +445,6 @@
final int y = (int) ev.getY(activePointerIndex);
int deltaY = mLastMotionY - y;
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
setIsBeingDragged(true);
if (deltaY > 0) {
deltaY -= mTouchSlop;
@@ -621,7 +644,7 @@
if (getChildCount() > 0) {
int contentHeight = getContentHeight();
scrollRange = Math.max(0,
- contentHeight - mMaxLayoutHeight + mCollapsedSize);
+ contentHeight - mMaxLayoutHeight + mBottomStackPeekSize);
}
return scrollRange;
}
@@ -676,7 +699,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean scrollWantsIt = false;
- if (mAllowScrolling) {
+ if (!mSwipingInProgress) {
scrollWantsIt = onInterceptTouchEventScroll(ev);
}
boolean swipeWantsIt = false;
@@ -742,10 +765,6 @@
mLastMotionY = y;
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
- final ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
}
break;
}
@@ -802,6 +821,7 @@
private void setIsBeingDragged(boolean isDragged) {
mIsBeingDragged = isDragged;
if (isDragged) {
+ requestDisallowInterceptTouchEvent(true);
mSwipeHelper.removeLongPressCallback();
}
}
@@ -820,7 +840,23 @@
}
@Override
+ public boolean isScrolledToBottom() {
+ return mOwnScrollY >= getScrollRange();
+ }
+
+ @Override
public View getHostView() {
return this;
}
+
+ public int getEmptyBottomMargin() {
+ return Math.max(getHeight() - mContentHeight, 0);
+ }
+
+ /**
+ * A listener that is notified when some child locations might have changed.
+ */
+ public interface OnChildLocationsChangedListener {
+ public void onChildLocationsChanged(NotificationStackScrollLayout stackScrollLayout);
+ }
}
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 9db4e77..4745f3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.stack;
import android.content.Context;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.R;
@@ -28,6 +29,8 @@
*/
public class StackScrollAlgorithm {
+ private static final String LOG_TAG = "StackScrollAlgorithm";
+
private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
private static final int MAX_ITEMS_IN_TOP_STACK = 3;
@@ -83,7 +86,7 @@
// First we reset the view states to their default values.
resultState.resetViewStates();
- // The first element is always in there so it's initialized with 1.0f.
+ // The first element is always in there so it's initialized with 1.0f;
algorithmState.itemsInTopStack = 1.0f;
algorithmState.partialInTop = 0.0f;
algorithmState.lastTopStackIndex = 0;
@@ -99,7 +102,7 @@
// Phase 3:
updateZValuesForState(resultState, algorithmState);
- // Write the algorithm state to the result.
+ // write the algorithm state to the result
resultState.setScrollY(algorithmState.scrollY);
}
@@ -130,6 +133,7 @@
View child = hostView.getChildAt(i);
StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
childViewState.yTranslation = currentYPosition;
+ childViewState.location = StackScrollState.ViewState.LOCATION_UNKNOWN;
int childHeight = child.getHeight();
// The y position after this element
float nextYPosition = currentYPosition + childHeight + mPaddingBetweenElements;
@@ -143,12 +147,12 @@
nextYPosition = updateStateForTopStackChild(algorithmState,
numberOfElementsCompletelyIn,
i, childViewState);
-
} else if (i == algorithmState.lastTopStackIndex) {
// Case 2:
// First element of regular scrollview comes next, so the position is just the
// scrolling position
- nextYPosition = scrollOffset;
+ nextYPosition = Math.min(scrollOffset, transitioningPositionStart);
+ childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
} else if (nextYPosition >= transitioningPositionStart) {
if (currentYPosition >= transitioningPositionStart) {
// Case 3:
@@ -156,8 +160,6 @@
// bottom of the screen so we are fully in the bottom stack
nextYPosition = updateStateForChildFullyInBottomStack(algorithmState,
transitioningPositionStart, childViewState, childHeight);
-
-
} else {
// Case 4:
// According to the regular scroll view we are currently translating out of /
@@ -167,7 +169,18 @@
currentYPosition, childViewState,
childHeight, nextYPosition);
}
+ } else {
+ childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
}
+ // The first card is always rendered.
+ if (i == 0) {
+ childViewState.alpha = 1.0f;
+ childViewState.location = StackScrollState.ViewState.LOCATION_FIRST_CARD;
+ }
+ if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
+ Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
+ }
+ nextYPosition = Math.max(0, nextYPosition);
currentYPosition = nextYPosition;
yPositionInScrollView = yPositionInScrollViewAfterElement;
}
@@ -192,6 +205,8 @@
if (childHeight != (int) newSize) {
childViewState.height = (int) newSize;
}
+ childViewState.location = StackScrollState.ViewState.LOCATION_MAIN_AREA;
+
return nextYPosition;
}
@@ -206,6 +221,7 @@
nextYPosition = transitioningPositionStart
+ mBottomStackIndentationFunctor.getValue(
algorithmState.itemsInBottomStack);
+ childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_PEEKING;
} else {
// we are fully inside the stack
if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
@@ -214,6 +230,7 @@
> MAX_ITEMS_IN_BOTTOM_STACK + 1) {
childViewState.alpha = 1.0f - algorithmState.partialInBottom;
}
+ childViewState.location = StackScrollState.ViewState.LOCATION_BOTTOM_STACK_HIDDEN;
nextYPosition = transitioningPositionStart + mBottomStackPeekSize;
}
// TODO: only temporarily collapse
@@ -237,14 +254,18 @@
nextYPosition = mCollapsedSize + mPaddingBetweenElements -
mTopStackIndentationFunctor.getValue(
algorithmState.itemsInTopStack - i - 1);
- if (paddedIndex == 0 && i != 0) {
+ nextYPosition = Math.min(nextYPosition, mLayoutHeight - mCollapsedSize
+ - mBottomStackPeekSize);
+ if (paddedIndex == 0) {
childViewState.alpha = 1.0f - algorithmState.partialInTop;
+ childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
+ } else {
+ childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
}
} else {
- // We are hidden behind the top card and faded out, so we can hide ourselfs
- if (i != 0) {
- childViewState.alpha = 0.0f;
- }
+ // We are hidden behind the top card and faded out, so we can hide ourselves.
+ childViewState.alpha = 0.0f;
+ childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
}
return nextYPosition;
}
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 f72a52f..881730a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -45,7 +45,7 @@
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
- mStateMap = new HashMap<View, ViewState>(mHostView.getChildCount());
+ mStateMap = new HashMap<View, ViewState>();
}
public ViewGroup getHostView() {
@@ -144,10 +144,28 @@
}
- public class ViewState {
+ public static class ViewState {
+
+ // These are flags such that we can create masks for filtering.
+
+ public static final int LOCATION_UNKNOWN = 0x00;
+ public static final int LOCATION_FIRST_CARD = 0x01;
+ public static final int LOCATION_TOP_STACK_HIDDEN = 0x02;
+ public static final int LOCATION_TOP_STACK_PEEKING = 0x04;
+ public static final int LOCATION_MAIN_AREA = 0x08;
+ public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10;
+ public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20;
+
float alpha;
float yTranslation;
float zTranslation;
int height;
+
+ /**
+ * The location this view is currently rendered at.
+ *
+ * <p>See <code>LOCATION_</code> flags.</p>
+ */
+ int location;
}
}
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index ef640d5..03d920a 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -1,10 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.vpndialogs">
<application android:label="VpnDialogs"
android:allowBackup="false" >
<activity android:name=".ConfirmDialog"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert">
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -12,7 +30,7 @@
</activity>
<activity android:name=".ManageDialog"
- android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+ android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/packages/WallpaperCropper/AndroidManifest.xml b/packages/WallpaperCropper/AndroidManifest.xml
index 27755bd..81d1085 100644
--- a/packages/WallpaperCropper/AndroidManifest.xml
+++ b/packages/WallpaperCropper/AndroidManifest.xml
@@ -1,3 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.wallpapercropper" >
<uses-permission android:name="android.permission.SET_WALLPAPER" />
diff --git a/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
index 97d7001..cf78989 100644
--- a/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
+++ b/packages/WallpaperCropper/res/layout/wallpaper_cropper.xml
@@ -28,7 +28,7 @@
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/loading"
- style="@android:style/Widget.Holo.ProgressBar.Large"
+ style="@android:style/Widget.DeviceDefault.Light.ProgressBar.Large"
android:visibility="invisible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
index 2b63fe0..b27a387 100644
--- a/packages/WallpaperCropper/res/values/styles.xml
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -15,13 +15,13 @@
-->
<resources>
- <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Holo">
+ <style name="Theme.WallpaperCropper" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowActionBarOverlay">true</item>
</style>
- <style name="WallpaperCropperActionBar" parent="android:style/Widget.Holo.ActionBar">
+ <style name="WallpaperCropperActionBar" parent="android:style/Widget.DeviceDefault.Light.ActionBar">
<item name="android:displayOptions">showCustom</item>
<item name="android:background">#88000000</item>
</style>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a65f677..f1db904 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -145,6 +145,7 @@
TypedValue mFixedWidthMinor;
TypedValue mFixedHeightMajor;
TypedValue mFixedHeightMinor;
+ TypedValue mOutsetBottom;
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
@@ -2370,7 +2371,6 @@
} else {
h = 0;
}
-
if (h > 0) {
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -2379,6 +2379,15 @@
}
}
+ if (mOutsetBottom != null) {
+ int mode = MeasureSpec.getMode(heightMeasureSpec);
+ if (mode != MeasureSpec.UNSPECIFIED) {
+ int outset = (int) mOutsetBottom.getDimension(metrics);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode);
+ }
+ }
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
@@ -2993,6 +3002,10 @@
if (a.getBoolean(com.android.internal.R.styleable.Window_windowContentTransitions, false)) {
requestFeature(FEATURE_CONTENT_TRANSITIONS);
}
+ if (a.hasValue(com.android.internal.R.styleable.Window_windowOutsetBottom)) {
+ if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
+ a.getValue(com.android.internal.R.styleable.Window_windowOutsetBottom, mOutsetBottom);
+ }
final Context context = getContext();
final int targetSdk = context.getApplicationInfo().targetSdkVersion;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ededbb2..ccdacea 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3417,8 +3417,9 @@
}
final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
+ final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
if (appWindow) {
- if (showWhenLocked) {
+ if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) {
mAppsToBeHidden.remove(win.getAppToken());
} else {
mAppsToBeHidden.add(win.getAppToken());
@@ -3435,8 +3436,7 @@
mHideLockScreen = true;
mForceStatusBarFromKeyguard = false;
}
- if ((fl & FLAG_DISMISS_KEYGUARD) != 0
- && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
+ if (dismissKeyguard && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
if (DEBUG_LAYOUT) Slog.v(TAG,
"Setting mDismissKeyguard true by win " + win);
mDismissKeyguard = mWinDismissingKeyguard == win ?
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 1a1512f..57c2f92 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -2035,6 +2035,7 @@
BackupState mCurrentState;
// carried information about the current in-flight operation
+ IBackupAgent mAgentBinder;
PackageInfo mCurrentPackage;
File mSavedStateName;
File mBackupDataName;
@@ -2097,6 +2098,7 @@
addBackupTrace(b.toString());
}
+ mAgentBinder = null;
mStatus = BackupConstants.TRANSPORT_OK;
// Sanity check: if the queue is empty we have no work to do.
@@ -2228,6 +2230,7 @@
IApplicationThread.BACKUP_MODE_INCREMENTAL);
addBackupTrace("agent bound; a? = " + (agent != null));
if (agent != null) {
+ mAgentBinder = agent;
mStatus = invokeAgentForBackup(request.packageName, agent, mTransport);
// at this point we'll either get a completion callback from the
// agent, or a timeout message on the main handler. either way, we're
@@ -2253,6 +2256,7 @@
// That means we need to direct to the next state ourselves.
if (mStatus != BackupConstants.TRANSPORT_OK) {
BackupState nextState = BackupState.RUNNING_QUEUE;
+ mAgentBinder = null;
// An agent-level failure means we reenqueue this one agent for
// a later retry, but otherwise proceed normally.
@@ -2274,6 +2278,7 @@
executeNextState(nextState);
} else {
+ // success case
addBackupTrace("expecting completion/timeout callback");
}
}
@@ -2402,14 +2407,52 @@
return BackupConstants.TRANSPORT_OK;
}
+ public void failAgent(IBackupAgent agent, String message) {
+ try {
+ agent.fail(message);
+ } catch (Exception e) {
+ Slog.w(TAG, "Error conveying failure to " + mCurrentPackage.packageName);
+ }
+ }
+
@Override
public void operationComplete() {
- // Okay, the agent successfully reported back to us. The next thing we do is
- // push the app widget state for the app, if any.
+ // Okay, the agent successfully reported back to us!
final String pkgName = mCurrentPackage.packageName;
final long filepos = mBackupDataName.length();
FileDescriptor fd = mBackupData.getFileDescriptor();
try {
+ // If it's a 3rd party app, see whether they wrote any protected keys
+ // and complain mightily if they are attempting shenanigans.
+ if (mCurrentPackage.applicationInfo != null &&
+ (mCurrentPackage.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ ParcelFileDescriptor readFd = ParcelFileDescriptor.open(mBackupDataName,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ BackupDataInput in = new BackupDataInput(readFd.getFileDescriptor());
+ try {
+ while (in.readNextHeader()) {
+ final String key = in.getKey();
+ if (key != null && key.charAt(0) >= 0xff00) {
+ // Not okay: crash them and bail.
+ failAgent(mAgentBinder, "Illegal backup key: " + key);
+ addBackupTrace("illegal key " + key + " from " + pkgName);
+ EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
+ "bad key");
+ mBackupHandler.removeMessages(MSG_TIMEOUT);
+ agentErrorCleanup();
+ // agentErrorCleanup() implicitly executes next state properly
+ return;
+ }
+ in.skipEntityData();
+ }
+ } finally {
+ if (readFd != null) {
+ readFd.close();
+ }
+ }
+ }
+
+ // Piggyback the widget state payload, if any
BackupDataOutput out = new BackupDataOutput(fd);
byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName,
UserHandle.USER_OWNER);
@@ -2434,8 +2477,7 @@
}
}
- // Spin the data off to the
- // transport and proceed with the next stage.
+ // Spin the data off to the transport and proceed with the next stage.
if (MORE_DEBUG) Slog.v(TAG, "operationComplete(): sending data to transport for "
+ pkgName);
mBackupHandler.removeMessages(MSG_TIMEOUT);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 5fb6405..e69c9a4 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -445,7 +445,7 @@
return;
} else if (Intent.ACTION_USER_ADDED.equals(action)
|| Intent.ACTION_USER_REMOVED.equals(action)) {
- updateRelatedUserIds();
+ updateCurrentProfileIds();
return;
} else {
Slog.w(TAG, "Unexpected intent " + intent);
@@ -689,7 +689,7 @@
// mSettings should be created before buildInputMethodListLocked
mSettings = new InputMethodSettings(
mRes, context.getContentResolver(), mMethodMap, mMethodList, userId);
- updateRelatedUserIds();
+ updateCurrentProfileIds();
mFileManager = new InputMethodFileManager(mMethodMap, userId);
mSwitchingController = new InputMethodSubtypeSwitchingController(mSettings);
mSwitchingController.resetCircularListLocked(context);
@@ -805,7 +805,7 @@
private void switchUserLocked(int newUserId) {
mSettings.setCurrentUserId(newUserId);
- updateRelatedUserIds();
+ updateCurrentProfileIds();
// InputMethodFileManager should be reset when the user is changed
mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
final String defaultImiId = mSettings.getSelectedInputMethod();
@@ -826,14 +826,14 @@
}
}
- void updateRelatedUserIds() {
- List<UserInfo> relatedUsers =
- UserManager.get(mContext).getRelatedUsers(mSettings.getCurrentUserId());
- int[] relatedUserIds = new int[relatedUsers.size()]; // relatedUsers will not be null
- for (int i = 0; i < relatedUserIds.length; i++) {
- relatedUserIds[i] = relatedUsers.get(i).id;
+ void updateCurrentProfileIds() {
+ List<UserInfo> profiles =
+ UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId());
+ int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
+ for (int i = 0; i < currentProfileIds.length; i++) {
+ currentProfileIds[i] = profiles.get(i).id;
}
- mSettings.setRelatedUserIds(relatedUserIds);
+ mSettings.setCurrentProfileIds(currentProfileIds);
}
@Override
@@ -931,7 +931,7 @@
+ mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()
+ InputMethodUtils.getApiCallStack());
}
- if (uid == Process.SYSTEM_UID || mSettings.isRelatedToOrCurrentUser(userId)) {
+ if (uid == Process.SYSTEM_UID || mSettings.isCurrentProfile(userId)) {
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 004d4fe..e9be1d7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -43,6 +43,7 @@
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessCpuTracker;
import com.android.internal.os.TransferPipe;
+import com.android.internal.os.Zygote;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.MemInfoReader;
@@ -61,8 +62,6 @@
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import dalvik.system.Zygote;
-
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -1020,7 +1019,7 @@
final ActivityThread mSystemThread;
int mCurrentUserId = 0;
- int[] mRelatedUserIds = new int[0]; // Accessed by ActivityStack
+ int[] mCurrentProfileIds = new int[] {UserHandle.USER_OWNER}; // Accessed by ActivityStack
private UserManagerService mUserManager;
private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1079,7 +1078,7 @@
static final int IMMERSIVE_MODE_LOCK_MSG = 37;
static final int PERSIST_URI_GRANTS_MSG = 38;
static final int REQUEST_ALL_PSS_MSG = 39;
- static final int START_RELATED_USERS_MSG = 40;
+ static final int START_PROFILES_MSG = 40;
static final int UPDATE_TIME = 41;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -1694,9 +1693,9 @@
requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
break;
}
- case START_RELATED_USERS_MSG: {
+ case START_PROFILES_MSG: {
synchronized (ActivityManagerService.this) {
- startRelatedUsersLocked();
+ startProfilesLocked();
}
break;
}
@@ -5209,7 +5208,7 @@
userId);
}
}
- scheduleStartRelatedUsersLocked();
+ scheduleStartProfilesLocked();
}
}
}
@@ -6864,8 +6863,8 @@
maxNum < N ? maxNum : N);
final Set<Integer> includedUsers;
- if ((flags & ActivityManager.RECENT_INCLUDE_RELATED) != 0) {
- includedUsers = getRelatedUsersLocked(userId);
+ if ((flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0) {
+ includedUsers = getProfileIdsLocked(userId);
} else {
includedUsers = new HashSet<Integer>();
}
@@ -6900,18 +6899,27 @@
rti.stackId = tr.stack.mStackId;
rti.userId = tr.userId;
+ // Traverse upwards looking for any break between main task activities and
+ // utility activities.
final ArrayList<ActivityRecord> activities = tr.mActivities;
- int numSet = 0;
- for (int activityNdx = activities.size() - 1; activityNdx >= 0 && numSet < 2;
- --activityNdx) {
+ int activityNdx;
+ final int numActivities = activities.size();
+ for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
+ ++activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- if (rti.activityLabel == null && r.recentsLabel != null) {
- rti.activityLabel = r.recentsLabel;
- ++numSet;
+ if (r.intent != null &&
+ (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
+ != 0) {
+ break;
}
- if (rti.activityIcon == null && r.recentsIcon != null) {
- rti.activityIcon = r.recentsIcon;
- ++numSet;
+ }
+ // 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;
}
}
@@ -6980,21 +6988,13 @@
}
@Override
- public void setRecentsLabel(IBinder token, CharSequence recentsLabel) {
+ public void setActivityLabelAndIcon(IBinder token, CharSequence activityLabel,
+ Bitmap activityIcon) {
synchronized (this) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.recentsLabel = recentsLabel.toString();
- }
- }
- }
-
- @Override
- public void setRecentsIcon(IBinder token, Bitmap recentsIcon) {
- synchronized (this) {
- ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r != null) {
- r.recentsIcon = recentsIcon;
+ r.activityLabel = activityLabel.toString();
+ r.activityIcon = activityIcon;
}
}
}
@@ -16318,19 +16318,19 @@
* user switch happens or when a new related user is started in the
* background.
*/
- private void updateRelatedUserIdsLocked() {
- final List<UserInfo> relatedUsers = getUserManagerLocked().getRelatedUsers(mCurrentUserId);
- int[] relatedUserIds = new int[relatedUsers.size()]; // relatedUsers will not be null
- for (int i = 0; i < relatedUserIds.length; i++) {
- relatedUserIds[i] = relatedUsers.get(i).id;
+ private void updateCurrentProfileIdsLocked() {
+ final List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+ int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
+ for (int i = 0; i < currentProfileIds.length; i++) {
+ currentProfileIds[i] = profiles.get(i).id;
}
- mRelatedUserIds = relatedUserIds;
+ mCurrentProfileIds = currentProfileIds;
}
- private Set getRelatedUsersLocked(int userId) {
+ private Set getProfileIdsLocked(int userId) {
Set userIds = new HashSet<Integer>();
- final List<UserInfo> relatedUsers = getUserManagerLocked().getRelatedUsers(userId);
- for (UserInfo user : relatedUsers) {
+ final List<UserInfo> profiles = getUserManagerLocked().getProfiles(userId);
+ for (UserInfo user : profiles) {
userIds.add(Integer.valueOf(user.id));
}
return userIds;
@@ -16391,15 +16391,15 @@
if (foreground) {
mCurrentUserId = userId;
- updateRelatedUserIdsLocked();
- mWindowManager.setCurrentUser(userId, mRelatedUserIds);
+ updateCurrentProfileIdsLocked();
+ mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
// Once the internal notion of the active user has switched, we lock the device
// with the option to show the user switcher on the keyguard.
mWindowManager.lockNow(null);
} else {
final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);
- updateRelatedUserIdsLocked();
- mWindowManager.updateRelatedUserIds(mRelatedUserIds);
+ updateCurrentProfileIdsLocked();
+ mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
mUserLru.remove(currentUserIdInt);
mUserLru.add(currentUserIdInt);
}
@@ -16619,20 +16619,21 @@
}
}
- void scheduleStartRelatedUsersLocked() {
- if (!mHandler.hasMessages(START_RELATED_USERS_MSG)) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(START_RELATED_USERS_MSG),
+ void scheduleStartProfilesLocked() {
+ if (!mHandler.hasMessages(START_PROFILES_MSG)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
DateUtils.SECOND_IN_MILLIS);
}
}
- void startRelatedUsersLocked() {
- if (DEBUG_MU) Slog.i(TAG_MU, "startRelatedUsersLocked");
- List<UserInfo> relatedUsers = getUserManagerLocked().getRelatedUsers(mCurrentUserId);
- List<UserInfo> toStart = new ArrayList<UserInfo>(relatedUsers.size());
- for (UserInfo relatedUser : relatedUsers) {
- if ((relatedUser.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED) {
- toStart.add(relatedUser);
+ void startProfilesLocked() {
+ if (DEBUG_MU) Slog.i(TAG_MU, "startProfilesLocked");
+ List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId);
+ List<UserInfo> toStart = new ArrayList<UserInfo>(profiles.size());
+ for (UserInfo user : profiles) {
+ if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
+ && user.id != mCurrentUserId) {
+ toStart.add(user);
}
}
final int n = toStart.size();
@@ -16641,7 +16642,7 @@
startUserInBackground(toStart.get(i).id);
}
if (i < n) {
- Slog.w(TAG_MU, "More related users than MAX_RUNNING_USERS");
+ Slog.w(TAG_MU, "More profiles than MAX_RUNNING_USERS");
}
}
@@ -16660,7 +16661,7 @@
true, false, MY_PID, Process.SYSTEM_UID, userId);
}
- startRelatedUsersLocked();
+ startProfilesLocked();
int num = mUserLru.size();
int i = 0;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 77f5c59..33b12c5 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -148,8 +148,8 @@
boolean mStartingWindowShown = false;
ActivityContainer mInitialActivityContainer;
- String recentsLabel;
- Bitmap recentsIcon;
+ String activityLabel;
+ Bitmap activityIcon;
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6ee3e07..b894724 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -341,18 +341,18 @@
}
/**
- * Checks whether the userid is either the current user or a related user.
+ * Checks whether the userid is a profile of the current user.
*/
- private boolean isRelatedToOrCurrentUserLocked(int userId) {
- if (mCurrentUser == userId) return true;
- for (int i = 0; i < mService.mRelatedUserIds.length; i++) {
- if (mService.mRelatedUserIds[i] == userId) return true;
+ private boolean isCurrentProfileLocked(int userId) {
+ if (userId == mCurrentUser) return true;
+ for (int i = 0; i < mService.mCurrentProfileIds.length; i++) {
+ if (mService.mCurrentProfileIds[i] == userId) return true;
}
return false;
}
boolean okToShowLocked(ActivityRecord r) {
- return isRelatedToOrCurrentUserLocked(r.userId)
+ return isCurrentProfileLocked(r.userId)
|| (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
}
@@ -571,7 +571,7 @@
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
TaskRecord task = mTaskHistory.get(taskNdx);
- if (!isRelatedToOrCurrentUserLocked(task.userId)) {
+ if (!isCurrentProfileLocked(task.userId)) {
return null;
}
final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -602,7 +602,7 @@
int index = mTaskHistory.size();
for (int i = 0; i < index; ) {
TaskRecord task = mTaskHistory.get(i);
- if (isRelatedToOrCurrentUserLocked(task.userId)) {
+ if (isCurrentProfileLocked(task.userId)) {
if (DEBUG_TASKS) Slog.d(TAG, "switchUserLocked: stack=" + getStackId() +
" moving " + task + " to top");
mTaskHistory.remove(i);
@@ -1766,10 +1766,10 @@
mTaskHistory.remove(task);
// Now put task at top.
int stackNdx = mTaskHistory.size();
- if (!isRelatedToOrCurrentUserLocked(task.userId)) {
+ if (!isCurrentProfileLocked(task.userId)) {
// Put non-current user tasks below current user tasks.
while (--stackNdx >= 0) {
- if (!isRelatedToOrCurrentUserLocked(mTaskHistory.get(stackNdx).userId)) {
+ if (!isCurrentProfileLocked(mTaskHistory.get(stackNdx).userId)) {
break;
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
index 9916435..64b51c9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
@@ -27,8 +27,12 @@
import java.util.List;
/**
- * CecDevice class represents a CEC logical device characterized
- * by its device type. A physical device can contain the functions of
+ * HdmiCecDevice class represents a CEC logical device characterized
+ * by its device type. It is a superclass of those serving concrete device type.
+ * Currently we're interested in playback(one of sources), display(sink) device type
+ * only. The support for the other types like recorder, audio system will come later.
+ *
+ * <p>A physical device can contain the functions of
* more than one logical device, in which case it should create
* as many logical devices as necessary.
*
@@ -41,7 +45,7 @@
*
* <p>Declared as package-private, accessed by HdmiCecService only.
*/
-final class HdmiCecDevice {
+abstract class HdmiCecDevice {
private static final String TAG = "HdmiCecDevice";
private final int mType;
@@ -49,19 +53,38 @@
// List of listeners to the message/event coming to the device.
private final List<IHdmiCecListener> mListeners = new ArrayList<IHdmiCecListener>();
private final Binder mBinder = new Binder();
+ private final HdmiCecService mService;
- private String mName;
private boolean mIsActiveSource;
/**
+ * Factory method that creates HdmiCecDevice instance to the device type.
+ */
+ public static HdmiCecDevice create(HdmiCecService service, int type) {
+ if (type == HdmiCec.DEVICE_PLAYBACK) {
+ return new HdmiCecDevicePlayback(service, type);
+ } else if (type == HdmiCec.DEVICE_TV) {
+ return new HdmiCecDeviceTv(service, type);
+ }
+ return null;
+ }
+
+ /**
* Constructor.
*/
- public HdmiCecDevice(int type) {
+ public HdmiCecDevice(HdmiCecService service, int type) {
+ mService = service;
mType = type;
mIsActiveSource = false;
}
/**
+ * Called right after the class is instantiated. This method can be used to
+ * implement any initialization tasks for the instance.
+ */
+ abstract public void initialize();
+
+ /**
* Return the binder token that identifies this instance.
*/
public Binder getToken() {
@@ -69,6 +92,13 @@
}
/**
+ * Return the service instance.
+ */
+ public HdmiCecService getService() {
+ return mService;
+ }
+
+ /**
* Return the type of this device.
*/
public int getType() {
@@ -76,24 +106,6 @@
}
/**
- * Set the name of the device. The name will be transferred via the message
- * <Set OSD Name> to other HDMI-CEC devices connected through HDMI
- * cables and shown on TV screen to identify the devicie.
- *
- * @param name name of the device
- */
- public void setName(String name) {
- mName = name;
- }
-
- /**
- * Return the name of this device.
- */
- public String getName() {
- return mName;
- }
-
- /**
* Register a listener to be invoked when events occur.
*
* @param listener the listern that will run
@@ -128,6 +140,7 @@
if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE) {
mIsActiveSource = false;
}
+
if (mListeners.size() == 0) {
return;
}
@@ -167,4 +180,13 @@
public void setIsActiveSource(boolean state) {
mIsActiveSource = state;
}
+
+ /**
+ * Check if the connected sink device is in powered-on state. The default implementation
+ * simply returns false. Should be overriden by subclass to report the correct state.
+ */
+ public boolean isSinkDeviceOn() {
+ Log.w(TAG, "Not valid for the device type: " + mType);
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
new file mode 100644
index 0000000..0310264
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+/**
+ * Class for the logical device of playback type. Devices such as DVD/Blueray player
+ * that support 'playback' feature are classified as playback device. It is common
+ * that they don't have built-in display, therefore need to talk, stream their contents
+ * to TV/display device which is connected through HDMI cable.
+ *
+ * <p>It closely monitors the status of display device (other devices can be of interest
+ * too, but with much less priority), declares itself as 'active source' to have
+ * display show its output, switch the source state as ordered by display that may be
+ * talking to many other devices connected to it. It also receives commands from display
+ * such as remote control signal, standby, status report, playback mode.
+ *
+ * <p>Declared as package-private, accessed by HdmiCecService only.
+ */
+final class HdmiCecDevicePlayback extends HdmiCecDevice {
+ private static final String TAG = "HdmiCecDevicePlayback";
+
+ private int mSinkDevicePowerStatus;
+
+ /**
+ * Constructor.
+ */
+ public HdmiCecDevicePlayback(HdmiCecService service, int type) {
+ super(service, type);
+ mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN;
+ }
+
+ @Override
+ public void initialize() {
+ // Playback device tries to obtain the power status of TV/display when created,
+ // and maintains it all through its lifecycle. CEC spec says there is
+ // a maximum 1 second response time. Therefore it should be kept in mind
+ // that there can be as much amount of period of time the power status
+ // of the display remains unknown after the query is sent out.
+ queryTvPowerStatus();
+ }
+
+ private void queryTvPowerStatus() {
+ getService().sendMessage(getType(), HdmiCec.ADDR_TV,
+ HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, HdmiCecService.EMPTY_PARAM);
+ }
+
+ @Override
+ public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
+ // Updates power status of display. The cases are:
+ // 1) Response for the queried power status request arrives. Update the status.
+ // 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going
+ // into standby mode too.
+ // 3) Broadcast <Report Physical Address> command from TV, which is sent while it boots up.
+ if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
+ mSinkDevicePowerStatus = params[0];
+ } else if (srcAddress == HdmiCec.ADDR_TV) {
+ if (opcode == HdmiCec.MESSAGE_STANDBY) {
+ mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY;
+ } else if (opcode == HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS) {
+ mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_ON;
+ }
+ }
+ super.handleMessage(srcAddress, dstAddress, opcode, params);
+ }
+
+ @Override
+ public void handleHotplug(boolean connected) {
+ // If cable get disconnected sink device becomes unreachable. Switch the status
+ // to unknown, and query the status once the cable gets connected back.
+ if (!connected) {
+ mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN;
+ } else {
+ queryTvPowerStatus();
+ }
+ super.handleHotplug(connected);
+ }
+
+ @Override
+ public boolean isSinkDeviceOn() {
+ return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON;
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java
new file mode 100644
index 0000000..09ff3ca
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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;
+
+/**
+ * Class for logical device of TV type.
+ */
+final class HdmiCecDeviceTv extends HdmiCecDevice {
+ private static final String TAG = "HdmiCecDeviceTv";
+
+ /**
+ * Constructor.
+ */
+ public HdmiCecDeviceTv(HdmiCecService service, int type) {
+ super(service, type);
+ }
+
+ public void initialize() {
+ // TODO: Do the initialization task for TV device here.
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java
index 0a7236c..aa496c5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecService.java
@@ -23,6 +23,7 @@
import android.hardware.hdmi.IHdmiCecListener;
import android.hardware.hdmi.IHdmiCecService;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
@@ -30,6 +31,7 @@
import android.util.SparseArray;
import com.android.server.SystemService;
+import libcore.util.EmptyArray;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -37,8 +39,6 @@
import java.util.ArrayList;
import java.util.Locale;
-import libcore.util.EmptyArray;
-
/**
* Provides a service for sending and processing HDMI-CEC messages, and providing
* the information on HDMI settings in general.
@@ -65,7 +65,7 @@
private static final String PERMISSION = "android.permission.HDMI_CEC";
- private static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
+ static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
public HdmiCecService(Context context) {
super(context);
@@ -76,7 +76,12 @@
@Override
public void onStart() {
mNativePtr = nativeInit(this);
- publishBinderService(Context.HDMI_CEC_SERVICE, new BinderService());
+ if (mNativePtr != 0) {
+ // TODO: Consider using a dedicated, configurable identifier for OSD name, maybe from
+ // Settings. It should be ASCII only, not a very long one (limited to 15 chars).
+ setOsdNameLocked(Build.MODEL);
+ publishBinderService(Context.HDMI_CEC_SERVICE, new BinderService());
+ }
}
/**
@@ -88,7 +93,6 @@
// but better be handled in service by turning off the screen
// or putting the device into suspend mode. List up such messages
// and handle them here.
- int type = HdmiCec.getTypeFromAddress(dstAddress);
synchronized (mLock) {
if (dstAddress == HdmiCec.ADDR_BROADCAST) {
for (int i = 0; i < mLogicalDevices.size(); ++i) {
@@ -96,6 +100,7 @@
params);
}
} else {
+ int type = HdmiCec.getTypeFromAddress(dstAddress);
HdmiCecDevice device = mLogicalDevices.get(type);
if (device == null) {
Log.w(TAG, "logical device not found. type: " + type);
@@ -138,22 +143,6 @@
}
/**
- * Called by native when a request for the device OSD name was received.
- * The native part uses the return value to generate the message
- * <Set Osd Name> in response.
- */
- private byte[] getOsdName(int type) {
- // TODO: Consider getting the OSD name from device name instead.
- synchronized (mLock) {
- HdmiCecDevice device = mLogicalDevices.get(type);
- if (device != null) {
- return device.getName().getBytes(Charset.forName("US-ASCII"));
- }
- }
- return null;
- }
-
- /**
* Called by native when a request for the menu language of the device was
* received. The native part uses the return value to generate the message
* <Set Menu Language> in response. The language should be of
@@ -174,8 +163,7 @@
synchronized (mLock) {
for (int i = 0; i < mLogicalDevices.size(); ++i) {
HdmiCecDevice device = mLogicalDevices.valueAt(i);
- pw.println("Device: name=" + device.getName() +
- ", type=" + device.getType() +
+ pw.println("Device: type=" + device.getType() +
", active=" + device.isActiveSource());
}
}
@@ -205,6 +193,15 @@
throw new IllegalArgumentException("Device not found");
}
+ // package-private. Used by HdmiCecDevice and its subclasses only.
+ void sendMessage(int type, int address, int opcode, byte[] params) {
+ nativeSendMessage(mNativePtr, type, address, opcode, params);
+ }
+
+ private void setOsdNameLocked(String name) {
+ nativeSetOsdName(mNativePtr, name.getBytes(Charset.forName("US-ASCII")));
+ }
+
private final class ListenerRecord implements IBinder.DeathRecipient {
private final IHdmiCecListener mListener;
private final int mType;
@@ -248,8 +245,12 @@
Log.e(TAG, "Logical address was not allocated");
return null;
} else {
- device = new HdmiCecDevice(type);
- device.setName(HdmiCec.getDefaultDeviceName(address));
+ device = HdmiCecDevice.create(HdmiCecService.this, type);
+ if (device == null) {
+ Log.e(TAG, "Device type not supported yet.");
+ return null;
+ }
+ device.initialize();
mLogicalDevices.put(type, device);
}
}
@@ -272,18 +273,6 @@
}
@Override
- public void setOsdName(IBinder b, String name) {
- enforceAccessPermission();
- if (TextUtils.isEmpty(name)) {
- throw new IllegalArgumentException("name must not be null");
- }
- synchronized (mLock) {
- HdmiCecDevice device = getLogicalDeviceLocked(b);
- device.setName(name);
- }
- }
-
- @Override
public void sendActiveSource(IBinder b) {
enforceAccessPermission();
synchronized (mLock) {
@@ -331,12 +320,11 @@
}
@Override
- public void sendGiveDevicePowerStatus(IBinder b, int address) {
+ public boolean isTvOn(IBinder b) {
enforceAccessPermission();
synchronized (mLock) {
HdmiCecDevice device = getLogicalDeviceLocked(b);
- nativeSendMessage(mNativePtr, device.getType(), address,
- HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
+ return device.isSinkDeviceOn();
}
}
@@ -398,4 +386,5 @@
private static native void nativeSendMessage(long handler, int deviceType, int destination,
int opcode, byte[] params);
private static native int nativeGetPhysicalAddress(long handler);
+ private static native void nativeSetOsdName(long handler, byte[] name);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b4f7ae6..3b6d288 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -219,8 +219,8 @@
));
private static final String EXTRA_INTERCEPT = "android.intercept";
- // Users related to the current user.
- final protected SparseArray<UserInfo> mRelatedUsers = new SparseArray<UserInfo>();
+ // Profiles of the current user.
+ final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
@@ -1120,9 +1120,9 @@
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
// reload per-user settings
mSettingsObserver.update(null);
- updateRelatedUserCache(context);
+ updateCurrentProfilesCache(context);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
- updateRelatedUserCache(context);
+ updateCurrentProfilesCache(context);
}
}
};
@@ -2458,12 +2458,12 @@
/**
* Determine whether the userId applies to the notification in question, either because
* they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
- * because it matches a related user.
+ * because it matches one of the users profiles.
*/
- private boolean notificationMatchesUserIdOrRelated(NotificationRecord r, int userId) {
- synchronized (mRelatedUsers) {
+ private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
+ synchronized (mCurrentProfiles) {
return notificationMatchesUserId(r, userId)
- || mRelatedUsers.get(r.getUserId()) != null;
+ || mCurrentProfiles.get(r.getUserId()) != null;
}
}
@@ -2561,7 +2561,7 @@
final int N = mNotificationList.size();
for (int i=N-1; i>=0; i--) {
NotificationRecord r = mNotificationList.get(i);
- if (!notificationMatchesUserIdOrRelated(r, userId)) {
+ if (!notificationMatchesCurrentProfiles(r, userId)) {
continue;
}
@@ -2676,15 +2676,15 @@
exceptionPackages);
}
- private void updateRelatedUserCache(Context context) {
+ private void updateCurrentProfilesCache(Context context) {
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
int currentUserId = ActivityManager.getCurrentUser();
if (userManager != null) {
- List<UserInfo> relatedUsers = userManager.getRelatedUsers(currentUserId);
- synchronized (mRelatedUsers) {
- mRelatedUsers.clear();
- for (UserInfo related : relatedUsers) {
- mRelatedUsers.put(related.id, related);
+ List<UserInfo> profiles = userManager.getProfiles(currentUserId);
+ synchronized (mCurrentProfiles) {
+ mCurrentProfiles.clear();
+ for (UserInfo user : profiles) {
+ mCurrentProfiles.put(user.id, user);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index faa5a43..d9e2b91 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -20,7 +20,6 @@
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
-import android.util.Log;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -250,21 +249,28 @@
*/
public static class Aggregate {
long numSamples;
- long sum;
- long avg;
+ double avg;
+ double sum2;
+ double var;
public void addSample(long sample) {
+ // Welford's "Method for Calculating Corrected Sums of Squares"
+ // http://www.jstor.org/stable/1266577?seq=2
numSamples++;
- sum += sample;
- avg = sum / numSamples;
+ final double n = numSamples;
+ final double delta = sample - avg;
+ avg += (1.0 / n) * delta;
+ sum2 += ((n - 1) / n) * delta * delta;
+ final double divisor = numSamples == 1 ? 1.0 : n - 1.0;
+ var = sum2 / divisor;
}
@Override
public String toString() {
return "Aggregate{" +
"numSamples=" + numSamples +
- ", sum=" + sum +
", avg=" + avg +
+ ", var=" + var +
'}';
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 288e8e0..ff90cae 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9201,7 +9201,7 @@
}
// Successfully disabled the old package. Now proceed with re-installation
- mLastScanError = PackageManager.INSTALL_SUCCEEDED;
+ res.returnCode = mLastScanError = PackageManager.INSTALL_SUCCEEDED;
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user);
if (newPackage == null) {
@@ -9214,9 +9214,20 @@
final PackageSetting newPkgSetting = (PackageSetting)newPackage.mExtras;
newPkgSetting.firstInstallTime = oldPkgSetting.firstInstallTime;
newPkgSetting.lastUpdateTime = System.currentTimeMillis();
+
+ // is the update attempting to change shared user? that isn't going to work...
+ if (oldPkgSetting.sharedUser != newPkgSetting.sharedUser) {
+ Slog.w(TAG, "Forbidding shared user change from " + oldPkgSetting.sharedUser
+ + " to " + newPkgSetting.sharedUser);
+ res.returnCode = PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+ updatedSettings = true;
+ }
}
- updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
- updatedSettings = true;
+
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
+ updatedSettings = true;
+ }
}
if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 7f55464..a39e958 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -92,7 +92,7 @@
private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
private static final String ATTR_PARTIAL = "partial";
private static final String ATTR_USER_VERSION = "version";
- private static final String ATTR_RELATED_GROUP_ID = "relatedGroupId";
+ private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
private static final String TAG_USERS = "users";
private static final String TAG_USER = "user";
private static final String TAG_RESTRICTIONS = "restrictions";
@@ -257,26 +257,26 @@
}
@Override
- public List<UserInfo> getRelatedUsers(int userId) {
+ public List<UserInfo> getProfiles(int userId) {
checkManageUsersPermission("query users");
synchronized (mPackagesLock) {
UserInfo user = getUserInfoLocked(userId);
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
for (int i = 0; i < mUsers.size(); i++) {
- UserInfo ui = mUsers.valueAt(i);
- if (!areRelatedUsers(user, ui)) {
+ UserInfo profile = mUsers.valueAt(i);
+ if (!isProfileOf(user, profile)) {
continue;
}
- users.add(ui);
+ users.add(profile);
}
return users;
}
}
- private boolean areRelatedUsers(UserInfo user1, UserInfo user2) {
- return user1.relatedGroupId != UserInfo.NO_RELATED_GROUP_ID &&
- user1.relatedGroupId == user2.relatedGroupId &&
- user1.id != user2.id;
+ private boolean isProfileOf(UserInfo user, UserInfo profile) {
+ return user.id == profile.id ||
+ (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+ && user.profileGroupId == profile.profileGroupId);
}
@Override
@@ -684,9 +684,9 @@
if (userInfo.partial) {
serializer.attribute(null, ATTR_PARTIAL, "true");
}
- if (userInfo.relatedGroupId != UserInfo.NO_RELATED_GROUP_ID) {
- serializer.attribute(null, ATTR_RELATED_GROUP_ID,
- Integer.toString(userInfo.relatedGroupId));
+ if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
+ serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
+ Integer.toString(userInfo.profileGroupId));
}
serializer.startTag(null, TAG_NAME);
@@ -771,7 +771,7 @@
long salt = 0L;
String pinHash = null;
int failedAttempts = 0;
- int relatedGroupId = UserInfo.NO_RELATED_GROUP_ID;
+ int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
long lastAttemptTime = 0L;
boolean partial = false;
Bundle restrictions = new Bundle();
@@ -809,8 +809,14 @@
pinHash = parser.getAttributeValue(null, ATTR_PIN_HASH);
failedAttempts = readIntAttribute(parser, ATTR_FAILED_ATTEMPTS, 0);
lastAttemptTime = readLongAttribute(parser, ATTR_LAST_RETRY_MS, 0L);
- relatedGroupId = readIntAttribute(parser, ATTR_RELATED_GROUP_ID,
- UserInfo.NO_RELATED_GROUP_ID);
+ profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
+ UserInfo.NO_PROFILE_GROUP_ID);
+ if (profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+ // This attribute was added and renamed during development of L.
+ // TODO Remove upgrade path by 1st May 2014
+ profileGroupId = readIntAttribute(parser, "relatedGroupId",
+ UserInfo.NO_PROFILE_GROUP_ID);
+ }
String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
if ("true".equals(valueString)) {
partial = true;
@@ -849,7 +855,7 @@
userInfo.creationTime = creationTime;
userInfo.lastLoggedInTime = lastLoggedInTime;
userInfo.partial = partial;
- userInfo.relatedGroupId = relatedGroupId;
+ userInfo.profileGroupId = profileGroupId;
mUserRestrictions.append(id, restrictions);
if (salt != 0L) {
RestrictionsPinState pinState = mRestrictionsPinStates.get(id);
@@ -964,25 +970,25 @@
}
}
- private int getNextRelatedGroupIdLocked() {
- int maxGroupId = UserInfo.NO_RELATED_GROUP_ID;
+ private int getNextProfileGroupIdLocked() {
+ int maxGroupId = UserInfo.NO_PROFILE_GROUP_ID;
for (int i = 0; i < mUsers.size(); i++) {
UserInfo ui = mUsers.valueAt(i);
- if (maxGroupId < ui.relatedGroupId) {
- maxGroupId = ui.relatedGroupId;
+ if (maxGroupId < ui.profileGroupId) {
+ maxGroupId = ui.profileGroupId;
}
}
return maxGroupId + 1;
}
@Override
- public UserInfo createRelatedUser(String name, int flags, int relatedUserId) {
+ public UserInfo createProfileForUser(String name, int flags, int userId) {
checkManageUsersPermission("Only the system can create users");
- if (relatedUserId != UserHandle.USER_OWNER) {
- Slog.w(LOG_TAG, "Only user owner can have related users");
+ if (userId != UserHandle.USER_OWNER) {
+ Slog.w(LOG_TAG, "Only user owner can have profiles");
return null;
}
- return createUserInternal(name, flags, relatedUserId);
+ return createUserInternal(name, flags, userId);
}
@Override
@@ -991,16 +997,16 @@
return createUserInternal(name, flags, UserHandle.USER_NULL);
}
- private UserInfo createUserInternal(String name, int flags, int relatedUserId) {
+ private UserInfo createUserInternal(String name, int flags, int profileId) {
final long ident = Binder.clearCallingIdentity();
UserInfo userInfo = null;
try {
synchronized (mInstallLock) {
synchronized (mPackagesLock) {
- UserInfo relatedUser = null;
- if (relatedUserId != UserHandle.USER_NULL) {
- relatedUser = getUserInfoLocked(relatedUserId);
- if (relatedUser == null) return null;
+ UserInfo profile = null;
+ if (profileId != UserHandle.USER_NULL) {
+ profile = getUserInfoLocked(profileId);
+ if (profile == null) return null;
}
if (isUserLimitReachedLocked()) return null;
int userId = getNextAvailableIdLocked();
@@ -1013,12 +1019,12 @@
Environment.getUserSystemDirectory(userInfo.id).mkdirs();
mUsers.put(userId, userInfo);
writeUserListLocked();
- if (relatedUser != null) {
- if (relatedUser.relatedGroupId == UserInfo.NO_RELATED_GROUP_ID) {
- relatedUser.relatedGroupId = getNextRelatedGroupIdLocked();
+ if (profile != null) {
+ if (profile.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+ profile.profileGroupId = getNextProfileGroupIdLocked();
+ writeUserLocked(profile);
}
- userInfo.relatedGroupId = relatedUser.relatedGroupId;
- writeUserLocked(relatedUser);
+ userInfo.profileGroupId = profile.profileGroupId;
}
writeUserLocked(userInfo);
mPm.createNewUserLILPw(userId, userPath);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a388318..80c3c8e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2541,6 +2541,9 @@
@Override // Binder call
public void acquireWakeLockWithUid(IBinder lock, int flags, String tag,
String packageName, int uid) {
+ if (uid < 0) {
+ uid = Binder.getCallingUid();
+ }
acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid), null);
}
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
new file mode 100644
index 0000000..fbfca93
--- /dev/null
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.Surface.OutOfResourcesException;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+class CircularDisplayMask {
+ private static final String TAG = "CircularDisplayMask";
+
+ private static final int STROKE_WIDTH = 2;
+
+ private final SurfaceControl mSurfaceControl;
+ private final Surface mSurface = new Surface();
+ private int mLastDW;
+ private int mLastDH;
+ private boolean mDrawNeeded;
+ private Paint mPaint;
+
+ public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) {
+ SurfaceControl ctrl = null;
+ try {
+ ctrl = new SurfaceControl(session, "CircularDisplayMask",
+ 320, 290, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+ ctrl.setLayerStack(display.getLayerStack());
+ ctrl.setLayer(zOrder);
+ ctrl.setPosition(0, 0);
+ ctrl.show();
+ mSurface.copyFrom(ctrl);
+ } catch (OutOfResourcesException e) {
+ }
+ mSurfaceControl = ctrl;
+ mDrawNeeded = true;
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setColor(Color.BLACK);
+ mPaint.setStrokeWidth(STROKE_WIDTH);
+ }
+
+ private void drawIfNeeded() {
+ if (!mDrawNeeded) {
+ return;
+ }
+ mDrawNeeded = false;
+
+ Rect dirty = new Rect(0, 0, mLastDW, mLastDH);
+ Canvas c = null;
+ try {
+ c = mSurface.lockCanvas(dirty);
+ } catch (IllegalArgumentException e) {
+ } catch (Surface.OutOfResourcesException e) {
+ }
+ if (c == null) {
+ return;
+ }
+ c.drawCircle(160, 160, 160, mPaint);
+
+ mSurface.unlockCanvasAndPost(c);
+ }
+
+ // Note: caller responsible for being inside
+ // Surface.openTransaction() / closeTransaction()
+ public void setVisibility(boolean on) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ drawIfNeeded();
+ if (on) {
+ mSurfaceControl.show();
+ } else {
+ mSurfaceControl.hide();
+ }
+ }
+
+ void positionSurface(int dw, int dh) {
+ if (mLastDW == dw && mLastDH == dh) {
+ return;
+ }
+ mLastDW = dw;
+ mLastDH = dh;
+ mSurfaceControl.setSize(dw, dh);
+ mDrawNeeded = true;
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dcf5880..b12ae4f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -86,6 +86,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.DisplayMetrics;
@@ -285,6 +286,8 @@
private static final String DENSITY_OVERRIDE = "ro.config.density_override";
private static final String SIZE_OVERRIDE = "ro.config.size_override";
+ private static final String SCREEN_CIRCULAR = "ro.display.circular";
+
private static final int MAX_SCREENSHOT_RETRIES = 3;
final private KeyguardDisableHandler mKeyguardDisableHandler;
@@ -302,14 +305,14 @@
/**
* Current user when multi-user is enabled. Don't show windows of
- * non-current user. Also see mRelatedUserIds.
+ * non-current user. Also see mCurrentProfileIds.
*/
int mCurrentUserId;
/**
- * Users related to the current user. These are also allowed to show windows
+ * Users that are profiles of the current user. These are also allowed to show windows
* on the current user.
*/
- int[] mRelatedUserIds = new int[0];
+ int[] mCurrentProfileIds = new int[] {UserHandle.USER_OWNER};
final Context mContext;
@@ -422,6 +425,7 @@
final SurfaceSession mFxSession;
Watermark mWatermark;
StrictModeFlash mStrictModeFlash;
+ CircularDisplayMask mCircularDisplayMask;
FocusedStackFrame mFocusedStackFrame;
int mFocusedStackLayer;
@@ -819,6 +823,7 @@
}
LocalServices.addService(WindowManagerInternal.class, new LocalService());
+ showCircularDisplayMaskIfNeeded();
}
public InputMonitor getInputMonitor() {
@@ -5225,16 +5230,16 @@
ShutdownThread.rebootSafeMode(mContext, confirm);
}
- public void updateRelatedUserIds(final int[] relatedUserIds) {
+ public void setCurrentProfileIds(final int[] currentProfileIds) {
synchronized (mWindowMap) {
- mRelatedUserIds = relatedUserIds;
+ mCurrentProfileIds = currentProfileIds;
}
}
- public void setCurrentUser(final int newUserId, final int[] relatedUserIds) {
+ public void setCurrentUser(final int newUserId, final int[] currentProfileIds) {
synchronized (mWindowMap) {
mCurrentUserId = newUserId;
- mRelatedUserIds = relatedUserIds;
+ mCurrentProfileIds = currentProfileIds;
mAppTransition.setCurrentUser(newUserId);
mPolicy.setCurrentUserLw(newUserId);
@@ -5250,10 +5255,10 @@
}
/* Called by WindowState */
- boolean isRelatedToOrCurrentUserLocked(int userId) {
+ boolean isCurrentProfileLocked(int userId) {
if (userId == mCurrentUserId) return true;
- for (int i = 0; i < mRelatedUserIds.length; i++) {
- if (mRelatedUserIds[i] == userId) return true;
+ for (int i = 0; i < mCurrentProfileIds.length; i++) {
+ if (mCurrentProfileIds[i] == userId) return true;
}
return false;
}
@@ -5483,6 +5488,37 @@
}
}
+ public void showCircularDisplayMaskIfNeeded() {
+ if (SystemProperties.getBoolean(SCREEN_CIRCULAR, false)) {
+ mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK));
+ }
+ }
+
+ public void showCircularMask() {
+ synchronized(mWindowMap) {
+
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+ ">>> OPEN TRANSACTION showDisplayMask");
+ SurfaceControl.openTransaction();
+ try {
+ // TODO(multi-display): support multiple displays
+ if (mCircularDisplayMask == null) {
+ mCircularDisplayMask = new CircularDisplayMask(
+ getDefaultDisplayContentLocked().getDisplay(),
+ mFxSession,
+ mPolicy.windowTypeToLayerLw(
+ WindowManager.LayoutParams.TYPE_POINTER)
+ * TYPE_LAYER_MULTIPLIER + 10);
+ }
+ mCircularDisplayMask.setVisibility(true);
+ } finally {
+ SurfaceControl.closeTransaction();
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+ "<<< CLOSE TRANSACTION showDisplayMask");
+ }
+ }
+ }
+
// TODO: more accounting of which pid(s) turned it on, keep count,
// only allow disables from pids which have count on, etc.
@Override
@@ -7107,6 +7143,8 @@
public static final int REMOVE_STARTING_TIMEOUT = 33;
+ public static final int SHOW_DISPLAY_MASK = 34;
+
@Override
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
@@ -7502,6 +7540,11 @@
break;
}
+ case SHOW_DISPLAY_MASK: {
+ showCircularMask();
+ break;
+ }
+
case DO_ANIMATION_CALLBACK: {
try {
((IRemoteCallback)msg.obj).sendResult(null);
@@ -8975,6 +9018,9 @@
if (mStrictModeFlash != null) {
mStrictModeFlash.positionSurface(defaultDw, defaultDh);
}
+ if (mCircularDisplayMask != null) {
+ mCircularDisplayMask.positionSurface(defaultDw, defaultDh);
+ }
boolean focusDisplayed = false;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2c0e99e..dff75ef 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1249,7 +1249,7 @@
}
return win.mShowToOwnerOnly
- && !mService.isRelatedToOrCurrentUserLocked(UserHandle.getUserId(win.mOwnerUid));
+ && !mService.isCurrentProfileLocked(UserHandle.getUserId(win.mOwnerUid));
}
private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index 61edda8..a00aaa8 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -20,7 +20,7 @@
#include "ScopedPrimitiveArray.h"
-#include <cstring>
+#include <string>
#include <deque>
#include <map>
@@ -34,7 +34,6 @@
jmethodID handleMessage;
jmethodID handleHotplug;
jmethodID getActiveSource;
- jmethodID getOsdName;
jmethodID getLanguage;
} gHdmiCecServiceClassInfo;
@@ -84,6 +83,7 @@
void sendSetMenuLanguage(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
void sendCecMessage(const cec_message_t& message);
+ void setOsdName(const char* name, size_t len);
private:
enum {
@@ -156,6 +156,7 @@
std::deque<MessageEntry> mMessageQueue;
uint16_t mPhysicalAddress;
+ std::string mOsdName;
};
@@ -373,6 +374,10 @@
mDevice->send_message(mDevice, &message);
}
+void HdmiCecHandler::setOsdName(const char* name, size_t len) {
+ mOsdName.assign(name, min(len, CEC_MESSAGE_BODY_MAX_LENGTH - 1));
+}
+
// static
void HdmiCecHandler::onReceived(const hdmi_event_t* event, void* arg) {
HdmiCecHandler* handler = static_cast<HdmiCecHandler*>(arg);
@@ -504,18 +509,9 @@
}
void HdmiCecHandler::handleGetOsdName(const cec_message_t& msg) {
- cec_logical_address_t addr = msg.destination;
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jbyteArray res = (jbyteArray) env->CallObjectMethod(mCallbacksObj,
- gHdmiCecServiceClassInfo.getOsdName,
- getDeviceType(addr));
- jbyte *name = env->GetByteArrayElements(res, NULL);
- if (name != NULL) {
- sendSetOsdName(addr, msg.initiator, reinterpret_cast<const char *>(name),
- env->GetArrayLength(res));
- env->ReleaseByteArrayElements(res, name, JNI_ABORT);
+ if (!mOsdName.empty()) {
+ sendSetOsdName(msg.destination, msg.initiator, mOsdName.c_str(), mOsdName.length());
}
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
void HdmiCecHandler::handleGiveDeviceVendorID(const cec_message_t& msg) {
@@ -562,8 +558,6 @@
"handleHotplug", "(Z)V");
GET_METHOD_ID(gHdmiCecServiceClassInfo.getActiveSource, clazz,
"getActiveSource", "()I");
- GET_METHOD_ID(gHdmiCecServiceClassInfo.getOsdName, clazz,
- "getOsdName", "(I)[B");
GET_METHOD_ID(gHdmiCecServiceClassInfo.getLanguage, clazz,
"getLanguage", "(I)Ljava/lang/String;");
@@ -603,6 +597,15 @@
return handler->getPhysicalAddress();
}
+static void nativeSetOsdName(JNIEnv* env, jclass clazz, jlong handlerPtr, jbyteArray name) {
+ HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
+ jsize len = env->GetArrayLength(name);
+ if (len > 0) {
+ ScopedByteArrayRO namePtr(env, name);
+ handler->setOsdName(reinterpret_cast<const char *>(namePtr.get()), len);
+ }
+}
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "(Lcom/android/server/hdmi/HdmiCecService;)J",
@@ -615,6 +618,8 @@
(void *)nativeRemoveLogicalAddress },
{ "nativeGetPhysicalAddress", "(J)I",
(void *)nativeGetPhysicalAddress },
+ { "nativeSetOsdName", "(J[B)V",
+ (void *)nativeSetOsdName },
};
#define CLASS_PATH "com/android/server/hdmi/HdmiCecService"
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ab4c89e..8f2adc8 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -50,6 +50,7 @@
import com.android.internal.R;
import com.android.internal.os.BinderInternal;
+import com.android.internal.os.Zygote;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accounts.AccountManagerService;
@@ -83,7 +84,6 @@
import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
import java.io.File;
import java.util.Timer;
@@ -269,7 +269,7 @@
private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
- mSystemContext.setTheme(android.R.style.Theme_Holo);
+ mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
}
private void startBootstrapServices() {
diff --git a/tests/DynamicDrawableTest/lint.xml b/tests/DynamicDrawableTest/lint.xml
deleted file mode 100644
index ee0eead..0000000
--- a/tests/DynamicDrawableTest/lint.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<lint>
-</lint>
\ No newline at end of file
diff --git a/tests/DynamicDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk
similarity index 94%
rename from tests/DynamicDrawableTest/Android.mk
rename to tests/VectorDrawableTest/Android.mk
index 5c51301..dd8a4d4 100644
--- a/tests/DynamicDrawableTest/Android.mk
+++ b/tests/VectorDrawableTest/Android.mk
@@ -19,7 +19,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_PACKAGE_NAME := DynamicDrawableTest
+LOCAL_PACKAGE_NAME := VectorDrawableTest
LOCAL_MODULE_TAGS := tests
diff --git a/tests/DynamicDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
similarity index 99%
rename from tests/DynamicDrawableTest/AndroidManifest.xml
rename to tests/VectorDrawableTest/AndroidManifest.xml
index 4ca3e3c..06effe2 100644
--- a/tests/DynamicDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -73,7 +73,7 @@
</intent-filter>
</activity>
-
+
<activity
android:name="VectorCheckbox"
android:label="On a Checkbox" >
diff --git a/tests/DynamicDrawableTest/res/drawable-hdpi/icon.png b/tests/VectorDrawableTest/res/drawable-hdpi/icon.png
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable-hdpi/icon.png
rename to tests/VectorDrawableTest/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/tests/DynamicDrawableTest/res/drawable/icon.png b/tests/VectorDrawableTest/res/drawable/icon.png
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/icon.png
rename to tests/VectorDrawableTest/res/drawable/icon.png
Binary files differ
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
similarity index 97%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable01.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index 4f4b386..538993f 100644
--- a/tests/DynamicDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:trigger="state_checked" >
+ android:trigger="state_checked" android:versionCode="1" >
<size
android:height="64dp"
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable02.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable03.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable04.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable05.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable06.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable06.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable07.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable08.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable09.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable10.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
similarity index 98%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable11.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
index a1a03be..8787b34 100644
--- a/tests/DynamicDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -29,7 +29,7 @@
android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
android:fill="#3388ff"
android:stroke="#ff8833"
- android:strokeWidth="1"
+ android:strokeWidth="1"
android:rotation="0"/>
<path
android:name="spark"
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable12.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable13.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable14.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable15.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable16.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable17.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable18.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable19.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_drawable20.xml
rename to tests/VectorDrawableTest/res/drawable/vector_drawable20.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_icon_create.xml
rename to tests/VectorDrawableTest/res/drawable/vector_icon_create.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_icon_delete.xml
rename to tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_icon_heart.xml
rename to tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_icon_schedule.xml
rename to tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_icon_settings.xml
rename to tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_test01.xml
rename to tests/VectorDrawableTest/res/drawable/vector_test01.xml
diff --git a/tests/DynamicDrawableTest/res/drawable/vector_test02.xml b/tests/VectorDrawableTest/res/drawable/vector_test02.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/drawable/vector_test02.xml
rename to tests/VectorDrawableTest/res/drawable/vector_test02.xml
diff --git a/tests/DynamicDrawableTest/res/values/strings.xml b/tests/VectorDrawableTest/res/values/strings.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/values/strings.xml
rename to tests/VectorDrawableTest/res/values/strings.xml
diff --git a/tests/DynamicDrawableTest/res/values/styles.xml b/tests/VectorDrawableTest/res/values/styles.xml
similarity index 100%
rename from tests/DynamicDrawableTest/res/values/styles.xml
rename to tests/VectorDrawableTest/res/values/styles.xml
diff --git a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java
similarity index 98%
rename from tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java
rename to tests/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java
index 1060d19..0b3ea4d 100644
--- a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java
@@ -60,7 +60,6 @@
CheckBox checkBox = new CheckBox(this);
bArray[i] = checkBox;
checkBox.setWidth(200);
- checkBox.setWidth(200);
checkBox.setButtonDrawable(icon[i]);
container.addView(checkBox);
}
diff --git a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
similarity index 98%
rename from tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
rename to tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
index 0ae4b6d..88ae398 100644
--- a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java
@@ -59,7 +59,6 @@
Button button = new Button(this);
bArray[i] = button;
button.setWidth(200);
- button.setWidth(200);
button.setBackgroundResource(icon[i]);
container.addView(button);
button.setOnClickListener(this);
diff --git a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java
similarity index 100%
rename from tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java
rename to tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java
diff --git a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
similarity index 98%
rename from tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
rename to tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index 9e8ea75..3929298 100644
--- a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -74,7 +74,6 @@
for (int i = 0; i < icon.length; i++) {
Button button = new Button(this);
button.setWidth(200);
- button.setWidth(200);
button.setBackgroundResource(icon[i]);
container.addView(button);
button.setOnClickListener(this);
diff --git a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java
similarity index 100%
rename from tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java
rename to tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java
diff --git a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java
similarity index 100%
rename from tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java
rename to tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java
diff --git a/tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java
similarity index 100%
rename from tests/DynamicDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java
rename to tests/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java
diff --git a/wifi/java/android/net/wifi/BatchedScanSettings.java b/wifi/java/android/net/wifi/BatchedScanSettings.java
index f7ebc17..54801ad 100644
--- a/wifi/java/android/net/wifi/BatchedScanSettings.java
+++ b/wifi/java/android/net/wifi/BatchedScanSettings.java
@@ -34,17 +34,17 @@
/** Used to indicate no preference for an int value */
public final static int UNSPECIFIED = Integer.MAX_VALUE;
- // TODO - make MIN/mAX dynamic and gservices adjustable.
+ // TODO - make MIN/mAX as standard for wifi batch capability requirement.
public final static int MIN_SCANS_PER_BATCH = 2;
- public final static int MAX_SCANS_PER_BATCH = 255;
+ public final static int MAX_SCANS_PER_BATCH = 20;
public final static int DEFAULT_SCANS_PER_BATCH = MAX_SCANS_PER_BATCH;
public final static int MIN_AP_PER_SCAN = 2;
- public final static int MAX_AP_PER_SCAN = 255;
+ public final static int MAX_AP_PER_SCAN = 16;
public final static int DEFAULT_AP_PER_SCAN = 16;
- public final static int MIN_INTERVAL_SEC = 0;
- public final static int MAX_INTERVAL_SEC = 3600;
+ public final static int MIN_INTERVAL_SEC = 10;
+ public final static int MAX_INTERVAL_SEC = 500;
public final static int DEFAULT_INTERVAL_SEC = 30;
public final static int MIN_AP_FOR_DISTANCE = 0;