Merge "Cleaning up some old animation code, only setting view properties that have changed."
diff --git a/Android.mk b/Android.mk
index c889fa1..58bc2c7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -98,6 +98,8 @@
core/java/android/app/maintenance/IIdleService.aidl \
core/java/android/bluetooth/IBluetooth.aidl \
core/java/android/bluetooth/IBluetoothA2dp.aidl \
+ core/java/android/bluetooth/IBluetoothA2dpSink.aidl \
+ core/java/android/bluetooth/IBluetoothAvrcpController.aidl \
core/java/android/bluetooth/IBluetoothCallback.aidl \
core/java/android/bluetooth/IBluetoothHeadset.aidl \
core/java/android/bluetooth/IBluetoothHeadsetPhone.aidl \
@@ -110,6 +112,7 @@
core/java/android/bluetooth/IBluetoothPbap.aidl \
core/java/android/bluetooth/IBluetoothMap.aidl \
core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
+ core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \
core/java/android/bluetooth/IBluetoothGatt.aidl \
core/java/android/bluetooth/IBluetoothGattCallback.aidl \
core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
@@ -341,6 +344,7 @@
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
+ telephony/java/com/android/internal/telephony/ISub.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 5b027b3..5d92792 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -193,6 +193,7 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/ITv*)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.txt b/api/current.txt
index 991186f..b7a4a3e0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -859,6 +859,7 @@
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
+ field public static final int overlapAnchor = 16843876; // 0x1010464
field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
field public static final int packageNames = 16843649; // 0x1010381
field public static final int padding = 16842965; // 0x10100d5
@@ -1343,6 +1344,7 @@
field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
field public static final int windowTitleSize = 16842842; // 0x101005a
field public static final int windowTitleStyle = 16842843; // 0x101005b
+ field public static final int windowTransitionBackgroundFadeDuration = 16843875; // 0x1010463
field public static final int windowTranslucentNavigation = 16843760; // 0x10103f0
field public static final int windowTranslucentStatus = 16843759; // 0x10103ef
field public static final int writePermission = 16842760; // 0x1010008
@@ -1868,28 +1870,28 @@
field public static final int TextAppearance_Large = 16973890; // 0x1030042
field public static final int TextAppearance_Large_Inverse = 16973891; // 0x1030043
field public static final int TextAppearance_Material = 16974350; // 0x103020e
- field public static final int TextAppearance_Material_Body1 = 16974550; // 0x10302d6
- field public static final int TextAppearance_Material_Body2 = 16974549; // 0x10302d5
- field public static final int TextAppearance_Material_Button = 16974553; // 0x10302d9
- field public static final int TextAppearance_Material_Caption = 16974551; // 0x10302d7
+ field public static final int TextAppearance_Material_Body1 = 16974552; // 0x10302d8
+ field public static final int TextAppearance_Material_Body2 = 16974551; // 0x10302d7
+ field public static final int TextAppearance_Material_Button = 16974555; // 0x10302db
+ field public static final int TextAppearance_Material_Caption = 16974553; // 0x10302d9
field public static final int TextAppearance_Material_DialogWindowTitle = 16974351; // 0x103020f
- field public static final int TextAppearance_Material_Display1 = 16974545; // 0x10302d1
- field public static final int TextAppearance_Material_Display2 = 16974544; // 0x10302d0
- field public static final int TextAppearance_Material_Display3 = 16974543; // 0x10302cf
- field public static final int TextAppearance_Material_Display4 = 16974542; // 0x10302ce
- field public static final int TextAppearance_Material_Headline = 16974546; // 0x10302d2
+ field public static final int TextAppearance_Material_Display1 = 16974547; // 0x10302d3
+ field public static final int TextAppearance_Material_Display2 = 16974546; // 0x10302d2
+ field public static final int TextAppearance_Material_Display3 = 16974545; // 0x10302d1
+ field public static final int TextAppearance_Material_Display4 = 16974544; // 0x10302d0
+ field public static final int TextAppearance_Material_Headline = 16974548; // 0x10302d4
field public static final int TextAppearance_Material_Inverse = 16974352; // 0x1030210
field public static final int TextAppearance_Material_Large = 16974353; // 0x1030211
field public static final int TextAppearance_Material_Large_Inverse = 16974354; // 0x1030212
field public static final int TextAppearance_Material_Medium = 16974355; // 0x1030213
field public static final int TextAppearance_Material_Medium_Inverse = 16974356; // 0x1030214
- field public static final int TextAppearance_Material_Menu = 16974552; // 0x10302d8
+ field public static final int TextAppearance_Material_Menu = 16974554; // 0x10302da
field public static final int TextAppearance_Material_SearchResult_Subtitle = 16974357; // 0x1030215
field public static final int TextAppearance_Material_SearchResult_Title = 16974358; // 0x1030216
field public static final int TextAppearance_Material_Small = 16974359; // 0x1030217
field public static final int TextAppearance_Material_Small_Inverse = 16974360; // 0x1030218
- field public static final int TextAppearance_Material_Subhead = 16974548; // 0x10302d4
- field public static final int TextAppearance_Material_Title = 16974547; // 0x10302d3
+ field public static final int TextAppearance_Material_Subhead = 16974550; // 0x10302d6
+ field public static final int TextAppearance_Material_Title = 16974549; // 0x10302d5
field public static final int TextAppearance_Material_Widget = 16974362; // 0x103021a
field public static final int TextAppearance_Material_Widget_ActionBar_Menu = 16974363; // 0x103021b
field public static final int TextAppearance_Material_Widget_ActionBar_Subtitle = 16974364; // 0x103021c
@@ -1938,12 +1940,12 @@
field public static final int TextAppearance_Widget_TextView_SpinnerItem = 16973906; // 0x1030052
field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053
field public static final int Theme = 16973829; // 0x1030005
- field public static final int ThemeOverlay = 16974414; // 0x103024e
- field public static final int ThemeOverlay_Material = 16974415; // 0x103024f
- field public static final int ThemeOverlay_Material_ActionBar = 16974416; // 0x1030250
- field public static final int ThemeOverlay_Material_Dark = 16974418; // 0x1030252
- field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974419; // 0x1030253
- field public static final int ThemeOverlay_Material_Light = 16974417; // 0x1030251
+ field public static final int ThemeOverlay = 16974416; // 0x1030250
+ field public static final int ThemeOverlay_Material = 16974417; // 0x1030251
+ field public static final int ThemeOverlay_Material_ActionBar = 16974418; // 0x1030252
+ field public static final int ThemeOverlay_Material_Dark = 16974420; // 0x1030254
+ field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974421; // 0x1030255
+ field public static final int ThemeOverlay_Material_Light = 16974419; // 0x1030253
field public static final int Theme_Black = 16973832; // 0x1030008
field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
@@ -1973,6 +1975,7 @@
field public static final int Theme_DeviceDefault_NoActionBar_Overscan = 16974303; // 0x10301df
field public static final int Theme_DeviceDefault_NoActionBar_TranslucentDecor = 16974307; // 0x10301e3
field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
+ field public static final int Theme_DeviceDefault_Settings = 16974384; // 0x1030230
field public static final int Theme_DeviceDefault_Wallpaper = 16974140; // 0x103013c
field public static final int Theme_DeviceDefault_Wallpaper_NoTitleBar = 16974141; // 0x103013d
field public static final int Theme_Dialog = 16973835; // 0x103000b
@@ -2010,36 +2013,37 @@
field public static final int Theme_Light_NoTitleBar_Fullscreen = 16973838; // 0x103000e
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
- field public static final int Theme_Material = 16974384; // 0x1030230
- field public static final int Theme_Material_Dialog = 16974385; // 0x1030231
- field public static final int Theme_Material_DialogWhenLarge = 16974389; // 0x1030235
- field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974390; // 0x1030236
- field public static final int Theme_Material_Dialog_MinWidth = 16974386; // 0x1030232
- field public static final int Theme_Material_Dialog_NoActionBar = 16974387; // 0x1030233
- field public static final int Theme_Material_Dialog_NoActionBar_MinWidth = 16974388; // 0x1030234
- field public static final int Theme_Material_InputMethod = 16974391; // 0x1030237
- field public static final int Theme_Material_Light = 16974400; // 0x1030240
- field public static final int Theme_Material_Light_DarkActionBar = 16974401; // 0x1030241
- field public static final int Theme_Material_Light_Dialog = 16974402; // 0x1030242
- field public static final int Theme_Material_Light_DialogWhenLarge = 16974406; // 0x1030246
- field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974407; // 0x1030247
- field public static final int Theme_Material_Light_Dialog_MinWidth = 16974403; // 0x1030243
- field public static final int Theme_Material_Light_Dialog_NoActionBar = 16974404; // 0x1030244
- field public static final int Theme_Material_Light_Dialog_NoActionBar_MinWidth = 16974405; // 0x1030245
- field public static final int Theme_Material_Light_NoActionBar = 16974408; // 0x1030248
- field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974409; // 0x1030249
- field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974410; // 0x103024a
- field public static final int Theme_Material_Light_NoActionBar_TranslucentDecor = 16974411; // 0x103024b
- field public static final int Theme_Material_Light_Panel = 16974412; // 0x103024c
- field public static final int Theme_Material_Light_Voice = 16974413; // 0x103024d
- field public static final int Theme_Material_NoActionBar = 16974392; // 0x1030238
- field public static final int Theme_Material_NoActionBar_Fullscreen = 16974393; // 0x1030239
- field public static final int Theme_Material_NoActionBar_Overscan = 16974394; // 0x103023a
- field public static final int Theme_Material_NoActionBar_TranslucentDecor = 16974395; // 0x103023b
- field public static final int Theme_Material_Panel = 16974396; // 0x103023c
- field public static final int Theme_Material_Voice = 16974397; // 0x103023d
- field public static final int Theme_Material_Wallpaper = 16974398; // 0x103023e
- field public static final int Theme_Material_Wallpaper_NoTitleBar = 16974399; // 0x103023f
+ field public static final int Theme_Material = 16974385; // 0x1030231
+ field public static final int Theme_Material_Dialog = 16974386; // 0x1030232
+ field public static final int Theme_Material_DialogWhenLarge = 16974390; // 0x1030236
+ field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974391; // 0x1030237
+ field public static final int Theme_Material_Dialog_MinWidth = 16974387; // 0x1030233
+ field public static final int Theme_Material_Dialog_NoActionBar = 16974388; // 0x1030234
+ field public static final int Theme_Material_Dialog_NoActionBar_MinWidth = 16974389; // 0x1030235
+ field public static final int Theme_Material_InputMethod = 16974392; // 0x1030238
+ field public static final int Theme_Material_Light = 16974402; // 0x1030242
+ field public static final int Theme_Material_Light_DarkActionBar = 16974403; // 0x1030243
+ field public static final int Theme_Material_Light_Dialog = 16974404; // 0x1030244
+ field public static final int Theme_Material_Light_DialogWhenLarge = 16974408; // 0x1030248
+ field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974409; // 0x1030249
+ field public static final int Theme_Material_Light_Dialog_MinWidth = 16974405; // 0x1030245
+ field public static final int Theme_Material_Light_Dialog_NoActionBar = 16974406; // 0x1030246
+ field public static final int Theme_Material_Light_Dialog_NoActionBar_MinWidth = 16974407; // 0x1030247
+ field public static final int Theme_Material_Light_NoActionBar = 16974410; // 0x103024a
+ field public static final int Theme_Material_Light_NoActionBar_Fullscreen = 16974411; // 0x103024b
+ field public static final int Theme_Material_Light_NoActionBar_Overscan = 16974412; // 0x103024c
+ field public static final int Theme_Material_Light_NoActionBar_TranslucentDecor = 16974413; // 0x103024d
+ field public static final int Theme_Material_Light_Panel = 16974414; // 0x103024e
+ field public static final int Theme_Material_Light_Voice = 16974415; // 0x103024f
+ field public static final int Theme_Material_NoActionBar = 16974393; // 0x1030239
+ field public static final int Theme_Material_NoActionBar_Fullscreen = 16974394; // 0x103023a
+ field public static final int Theme_Material_NoActionBar_Overscan = 16974395; // 0x103023b
+ field public static final int Theme_Material_NoActionBar_TranslucentDecor = 16974396; // 0x103023c
+ field public static final int Theme_Material_Panel = 16974397; // 0x103023d
+ field public static final int Theme_Material_Settings = 16974398; // 0x103023e
+ field public static final int Theme_Material_Voice = 16974399; // 0x103023f
+ field public static final int Theme_Material_Wallpaper = 16974400; // 0x1030240
+ field public static final int Theme_Material_Wallpaper_NoTitleBar = 16974401; // 0x1030241
field public static final int Theme_NoDisplay = 16973909; // 0x1030055
field public static final int Theme_NoTitleBar = 16973830; // 0x1030006
field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
@@ -2324,128 +2328,128 @@
field public static final int Widget_ListView_DropDown = 16973872; // 0x1030030
field public static final int Widget_ListView_Menu = 16973873; // 0x1030031
field public static final int Widget_ListView_White = 16973871; // 0x103002f
- field public static final int Widget_Material = 16974420; // 0x1030254
- field public static final int Widget_Material_ActionBar = 16974421; // 0x1030255
- field public static final int Widget_Material_ActionBar_Solid = 16974422; // 0x1030256
- field public static final int Widget_Material_ActionBar_TabBar = 16974423; // 0x1030257
- field public static final int Widget_Material_ActionBar_TabText = 16974424; // 0x1030258
- field public static final int Widget_Material_ActionBar_TabView = 16974425; // 0x1030259
- field public static final int Widget_Material_ActionButton = 16974426; // 0x103025a
- field public static final int Widget_Material_ActionButton_CloseMode = 16974427; // 0x103025b
- field public static final int Widget_Material_ActionButton_Overflow = 16974428; // 0x103025c
- field public static final int Widget_Material_ActionMode = 16974429; // 0x103025d
- field public static final int Widget_Material_AutoCompleteTextView = 16974430; // 0x103025e
- field public static final int Widget_Material_Button = 16974431; // 0x103025f
- field public static final int Widget_Material_ButtonBar = 16974437; // 0x1030265
- field public static final int Widget_Material_ButtonBar_AlertDialog = 16974438; // 0x1030266
- field public static final int Widget_Material_Button_Borderless = 16974432; // 0x1030260
- field public static final int Widget_Material_Button_Borderless_Small = 16974433; // 0x1030261
- field public static final int Widget_Material_Button_Inset = 16974434; // 0x1030262
- field public static final int Widget_Material_Button_Small = 16974435; // 0x1030263
- field public static final int Widget_Material_Button_Toggle = 16974436; // 0x1030264
- field public static final int Widget_Material_CalendarView = 16974439; // 0x1030267
- field public static final int Widget_Material_CheckedTextView = 16974440; // 0x1030268
- field public static final int Widget_Material_CompoundButton_CheckBox = 16974441; // 0x1030269
- field public static final int Widget_Material_CompoundButton_RadioButton = 16974442; // 0x103026a
- field public static final int Widget_Material_CompoundButton_Star = 16974443; // 0x103026b
- field public static final int Widget_Material_DatePicker = 16974444; // 0x103026c
- field public static final int Widget_Material_DropDownItem = 16974445; // 0x103026d
- field public static final int Widget_Material_DropDownItem_Spinner = 16974446; // 0x103026e
- field public static final int Widget_Material_EditText = 16974447; // 0x103026f
- field public static final int Widget_Material_ExpandableListView = 16974448; // 0x1030270
- field public static final int Widget_Material_FastScroll = 16974449; // 0x1030271
- field public static final int Widget_Material_GridView = 16974450; // 0x1030272
- field public static final int Widget_Material_HorizontalScrollView = 16974451; // 0x1030273
- field public static final int Widget_Material_ImageButton = 16974452; // 0x1030274
- field public static final int Widget_Material_Light = 16974481; // 0x1030291
- field public static final int Widget_Material_Light_ActionBar = 16974482; // 0x1030292
- field public static final int Widget_Material_Light_ActionBar_Solid = 16974483; // 0x1030293
- field public static final int Widget_Material_Light_ActionBar_TabBar = 16974484; // 0x1030294
- field public static final int Widget_Material_Light_ActionBar_TabText = 16974485; // 0x1030295
- field public static final int Widget_Material_Light_ActionBar_TabView = 16974486; // 0x1030296
- field public static final int Widget_Material_Light_ActionButton = 16974487; // 0x1030297
- field public static final int Widget_Material_Light_ActionButton_CloseMode = 16974488; // 0x1030298
- field public static final int Widget_Material_Light_ActionButton_Overflow = 16974489; // 0x1030299
- field public static final int Widget_Material_Light_ActionMode = 16974490; // 0x103029a
- field public static final int Widget_Material_Light_AutoCompleteTextView = 16974491; // 0x103029b
- field public static final int Widget_Material_Light_Button = 16974492; // 0x103029c
- field public static final int Widget_Material_Light_ButtonBar = 16974498; // 0x10302a2
- field public static final int Widget_Material_Light_ButtonBar_AlertDialog = 16974499; // 0x10302a3
- field public static final int Widget_Material_Light_Button_Borderless = 16974493; // 0x103029d
- field public static final int Widget_Material_Light_Button_Borderless_Small = 16974494; // 0x103029e
- field public static final int Widget_Material_Light_Button_Inset = 16974495; // 0x103029f
- field public static final int Widget_Material_Light_Button_Small = 16974496; // 0x10302a0
- field public static final int Widget_Material_Light_Button_Toggle = 16974497; // 0x10302a1
- field public static final int Widget_Material_Light_CalendarView = 16974500; // 0x10302a4
- field public static final int Widget_Material_Light_CheckedTextView = 16974501; // 0x10302a5
- field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974502; // 0x10302a6
- field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974503; // 0x10302a7
- field public static final int Widget_Material_Light_CompoundButton_Star = 16974504; // 0x10302a8
- field public static final int Widget_Material_Light_DropDownItem = 16974505; // 0x10302a9
- field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974506; // 0x10302aa
- field public static final int Widget_Material_Light_EditText = 16974507; // 0x10302ab
- field public static final int Widget_Material_Light_ExpandableListView = 16974508; // 0x10302ac
- field public static final int Widget_Material_Light_FastScroll = 16974509; // 0x10302ad
- field public static final int Widget_Material_Light_GridView = 16974510; // 0x10302ae
- field public static final int Widget_Material_Light_HorizontalScrollView = 16974511; // 0x10302af
- field public static final int Widget_Material_Light_ImageButton = 16974512; // 0x10302b0
- field public static final int Widget_Material_Light_ListPopupWindow = 16974513; // 0x10302b1
- field public static final int Widget_Material_Light_ListView = 16974514; // 0x10302b2
- field public static final int Widget_Material_Light_ListView_DropDown = 16974515; // 0x10302b3
- field public static final int Widget_Material_Light_MediaRouteButton = 16974516; // 0x10302b4
- field public static final int Widget_Material_Light_PopupMenu = 16974517; // 0x10302b5
- field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974518; // 0x10302b6
- field public static final int Widget_Material_Light_PopupWindow = 16974519; // 0x10302b7
- field public static final int Widget_Material_Light_ProgressBar = 16974520; // 0x10302b8
- field public static final int Widget_Material_Light_ProgressBar_Horizontal = 16974521; // 0x10302b9
- field public static final int Widget_Material_Light_ProgressBar_Inverse = 16974522; // 0x10302ba
- field public static final int Widget_Material_Light_ProgressBar_Large = 16974523; // 0x10302bb
- field public static final int Widget_Material_Light_ProgressBar_Large_Inverse = 16974524; // 0x10302bc
- field public static final int Widget_Material_Light_ProgressBar_Small = 16974525; // 0x10302bd
- field public static final int Widget_Material_Light_ProgressBar_Small_Inverse = 16974526; // 0x10302be
- field public static final int Widget_Material_Light_ProgressBar_Small_Title = 16974527; // 0x10302bf
- field public static final int Widget_Material_Light_RatingBar = 16974528; // 0x10302c0
- field public static final int Widget_Material_Light_RatingBar_Indicator = 16974529; // 0x10302c1
- field public static final int Widget_Material_Light_RatingBar_Small = 16974530; // 0x10302c2
- field public static final int Widget_Material_Light_ScrollView = 16974531; // 0x10302c3
- field public static final int Widget_Material_Light_SeekBar = 16974532; // 0x10302c4
- field public static final int Widget_Material_Light_SegmentedButton = 16974533; // 0x10302c5
- field public static final int Widget_Material_Light_Spinner = 16974535; // 0x10302c7
- field public static final int Widget_Material_Light_StackView = 16974534; // 0x10302c6
- field public static final int Widget_Material_Light_Tab = 16974536; // 0x10302c8
- field public static final int Widget_Material_Light_TabWidget = 16974537; // 0x10302c9
- field public static final int Widget_Material_Light_TextView = 16974538; // 0x10302ca
- field public static final int Widget_Material_Light_TextView_SpinnerItem = 16974539; // 0x10302cb
- field public static final int Widget_Material_Light_WebTextView = 16974540; // 0x10302cc
- field public static final int Widget_Material_Light_WebView = 16974541; // 0x10302cd
- field public static final int Widget_Material_ListPopupWindow = 16974453; // 0x1030275
- field public static final int Widget_Material_ListView = 16974454; // 0x1030276
- field public static final int Widget_Material_ListView_DropDown = 16974455; // 0x1030277
- field public static final int Widget_Material_MediaRouteButton = 16974456; // 0x1030278
- field public static final int Widget_Material_PopupMenu = 16974457; // 0x1030279
- field public static final int Widget_Material_PopupMenu_Overflow = 16974458; // 0x103027a
- field public static final int Widget_Material_PopupWindow = 16974459; // 0x103027b
- field public static final int Widget_Material_ProgressBar = 16974460; // 0x103027c
- field public static final int Widget_Material_ProgressBar_Horizontal = 16974461; // 0x103027d
- field public static final int Widget_Material_ProgressBar_Large = 16974462; // 0x103027e
- field public static final int Widget_Material_ProgressBar_Small = 16974463; // 0x103027f
- field public static final int Widget_Material_ProgressBar_Small_Title = 16974464; // 0x1030280
- field public static final int Widget_Material_RatingBar = 16974465; // 0x1030281
- field public static final int Widget_Material_RatingBar_Indicator = 16974466; // 0x1030282
- field public static final int Widget_Material_RatingBar_Small = 16974467; // 0x1030283
- field public static final int Widget_Material_ScrollView = 16974468; // 0x1030284
- field public static final int Widget_Material_SeekBar = 16974469; // 0x1030285
- field public static final int Widget_Material_SegmentedButton = 16974470; // 0x1030286
- field public static final int Widget_Material_Spinner = 16974472; // 0x1030288
- field public static final int Widget_Material_StackView = 16974471; // 0x1030287
- field public static final int Widget_Material_Tab = 16974473; // 0x1030289
- field public static final int Widget_Material_TabWidget = 16974474; // 0x103028a
- field public static final int Widget_Material_TextView = 16974475; // 0x103028b
- field public static final int Widget_Material_TextView_SpinnerItem = 16974476; // 0x103028c
- field public static final int Widget_Material_Toolbar = 16974477; // 0x103028d
- field public static final int Widget_Material_Toolbar_Button_Navigation = 16974478; // 0x103028e
- field public static final int Widget_Material_WebTextView = 16974479; // 0x103028f
- field public static final int Widget_Material_WebView = 16974480; // 0x1030290
+ field public static final int Widget_Material = 16974422; // 0x1030256
+ field public static final int Widget_Material_ActionBar = 16974423; // 0x1030257
+ field public static final int Widget_Material_ActionBar_Solid = 16974424; // 0x1030258
+ field public static final int Widget_Material_ActionBar_TabBar = 16974425; // 0x1030259
+ field public static final int Widget_Material_ActionBar_TabText = 16974426; // 0x103025a
+ field public static final int Widget_Material_ActionBar_TabView = 16974427; // 0x103025b
+ field public static final int Widget_Material_ActionButton = 16974428; // 0x103025c
+ field public static final int Widget_Material_ActionButton_CloseMode = 16974429; // 0x103025d
+ field public static final int Widget_Material_ActionButton_Overflow = 16974430; // 0x103025e
+ field public static final int Widget_Material_ActionMode = 16974431; // 0x103025f
+ field public static final int Widget_Material_AutoCompleteTextView = 16974432; // 0x1030260
+ field public static final int Widget_Material_Button = 16974433; // 0x1030261
+ field public static final int Widget_Material_ButtonBar = 16974439; // 0x1030267
+ field public static final int Widget_Material_ButtonBar_AlertDialog = 16974440; // 0x1030268
+ field public static final int Widget_Material_Button_Borderless = 16974434; // 0x1030262
+ field public static final int Widget_Material_Button_Borderless_Small = 16974435; // 0x1030263
+ field public static final int Widget_Material_Button_Inset = 16974436; // 0x1030264
+ field public static final int Widget_Material_Button_Small = 16974437; // 0x1030265
+ field public static final int Widget_Material_Button_Toggle = 16974438; // 0x1030266
+ field public static final int Widget_Material_CalendarView = 16974441; // 0x1030269
+ field public static final int Widget_Material_CheckedTextView = 16974442; // 0x103026a
+ field public static final int Widget_Material_CompoundButton_CheckBox = 16974443; // 0x103026b
+ field public static final int Widget_Material_CompoundButton_RadioButton = 16974444; // 0x103026c
+ field public static final int Widget_Material_CompoundButton_Star = 16974445; // 0x103026d
+ field public static final int Widget_Material_DatePicker = 16974446; // 0x103026e
+ field public static final int Widget_Material_DropDownItem = 16974447; // 0x103026f
+ field public static final int Widget_Material_DropDownItem_Spinner = 16974448; // 0x1030270
+ field public static final int Widget_Material_EditText = 16974449; // 0x1030271
+ field public static final int Widget_Material_ExpandableListView = 16974450; // 0x1030272
+ field public static final int Widget_Material_FastScroll = 16974451; // 0x1030273
+ field public static final int Widget_Material_GridView = 16974452; // 0x1030274
+ field public static final int Widget_Material_HorizontalScrollView = 16974453; // 0x1030275
+ field public static final int Widget_Material_ImageButton = 16974454; // 0x1030276
+ field public static final int Widget_Material_Light = 16974483; // 0x1030293
+ field public static final int Widget_Material_Light_ActionBar = 16974484; // 0x1030294
+ field public static final int Widget_Material_Light_ActionBar_Solid = 16974485; // 0x1030295
+ field public static final int Widget_Material_Light_ActionBar_TabBar = 16974486; // 0x1030296
+ field public static final int Widget_Material_Light_ActionBar_TabText = 16974487; // 0x1030297
+ field public static final int Widget_Material_Light_ActionBar_TabView = 16974488; // 0x1030298
+ field public static final int Widget_Material_Light_ActionButton = 16974489; // 0x1030299
+ field public static final int Widget_Material_Light_ActionButton_CloseMode = 16974490; // 0x103029a
+ field public static final int Widget_Material_Light_ActionButton_Overflow = 16974491; // 0x103029b
+ field public static final int Widget_Material_Light_ActionMode = 16974492; // 0x103029c
+ field public static final int Widget_Material_Light_AutoCompleteTextView = 16974493; // 0x103029d
+ field public static final int Widget_Material_Light_Button = 16974494; // 0x103029e
+ field public static final int Widget_Material_Light_ButtonBar = 16974500; // 0x10302a4
+ field public static final int Widget_Material_Light_ButtonBar_AlertDialog = 16974501; // 0x10302a5
+ field public static final int Widget_Material_Light_Button_Borderless = 16974495; // 0x103029f
+ field public static final int Widget_Material_Light_Button_Borderless_Small = 16974496; // 0x10302a0
+ field public static final int Widget_Material_Light_Button_Inset = 16974497; // 0x10302a1
+ field public static final int Widget_Material_Light_Button_Small = 16974498; // 0x10302a2
+ field public static final int Widget_Material_Light_Button_Toggle = 16974499; // 0x10302a3
+ field public static final int Widget_Material_Light_CalendarView = 16974502; // 0x10302a6
+ field public static final int Widget_Material_Light_CheckedTextView = 16974503; // 0x10302a7
+ field public static final int Widget_Material_Light_CompoundButton_CheckBox = 16974504; // 0x10302a8
+ field public static final int Widget_Material_Light_CompoundButton_RadioButton = 16974505; // 0x10302a9
+ field public static final int Widget_Material_Light_CompoundButton_Star = 16974506; // 0x10302aa
+ field public static final int Widget_Material_Light_DropDownItem = 16974507; // 0x10302ab
+ field public static final int Widget_Material_Light_DropDownItem_Spinner = 16974508; // 0x10302ac
+ field public static final int Widget_Material_Light_EditText = 16974509; // 0x10302ad
+ field public static final int Widget_Material_Light_ExpandableListView = 16974510; // 0x10302ae
+ field public static final int Widget_Material_Light_FastScroll = 16974511; // 0x10302af
+ field public static final int Widget_Material_Light_GridView = 16974512; // 0x10302b0
+ field public static final int Widget_Material_Light_HorizontalScrollView = 16974513; // 0x10302b1
+ field public static final int Widget_Material_Light_ImageButton = 16974514; // 0x10302b2
+ field public static final int Widget_Material_Light_ListPopupWindow = 16974515; // 0x10302b3
+ field public static final int Widget_Material_Light_ListView = 16974516; // 0x10302b4
+ field public static final int Widget_Material_Light_ListView_DropDown = 16974517; // 0x10302b5
+ field public static final int Widget_Material_Light_MediaRouteButton = 16974518; // 0x10302b6
+ field public static final int Widget_Material_Light_PopupMenu = 16974519; // 0x10302b7
+ field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974520; // 0x10302b8
+ field public static final int Widget_Material_Light_PopupWindow = 16974521; // 0x10302b9
+ field public static final int Widget_Material_Light_ProgressBar = 16974522; // 0x10302ba
+ field public static final int Widget_Material_Light_ProgressBar_Horizontal = 16974523; // 0x10302bb
+ field public static final int Widget_Material_Light_ProgressBar_Inverse = 16974524; // 0x10302bc
+ field public static final int Widget_Material_Light_ProgressBar_Large = 16974525; // 0x10302bd
+ field public static final int Widget_Material_Light_ProgressBar_Large_Inverse = 16974526; // 0x10302be
+ field public static final int Widget_Material_Light_ProgressBar_Small = 16974527; // 0x10302bf
+ field public static final int Widget_Material_Light_ProgressBar_Small_Inverse = 16974528; // 0x10302c0
+ field public static final int Widget_Material_Light_ProgressBar_Small_Title = 16974529; // 0x10302c1
+ field public static final int Widget_Material_Light_RatingBar = 16974530; // 0x10302c2
+ field public static final int Widget_Material_Light_RatingBar_Indicator = 16974531; // 0x10302c3
+ field public static final int Widget_Material_Light_RatingBar_Small = 16974532; // 0x10302c4
+ field public static final int Widget_Material_Light_ScrollView = 16974533; // 0x10302c5
+ field public static final int Widget_Material_Light_SeekBar = 16974534; // 0x10302c6
+ field public static final int Widget_Material_Light_SegmentedButton = 16974535; // 0x10302c7
+ field public static final int Widget_Material_Light_Spinner = 16974537; // 0x10302c9
+ field public static final int Widget_Material_Light_StackView = 16974536; // 0x10302c8
+ field public static final int Widget_Material_Light_Tab = 16974538; // 0x10302ca
+ field public static final int Widget_Material_Light_TabWidget = 16974539; // 0x10302cb
+ field public static final int Widget_Material_Light_TextView = 16974540; // 0x10302cc
+ field public static final int Widget_Material_Light_TextView_SpinnerItem = 16974541; // 0x10302cd
+ field public static final int Widget_Material_Light_WebTextView = 16974542; // 0x10302ce
+ field public static final int Widget_Material_Light_WebView = 16974543; // 0x10302cf
+ field public static final int Widget_Material_ListPopupWindow = 16974455; // 0x1030277
+ field public static final int Widget_Material_ListView = 16974456; // 0x1030278
+ field public static final int Widget_Material_ListView_DropDown = 16974457; // 0x1030279
+ field public static final int Widget_Material_MediaRouteButton = 16974458; // 0x103027a
+ field public static final int Widget_Material_PopupMenu = 16974459; // 0x103027b
+ field public static final int Widget_Material_PopupMenu_Overflow = 16974460; // 0x103027c
+ field public static final int Widget_Material_PopupWindow = 16974461; // 0x103027d
+ field public static final int Widget_Material_ProgressBar = 16974462; // 0x103027e
+ field public static final int Widget_Material_ProgressBar_Horizontal = 16974463; // 0x103027f
+ field public static final int Widget_Material_ProgressBar_Large = 16974464; // 0x1030280
+ field public static final int Widget_Material_ProgressBar_Small = 16974465; // 0x1030281
+ field public static final int Widget_Material_ProgressBar_Small_Title = 16974466; // 0x1030282
+ field public static final int Widget_Material_RatingBar = 16974467; // 0x1030283
+ field public static final int Widget_Material_RatingBar_Indicator = 16974468; // 0x1030284
+ field public static final int Widget_Material_RatingBar_Small = 16974469; // 0x1030285
+ field public static final int Widget_Material_ScrollView = 16974470; // 0x1030286
+ field public static final int Widget_Material_SeekBar = 16974471; // 0x1030287
+ field public static final int Widget_Material_SegmentedButton = 16974472; // 0x1030288
+ field public static final int Widget_Material_Spinner = 16974474; // 0x103028a
+ field public static final int Widget_Material_StackView = 16974473; // 0x1030289
+ field public static final int Widget_Material_Tab = 16974475; // 0x103028b
+ field public static final int Widget_Material_TabWidget = 16974476; // 0x103028c
+ field public static final int Widget_Material_TextView = 16974477; // 0x103028d
+ field public static final int Widget_Material_TextView_SpinnerItem = 16974478; // 0x103028e
+ field public static final int Widget_Material_Toolbar = 16974479; // 0x103028f
+ field public static final int Widget_Material_Toolbar_Button_Navigation = 16974480; // 0x1030290
+ field public static final int Widget_Material_WebTextView = 16974481; // 0x1030291
+ field public static final int Widget_Material_WebView = 16974482; // 0x1030292
field public static final int Widget_PopupMenu = 16973958; // 0x1030086
field public static final int Widget_PopupWindow = 16973878; // 0x1030036
field public static final int Widget_ProgressBar = 16973852; // 0x103001c
@@ -5196,6 +5200,7 @@
method public void clearDeviceOwnerApp();
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
+ method public android.os.UserHandle createAndInitializeUser(android.content.ComponentName, java.lang.String, java.lang.String, android.content.ComponentName, android.os.Bundle);
method public android.os.UserHandle createUser(android.content.ComponentName, java.lang.String);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
@@ -8242,11 +8247,11 @@
}
public static abstract interface LauncherApps.OnAppsChangedListener {
- method public abstract void onPackageAdded(java.lang.String, android.os.UserHandle);
- method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
- method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
- method public abstract void onPackagesAvailable(java.lang.String[], android.os.UserHandle, boolean);
- method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
+ method public abstract void onPackageAdded(android.os.UserHandle, java.lang.String);
+ method public abstract void onPackageChanged(android.os.UserHandle, java.lang.String);
+ method public abstract void onPackageRemoved(android.os.UserHandle, java.lang.String);
+ method public abstract void onPackagesAvailable(android.os.UserHandle, java.lang.String[], boolean);
+ method public abstract void onPackagesUnavailable(android.os.UserHandle, java.lang.String[], boolean);
}
public class PackageInfo implements android.os.Parcelable {
@@ -11960,14 +11965,18 @@
method public int getMinDelay();
method public java.lang.String getName();
method public float getPower();
+ method public int getReportingMode();
method public float getResolution();
method public java.lang.String getStringType();
method public int getType();
method public java.lang.String getVendor();
method public int getVersion();
method public boolean isWakeUpSensor();
+ field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
+ field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
+ field public static final int REPORTING_MODE_ON_CHANGE = 1; // 0x1
+ field public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3; // 0x3
field public static final java.lang.String SENSOR_STRING_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR = "android.sensor.non_wake_up_proximity_sensor";
- field public static final java.lang.String SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR = "android.sensor.wake_up_tilt_detector";
field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
@@ -12048,7 +12057,6 @@
field public static final int TYPE_WAKE_UP_ROTATION_VECTOR = 31; // 0x1f
field public static final int TYPE_WAKE_UP_STEP_COUNTER = 38; // 0x26
field public static final int TYPE_WAKE_UP_STEP_DETECTOR = 37; // 0x25
- field public static final int TYPE_WAKE_UP_TILT_DETECTOR = 41; // 0x29
}
public class SensorEvent {
@@ -12655,6 +12663,7 @@
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_FRAME_DURATION;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_GREEN_SPLIT;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NEUTRAL_COLOR_POINT;
+ field public static final android.hardware.camera2.CaptureResult.Key SENSOR_ROLLING_SHUTTER_SKEW;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_SENSITIVITY;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_DATA;
field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_MODE;
@@ -15880,6 +15889,7 @@
method public android.content.Intent getIntentForSetupActivity();
method public android.content.pm.ServiceInfo getServiceInfo();
method public int getType();
+ method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String EXTRA_SERVICE_NAME = "serviceName";
@@ -16090,28 +16100,25 @@
method public deprecated int getNetworkPreference();
method public static android.net.Network getProcessDefaultNetwork();
method public boolean isActiveNetworkMetered();
- method public boolean isNetworkActive();
+ method public boolean isDefaultNetworkActive();
method public static boolean isNetworkTypeValid(int);
- method public android.net.NetworkRequest listenForNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
- method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
- method public void releaseNetworkRequest(android.net.NetworkRequest);
+ method public void registerDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+ method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
method public void reportBadNetwork(android.net.Network);
- method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.net.ConnectivityManager.NetworkCallbackListener);
- method public android.net.NetworkRequest requestNetwork(android.net.NetworkCapabilities, android.app.PendingIntent);
+ method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback);
method public deprecated boolean requestRouteToHost(int, int);
method public deprecated void setNetworkPreference(int);
method public static boolean setProcessDefaultNetwork(android.net.Network);
method public deprecated int startUsingNetworkFeature(int, java.lang.String);
method public deprecated int stopUsingNetworkFeature(int, java.lang.String);
- method public void unregisterNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+ method public void unregisterDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+ method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback);
field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
- field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
- field public static final java.lang.String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES = "networkRequestNetworkCapabilities";
field public static final java.lang.String EXTRA_NETWORK_TYPE = "networkType";
field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
@@ -16128,14 +16135,13 @@
field public static final int TYPE_WIMAX = 6; // 0x6
}
- public static class ConnectivityManager.NetworkCallbackListener {
- ctor public ConnectivityManager.NetworkCallbackListener();
- method public void onAvailable(android.net.NetworkRequest, android.net.Network);
- method public void onLinkPropertiesChanged(android.net.NetworkRequest, android.net.Network, android.net.LinkProperties);
- method public void onLosing(android.net.NetworkRequest, android.net.Network, int);
- method public void onLost(android.net.NetworkRequest, android.net.Network);
- method public void onNetworkCapabilitiesChanged(android.net.NetworkRequest, android.net.Network, android.net.NetworkCapabilities);
- method public void onReleased(android.net.NetworkRequest);
+ public static class ConnectivityManager.NetworkCallback {
+ ctor public ConnectivityManager.NetworkCallback();
+ method public void onAvailable(android.net.Network);
+ method public void onCapabilitiesChanged(android.net.Network, android.net.NetworkCapabilities);
+ method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
+ method public void onLosing(android.net.Network, int);
+ method public void onLost(android.net.Network);
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -16162,12 +16168,13 @@
field public int serverAddress;
}
- public class IpPrefix implements android.os.Parcelable {
+ public final class IpPrefix implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
method public int getPrefixLength();
method public byte[] getRawAddress();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
}
public class LinkAddress implements android.os.Parcelable {
@@ -16179,7 +16186,7 @@
method public void writeToParcel(android.os.Parcel, int);
}
- public class LinkProperties implements android.os.Parcelable {
+ public final class LinkProperties implements android.os.Parcelable {
method public int describeContents();
method public java.util.List<java.net.InetAddress> getDnsServers();
method public java.lang.String getDomains();
@@ -16269,21 +16276,12 @@
}
public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities();
ctor public NetworkCapabilities(android.net.NetworkCapabilities);
- method public void addNetworkCapability(int);
- method public void addTransportType(int);
method public int describeContents();
method public int getLinkDownstreamBandwidthKbps();
method public int getLinkUpstreamBandwidthKbps();
- method public java.util.Collection<java.lang.Integer> getNetworkCapabilities();
- method public java.util.Collection<java.lang.Integer> getTransportTypes();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
- method public void removeNetworkCapability(int);
- method public void removeTransportType(int);
- method public void setLinkDownstreamBandwidthKbps(int);
- method public void setLinkUpstreamBandwidthKbps(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int NET_CAPABILITY_CBS = 5; // 0x5
@@ -16357,7 +16355,15 @@
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
- field public final android.net.NetworkCapabilities networkCapabilities;
+ }
+
+ public static class NetworkRequest.Builder {
+ ctor public NetworkRequest.Builder();
+ method public android.net.NetworkRequest.Builder addCapability(int);
+ method public android.net.NetworkRequest.Builder addTransportType(int);
+ method public android.net.NetworkRequest build();
+ method public android.net.NetworkRequest.Builder removeCapability(int);
+ method public android.net.NetworkRequest.Builder removeTransportType(int);
}
public class ParseException extends java.lang.RuntimeException {
@@ -16386,7 +16392,7 @@
method public void writeToParcel(android.os.Parcel, int);
}
- public class RouteInfo implements android.os.Parcelable {
+ public final class RouteInfo implements android.os.Parcelable {
method public int describeContents();
method public android.net.IpPrefix getDestination();
method public java.net.InetAddress getGateway();
@@ -16394,6 +16400,7 @@
method public boolean isDefaultRoute();
method public boolean matches(java.net.InetAddress);
method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
}
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
@@ -26516,6 +26523,7 @@
}
public static final class TextToSpeechClient.EngineStatus {
+ method public java.util.Locale getDefaultLocale();
method public java.lang.String getEnginePackage();
method public java.util.List<android.speech.tts.VoiceInfo> getVoices();
}
@@ -27352,8 +27360,8 @@
field public final int supportedRouteMask;
}
- public class CallCapabilities {
- ctor public CallCapabilities();
+ public final class CallCapabilities {
+ method public static java.lang.String toString(int);
field public static final int ADD_CALL = 16; // 0x10
field public static final int ALL = 511; // 0x1ff
field public static final int CONNECTION_HANDOFF = 256; // 0x100
@@ -27412,6 +27420,7 @@
}
public final class CallServiceAdapter {
+ method public void addConferenceCall(java.lang.String);
method public void handleFailedOutgoingCall(android.telecomm.ConnectionRequest, int, java.lang.String);
method public void handleSuccessfulOutgoingCall(java.lang.String);
method public void handoffCall(java.lang.String);
@@ -27486,16 +27495,23 @@
public abstract class Connection {
ctor protected Connection();
+ method public final void conference();
method public final android.telecomm.CallAudioState getCallAudioState();
+ method public java.util.List<android.telecomm.Connection> getChildConnections();
method public final android.net.Uri getHandle();
+ method public android.telecomm.Connection getParentConnection();
+ method public boolean isConferenceConnection();
method public boolean isRequestingRingback();
method protected void onAbort();
method protected void onAnswer();
+ method protected void onChildrenChanged(java.util.List<android.telecomm.Connection>);
+ method protected void onConference();
method protected void onDisconnect();
method protected void onHold();
method protected void onPlayDtmfTone(char);
method protected void onPostDialContinue(boolean);
method protected void onReject();
+ method protected void onSeparate();
method protected void onSetAudioState(android.telecomm.CallAudioState);
method protected void onSetSignal(android.os.Bundle);
method protected void onSetState(int);
@@ -27503,10 +27519,13 @@
method protected void onUnhold();
method protected void setActive();
method public void setAudioState(android.telecomm.CallAudioState);
+ method protected void setDestroyed();
method protected void setDialing();
method protected void setDisconnected(int, java.lang.String);
method protected void setHandle(android.net.Uri);
+ method protected void setIsConferenceCapable(boolean);
method protected void setOnHold();
+ method public void setParentConnection(android.telecomm.Connection);
method protected void setRequestingRingback(boolean);
method protected void setRinging();
method public static java.lang.String stateToString(int);
@@ -27514,9 +27533,11 @@
public static abstract interface Connection.Listener {
method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+ method public abstract void onConferenceCapableChanged(android.telecomm.Connection, boolean);
method public abstract void onDestroyed(android.telecomm.Connection);
method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+ method public abstract void onParentConnectionChanged(android.telecomm.Connection, android.telecomm.Connection);
method public abstract void onRequestingRingback(android.telecomm.Connection, boolean);
method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
method public abstract void onStateChanged(android.telecomm.Connection, int);
@@ -27525,9 +27546,11 @@
public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
ctor public Connection.ListenerBase();
method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+ method public void onConferenceCapableChanged(android.telecomm.Connection, boolean);
method public void onDestroyed(android.telecomm.Connection);
method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+ method public void onParentConnectionChanged(android.telecomm.Connection, android.telecomm.Connection);
method public void onRequestingRingback(android.telecomm.Connection, boolean);
method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
method public void onStateChanged(android.telecomm.Connection, int);
@@ -27559,9 +27582,13 @@
method public final void answer(java.lang.String);
method public final void call(android.telecomm.CallInfo);
method public final void disconnect(java.lang.String);
+ method public java.util.Collection<android.telecomm.Connection> getAllConnections();
method public final void hold(java.lang.String);
method public final void isCompatibleWith(android.telecomm.CallInfo);
method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
+ method public void onConnectionAdded(android.telecomm.Connection);
+ method public void onConnectionRemoved(android.telecomm.Connection);
+ method public void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>);
method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
@@ -33518,6 +33545,7 @@
method public android.transition.Transition getSharedElementEnterTransition();
method public android.transition.Transition getSharedElementExitTransition();
method public abstract int getStatusBarColor();
+ method public long getTransitionBackgroundFadeDuration();
method public android.transition.TransitionManager getTransitionManager();
method public abstract int getVolumeControlStream();
method public android.view.WindowManager getWindowManager();
@@ -33576,6 +33604,7 @@
method public abstract void setStatusBarColor(int);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract deprecated void setTitleColor(int);
+ method public void setTransitionBackgroundFadeDuration(long);
method public void setTransitionManager(android.transition.TransitionManager);
method public void setType(int);
method public void setUiOptions(int);
@@ -34590,15 +34619,15 @@
field public static final android.os.Parcelable.Creator CREATOR;
}
- public static final class CursorAnchorInfo.CursorAnchorInfoBuilder {
- ctor public CursorAnchorInfo.CursorAnchorInfoBuilder();
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder addCharacterRect(int, float, float, float, float);
+ public static final class CursorAnchorInfo.Builder {
+ ctor public CursorAnchorInfo.Builder();
+ method public android.view.inputmethod.CursorAnchorInfo.Builder addCharacterRect(int, float, float, float, float);
method public android.view.inputmethod.CursorAnchorInfo build();
method public void reset();
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setComposingText(int, java.lang.CharSequence);
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setInsertionMarkerLocation(float, float, float, float);
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setMatrix(android.graphics.Matrix);
- method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setSelectionRange(int, int);
+ method public android.view.inputmethod.CursorAnchorInfo.Builder setComposingText(int, java.lang.CharSequence);
+ method public android.view.inputmethod.CursorAnchorInfo.Builder setInsertionMarkerLocation(float, float, float, float);
+ method public android.view.inputmethod.CursorAnchorInfo.Builder setMatrix(android.graphics.Matrix);
+ method public android.view.inputmethod.CursorAnchorInfo.Builder setSelectionRange(int, int);
}
public class EditorInfo implements android.text.InputType android.os.Parcelable {
@@ -34973,7 +35002,8 @@
package android.webkit {
- public abstract interface ClientCertRequest {
+ public abstract class ClientCertRequest {
+ ctor public ClientCertRequest();
method public abstract void cancel();
method public abstract java.lang.String getHost();
method public abstract java.lang.String[] getKeyTypes();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 2620c44..cbc8150 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -462,7 +462,9 @@
* anything behind it, then only the modal window will be reported
* (assuming it is the top one). For convenience the returned windows
* are ordered in a descending layer order, which is the windows that
- * are higher in the Z-order are reported first.
+ * are higher in the Z-order are reported first. Since the user can always
+ * interact with the window that has input focus by typing, the focused
+ * window is always returned (even if covered by a modal window).
* <p>
* <strong>Note:</strong> In order to access the windows your service has
* to declare the capability to retrieve window content by setting the
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4f9ba59..4edb0c6 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -286,8 +286,8 @@
/**
* This flag indicates to the system that the accessibility service wants
* to access content of all interactive windows. An interactive window is a
- * window that can be touched by a sighted user when explore by touch is not
- * enabled. If this flag is not set your service will not receive
+ * window that has input focus or can be touched by a sighted user when explore
+ * by touch is not enabled. If this flag is not set your service will not receive
* {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED}
* events, calling AccessibilityService{@link AccessibilityService#getWindows()
* AccessibilityService.getWindows()} will return an empty list, and {@link
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 12fcdcf..806a55b 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -359,7 +359,29 @@
*/
public AuthenticatorDescription[] getAuthenticatorTypes() {
try {
- return mService.getAuthenticatorTypes();
+ return mService.getAuthenticatorTypes(UserHandle.getCallingUserId());
+ } catch (RemoteException e) {
+ // will never happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @hide
+ * Lists the currently registered authenticators for a given user id.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>The caller has to be in the same user or have the permission
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ *
+ * @return An array of {@link AuthenticatorDescription} for every
+ * authenticator known to the AccountManager service. Empty (never
+ * null) if no authenticators are known.
+ */
+ public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) {
+ try {
+ return mService.getAuthenticatorTypes(userId);
} catch (RemoteException e) {
// will never happen
throw new RuntimeException(e);
@@ -389,6 +411,28 @@
/**
* @hide
+ * Lists all accounts of any type registered on the device for a given
+ * user id. Equivalent to getAccountsByType(null).
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#GET_ACCOUNTS}.
+ *
+ * @return An array of {@link Account}, one for each account. Empty
+ * (never null) if no accounts have been added.
+ */
+ public Account[] getAccountsAsUser(int userId) {
+ try {
+ return mService.getAccountsAsUser(null, userId);
+ } catch (RemoteException e) {
+ // won't ever happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * @hide
* For use by internal activities. Returns the list of accounts that the calling package
* is authorized to use, particularly for shared accounts.
* @param packageName package name of the calling app.
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 86e279f..1373dc8 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -29,7 +29,7 @@
interface IAccountManager {
String getPassword(in Account account);
String getUserData(in Account account, String key);
- AuthenticatorDescription[] getAuthenticatorTypes();
+ AuthenticatorDescription[] getAuthenticatorTypes(int userId);
Account[] getAccounts(String accountType);
Account[] getAccountsForPackage(String packageName, int uid);
Account[] getAccountsByTypeForPackage(String type, String packageName);
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 933135d..06f5aca 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
@@ -25,6 +26,9 @@
import android.util.TypedValue;
import android.util.Xml;
import android.view.animation.AnimationUtils;
+
+import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -66,11 +70,26 @@
*/
public static Animator loadAnimator(Context context, int id)
throws NotFoundException {
+ return loadAnimator(context.getResources(), context.getTheme(), id);
+ }
+
+ /**
+ * Loads an {@link Animator} object from a resource
+ *
+ * @param resources The resources
+ * @param theme The theme
+ * @param id The resource id of the animation to load
+ * @return The animator object reference by the specified id
+ * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded
+ * @hide
+ */
+ public static Animator loadAnimator(Resources resources, Theme theme, int id)
+ throws NotFoundException {
XmlResourceParser parser = null;
try {
- parser = context.getResources().getAnimation(id);
- return createAnimatorFromXml(context, parser);
+ parser = resources.getAnimation(id);
+ return createAnimatorFromXml(resources, theme, parser);
} catch (XmlPullParserException ex) {
Resources.NotFoundException rnf =
new Resources.NotFoundException("Can't load animation resource ID #0x" +
@@ -150,7 +169,8 @@
}
if (animator == null) {
- animator = createAnimatorFromXml(context, parser);
+ animator = createAnimatorFromXml(context.getResources(),
+ context.getTheme(), parser);
}
if (animator == null) {
@@ -166,103 +186,8 @@
}
}
- private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
- throws XmlPullParserException, IOException {
- return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
- }
- private static Animator createAnimatorFromXml(Context c, XmlPullParser parser,
- AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
- throws XmlPullParserException, IOException {
-
- Animator anim = null;
- ArrayList<Animator> childAnims = null;
-
- // Make sure we are on a start tag.
- int type;
- int depth = parser.getDepth();
-
- while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
- && type != XmlPullParser.END_DOCUMENT) {
-
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
-
- String name = parser.getName();
-
- if (name.equals("objectAnimator")) {
- anim = loadObjectAnimator(c, attrs);
- } else if (name.equals("animator")) {
- anim = loadAnimator(c, attrs, null);
- } else if (name.equals("set")) {
- anim = new AnimatorSet();
- TypedArray a = c.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.AnimatorSet);
- int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering,
- TOGETHER);
- createAnimatorFromXml(c, parser, attrs, (AnimatorSet) anim, ordering);
- a.recycle();
- } else {
- throw new RuntimeException("Unknown animator name: " + parser.getName());
- }
-
- if (parent != null) {
- if (childAnims == null) {
- childAnims = new ArrayList<Animator>();
- }
- childAnims.add(anim);
- }
- }
- if (parent != null && childAnims != null) {
- Animator[] animsArray = new Animator[childAnims.size()];
- int index = 0;
- for (Animator a : childAnims) {
- animsArray[index++] = a;
- }
- if (sequenceOrdering == TOGETHER) {
- parent.playTogether(animsArray);
- } else {
- parent.playSequentially(animsArray);
- }
- }
-
- return anim;
-
- }
-
- private static ObjectAnimator loadObjectAnimator(Context context, AttributeSet attrs)
- throws NotFoundException {
-
- ObjectAnimator anim = new ObjectAnimator();
-
- loadAnimator(context, attrs, anim);
-
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.PropertyAnimator);
-
- String propertyName = a.getString(com.android.internal.R.styleable.PropertyAnimator_propertyName);
-
- anim.setPropertyName(propertyName);
-
- a.recycle();
-
- return anim;
- }
-
- /**
- * Creates a new animation whose parameters come from the specified context and
- * attributes set.
- *
- * @param context the application environment
- * @param attrs the set of attributes holding the animation parameters
- */
- private static ValueAnimator loadAnimator(Context context, AttributeSet attrs, ValueAnimator anim)
- throws NotFoundException {
-
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animator);
-
+ private static void parseAnimatorFromTypeArray(ValueAnimator anim, TypedArray a) {
long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 300);
long startDelay = a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0);
@@ -378,11 +303,123 @@
if (evaluator != null) {
anim.setEvaluator(evaluator);
}
+ }
+
+ private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0);
+ }
+
+ private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
+ AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
+ throws XmlPullParserException, IOException {
+
+ Animator anim = null;
+ ArrayList<Animator> childAnims = null;
+
+ // Make sure we are on a start tag.
+ int type;
+ int depth = parser.getDepth();
+
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+
+ if (name.equals("objectAnimator")) {
+ anim = loadObjectAnimator(res, theme, attrs);
+ } else if (name.equals("animator")) {
+ anim = loadAnimator(res, theme, attrs, null);
+ } else if (name.equals("set")) {
+ anim = new AnimatorSet();
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnimatorSet, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, com.android.internal.R.styleable.AnimatorSet);
+ }
+ int ordering = a.getInt(com.android.internal.R.styleable.AnimatorSet_ordering,
+ TOGETHER);
+ createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering);
+ a.recycle();
+ } else {
+ throw new RuntimeException("Unknown animator name: " + parser.getName());
+ }
+
+ if (parent != null) {
+ if (childAnims == null) {
+ childAnims = new ArrayList<Animator>();
+ }
+ childAnims.add(anim);
+ }
+ }
+ if (parent != null && childAnims != null) {
+ Animator[] animsArray = new Animator[childAnims.size()];
+ int index = 0;
+ for (Animator a : childAnims) {
+ animsArray[index++] = a;
+ }
+ if (sequenceOrdering == TOGETHER) {
+ parent.playTogether(animsArray);
+ } else {
+ parent.playSequentially(animsArray);
+ }
+ }
+
+ return anim;
+
+ }
+
+ private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs)
+ throws NotFoundException {
+ ObjectAnimator anim = new ObjectAnimator();
+
+ loadAnimator(res, theme, attrs, anim);
+
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.PropertyAnimator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.PropertyAnimator);
+ }
+
+ String propertyName = a.getString(R.styleable.PropertyAnimator_propertyName);
+
+ anim.setPropertyName(propertyName);
+
+ a.recycle();
+
+ return anim;
+ }
+
+ /**
+ * Creates a new animation whose parameters come from the specified context
+ * and attributes set.
+ *
+ * @param res The resources
+ * @param attrs The set of attributes holding the animation parameters
+ */
+ private static ValueAnimator loadAnimator(Resources res, Theme theme,
+ AttributeSet attrs, ValueAnimator anim)
+ throws NotFoundException {
+
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.Animator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.Animator);
+ }
+
+ parseAnimatorFromTypeArray(anim, a);
final int resID =
a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
if (resID > 0) {
- anim.setInterpolator(AnimationUtils.loadInterpolator(context, resID));
+ anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID));
}
a.recycle();
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 1f3218b..0cccedc 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -129,9 +129,6 @@
protected static final String KEY_SCALE_TYPE = "shared_element:scaleType";
protected static final String KEY_IMAGE_MATRIX = "shared_element:imageMatrix";
- // The background fade in/out duration. TODO: Enable tuning this.
- public static final int FADE_BACKGROUND_DURATION_MS = 300;
-
protected static final ImageView.ScaleType[] SCALE_TYPE_VALUES = ImageView.ScaleType.values();
/**
@@ -512,6 +509,10 @@
return bundle;
}
+ protected long getFadeDuration() {
+ return getWindow().getTransitionBackgroundFadeDuration();
+ }
+
/**
* Captures placement information for Views with a shared element name for
* Activity Transitions.
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 94ea2c5..c29d75e 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -354,11 +354,9 @@
private static class ActivityContainerWrapper {
private final IActivityContainer mIActivityContainer;
private final CloseGuard mGuard = CloseGuard.get();
- boolean mOpened; // Protected by mGuard.
ActivityContainerWrapper(IActivityContainer container) {
mIActivityContainer = container;
- mOpened = true;
mGuard.open("release");
}
@@ -426,16 +424,11 @@
}
void release() {
- synchronized (mGuard) {
- if (mOpened) {
- if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
- try {
- mIActivityContainer.release();
- mGuard.close();
- } catch (RemoteException e) {
- }
- mOpened = false;
- }
+ if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
+ try {
+ mIActivityContainer.release();
+ mGuard.close();
+ } catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 779e3de..f54cb87 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -66,15 +66,16 @@
Bundle resultReceiverBundle = new Bundle();
resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this);
mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
- getDecor().getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (mIsReadyForTransition) {
- getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
- }
- return mIsReadyForTransition;
- }
- });
+ getDecor().getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ if (mIsReadyForTransition) {
+ getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
+ }
+ return mIsReadyForTransition;
+ }
+ });
}
public void viewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
@@ -315,7 +316,7 @@
if (background != null) {
background = background.mutate();
mBackgroundAnimator = ObjectAnimator.ofInt(background, "alpha", 255);
- mBackgroundAnimator.setDuration(FADE_BACKGROUND_DURATION_MS);
+ mBackgroundAnimator.setDuration(getFadeDuration());
mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index ba1638ff..8d5b8317 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -199,7 +199,7 @@
}
}
});
- mBackgroundAnimator.setDuration(FADE_BACKGROUND_DURATION_MS);
+ mBackgroundAnimator.setDuration(getFadeDuration());
mBackgroundAnimator.start();
}
}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 85e970c..0d947217 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -293,7 +293,7 @@
IVoiceInteractorRequest submit(IVoiceInteractor interactor, String packageName,
IVoiceInteractorCallback callback) throws RemoteException {
- return interactor.startConfirmation(packageName, callback, mCommand, mArgs);
+ return interactor.startCommand(packageName, callback, mCommand, mArgs);
}
}
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 1015514..45a2625 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -222,6 +222,12 @@
* Called after the administrator is first enabled, as a result of
* receiving {@link #ACTION_DEVICE_ADMIN_ENABLED}. At this point you
* can use {@link DevicePolicyManager} to set your desired policies.
+ *
+ * <p> If the admin is activated by a device owner, then the intent
+ * may contain private extras that are relevant to user setup.
+ * {@see DevicePolicyManager#createAndInitializeUser(ComponentName, String, String,
+ * ComponentName, Intent)}
+ *
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
*/
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 04be028..e80c761 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2111,6 +2111,41 @@
}
/**
+ * Called by a device owner to create a user with the specified name. The UserHandle returned
+ * by this method should not be persisted as user handles are recycled as users are removed and
+ * created. If you need to persist an identifier for this user, use
+ * {@link UserManager#getSerialNumberForUser}. The new user will be started in the background
+ * immediately.
+ *
+ * <p> profileOwnerComponent is the {@link DeviceAdminReceiver} to be the profile owner as well
+ * as registered as an active admin on the new user. The profile owner package will be
+ * installed on the new user if it already is installed on the device.
+ *
+ * <p>If the optionalInitializeData is not null, then the extras will be passed to the
+ * profileOwnerComponent when onEnable is called.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param name the user's name
+ * @param ownerName the human readable name of the organisation associated with this DPM.
+ * @param profileOwnerComponent The {@link DeviceAdminReceiver} that will be an active admin on
+ * the user.
+ * @param adminExtras Extras that will be passed to onEnable of the admin receiver
+ * on the new user.
+ * @see UserHandle
+ * @return the UserHandle object for the created user, or null if the user could not be created.
+ */
+ public UserHandle createAndInitializeUser(ComponentName admin, String name, String ownerName,
+ ComponentName profileOwnerComponent, Bundle adminExtras) {
+ try {
+ return mService.createAndInitializeUser(admin, name, ownerName, profileOwnerComponent,
+ adminExtras);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not create a user", re);
+ }
+ return null;
+ }
+
+ /**
* Called by a device owner to remove a user and all associated data. The primary user can
* not be removed.
*
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index f8df780b..a1caa21 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -136,6 +136,7 @@
boolean isApplicationBlocked(in ComponentName admin, in String packageName);
UserHandle createUser(in ComponentName who, in String name);
+ UserHandle createAndInitializeUser(in ComponentName who, in String name, in String profileOwnerName, in ComponentName profileOwnerComponent, in Bundle adminExtras);
boolean removeUser(in ComponentName who, in UserHandle userHandle);
void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 7b709ac..5175490 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -90,6 +90,11 @@
public static final String ACTION_PLAYING_STATE_CHANGED =
"android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
+ /** @hide */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
+
/**
* A2DP sink device is streaming music. This state can be one of
* {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
new file mode 100644
index 0000000..2e27345
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth A2DP Sink
+ * profile.
+ *
+ *<p>BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothA2dpSink proxy object.
+ *
+ * @hide
+ */
+public final class BluetoothA2dpSink implements BluetoothProfile {
+ private static final String TAG = "BluetoothA2dpSink";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the A2DP Sink
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent used to broadcast the change in the Playing state of the A2DP Sink
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ public static final String ACTION_PLAYING_STATE_CHANGED =
+ "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED";
+
+ /**
+ * A2DP sink device is streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_PLAYING = 10;
+
+ /**
+ * A2DP sink device is NOT streaming music. This state can be one of
+ * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
+ * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
+ */
+ public static final int STATE_NOT_PLAYING = 11;
+
+ /**
+ * Intent used to broadcast the change in the Playing state of the A2DP Sink
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_AUDIO_CONFIG} - The audio configuration for the remote device. </li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ public static final String ACTION_AUDIO_CONFIG_CHANGED =
+ "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED";
+
+ /**
+ * Extra for the {@link #ACTION_AUDIO_CONFIG_CHANGED} intent.
+ *
+ * This extra represents the current audio configuration of the A2DP source device.
+ * {@see BluetoothAudioConfig}
+ */
+ public static final String EXTRA_AUDIO_CONFIG
+ = "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG";
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private IBluetoothA2dpSink mService;
+ private BluetoothAdapter mAdapter;
+
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (VDBG) Log.d(TAG,"Binding service...");
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+ /**
+ * Create a BluetoothA2dp proxy object for interacting with the local
+ * Bluetooth A2DP service.
+ *
+ */
+ /*package*/ BluetoothA2dpSink(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothA2dpSink.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+ /*package*/ void close() {
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+
+ public void finalize() {
+ close();
+ }
+ /**
+ * Initiate connection to a profile of the remote bluetooth device.
+ *
+ * <p> Currently, the system supports only 1 connection to the
+ * A2DP profile. The API will automatically disconnect connected
+ * devices before connecting.
+ *
+ * <p> This API returns false in scenarios like the profile on the
+ * device is already connected or Bluetooth is not turned on.
+ * When this API returns true, it is guaranteed that
+ * connection state intent for the profile will be broadcasted with
+ * the state. Users can get the connection state of the profile
+ * from this intent.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.connect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Initiate disconnection from a profile
+ *
+ * <p> This API will return false in scenarios like the profile on the
+ * Bluetooth device is not in connected state etc. When this API returns,
+ * true, it is guaranteed that the connection state change
+ * intent will be broadcasted with the state. Users can get the
+ * disconnection state of the profile from this intent.
+ *
+ * <p> If the disconnection is initiated by a remote device, the state
+ * will transition from {@link #STATE_CONNECTED} to
+ * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
+ * host (local) device the state will transition from
+ * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
+ * state {@link #STATE_DISCONNECTED}. The transition to
+ * {@link #STATE_DISCONNECTING} can be used to distinguish between the
+ * two scenarios.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * permission.
+ *
+ * @param device Remote Bluetooth Device
+ * @return false on immediate error,
+ * true otherwise
+ * @hide
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.disconnect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * Get the current audio configuration for the A2DP source device,
+ * or null if the device has no audio configuration
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device Remote bluetooth device.
+ * @return audio configuration for the device, or null
+ *
+ * {@see BluetoothAudioConfig}
+ */
+ public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
+ if (VDBG) log("getAudioConfig(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getAudioConfig(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return null;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ }
+
+ /**
+ * Helper for converting a state to a string.
+ *
+ * For debug use only - strings are not internationalized.
+ * @hide
+ */
+ public static String stateToString(int state) {
+ switch (state) {
+ case STATE_DISCONNECTED:
+ return "disconnected";
+ case STATE_CONNECTING:
+ return "connecting";
+ case STATE_CONNECTED:
+ return "connected";
+ case STATE_DISCONNECTING:
+ return "disconnecting";
+ case STATE_PLAYING:
+ return "playing";
+ case STATE_NOT_PLAYING:
+ return "not playing";
+ default:
+ return "<unknown state " + state + ">";
+ }
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ mService = IBluetoothA2dpSink.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK,
+ BluetoothA2dpSink.this);
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP_SINK);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 42c2aeb..ba42f51b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1390,6 +1390,12 @@
} else if (profile == BluetoothProfile.A2DP) {
BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
return true;
+ } else if (profile == BluetoothProfile.A2DP_SINK) {
+ BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
+ return true;
+ } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
+ BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
+ return true;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
return true;
@@ -1402,6 +1408,9 @@
} else if (profile == BluetoothProfile.MAP) {
BluetoothMap map = new BluetoothMap(context, listener);
return true;
+ } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
+ BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
+ return true;
} else {
return false;
}
@@ -1430,6 +1439,14 @@
BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
a2dp.close();
break;
+ case BluetoothProfile.A2DP_SINK:
+ BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy;
+ a2dpSink.close();
+ break;
+ case BluetoothProfile.AVRCP_CONTROLLER:
+ BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy;
+ avrcp.close();
+ break;
case BluetoothProfile.INPUT_DEVICE:
BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
iDev.close();
@@ -1454,6 +1471,10 @@
BluetoothMap map = (BluetoothMap)proxy;
map.close();
break;
+ case BluetoothProfile.HEADSET_CLIENT:
+ BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy;
+ headsetClient.close();
+ break;
}
}
diff --git a/core/java/android/bluetooth/BluetoothAudioConfig.aidl b/core/java/android/bluetooth/BluetoothAudioConfig.aidl
new file mode 100644
index 0000000..63be5cf
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAudioConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+parcelable BluetoothAudioConfig;
diff --git a/core/java/android/bluetooth/BluetoothAudioConfig.java b/core/java/android/bluetooth/BluetoothAudioConfig.java
new file mode 100644
index 0000000..03176b9
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAudioConfig.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents the audio configuration for a Bluetooth A2DP source device.
+ *
+ * {@see BluetoothA2dpSink}
+ *
+ * {@hide}
+ */
+public final class BluetoothAudioConfig implements Parcelable {
+
+ private final int mSampleRate;
+ private final int mChannelConfig;
+ private final int mAudioFormat;
+
+ public BluetoothAudioConfig(int sampleRate, int channelConfig, int audioFormat) {
+ mSampleRate = sampleRate;
+ mChannelConfig = channelConfig;
+ mAudioFormat = audioFormat;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothAudioConfig) {
+ BluetoothAudioConfig bac = (BluetoothAudioConfig)o;
+ return (bac.mSampleRate == mSampleRate &&
+ bac.mChannelConfig == mChannelConfig &&
+ bac.mAudioFormat == mAudioFormat);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mSampleRate | (mChannelConfig << 24) | (mAudioFormat << 28);
+ }
+
+ @Override
+ public String toString() {
+ return "{mSampleRate:" + mSampleRate + ",mChannelConfig:" + mChannelConfig
+ + ",mAudioFormat:" + mAudioFormat + "}";
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<BluetoothAudioConfig> CREATOR =
+ new Parcelable.Creator<BluetoothAudioConfig>() {
+ public BluetoothAudioConfig createFromParcel(Parcel in) {
+ int sampleRate = in.readInt();
+ int channelConfig = in.readInt();
+ int audioFormat = in.readInt();
+ return new BluetoothAudioConfig(sampleRate, channelConfig, audioFormat);
+ }
+ public BluetoothAudioConfig[] newArray(int size) {
+ return new BluetoothAudioConfig[size];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mSampleRate);
+ out.writeInt(mChannelConfig);
+ out.writeInt(mAudioFormat);
+ }
+
+ /**
+ * Returns the sample rate in samples per second
+ * @return sample rate
+ */
+ public int getSampleRate() {
+ return mSampleRate;
+ }
+
+ /**
+ * Returns the channel configuration (either {@link android.media.AudioFormat#CHANNEL_IN_MONO}
+ * or {@link android.media.AudioFormat#CHANNEL_IN_STEREO})
+ * @return channel configuration
+ */
+ public int getChannelConfig() {
+ return mChannelConfig;
+ }
+
+ /**
+ * Returns the channel audio format (either {@link android.media.AudioFormat#ENCODING_PCM_16BIT}
+ * or {@link android.media.AudioFormat#ENCODING_PCM_8BIT}
+ * @return audio format
+ */
+ public int getAudioFormat() {
+ return mAudioFormat;
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothAvrcp.java b/core/java/android/bluetooth/BluetoothAvrcp.java
new file mode 100644
index 0000000..44fe1b7
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcp.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+/**
+ * This class contains constants for Bluetooth AVRCP profile.
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcp {
+
+ /*
+ * State flags for Passthrough commands
+ */
+ public static final int PASSTHROUGH_STATE_PRESS = 0;
+ public static final int PASSTHROUGH_STATE_RELEASE = 1;
+
+ /*
+ * Operation IDs for Passthrough commands
+ */
+ public static final int PASSTHROUGH_ID_SELECT = 0x00; /* select */
+ public static final int PASSTHROUGH_ID_UP = 0x01; /* up */
+ public static final int PASSTHROUGH_ID_DOWN = 0x02; /* down */
+ public static final int PASSTHROUGH_ID_LEFT = 0x03; /* left */
+ public static final int PASSTHROUGH_ID_RIGHT = 0x04; /* right */
+ public static final int PASSTHROUGH_ID_RIGHT_UP = 0x05; /* right-up */
+ public static final int PASSTHROUGH_ID_RIGHT_DOWN = 0x06; /* right-down */
+ public static final int PASSTHROUGH_ID_LEFT_UP = 0x07; /* left-up */
+ public static final int PASSTHROUGH_ID_LEFT_DOWN = 0x08; /* left-down */
+ public static final int PASSTHROUGH_ID_ROOT_MENU = 0x09; /* root menu */
+ public static final int PASSTHROUGH_ID_SETUP_MENU = 0x0A; /* setup menu */
+ public static final int PASSTHROUGH_ID_CONT_MENU = 0x0B; /* contents menu */
+ public static final int PASSTHROUGH_ID_FAV_MENU = 0x0C; /* favorite menu */
+ public static final int PASSTHROUGH_ID_EXIT = 0x0D; /* exit */
+ public static final int PASSTHROUGH_ID_0 = 0x20; /* 0 */
+ public static final int PASSTHROUGH_ID_1 = 0x21; /* 1 */
+ public static final int PASSTHROUGH_ID_2 = 0x22; /* 2 */
+ public static final int PASSTHROUGH_ID_3 = 0x23; /* 3 */
+ public static final int PASSTHROUGH_ID_4 = 0x24; /* 4 */
+ public static final int PASSTHROUGH_ID_5 = 0x25; /* 5 */
+ public static final int PASSTHROUGH_ID_6 = 0x26; /* 6 */
+ public static final int PASSTHROUGH_ID_7 = 0x27; /* 7 */
+ public static final int PASSTHROUGH_ID_8 = 0x28; /* 8 */
+ public static final int PASSTHROUGH_ID_9 = 0x29; /* 9 */
+ public static final int PASSTHROUGH_ID_DOT = 0x2A; /* dot */
+ public static final int PASSTHROUGH_ID_ENTER = 0x2B; /* enter */
+ public static final int PASSTHROUGH_ID_CLEAR = 0x2C; /* clear */
+ public static final int PASSTHROUGH_ID_CHAN_UP = 0x30; /* channel up */
+ public static final int PASSTHROUGH_ID_CHAN_DOWN = 0x31; /* channel down */
+ public static final int PASSTHROUGH_ID_PREV_CHAN = 0x32; /* previous channel */
+ public static final int PASSTHROUGH_ID_SOUND_SEL = 0x33; /* sound select */
+ public static final int PASSTHROUGH_ID_INPUT_SEL = 0x34; /* input select */
+ public static final int PASSTHROUGH_ID_DISP_INFO = 0x35; /* display information */
+ public static final int PASSTHROUGH_ID_HELP = 0x36; /* help */
+ public static final int PASSTHROUGH_ID_PAGE_UP = 0x37; /* page up */
+ public static final int PASSTHROUGH_ID_PAGE_DOWN = 0x38; /* page down */
+ public static final int PASSTHROUGH_ID_POWER = 0x40; /* power */
+ public static final int PASSTHROUGH_ID_VOL_UP = 0x41; /* volume up */
+ public static final int PASSTHROUGH_ID_VOL_DOWN = 0x42; /* volume down */
+ public static final int PASSTHROUGH_ID_MUTE = 0x43; /* mute */
+ public static final int PASSTHROUGH_ID_PLAY = 0x44; /* play */
+ public static final int PASSTHROUGH_ID_STOP = 0x45; /* stop */
+ public static final int PASSTHROUGH_ID_PAUSE = 0x46; /* pause */
+ public static final int PASSTHROUGH_ID_RECORD = 0x47; /* record */
+ public static final int PASSTHROUGH_ID_REWIND = 0x48; /* rewind */
+ public static final int PASSTHROUGH_ID_FAST_FOR = 0x49; /* fast forward */
+ public static final int PASSTHROUGH_ID_EJECT = 0x4A; /* eject */
+ public static final int PASSTHROUGH_ID_FORWARD = 0x4B; /* forward */
+ public static final int PASSTHROUGH_ID_BACKWARD = 0x4C; /* backward */
+ public static final int PASSTHROUGH_ID_ANGLE = 0x50; /* angle */
+ public static final int PASSTHROUGH_ID_SUBPICT = 0x51; /* subpicture */
+ public static final int PASSTHROUGH_ID_F1 = 0x71; /* F1 */
+ public static final int PASSTHROUGH_ID_F2 = 0x72; /* F2 */
+ public static final int PASSTHROUGH_ID_F3 = 0x73; /* F3 */
+ public static final int PASSTHROUGH_ID_F4 = 0x74; /* F4 */
+ public static final int PASSTHROUGH_ID_F5 = 0x75; /* F5 */
+ public static final int PASSTHROUGH_ID_VENDOR = 0x7E; /* vendor unique */
+ public static final int PASSTHROUGH_KEYPRESSED_RELEASE = 0x80;
+}
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
new file mode 100644
index 0000000..b53a8fc
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothAvrcpController.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth AVRCP Controller
+ * profile.
+ *
+ *<p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothAvrcpController proxy object.
+ *
+ * {@hide}
+ */
+public final class BluetoothAvrcpController implements BluetoothProfile {
+ private static final String TAG = "BluetoothAvrcpController";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent used to broadcast the change in connection state of the AVRCP Controller
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.acrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private IBluetoothAvrcpController mService;
+ private BluetoothAdapter mAdapter;
+
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (VDBG) Log.d(TAG,"Binding service...");
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Create a BluetoothAvrcpController proxy object for interacting with the local
+ * Bluetooth AVRCP service.
+ *
+ */
+ /*package*/ BluetoothAvrcpController(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothAvrcpController.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth AVRCP Controller Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+ /*package*/ void close() {
+ mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+
+ public void finalize() {
+ close();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getState(" + device + ")");
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ try {
+ return mService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
+ if (DBG) Log.d(TAG, "sendPassThroughCmd");
+ if (mService != null && isEnabled()) {
+ try {
+ mService.sendPassThroughCmd(device, keyCode, keyState);
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in sendPassThroughCmd()", e);
+ return;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ }
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ mService = IBluetoothAvrcpController.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.AVRCP_CONTROLLER,
+ BluetoothAvrcpController.this);
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.AVRCP_CONTROLLER);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
new file mode 100644
index 0000000..ff4ebee
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -0,0 +1,1167 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Public API to control Hands Free Profile (HFP role only).
+ * <p>
+ * This class defines methods that shall be used by application to manage profile
+ * connection, calls states and calls actions.
+ * <p>
+ *
+ * @hide
+ * */
+public final class BluetoothHeadsetClient implements BluetoothProfile {
+ private static final String TAG = "BluetoothHeadsetClient";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ /**
+ * Intent sent whenever connection to remote changes.
+ *
+ * <p>It includes two extras:
+ * <code>BluetoothProfile.EXTRA_PREVIOUS_STATE</code>
+ * and <code>BluetoothProfile.EXTRA_STATE</code>, which
+ * are mandatory.
+ * <p>There are also non mandatory feature extras:
+ * {@link #EXTRA_AG_FEATURE_3WAY_CALLING},
+ * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION},
+ * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT},
+ * {@link #EXTRA_AG_FEATURE_REJECT_CALL},
+ * {@link #EXTRA_AG_FEATURE_ECC},
+ * {@link #EXTRA_AG_FEATURE_RESPONSE_AND_HOLD},
+ * {@link #EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL},
+ * {@link #EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL},
+ * {@link #EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT},
+ * {@link #EXTRA_AG_FEATURE_MERGE},
+ * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH},
+ * sent as boolean values only when <code>EXTRA_STATE</code>
+ * is set to <code>STATE_CONNECTED</code>.</p>
+ *
+ * <p>Note that features supported by AG are being sent as
+ * booleans with value <code>true</code>,
+ * and not supported ones are <strong>not</strong> being sent at all.</p>
+ */
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED";
+
+ /**
+ * Intent sent whenever audio state changes.
+ *
+ * <p>It includes two mandatory extras:
+ * {@link BluetoothProfile.EXTRA_STATE},
+ * {@link BluetoothProfile.EXTRA_PREVIOUS_STATE},
+ * with possible values:
+ * {@link #STATE_AUDIO_CONNECTING},
+ * {@link #STATE_AUDIO_CONNECTED},
+ * {@link #STATE_AUDIO_DISCONNECTED}</p>
+ * <p>When <code>EXTRA_STATE</code> is set
+ * to </code>STATE_AUDIO_CONNECTED</code>,
+ * it also includes {@link #EXTRA_AUDIO_WBS}
+ * indicating wide band speech support.</p>
+ */
+ public static final String ACTION_AUDIO_STATE_CHANGED =
+ "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED";
+
+ /**
+ * Intent sending updates of the Audio Gateway state.
+ * Each extra is being sent only when value it
+ * represents has been changed recently on AG.
+ * <p>It can contain one or more of the following extras:
+ * {@link #EXTRA_NETWORK_STATUS},
+ * {@link #EXTRA_NETWORK_SIGNAL_STRENGTH},
+ * {@link #EXTRA_NETWORK_ROAMING},
+ * {@link #EXTRA_BATTERY_LEVEL},
+ * {@link #EXTRA_OPERATOR_NAME},
+ * {@link #EXTRA_VOICE_RECOGNITION},
+ * {@link #EXTRA_IN_BAND_RING}</p>
+ */
+ public static final String ACTION_AG_EVENT =
+ "android.bluetooth.headsetclient.profile.action.AG_EVENT";
+
+ /**
+ * Intent sent whenever state of a call changes.
+ *
+ * <p>It includes:
+ * {@link #EXTRA_CALL},
+ * with value of {@link BluetoothHeadsetClientCall} instance,
+ * representing actual call state.</p>
+ */
+ public static final String ACTION_CALL_CHANGED =
+ "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";
+
+ /**
+ * Intent that notifies about the result of the last issued action.
+ * Please note that not every action results in explicit action result code being sent.
+ * Instead other notifications about new Audio Gateway state might be sent,
+ * like <code>ACTION_AG_EVENT</code> with <code>EXTRA_VOICE_RECOGNITION</code> value
+ * when for example user started voice recognition from HF unit.
+ */
+ public static final String ACTION_RESULT =
+ "android.bluetooth.headsetclient.profile.action.RESULT";
+
+ /**
+ * Intent that notifies about the number attached to the last voice tag
+ * recorded on AG.
+ *
+ * <p>It contains:
+ * {@link #EXTRA_NUMBER},
+ * with a <code>String</code> value representing phone number.</p>
+ */
+ public static final String ACTION_LAST_VTAG =
+ "android.bluetooth.headsetclient.profile.action.LAST_VTAG";
+
+ public static final int STATE_AUDIO_DISCONNECTED = 0;
+ public static final int STATE_AUDIO_CONNECTING = 1;
+ public static final int STATE_AUDIO_CONNECTED = 2;
+
+ /**
+ * Extra with information if connected audio is WBS.
+ * <p>Possible values: <code>true</code>,
+ * <code>false</code>.</p>
+ */
+ public static final String EXTRA_AUDIO_WBS =
+ "android.bluetooth.headsetclient.extra.AUDIO_WBS";
+
+ /**
+ * Extra for AG_EVENT indicates network status.
+ * <p>Value: 0 - network unavailable,
+ * 1 - network available </p>
+ */
+ public static final String EXTRA_NETWORK_STATUS =
+ "android.bluetooth.headsetclient.extra.NETWORK_STATUS";
+ /**
+ * Extra for AG_EVENT intent indicates network signal strength.
+ * <p>Value: <code>Integer</code> representing signal strength.</p>
+ */
+ public static final String EXTRA_NETWORK_SIGNAL_STRENGTH =
+ "android.bluetooth.headsetclient.extra.NETWORK_SIGNAL_STRENGTH";
+ /**
+ * Extra for AG_EVENT intent indicates roaming state.
+ * <p>Value: 0 - no roaming
+ * 1 - active roaming</p>
+ */
+ public static final String EXTRA_NETWORK_ROAMING =
+ "android.bluetooth.headsetclient.extra.NETWORK_ROAMING";
+ /**
+ * Extra for AG_EVENT intent indicates the battery level.
+ * <p>Value: <code>Integer</code> representing signal strength.</p>
+ */
+ public static final String EXTRA_BATTERY_LEVEL =
+ "android.bluetooth.headsetclient.extra.BATTERY_LEVEL";
+ /**
+ * Extra for AG_EVENT intent indicates operator name.
+ * <p>Value: <code>String</code> representing operator name.</p>
+ */
+ public static final String EXTRA_OPERATOR_NAME =
+ "android.bluetooth.headsetclient.extra.OPERATOR_NAME";
+ /**
+ * Extra for AG_EVENT intent indicates voice recognition state.
+ * <p>Value:
+ * 0 - voice recognition stopped,
+ * 1 - voice recognition started.</p>
+ */
+ public static final String EXTRA_VOICE_RECOGNITION =
+ "android.bluetooth.headsetclient.extra.VOICE_RECOGNITION";
+ /**
+ * Extra for AG_EVENT intent indicates in band ring state.
+ * <p>Value:
+ * 0 - in band ring tone not supported, or
+ * 1 - in band ring tone supported.</p>
+ */
+ public static final String EXTRA_IN_BAND_RING =
+ "android.bluetooth.headsetclient.extra.IN_BAND_RING";
+
+ /**
+ * Extra for AG_EVENT intent indicates subscriber info.
+ * <p>Value: <code>String</code> containing subscriber information.</p>
+ */
+ public static final String EXTRA_SUBSCRIBER_INFO =
+ "android.bluetooth.headsetclient.extra.SUBSCRIBER_INFO";
+
+ /**
+ * Extra for AG_CALL_CHANGED intent indicates the
+ * {@link BluetoothHeadsetClientCall} object that has changed.
+ */
+ public static final String EXTRA_CALL =
+ "android.bluetooth.headsetclient.extra.CALL";
+
+ /**
+ * Extra for ACTION_LAST_VTAG intent.
+ * <p>Value: <code>String</code> representing phone number
+ * corresponding to last voice tag recorded on AG</p>
+ */
+ public static final String EXTRA_NUMBER =
+ "android.bluetooth.headsetclient.extra.NUMBER";
+
+ /**
+ * Extra for ACTION_RESULT intent that shows the result code of
+ * last issued action.
+ * <p>Possible results:
+ * {@link #ACTION_RESULT_OK},
+ * {@link #ACTION_RESULT_ERROR},
+ * {@link #ACTION_RESULT_ERROR_NO_CARRIER},
+ * {@link #ACTION_RESULT_ERROR_BUSY},
+ * {@link #ACTION_RESULT_ERROR_NO_ANSWER},
+ * {@link #ACTION_RESULT_ERROR_DELAYED},
+ * {@link #ACTION_RESULT_ERROR_BLACKLISTED},
+ * {@link #ACTION_RESULT_ERROR_CME}</p>
+ */
+ public static final String EXTRA_RESULT_CODE =
+ "android.bluetooth.headsetclient.extra.RESULT_CODE";
+
+ /**
+ * Extra for ACTION_RESULT intent that shows the extended result code of
+ * last issued action.
+ * <p>Value: <code>Integer</code> - error code.</p>
+ */
+ public static final String EXTRA_CME_CODE =
+ "android.bluetooth.headsetclient.extra.CME_CODE";
+
+ /* Extras for AG_FEATURES, extras type is boolean */
+ // TODO verify if all of those are actually useful
+ /**
+ * AG feature: three way calling.
+ */
+ public final static String EXTRA_AG_FEATURE_3WAY_CALLING =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_3WAY_CALLING";
+ /**
+ * AG feature: voice recognition.
+ */
+ public final static String EXTRA_AG_FEATURE_VOICE_RECOGNITION =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_VOICE_RECOGNITION";
+ /**
+ * AG feature: fetching phone number for voice tagging procedure.
+ */
+ public final static String EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT";
+ /**
+ * AG feature: ability to reject incoming call.
+ */
+ public final static String EXTRA_AG_FEATURE_REJECT_CALL =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_REJECT_CALL";
+ /**
+ * AG feature: enhanced call handling (terminate specific call, private consultation).
+ */
+ public final static String EXTRA_AG_FEATURE_ECC =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ECC";
+ /**
+ * AG feature: response and hold.
+ */
+ public final static String EXTRA_AG_FEATURE_RESPONSE_AND_HOLD =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RESPONSE_AND_HOLD";
+ /**
+ * AG call handling feature: accept held or waiting call in three way calling scenarios.
+ */
+ public final static String EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL";
+ /**
+ * AG call handling feature: release held or waiting call in three way calling scenarios.
+ */
+ public final static String EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL";
+ /**
+ * AG call handling feature: release active call and accept held or waiting call in three way
+ * calling scenarios.
+ */
+ public final static String EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT";
+ /**
+ * AG call handling feature: merge two calls, held and active - multi party conference mode.
+ */
+ public final static String EXTRA_AG_FEATURE_MERGE =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE";
+ /**
+ * AG call handling feature: merge calls and disconnect from multi party
+ * conversation leaving peers connected to each other.
+ * Note that this feature needs to be supported by mobile network operator
+ * as it requires connection and billing transfer.
+ */
+ public final static String EXTRA_AG_FEATURE_MERGE_AND_DETACH =
+ "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE_AND_DETACH";
+
+ /* Action result codes */
+ public final static int ACTION_RESULT_OK = 0;
+ public final static int ACTION_RESULT_ERROR = 1;
+ public final static int ACTION_RESULT_ERROR_NO_CARRIER = 2;
+ public final static int ACTION_RESULT_ERROR_BUSY = 3;
+ public final static int ACTION_RESULT_ERROR_NO_ANSWER = 4;
+ public final static int ACTION_RESULT_ERROR_DELAYED = 5;
+ public final static int ACTION_RESULT_ERROR_BLACKLISTED = 6;
+ public final static int ACTION_RESULT_ERROR_CME = 7;
+
+ /* Detailed CME error codes */
+ public final static int CME_PHONE_FAILURE = 0;
+ public final static int CME_NO_CONNECTION_TO_PHONE = 1;
+ public final static int CME_OPERATION_NOT_ALLOWED = 3;
+ public final static int CME_OPERATION_NOT_SUPPORTED = 4;
+ public final static int CME_PHSIM_PIN_REQUIRED = 5;
+ public final static int CME_PHFSIM_PIN_REQUIRED = 6;
+ public final static int CME_PHFSIM_PUK_REQUIRED = 7;
+ public final static int CME_SIM_NOT_INSERTED = 10;
+ public final static int CME_SIM_PIN_REQUIRED = 11;
+ public final static int CME_SIM_PUK_REQUIRED = 12;
+ public final static int CME_SIM_FAILURE = 13;
+ public final static int CME_SIM_BUSY = 14;
+ public final static int CME_SIM_WRONG = 15;
+ public final static int CME_INCORRECT_PASSWORD = 16;
+ public final static int CME_SIM_PIN2_REQUIRED = 17;
+ public final static int CME_SIM_PUK2_REQUIRED = 18;
+ public final static int CME_MEMORY_FULL = 20;
+ public final static int CME_INVALID_INDEX = 21;
+ public final static int CME_NOT_FOUND = 22;
+ public final static int CME_MEMORY_FAILURE = 23;
+ public final static int CME_TEXT_STRING_TOO_LONG = 24;
+ public final static int CME_INVALID_CHARACTER_IN_TEXT_STRING = 25;
+ public final static int CME_DIAL_STRING_TOO_LONG = 26;
+ public final static int CME_INVALID_CHARACTER_IN_DIAL_STRING = 27;
+ public final static int CME_NO_NETWORK_SERVICE = 30;
+ public final static int CME_NETWORK_TIMEOUT = 31;
+ public final static int CME_EMERGENCY_SERVICE_ONLY = 32;
+ public final static int CME_NO_SIMULTANOUS_VOIP_CS_CALLS = 33;
+ public final static int CME_NOT_SUPPORTED_FOR_VOIP = 34;
+ public final static int CME_SIP_RESPONSE_CODE = 35;
+ public final static int CME_NETWORK_PERSONALIZATION_PIN_REQUIRED = 40;
+ public final static int CME_NETWORK_PERSONALIZATION_PUK_REQUIRED = 41;
+ public final static int CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED = 42;
+ public final static int CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED = 43;
+ public final static int CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED = 44;
+ public final static int CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED = 45;
+ public final static int CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED = 46;
+ public final static int CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED = 47;
+ public final static int CME_HIDDEN_KEY_REQUIRED = 48;
+ public final static int CME_EAP_NOT_SUPPORTED = 49;
+ public final static int CME_INCORRECT_PARAMETERS = 50;
+
+ /* Action policy for other calls when accepting call */
+ public static final int CALL_ACCEPT_NONE = 0;
+ public static final int CALL_ACCEPT_HOLD = 1;
+ public static final int CALL_ACCEPT_TERMINATE = 2;
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private IBluetoothHeadsetClient mService;
+ private BluetoothAdapter mAdapter;
+
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ @Override
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (VDBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (VDBG) Log.d(TAG,"Binding service...");
+ Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
+ doBind();
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+
+ /**
+ * Create a BluetoothHeadsetClient proxy object.
+ */
+ /*package*/ BluetoothHeadsetClient(Context context, ServiceListener l) {
+ mContext = context;
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ doBind();
+ }
+
+ boolean doBind() {
+ Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
+ android.os.Process.myUserHandle())) {
+ Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Close the connection to the backing service.
+ * Other public functions of BluetoothHeadsetClient will return default error
+ * results once close() has been called. Multiple invocations of close()
+ * are ok.
+ */
+ /*package*/ void close() {
+ if (VDBG) log("close()");
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ mServiceListener = null;
+ }
+
+ /**
+ * Connects to remote device.
+ *
+ * Currently, the system supports only 1 connection. So, in case of the
+ * second connection, this implementation will disconnect already connected
+ * device automatically and will process the new one.
+ *
+ * @param device a remote device we want connect to
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED}
+ * intent.
+ */
+ public boolean connect(BluetoothDevice device) {
+ if (DBG) log("connect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.connect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Disconnects remote device
+ *
+ * @param device a remote device we want disconnect
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED}
+ * intent.
+ */
+ public boolean disconnect(BluetoothDevice device) {
+ if (DBG) log("disconnect(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.disconnect(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Return the list of connected remote devices
+ *
+ * @return list of connected devices; empty list if nothing is connected.
+ */
+ @Override
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (VDBG) log("getConnectedDevices()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Returns list of remote devices in a particular state
+ *
+ * @param states collection of states
+ * @return list of devices that state matches the states listed in
+ * <code>states</code>; empty list if nothing matches the
+ * <code>states</code>
+ */
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (VDBG) log("getDevicesMatchingStates()");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Returns state of the <code>device</code>
+ *
+ * @param device a remote device
+ * @return the state of connection of the device
+ */
+ @Override
+ public int getConnectionState(BluetoothDevice device) {
+ if (VDBG) log("getConnectionState(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * Set priority of the profile
+ *
+ * The device should already be paired.
+ */
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF &&
+ priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
+ try {
+ return mService.setPriority(device, priority);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Get the priority of the profile.
+ */
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getPriority(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return PRIORITY_OFF;
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return PRIORITY_OFF;
+ }
+
+ /**
+ * Starts voice recognition.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_AG_EVENT}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean startVoiceRecognition(BluetoothDevice device) {
+ if (DBG) log("startVoiceRecognition()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.startVoiceRecognition(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Stops voice recognition.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_AG_EVENT}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean stopVoiceRecognition(BluetoothDevice device) {
+ if (DBG) log("stopVoiceRecognition()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.stopVoiceRecognition(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Returns list of all calls in any state.
+ *
+ * @param device remote device
+ * @return list of calls; empty list if none call exists
+ */
+ public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
+ if (DBG) log("getCurrentCalls()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getCurrentCalls(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ }
+
+ /**
+ * Returns list of current values of AG indicators.
+ *
+ * @param device remote device
+ * @return bundle of AG indicators; null if device is not in
+ * CONNECTED state
+ */
+ public Bundle getCurrentAgEvents(BluetoothDevice device) {
+ if (DBG) log("getCurrentCalls()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getCurrentAgEvents(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return null;
+ }
+
+ /**
+ * Accepts a call
+ *
+ * @param device remote device
+ * @param flag action policy while accepting a call. Possible values
+ * {@link #CALL_ACCEPT_NONE}, {@link #CALL_ACCEPT_HOLD},
+ * {@link #CALL_ACCEPT_TERMINATE}
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ */
+ public boolean acceptCall(BluetoothDevice device, int flag) {
+ if (DBG) log("acceptCall()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.acceptCall(device, flag);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Holds a call.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ */
+ public boolean holdCall(BluetoothDevice device) {
+ if (DBG) log("holdCall()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.holdCall(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Rejects a call.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_REJECT_CALL}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean rejectCall(BluetoothDevice device) {
+ if (DBG) log("rejectCall()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.rejectCall(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Terminates a specified call.
+ *
+ * Works only when Extended Call Control is supported by Audio Gateway.
+ *
+ * @param device remote device
+ * @param index index of the call to be terminated
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_ECC}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean terminateCall(BluetoothDevice device, int index) {
+ if (DBG) log("terminateCall()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.terminateCall(device, index);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Enters private mode with a specified call.
+ *
+ * Works only when Extended Call Control is supported by Audio Gateway.
+ *
+ * @param device remote device
+ * @param index index of the call to connect in private mode
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_ECC}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean enterPrivateMode(BluetoothDevice device, int index) {
+ if (DBG) log("enterPrivateMode()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.enterPrivateMode(device, index);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Performs explicit call transfer.
+ *
+ * That means connect other calls and disconnect.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent.
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean explicitCallTransfer(BluetoothDevice device) {
+ if (DBG) log("explicitCallTransfer()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.explicitCallTransfer(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Redials last number from Audio Gateway.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent in case of success; {@link #ACTION_RESULT} is sent
+ * otherwise;
+ */
+ public boolean redial(BluetoothDevice device) {
+ if (DBG) log("redial()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.redial(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Places a call with specified number.
+ *
+ * @param device remote device
+ * @param number valid phone number
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent in case of success; {@link #ACTION_RESULT} is sent
+ * otherwise;
+ */
+ public boolean dial(BluetoothDevice device, String number) {
+ if (DBG) log("dial()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.dial(device, number);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Places a call to the number under specified memory location.
+ *
+ * @param device remote device
+ * @param location valid memory location
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_CALL_CHANGED}
+ * intent in case of success; {@link #ACTION_RESULT} is sent
+ * otherwise;
+ */
+ public boolean dialMemory(BluetoothDevice device, int location) {
+ if (DBG) log("dialMemory()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.dialMemory(device, location);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Sends DTMF code.
+ *
+ * Possible code values : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,*,#
+ *
+ * @param device remote device
+ * @param code ASCII code
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_RESULT} intent;
+ */
+ public boolean sendDTMF(BluetoothDevice device, byte code) {
+ if (DBG) log("sendDTMF()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.sendDTMF(device, code);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Get a number corresponding to last voice tag recorded on AG.
+ *
+ * @param device remote device
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_LAST_VTAG}
+ * or {@link #ACTION_RESULT} intent;
+ *
+ * <p>Feature required for successful execution is being reported by:
+ * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT}.
+ * This method invocation will fail silently when feature is not supported.</p>
+ */
+ public boolean getLastVoiceTagNumber(BluetoothDevice device) {
+ if (DBG) log("getLastVoiceTagNumber()");
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
+ try {
+ return mService.getLastVoiceTagNumber(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Accept the incoming connection.
+ */
+ public boolean acceptIncomingConnect(BluetoothDevice device) {
+ if (DBG) log("acceptIncomingConnect");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.acceptIncomingConnect(device);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Reject the incoming connection.
+ */
+ public boolean rejectIncomingConnect(BluetoothDevice device) {
+ if (DBG) log("rejectIncomingConnect");
+ if (mService != null) {
+ try {
+ return mService.rejectIncomingConnect(device);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Returns current audio state of Audio Gateway.
+ *
+ * Note: This is an internal function and shouldn't be exposed
+ */
+ public int getAudioState(BluetoothDevice device) {
+ if (VDBG) log("getAudioState");
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getAudioState(device);
+ } catch (RemoteException e) {Log.e(TAG, e.toString());}
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
+ }
+
+ /**
+ * Initiates a connection of audio channel.
+ *
+ * It setup SCO channel with remote connected Handsfree AG device.
+ *
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED}
+ * intent;
+ */
+ public boolean connectAudio() {
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.connectAudio();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Disconnects audio channel.
+ *
+ * It tears down the SCO channel from remote AG device.
+ *
+ * @return <code>true</code> if command has been issued successfully;
+ * <code>false</code> otherwise;
+ * upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED}
+ * intent;
+ */
+ public boolean disconnectAudio() {
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.disconnectAudio();
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Get Audio Gateway features
+ *
+ * @param device remote device
+ * @return bundle of AG features; null if no service or
+ * AG not connected
+ */
+ public Bundle getCurrentAgFeatures(BluetoothDevice device) {
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getCurrentAgFeatures(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return null;
+ }
+
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ mService = IBluetoothHeadsetClient.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
+ BluetoothHeadsetClient.this);
+ }
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET_CLIENT);
+ }
+ }
+ };
+
+ private boolean isEnabled() {
+ if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl b/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl
new file mode 100644
index 0000000..35f7923
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.bluetooth;
+
+parcelable BluetoothHeadsetClientCall;
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
new file mode 100644
index 0000000..a15bd97
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class represents a single call, its state and properties.
+ * It implements {@link Parcelable} for inter-process message passing.
+ * @hide
+ */
+public final class BluetoothHeadsetClientCall implements Parcelable {
+
+ /* Call state */
+ /**
+ * Call is active.
+ */
+ public static final int CALL_STATE_ACTIVE = 0;
+ /**
+ * Call is in held state.
+ */
+ public static final int CALL_STATE_HELD = 1;
+ /**
+ * Outgoing call that is being dialed right now.
+ */
+ public static final int CALL_STATE_DIALING = 2;
+ /**
+ * Outgoing call that remote party has already been alerted about.
+ */
+ public static final int CALL_STATE_ALERTING = 3;
+ /**
+ * Incoming call that can be accepted or rejected.
+ */
+ public static final int CALL_STATE_INCOMING = 4;
+ /**
+ * Waiting call state when there is already an active call.
+ */
+ public static final int CALL_STATE_WAITING = 5;
+ /**
+ * Call that has been held by response and hold
+ * (see Bluetooth specification for further references).
+ */
+ public static final int CALL_STATE_HELD_BY_RESPONSE_AND_HOLD = 6;
+ /**
+ * Call that has been already terminated and should not be referenced as a valid call.
+ */
+ public static final int CALL_STATE_TERMINATED = 7;
+
+ private final int mId;
+ private int mState;
+ private String mNumber;
+ private boolean mMultiParty;
+ private final boolean mOutgoing;
+
+ /**
+ * Creates BluetoothHeadsetClientCall instance.
+ */
+ public BluetoothHeadsetClientCall(int id, int state, String number, boolean multiParty,
+ boolean outgoing) {
+ mId = id;
+ mState = state;
+ mNumber = number != null ? number : "";
+ mMultiParty = multiParty;
+ mOutgoing = outgoing;
+ }
+
+ /**
+ * Sets call's state.
+ *
+ * <p>Note: This is an internal function and shouldn't be exposed</p>
+ *
+ * @param state new call state.
+ */
+ public void setState(int state) {
+ mState = state;
+ }
+
+ /**
+ * Sets call's number.
+ *
+ * <p>Note: This is an internal function and shouldn't be exposed</p>
+ *
+ * @param number String representing phone number.
+ */
+ public void setNumber(String number) {
+ mNumber = number;
+ }
+
+ /**
+ * Sets this call as multi party call.
+ *
+ * <p>Note: This is an internal function and shouldn't be exposed</p>
+ *
+ * @param multiParty if <code>true</code> sets this call as a part
+ * of multi party conference.
+ */
+ public void setMultiParty(boolean multiParty) {
+ mMultiParty = multiParty;
+ }
+
+ /**
+ * Gets call's Id.
+ *
+ * @return call id.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Gets call's current state.
+ *
+ * @return state of this particular phone call.
+ */
+ public int getState() {
+ return mState;
+ }
+
+ /**
+ * Gets call's number.
+ *
+ * @return string representing phone number.
+ */
+ public String getNumber() {
+ return mNumber;
+ }
+
+ /**
+ * Checks if call is an active call in a conference mode (aka multi party).
+ *
+ * @return <code>true</code> if call is a multi party call,
+ * <code>false</code> otherwise.
+ */
+ public boolean isMultiParty() {
+ return mMultiParty;
+ }
+
+ /**
+ * Checks if this call is an outgoing call.
+ *
+ * @return <code>true</code> if its outgoing call,
+ * <code>false</code> otherwise.
+ */
+ public boolean isOutgoing() {
+ return mOutgoing;
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mId: ");
+ builder.append(mId);
+ builder.append(", mState: ");
+ switch (mState) {
+ case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break;
+ case CALL_STATE_HELD: builder.append("HELD"); break;
+ case CALL_STATE_DIALING: builder.append("DIALING"); break;
+ case CALL_STATE_ALERTING: builder.append("ALERTING"); break;
+ case CALL_STATE_INCOMING: builder.append("INCOMING"); break;
+ case CALL_STATE_WAITING: builder.append("WAITING"); break;
+ case CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: builder.append("HELD_BY_RESPONSE_AND_HOLD"); break;
+ case CALL_STATE_TERMINATED: builder.append("TERMINATED"); break;
+ default: builder.append(mState); break;
+ }
+ builder.append(", mNumber: ");
+ builder.append(mNumber);
+ builder.append(", mMultiParty: ");
+ builder.append(mMultiParty);
+ builder.append(", mOutgoing: ");
+ builder.append(mOutgoing);
+ builder.append("}");
+ return builder.toString();
+ }
+
+ /**
+ * {@link Parcelable.Creator} interface implementation.
+ */
+ public static final Parcelable.Creator<BluetoothHeadsetClientCall> CREATOR =
+ new Parcelable.Creator<BluetoothHeadsetClientCall>() {
+ @Override
+ public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
+ return new BluetoothHeadsetClientCall(in.readInt(), in.readInt(),
+ in.readString(), in.readInt() == 1, in.readInt() == 1);
+ }
+
+ @Override
+ public BluetoothHeadsetClientCall[] newArray(int size) {
+ return new BluetoothHeadsetClientCall[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mId);
+ out.writeInt(mState);
+ out.writeString(mNumber);
+ out.writeInt(mMultiParty ? 1 : 0);
+ out.writeInt(mOutgoing ? 1 : 0);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index d898060..1367405 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2010-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -110,6 +110,18 @@
public static final int A2DP_SINK = 10;
/**
+ * AVRCP Controller Profile
+ * @hide
+ */
+ public static final int AVRCP_CONTROLLER = 11;
+
+ /**
+ * Headset Client - HFP HF Role
+ * @hide
+ */
+ public static final int HEADSET_CLIENT = 16;
+
+ /**
* Default priority for devices that we try to auto-connect to and
* and allow incoming connections for the profile
* @hide
diff --git a/core/java/android/bluetooth/IBluetoothA2dpSink.aidl b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
new file mode 100644
index 0000000..b7c6476
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothA2dpSink.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothAudioConfig;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * APIs for Bluetooth A2DP sink service
+ *
+ * @hide
+ */
+interface IBluetoothA2dpSink {
+ boolean connect(in BluetoothDevice device);
+ boolean disconnect(in BluetoothDevice device);
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ int getConnectionState(in BluetoothDevice device);
+ BluetoothAudioConfig getAudioConfig(in BluetoothDevice device);
+}
diff --git a/core/java/android/bluetooth/IBluetoothAvrcpController.aidl b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
new file mode 100644
index 0000000..f917a50
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothAvrcpController.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * APIs for Bluetooth AVRCP controller service
+ *
+ * @hide
+ */
+interface IBluetoothAvrcpController {
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ int getConnectionState(in BluetoothDevice device);
+ void sendPassThroughCmd(in BluetoothDevice device, int keyCode, int keyState);
+}
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 00a0750..273d76d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -35,8 +35,6 @@
void startScan(in int appIf, in boolean isServer);
void startScanWithUuids(in int appIf, in boolean isServer, in ParcelUuid[] ids);
- void startScanWithUuidsScanParam(in int appIf, in boolean isServer,
- in ParcelUuid[] ids, int scanWindow, int scanInterval);
void startScanWithFilters(in int appIf, in boolean isServer,
in ScanSettings settings, in List<ScanFilter> filters);
void stopScan(in int appIf, in boolean isServer);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index bf9e0a7..2d8eed4 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -22,7 +22,7 @@
* Callback definitions for interacting with BLE / GATT
* @hide
*/
-interface IBluetoothGattCallback {
+oneway interface IBluetoothGattCallback {
void onClientRegistered(in int status, in int clientIf);
void onClientConnectionState(in int status, in int clientIf,
in boolean connected, in String address);
@@ -63,7 +63,7 @@
in int charInstId, in ParcelUuid charUuid,
in byte[] value);
void onReadRemoteRssi(in String address, in int rssi, in int status);
- oneway void onAdvertiseStateChange(in int advertiseState, in int status);
- oneway void onMultiAdvertiseCallback(in int status);
+ void onAdvertiseStateChange(in int advertiseState, in int status);
+ void onMultiAdvertiseCallback(in int status);
void onConfigureMTU(in String address, in int mtu, in int status);
}
diff --git a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
new file mode 100644
index 0000000..e518b7d
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClientCall;
+import android.os.Bundle;
+
+/**
+ * API for Bluetooth Headset Client service (HFP HF Role)
+ *
+ * {@hide}
+ */
+interface IBluetoothHeadsetClient {
+ boolean connect(in BluetoothDevice device);
+ boolean disconnect(in BluetoothDevice device);
+
+ boolean acceptIncomingConnect(in BluetoothDevice device);
+ boolean rejectIncomingConnect(in BluetoothDevice device);
+
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ int getConnectionState(in BluetoothDevice device);
+ boolean setPriority(in BluetoothDevice device, int priority);
+ int getPriority(in BluetoothDevice device);
+
+ boolean startVoiceRecognition(in BluetoothDevice device);
+ boolean stopVoiceRecognition(in BluetoothDevice device);
+
+ List<BluetoothHeadsetClientCall> getCurrentCalls(in BluetoothDevice device);
+ Bundle getCurrentAgEvents(in BluetoothDevice device);
+
+ boolean acceptCall(in BluetoothDevice device, int flag);
+ boolean holdCall(in BluetoothDevice device);
+ boolean rejectCall(in BluetoothDevice device);
+ boolean terminateCall(in BluetoothDevice device, int index);
+
+ boolean enterPrivateMode(in BluetoothDevice device, int index);
+ boolean explicitCallTransfer(in BluetoothDevice device);
+
+ boolean redial(in BluetoothDevice device);
+ boolean dial(in BluetoothDevice device, String number);
+ boolean dialMemory(in BluetoothDevice device, int location);
+
+ boolean sendDTMF(in BluetoothDevice device, byte code);
+ boolean getLastVoiceTagNumber(in BluetoothDevice device);
+
+ int getAudioState(in BluetoothDevice device);
+ boolean connectAudio();
+ boolean disconnectAudio();
+
+ Bundle getCurrentAgFeatures(in BluetoothDevice device);
+}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 04c0b9f..69fa408 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -67,7 +67,6 @@
*
* @param user The UserHandle of the profile that generated the change.
* @param packageName The name of the package that was removed.
- * @hide remove before ship
*/
void onPackageRemoved(UserHandle user, String packageName);
@@ -76,7 +75,6 @@
*
* @param user The UserHandle of the profile that generated the change.
* @param packageName The name of the package that was added.
- * @hide remove before ship
*/
void onPackageAdded(UserHandle user, String packageName);
@@ -85,7 +83,6 @@
*
* @param user The UserHandle of the profile that generated the change.
* @param packageName The name of the package that has changed.
- * @hide remove before ship
*/
void onPackageChanged(UserHandle user, String packageName);
@@ -99,7 +96,6 @@
* available.
* @param replacing Indicates whether these packages are replacing
* existing ones.
- * @hide remove before ship
*/
void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing);
@@ -113,59 +109,9 @@
* unavailable.
* @param replacing Indicates whether the packages are about to be
* replaced with new versions.
- * @hide remove before ship
*/
void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing);
- /**
- * Indicates that a package was removed from the specified profile.
- *
- * @param packageName The name of the package that was removed.
- * @param user The UserHandle of the profile that generated the change.
- */
- void onPackageRemoved(String packageName, UserHandle user);
-
- /**
- * Indicates that a package was added to the specified profile.
- *
- * @param packageName The name of the package that was added.
- * @param user The UserHandle of the profile that generated the change.
- */
- void onPackageAdded(String packageName, UserHandle user);
-
- /**
- * Indicates that a package was modified in the specified profile.
- *
- * @param packageName The name of the package that has changed.
- * @param user The UserHandle of the profile that generated the change.
- */
- void onPackageChanged(String packageName, UserHandle user);
-
- /**
- * Indicates that one or more packages have become available. For
- * example, this can happen when a removable storage card has
- * reappeared.
- *
- * @param packageNames The names of the packages that have become
- * available.
- * @param user The UserHandle of the profile that generated the change.
- * @param replacing Indicates whether these packages are replacing
- * existing ones.
- */
- void onPackagesAvailable(String [] packageNames, UserHandle user, boolean replacing);
-
- /**
- * Indicates that one or more packages have become unavailable. For
- * example, this can happen when a removable storage card has been
- * removed.
- *
- * @param packageNames The names of the packages that have become
- * unavailable.
- * @param user The UserHandle of the profile that generated the change.
- * @param replacing Indicates whether the packages are about to be
- * replaced with new versions.
- */
- void onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing);
}
/** @hide */
@@ -361,8 +307,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackageRemoved(user, packageName); // TODO: Remove before ship
- listener.onPackageRemoved(packageName, user);
+ listener.onPackageRemoved(user, packageName);
}
}
}
@@ -374,8 +319,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackageChanged(user, packageName); // TODO: Remove before ship
- listener.onPackageChanged(packageName, user);
+ listener.onPackageChanged(user, packageName);
}
}
}
@@ -387,8 +331,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackageAdded(user, packageName); // TODO: Remove before ship
- listener.onPackageAdded(packageName, user);
+ listener.onPackageAdded(user, packageName);
}
}
}
@@ -401,8 +344,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackagesAvailable(user, packageNames, replacing); // TODO: Remove
- listener.onPackagesAvailable(packageNames, user, replacing);
+ listener.onPackagesAvailable(user, packageNames, replacing);
}
}
}
@@ -415,8 +357,7 @@
}
synchronized (LauncherApps.this) {
for (OnAppsChangedListener listener : mListeners) {
- listener.onPackagesUnavailable(user, packageNames, replacing); // TODO: Remove
- listener.onPackagesUnavailable(packageNames, user, replacing);
+ listener.onPackagesUnavailable(user, packageNames, replacing);
}
}
}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index c8de2f1..de2cc67 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -708,6 +708,7 @@
* is generated if the direction of the 2-seconds window average gravity changed by at
* least 35 degrees since the activation of the sensor. It is a wake up sensor.
*
+ * @hide
* @see #isWakeUpSensor()
*/
public static final int TYPE_WAKE_UP_TILT_DETECTOR = 41;
@@ -715,6 +716,7 @@
/**
* A constant string describing a wake up tilt detector sensor type.
*
+ * @hide
* @see #TYPE_WAKE_UP_TILT_DETECTOR
*/
public static final String SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR =
@@ -752,16 +754,47 @@
*/
public static final int TYPE_ALL = -1;
- /* Reporting mode constants for sensors. Each sensor will have exactly one
- reporting mode associated with it. */
- // Events are reported at a constant rate.
- static int REPORTING_MODE_CONTINUOUS = 1;
+ // If this flag is set, the sensor defined as a wake up sensor. This field and REPORTING_MODE_*
+ // constants are defined as flags in sensors.h. Modify at both places if needed.
+ private static final int SENSOR_FLAG_WAKE_UP_SENSOR = 1;
- // Events are reported only when the value changes.
- static int REPORTING_MODE_ON_CHANGE = 2;
+ /**
+ * Events are reported at a constant rate which is set by the rate parameter of
+ * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}. Note: If other
+ * applications are requesting a higher rate, the sensor data might be delivered at faster rates
+ * than requested.
+ */
+ public static final int REPORTING_MODE_CONTINUOUS = 0;
- // Upon detection of an event, the sensor deactivates itself and then sends a single event.
- static int REPORTING_MODE_ONE_SHOT = 3;
+ /**
+ * Events are reported only when the value changes. Event delivery rate can be limited by
+ * setting appropriate value for rate parameter of
+ * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)} Note: If other
+ * applications are requesting a higher rate, the sensor data might be delivered at faster rates
+ * than requested.
+ */
+ public static final int REPORTING_MODE_ON_CHANGE = 1;
+
+ /**
+ * Events are reported in one-shot mode. Upon detection of an event, the sensor deactivates
+ * itself and then sends a single event. Sensors of this reporting mode must be registered to
+ * using {@link SensorManager#requestTriggerSensor(TriggerEventListener, Sensor)}.
+ */
+ public static final int REPORTING_MODE_ONE_SHOT = 2;
+
+ /**
+ * Events are reported as described in the description of the sensor. The rate passed to
+ * registerListener might not have an impact on the rate of event delivery. See the sensor
+ * definition for more information on when and how frequently the events are reported. For
+ * example, step detectors report events when a step is detected.
+ *
+ * @see SensorManager#registerListener(SensorEventListener, Sensor, int, int)
+ */
+ public static final int REPORTING_MODE_SPECIAL_TRIGGER = 3;
+
+ // Mask for the LSB 2nd, 3rd and fourth bits.
+ private static final int REPORTING_MODE_MASK = 0xE;
+ private static final int REPORTING_MODE_SHIFT = 1;
// TODO(): The following arrays are fragile and error-prone. This needs to be refactored.
@@ -770,80 +803,74 @@
// associated with
// {@link SensorEvent} or {@link TriggerEvent} for the Sensor
private static final int[] sSensorReportingModes = {
- 0, 0, // padding because sensor types start at 1
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_ACCELEROMETER
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GEOMAGNETIC_FIELD
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_ORIENTATION
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GYROSCOPE
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_LIGHT
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_PRESSURE
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_TEMPERATURE
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_PROXIMITY
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_GRAVITY
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_LINEAR_ACCELERATION
- REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_ROTATION_VECTOR
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_RELATIVE_HUMIDITY
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_AMBIENT_TEMPERATURE
- REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED
- REPORTING_MODE_CONTINUOUS, 4, // SENSOR_TYPE_GAME_ROTATION_VECTOR
- REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
- REPORTING_MODE_ONE_SHOT, 1, // SENSOR_TYPE_SIGNIFICANT_MOTION
- // added post 4.3
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_DETECTOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_STEP_COUNTER
- REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_HEART_RATE_MONITOR
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR
+ 0, // padding because sensor types start at 1
+ 3, // SENSOR_TYPE_ACCELEROMETER
+ 3, // SENSOR_TYPE_GEOMAGNETIC_FIELD
+ 3, // SENSOR_TYPE_ORIENTATION
+ 3, // SENSOR_TYPE_GYROSCOPE
+ 3, // SENSOR_TYPE_LIGHT
+ 3, // SENSOR_TYPE_PRESSURE
+ 3, // SENSOR_TYPE_TEMPERATURE
+ 3, // SENSOR_TYPE_PROXIMITY
+ 3, // SENSOR_TYPE_GRAVITY
+ 3, // SENSOR_TYPE_LINEAR_ACCELERATION
+ 5, // SENSOR_TYPE_ROTATION_VECTOR
+ 3, // SENSOR_TYPE_RELATIVE_HUMIDITY
+ 3, // SENSOR_TYPE_AMBIENT_TEMPERATURE
+ 6, // SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED
+ 4, // SENSOR_TYPE_GAME_ROTATION_VECTOR
+ 6, // SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
+ 1, // SENSOR_TYPE_SIGNIFICANT_MOTION
+ 1, // SENSOR_TYPE_STEP_DETECTOR
+ 1, // SENSOR_TYPE_STEP_COUNTER
+ 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+ 1, // SENSOR_TYPE_HEART_RATE_MONITOR
+ 3, // SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR
// wake up variants of base sensors
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_ACCELEROMETER
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_ORIENTATION
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_GYROSCOPE
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_WAKE_UP_LIGHT
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_PRESSURE
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_GRAVITY
- REPORTING_MODE_CONTINUOUS, 3, // SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION
- REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY
- REPORTING_MODE_ON_CHANGE, 3, // SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE
- REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED
- REPORTING_MODE_CONTINUOUS, 4, // SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR
- REPORTING_MODE_CONTINUOUS, 6, // SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_WAKE_UP_STEP_DETECTOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_WAKE_UP_STEP_COUNTER
- REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_WAKE_UP_HEART_RATE_MONITOR
- REPORTING_MODE_ON_CHANGE, 1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR
- REPORTING_MODE_ONE_SHOT, 1, // SENSOR_TYPE_WAKE_GESTURE
+ 3, // SENSOR_TYPE_WAKE_UP_ACCELEROMETER
+ 3, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD
+ 3, // SENSOR_TYPE_WAKE_UP_ORIENTATION
+ 3, // SENSOR_TYPE_WAKE_UP_GYROSCOPE
+ 3, // SENSOR_TYPE_WAKE_UP_LIGHT
+ 3, // SENSOR_TYPE_WAKE_UP_PRESSURE
+ 3, // SENSOR_TYPE_WAKE_UP_GRAVITY
+ 3, // SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION
+ 5, // SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR
+ 3, // SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY
+ 3, // SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE
+ 6, // SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED
+ 4, // SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR
+ 6, // SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED
+ 1, // SENSOR_TYPE_WAKE_UP_STEP_DETECTOR
+ 1, // SENSOR_TYPE_WAKE_UP_STEP_COUNTER
+ 5, // SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR
+ 1, // SENSOR_TYPE_WAKE_UP_HEART_RATE_MONITOR
+ 1, // SENSOR_TYPE_WAKE_UP_TILT_DETECTOR
+ 1, // SENSOR_TYPE_WAKE_GESTURE
};
- static int getReportingMode(Sensor sensor) {
- int offset = sensor.mType * 2;
- if (offset >= sSensorReportingModes.length) {
- // we don't know about this sensor, so this is probably a
- // vendor-defined sensor, in that case, we figure out the reporting
- // mode from the sensor meta-data.
- int minDelay = sensor.mMinDelay;
- if (minDelay == 0) {
- return REPORTING_MODE_ON_CHANGE;
- } else if (minDelay < 0) {
- return REPORTING_MODE_ONE_SHOT;
- } else {
- return REPORTING_MODE_CONTINUOUS;
- }
- }
- return sSensorReportingModes[offset];
+ /**
+ * Each sensor has exactly one reporting mode associated with it. This method returns the
+ * reporting mode constant for this sensor type.
+ *
+ * @return Reporting mode for the input sensor, one of REPORTING_MODE_* constants.
+ * @see #REPORTING_MODE_CONTINUOUS
+ * @see #REPORTING_MODE_ON_CHANGE
+ * @see #REPORTING_MODE_ONE_SHOT
+ * @see #REPORTING_MODE_SPECIAL_TRIGGER
+ */
+ public int getReportingMode() {
+ return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT);
}
static int getMaxLengthValuesArray(Sensor sensor, int sdkLevel) {
- int type = sensor.mType;
// RotationVector length has changed to 3 to 5 for API level 18
// Set it to 3 for backward compatibility.
- if (type == Sensor.TYPE_ROTATION_VECTOR &&
+ if (sensor.mType == Sensor.TYPE_ROTATION_VECTOR &&
sdkLevel <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return 3;
}
- int offset = type * 2 + 1;
+ int offset = sensor.mType;
if (offset >= sSensorReportingModes.length) {
// we don't know about this sensor, so this is probably a
// vendor-defined sensor, in that case, we don't know how many value
@@ -873,7 +900,7 @@
private String mStringType;
private String mRequiredPermission;
private int mMaxDelay;
- private boolean mWakeUpSensor;
+ private int mFlags;
Sensor() {
}
@@ -1016,7 +1043,7 @@
* @return true if this is a wake up sensor, false otherwise.
*/
public boolean isWakeUpSensor() {
- return mWakeUpSensor;
+ return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0;
}
void setRange(float max, float res) {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index b66ec86..a6c3ea4 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -99,7 +99,7 @@
return false;
}
// Trigger Sensors should use the requestTriggerSensor call.
- if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
+ if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
return false;
}
@@ -133,7 +133,7 @@
@Override
protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
// Trigger Sensors should use the cancelTriggerSensor call.
- if (sensor != null && Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) {
+ if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
return;
}
@@ -159,7 +159,7 @@
protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
- if (Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) return false;
+ if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false;
synchronized (mTriggerListeners) {
TriggerEventQueue queue = mTriggerListeners.get(listener);
@@ -181,7 +181,7 @@
@Override
protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
boolean disable) {
- if (sensor != null && Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) {
+ if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) {
return false;
}
synchronized (mTriggerListeners) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index ff56720..9eea545 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -30,7 +30,7 @@
*
* <p>These properties are fixed for a given CameraDevice, and can be queried
* through the {@link CameraManager CameraManager}
- * interface in addition to through the CameraDevice interface.</p>
+ * interface with {@link CameraManager#getCameraCharacteristics}.</p>
*
* <p>{@link CameraCharacteristics} objects are immutable.</p>
*
@@ -555,7 +555,7 @@
* <p>List containing a subset of the optical image
* stabilization (OIS) modes specified in
* {@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}.</p>
- * <p>If OIS is not implemented for a given camera device, this should
+ * <p>If OIS is not implemented for a given camera device, this will
* contain only OFF.</p>
*
* @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
@@ -612,7 +612,7 @@
/**
* <p>Direction the camera faces relative to
- * device screen</p>
+ * device screen.</p>
* @see #LENS_FACING_FRONT
* @see #LENS_FACING_BACK
*/
@@ -622,7 +622,7 @@
/**
* <p>The set of noise reduction modes supported by this camera device.</p>
* <p>This tag lists the valid modes for {@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}.</p>
- * <p>Full-capability camera devices must laways support OFF and FAST.</p>
+ * <p>Full-capability camera devices must always support OFF and FAST.</p>
*
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
@@ -778,18 +778,20 @@
new Key<Byte>("android.request.pipelineMaxDepth", byte.class);
/**
- * <p>Optional. Defaults to 1. Defines how many sub-components
+ * <p>Defines how many sub-components
* a result will be composed of.</p>
* <p>In order to combat the pipeline latency, partial results
* may be delivered to the application layer from the camera device as
* soon as they are available.</p>
- * <p>A value of 1 means that partial results are not supported.</p>
+ * <p>Optional; defaults to 1. A value of 1 means that partial
+ * results are not supported, and only the final TotalCaptureResult will
+ * be produced by the camera device.</p>
* <p>A typical use case for this might be: after requesting an
* auto-focus (AF) lock the new AF state might be available 50%
* of the way through the pipeline. The camera device could
* then immediately dispatch this state via a partial result to
- * the framework/application layer, and the rest of the
- * metadata via later partial results.</p>
+ * the application, and the rest of the metadata via later
+ * partial results.</p>
*/
public static final Key<Integer> REQUEST_PARTIAL_RESULT_COUNT =
new Key<Integer>("android.request.partialResultCount", int.class);
@@ -806,8 +808,6 @@
* to do this query each of android.request.availableRequestKeys,
* android.request.availableResultKeys,
* android.request.availableCharacteristicsKeys.</p>
- * <p>XX: Maybe these should go into {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}
- * as a table instead?</p>
* <p>The following capabilities are guaranteed to be available on
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL devices:</p>
* <ul>
@@ -815,14 +815,11 @@
* <li>MANUAL_POST_PROCESSING</li>
* </ul>
* <p>Other capabilities may be available on either FULL or LIMITED
- * devices, but the app. should query this field to be sure.</p>
+ * devices, but the application should query this field to be sure.</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
- * @see #REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
- * @see #REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL
* @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR
* @see #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING
- * @see #REQUEST_AVAILABLE_CAPABILITIES_ZSL
* @see #REQUEST_AVAILABLE_CAPABILITIES_DNG
*/
public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -838,7 +835,6 @@
* at a more granular level than capabilities. This is especially
* important for optional keys that are not listed under any capability
* in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
- * <p>TODO: This should be used by #getAvailableCaptureRequestKeys.</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @hide
@@ -863,7 +859,6 @@
* at a more granular level than capabilities. This is especially
* important for optional keys that are not listed under any capability
* in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
- * <p>TODO: This should be used by #getAvailableCaptureResultKeys.</p>
*
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
@@ -879,7 +874,6 @@
* android.request.availableResultKeys (except that it applies for
* CameraCharacteristics instead of CaptureResult). See above for more
* details.</p>
- * <p>TODO: This should be used by CameraCharacteristics#getKeys.</p>
* @hide
*/
public static final Key<int[]> REQUEST_AVAILABLE_CHARACTERISTICS_KEYS =
@@ -927,10 +921,15 @@
new Key<android.util.Size[]>("android.scaler.availableJpegSizes", android.util.Size[].class);
/**
- * <p>The maximum ratio between active area width
- * and crop region width, or between active area height and
- * crop region height, if the crop region height is larger
- * than width</p>
+ * <p>The maximum ratio between both active area width
+ * and crop region width, and active area height and
+ * crop region height.</p>
+ * <p>This represents the maximum amount of zooming possible by
+ * the camera device, or equivalently, the minimum cropping
+ * window size.</p>
+ * <p>Crop regions that have a width or height that is smaller
+ * than this ratio allows will be rounded up to the minimum
+ * allowed size by the camera device.</p>
*/
public static final Key<Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM =
new Key<Float>("android.scaler.availableMaxDigitalZoom", float.class);
@@ -1339,9 +1338,9 @@
new Key<android.util.Range<Integer>>("android.sensor.info.sensitivityRange", new TypeReference<android.util.Range<Integer>>() {{ }});
/**
- * <p>Arrangement of color filters on sensor;
+ * <p>The arrangement of color filters on sensor;
* represents the colors in the top-left 2x2 section of
- * the sensor, in reading order</p>
+ * the sensor, in reading order.</p>
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG
* @see #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG
@@ -1666,10 +1665,9 @@
new Key<int[]>("android.sensor.availableTestPatternModes", int[].class);
/**
- * <p>Which face detection modes are available,
- * if any.</p>
- * <p>OFF means face detection is disabled, it must
- * be included in the list.</p>
+ * <p>The face detection modes that are available
+ * for this camera device.</p>
+ * <p>OFF is always supported.</p>
* <p>SIMPLE means the device supports the
* android.statistics.faceRectangles and
* android.statistics.faceScores outputs.</p>
@@ -1681,8 +1679,8 @@
new Key<int[]>("android.statistics.info.availableFaceDetectModes", int[].class);
/**
- * <p>Maximum number of simultaneously detectable
- * faces</p>
+ * <p>The maximum number of simultaneously detectable
+ * faces.</p>
*/
public static final Key<Integer> STATISTICS_INFO_MAX_FACE_COUNT =
new Key<Integer>("android.statistics.info.maxFaceCount", int.class);
@@ -1691,7 +1689,7 @@
* <p>The set of hot pixel map output modes supported by this camera device.</p>
* <p>This tag lists valid output modes for {@link CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE android.statistics.hotPixelMapMode}.</p>
* <p>If no hotpixel map is available for this camera device, this will contain
- * only OFF. If the hotpixel map is available, this should include both
+ * only OFF. If the hotpixel map is available, this will include both
* the ON and OFF options.</p>
*
* @see CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 68f4d64..1f89d33 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -154,10 +154,11 @@
*
* <ul>
*
- * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Set the size of the
- * Surface with {@link android.view.SurfaceHolder#setFixedSize} to be one of the sizes
- * returned by
- * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceView.class)}
+ * <li>For drawing to a {@link android.view.SurfaceView SurfaceView}: Once the SurfaceView's
+ * Surface is {@link android.view.SurfaceHolder.Callback#surfaceCreated created}, set the
+ * size of the Surface with {@link android.view.SurfaceHolder#setFixedSize} to be one of the
+ * sizes returned by
+ * {@link StreamConfigurationMap#getOutputSizes(Class) getOutputSizes(SurfaceHolder.class)}
* and then obtain the Surface by calling {@link android.view.SurfaceHolder#getSurface}.</li>
*
* <li>For accessing through an OpenGL texture via a
@@ -190,22 +191,18 @@
* Then obtain the Surface with
* {@link android.renderscript.Allocation#getSurface}.</li>
*
- * <li>For access to raw, uncompressed or JPEG data in the application: Create a
- * {@link android.media.ImageReader} object with the one of the supported
- * {@link StreamConfigurationMap#getOutputFormats() output image formats}, and a
- * size from the supported
- * {@link StreamConfigurationMap#getOutputSizes(int) sizes for that format}. Then obtain
- * a Surface from it with {@link android.media.ImageReader#getSurface}.</li>
+ * <li>For access to raw, uncompressed JPEG data in the application: Create an
+ * {@link android.media.ImageReader} object with one of the supported output formats given by
+ * {@link StreamConfigurationMap#getOutputFormats()}, setting its size to one of the
+ * corresponding supported sizes by passing the chosen output format into
+ * {@link StreamConfigurationMap#getOutputSizes(int)}. Then obtain a
+ * {@link android.view.Surface} from it with {@link android.media.ImageReader#getSurface()}.
+ * </li>
*
* </ul>
*
- * </p>
- *
* <p>The camera device will query each Surface's size and formats upon this
- * call, so they must be set to a valid setting at this time (in particular:
- * if the format is user-visible, it must be one of
- * {@link StreamConfigurationMap#getOutputFormats}; and the size must be one of
- * {@link StreamConfigurationMap#getOutputSizes(int)}).</p>
+ * call, so they must be set to a valid setting at this time.</p>
*
* <p>It can take several hundred milliseconds for the session's configuration to complete,
* since camera hardware may need to be powered on or reconfigured. Once the configuration is
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 90e5e4e..33e1915 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -157,8 +157,8 @@
/**
* <p>The lens focus distance is not accurate, and the units used for
- * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.
- * Setting the lens to the same focus distance on separate occasions may
+ * {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} do not correspond to any physical units.</p>
+ * <p>Setting the lens to the same focus distance on separate occasions may
* result in a different real focus distance, depending on factors such
* as the orientation of the device, the age of the focusing mechanism,
* and the device temperature. The focus distance value will still be
@@ -172,20 +172,24 @@
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED = 0;
/**
- * <p>The lens focus distance is measured in diopters. However, setting the lens
- * to the same focus distance on separate occasions may result in a
- * different real focus distance, depending on factors such as the
- * orientation of the device, the age of the focusing mechanism, and
- * the device temperature.</p>
+ * <p>The lens focus distance is measured in diopters.</p>
+ * <p>However, setting the lens to the same focus distance
+ * on separate occasions may result in a different real
+ * focus distance, depending on factors such as the
+ * orientation of the device, the age of the focusing
+ * mechanism, and the device temperature.</p>
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
*/
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE = 1;
/**
- * <p>The lens focus distance is measured in diopters. The lens mechanism is
- * calibrated so that setting the same focus distance is repeatable on
- * multiple occasions with good accuracy, and the focus distance corresponds
- * to the real physical distance to the plane of best focus.</p>
+ * <p>The lens focus distance is measured in diopters, and
+ * is calibrated.</p>
+ * <p>The lens mechanism is calibrated so that setting the
+ * same focus distance is repeatable on multiple
+ * occasions with good accuracy, and the focus distance
+ * corresponds to the real physical distance to the plane
+ * of best focus.</p>
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
*/
public static final int LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED = 2;
@@ -195,11 +199,13 @@
//
/**
+ * <p>The camera device faces the same direction as the device's screen.</p>
* @see CameraCharacteristics#LENS_FACING
*/
public static final int LENS_FACING_FRONT = 0;
/**
+ * <p>The camera device faces the opposite direction as the device's screen.</p>
* @see CameraCharacteristics#LENS_FACING
*/
public static final int LENS_FACING_BACK = 1;
@@ -215,11 +221,10 @@
* <p>The full set of features supported by this capability makes
* the camera2 api backwards compatible with the camera1
* (android.hardware.Camera) API.</p>
- * <p>TODO: @hide this. Doesn't really mean anything except
- * act as a catch-all for all the 'base' functionality.</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0;
@@ -228,15 +233,14 @@
* tags or functionality not encapsulated by one of the other
* capabilities.</p>
* <p>A typical example is all tags marked 'optional'.</p>
- * <p>TODO: @hide. We may not need this if we @hide all the optional
- * tags not belonging to a capability.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_OPTIONAL = 1;
/**
* <p>The camera device can be manually controlled (3A algorithms such
- * as auto exposure, and auto focus can be bypassed).
+ * as auto-exposure, and auto-focus can be bypassed).
* The camera device supports basic manual control of the sensor image
* acquisition related stages. This means the following controls are
* guaranteed to be supported:</p>
@@ -257,11 +261,11 @@
* <li>{@link CameraCharacteristics#SENSOR_INFO_SENSITIVITY_RANGE android.sensor.info.sensitivityRange}</li>
* </ul>
* </li>
- * <li>Manual lens control<ul>
+ * <li>Manual lens control (if the lens is adjustable)<ul>
* <li>android.lens.*</li>
* </ul>
* </li>
- * <li>Manual flash control<ul>
+ * <li>Manual flash control (if a flash unit is present)<ul>
* <li>android.flash.*</li>
* </ul>
* </li>
@@ -312,8 +316,6 @@
* </ul>
* <p>If auto white balance is enabled, then the camera device
* will accurately report the values applied by AWB in the result.</p>
- * <p>The camera device will also support everything in MANUAL_SENSOR
- * except manual lens control and manual flash control.</p>
* <p>A given camera device may also support additional post-processing
* controls, but this capability only covers the above list of controls.</p>
*
@@ -340,8 +342,8 @@
* (both input/output) will match the maximum available
* resolution of JPEG streams.</li>
* </ul>
- * <p>@hide this, TODO: remove it when input related APIs are ready.</p>
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @hide
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4;
@@ -355,7 +357,7 @@
* <li>RAW16 is reprocessable into both YUV_420_888 and JPEG
* formats.</li>
* <li>The maximum available resolution for RAW16 streams (both
- * input/output) will match the either value in
+ * input/output) will match either the value in
* {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} or
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</li>
* <li>All DNG-related optional metadata entries are provided
@@ -373,13 +375,13 @@
//
/**
- * <p>The camera device will only support centered crop regions.</p>
+ * <p>The camera device only supports centered crop regions.</p>
* @see CameraCharacteristics#SCALER_CROPPING_TYPE
*/
public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0;
/**
- * <p>The camera device will support arbitrarily chosen crop regions.</p>
+ * <p>The camera device supports arbitrarily chosen crop regions.</p>
* @see CameraCharacteristics#SCALER_CROPPING_TYPE
*/
public static final int SCALER_CROPPING_TYPE_FREEFORM = 1;
@@ -525,7 +527,7 @@
//
/**
- * <p>android.led.transmit control is used</p>
+ * <p>android.led.transmit control is used.</p>
* @see CameraCharacteristics#LED_AVAILABLE_LEDS
* @hide
*/
@@ -536,11 +538,14 @@
//
/**
+ * <p>This camera device has only limited capabilities.</p>
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0;
/**
+ * <p>This camera device is capable of supporting advanced imaging
+ * applications.</p>
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1;
@@ -550,9 +555,9 @@
//
/**
- * <p>Every frame has the requests immediately applied.
- * (and furthermore for all results,
- * <code>android.sync.frameNumber == android.request.frameCount</code>)</p>
+ * <p>Every frame has the requests immediately applied.</p>
+ * <p>Furthermore for all results,
+ * <code>android.sync.frameNumber == android.request.frameCount</code></p>
* <p>Changing controls over multiple requests one after another will
* produce results that have those controls applied atomically
* each frame.</p>
@@ -592,8 +597,8 @@
public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0;
/**
- * <p>Must not slow down capture rate relative to sensor raw
- * output.</p>
+ * <p>Color correction processing must not slow down
+ * capture rate relative to sensor raw output.</p>
* <p>Advanced white balance adjustments above and beyond
* the specified white balance pipeline may be applied.</p>
* <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -606,8 +611,9 @@
public static final int COLOR_CORRECTION_MODE_FAST = 1;
/**
- * <p>Capture rate (relative to sensor raw output)
- * may be reduced by high quality.</p>
+ * <p>Color correction processing operates at improved
+ * quality but reduced capture rate (relative to sensor raw
+ * output).</p>
* <p>Advanced white balance adjustments above and beyond
* the specified white balance pipeline may be applied.</p>
* <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -658,8 +664,8 @@
//
/**
- * <p>The camera device's autoexposure routine is disabled;
- * the application-selected {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
+ * <p>The camera device's autoexposure routine is disabled.</p>
+ * <p>The application-selected {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
* {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} and
* {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are used by the camera
* device, along with android.flash.* fields, if there's
@@ -674,7 +680,8 @@
/**
* <p>The camera device's autoexposure routine is active,
- * with no flash control. The application's values for
+ * with no flash control.</p>
+ * <p>The application's values for
* {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime},
* {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, and
* {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} are ignored. The
@@ -691,10 +698,10 @@
/**
* <p>Like ON, except that the camera device also controls
* the camera's flash unit, firing it in low-light
- * conditions. The flash may be fired during a
- * precapture sequence (triggered by
- * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and may be fired
- * for captures for which the
+ * conditions.</p>
+ * <p>The flash may be fired during a precapture sequence
+ * (triggered by {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and
+ * may be fired for captures for which the
* {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} field is set to
* STILL_CAPTURE</p>
*
@@ -707,10 +714,10 @@
/**
* <p>Like ON, except that the camera device also controls
* the camera's flash unit, always firing it for still
- * captures. The flash may be fired during a precapture
- * sequence (triggered by
- * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and will always
- * be fired for captures for which the
+ * captures.</p>
+ * <p>The flash may be fired during a precapture sequence
+ * (triggered by {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}) and
+ * will always be fired for captures for which the
* {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} field is set to
* STILL_CAPTURE</p>
*
@@ -722,9 +729,10 @@
/**
* <p>Like ON_AUTO_FLASH, but with automatic red eye
- * reduction. If deemed necessary by the camera device,
- * a red eye reduction flash will fire during the
- * precapture sequence.</p>
+ * reduction.</p>
+ * <p>If deemed necessary by the camera device, a red eye
+ * reduction flash will fire during the precapture
+ * sequence.</p>
* @see CaptureRequest#CONTROL_AE_MODE
*/
public static final int CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE = 4;
@@ -741,8 +749,9 @@
/**
* <p>The precapture metering sequence will be started
- * by the camera device. The exact effect of the precapture
- * trigger depends on the current AE mode and state.</p>
+ * by the camera device.</p>
+ * <p>The exact effect of the precapture trigger depends on
+ * the current AE mode and state.</p>
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
*/
public static final int CONTROL_AE_PRECAPTURE_TRIGGER_START = 1;
@@ -754,7 +763,7 @@
/**
* <p>The auto-focus routine does not control the lens;
* {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance} is controlled by the
- * application</p>
+ * application.</p>
*
* @see CaptureRequest#LENS_FOCUS_DISTANCE
* @see CaptureRequest#CONTROL_AF_MODE
@@ -839,8 +848,11 @@
public static final int CONTROL_AF_MODE_CONTINUOUS_PICTURE = 4;
/**
- * <p>Extended depth of field (digital focus). AF
- * trigger is ignored, AF state should always be
+ * <p>Extended depth of field (digital focus) mode.</p>
+ * <p>The camera device will produce images with an extended
+ * depth of field automatically; no special focusing
+ * operations need to be done before taking a picture.</p>
+ * <p>AF triggers are ignored, and the AF state will always be
* INACTIVE.</p>
* @see CaptureRequest#CONTROL_AF_MODE
*/
@@ -874,8 +886,8 @@
//
/**
- * <p>The camera device's auto white balance routine is disabled;
- * the application-selected color transform matrix
+ * <p>The camera device's auto-white balance routine is disabled.</p>
+ * <p>The application-selected color transform matrix
* ({@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}) and gains
* ({@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}) are used by the camera
* device for manual white balance control.</p>
@@ -887,9 +899,12 @@
public static final int CONTROL_AWB_MODE_OFF = 0;
/**
- * <p>The camera device's auto white balance routine is active;
- * the application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
- * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.</p>
+ * <p>The camera device's auto-white balance routine is active.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
@@ -898,65 +913,125 @@
public static final int CONTROL_AWB_MODE_AUTO = 1;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses incandescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant A.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant A.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_INCANDESCENT = 2;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses fluorescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant F2.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant F2.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_FLUORESCENT = 3;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses warm fluorescent light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant F4.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant F4.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_WARM_FLUORESCENT = 4;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses daylight light as the assumed scene
- * illumination for white balance. While the exact white balance
- * transforms are up to the camera device, they will approximately
- * match the CIE standard illuminant D65.</p>
+ * illumination for white balance.</p>
+ * <p>While the exact white balance transforms are up to the
+ * camera device, they will approximately match the CIE
+ * standard illuminant D65.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_DAYLIGHT = 5;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses cloudy daylight light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_CLOUDY_DAYLIGHT = 6;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses twilight light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_TWILIGHT = 7;
/**
- * <p>The camera device's auto white balance routine is disabled;
+ * <p>The camera device's auto-white balance routine is disabled;
* the camera device uses shade light as the assumed scene
* illumination for white balance.</p>
+ * <p>The application's values for {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}
+ * and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} are ignored.
+ * For devices that support the MANUAL_POST_PROCESSING capability, the
+ * values used by the camera device for the transform and gains
+ * will be available in the capture result for this request.</p>
+ *
+ * @see CaptureRequest#COLOR_CORRECTION_GAINS
+ * @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final int CONTROL_AWB_MODE_SHADE = 8;
@@ -966,38 +1041,43 @@
//
/**
- * <p>This request doesn't fall into the other
- * categories. Default to preview-like
+ * <p>The goal of this request doesn't fall into the other
+ * categories. The camera device will default to preview-like
* behavior.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_CUSTOM = 0;
/**
- * <p>This request is for a preview-like usecase. The
- * precapture trigger may be used to start off a metering
- * w/flash sequence</p>
+ * <p>This request is for a preview-like use case.</p>
+ * <p>The precapture trigger may be used to start off a metering
+ * w/flash sequence.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_PREVIEW = 1;
/**
* <p>This request is for a still capture-type
- * usecase.</p>
+ * use case.</p>
+ * <p>If the flash unit is under automatic control, it may fire as needed.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_STILL_CAPTURE = 2;
/**
* <p>This request is for a video recording
- * usecase.</p>
+ * use case.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_VIDEO_RECORD = 3;
/**
* <p>This request is for a video snapshot (still
- * image while recording video) usecase</p>
+ * image while recording video) use case.</p>
+ * <p>The camera device should take the highest-quality image
+ * possible (given the other settings) without disrupting the
+ * frame rate of video recording.<br />
+ * </p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
@@ -1006,15 +1086,16 @@
* <p>This request is for a ZSL usecase; the
* application will stream full-resolution images and
* reprocess one or several later for a final
- * capture</p>
+ * capture.</p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG = 5;
/**
* <p>This request is for manual capture use case where
- * the applications want to directly control the capture parameters
- * (e.g. {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} etc.).</p>
+ * the applications want to directly control the capture parameters.</p>
+ * <p>For example, the application may wish to manually control
+ * {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}, {@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}, etc.</p>
*
* @see CaptureRequest#SENSOR_EXPOSURE_TIME
* @see CaptureRequest#SENSOR_SENSITIVITY
@@ -1034,7 +1115,8 @@
/**
* <p>A "monocolor" effect where the image is mapped into
- * a single color. This will typically be grayscale.</p>
+ * a single color.</p>
+ * <p>This will typically be grayscale.</p>
* @see CaptureRequest#CONTROL_EFFECT_MODE
*/
public static final int CONTROL_EFFECT_MODE_MONO = 1;
@@ -1094,31 +1176,42 @@
//
/**
- * <p>Full application control of pipeline. All 3A
- * routines are disabled, no other settings in
- * android.control.* have any effect</p>
+ * <p>Full application control of pipeline.</p>
+ * <p>All control by the device's metering and focusing (3A)
+ * routines is disabled, and no other settings in
+ * android.control.* have any effect, except that
+ * {@link CaptureRequest#CONTROL_CAPTURE_INTENT android.control.captureIntent} may be used by the camera
+ * device to select post-processing values for processing
+ * blocks that do not allow for manual control, or are not
+ * exposed by the camera API.</p>
+ * <p>However, the camera device's 3A routines may continue to
+ * collect statistics and update their internal state so that
+ * when control is switched to AUTO mode, good control values
+ * can be immediately applied.</p>
+ *
+ * @see CaptureRequest#CONTROL_CAPTURE_INTENT
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_OFF = 0;
/**
- * <p>Use settings for each individual 3A routine.
- * Manual control of capture parameters is disabled. All
+ * <p>Use settings for each individual 3A routine.</p>
+ * <p>Manual control of capture parameters is disabled. All
* controls in android.control.* besides sceneMode take
- * effect</p>
+ * effect.</p>
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_AUTO = 1;
/**
- * <p>Use specific scene mode. Enabling this disables
- * control.aeMode, control.awbMode and control.afMode
- * controls; the camera device will ignore those settings while
- * USE_SCENE_MODE is active (except for FACE_PRIORITY
- * scene mode). Other control entries are still active.
- * This setting can only be used if scene mode is supported
- * (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes} contain some modes
- * other than DISABLED).</p>
+ * <p>Use a specific scene mode.</p>
+ * <p>Enabling this disables control.aeMode, control.awbMode and
+ * control.afMode controls; the camera device will ignore
+ * those settings while USE_SCENE_MODE is active (except for
+ * FACE_PRIORITY scene mode). Other control entries are still
+ * active. This setting can only be used if scene mode is
+ * supported (i.e. {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}
+ * contain some modes other than DISABLED).</p>
*
* @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_MODE
@@ -1128,7 +1221,12 @@
/**
* <p>Same as OFF mode, except that this capture will not be
* used by camera device background auto-exposure, auto-white balance and
- * auto-focus algorithms to update their statistics.</p>
+ * auto-focus algorithms (3A) to update their statistics.</p>
+ * <p>Specifically, the 3A routines are locked to the last
+ * values set from a request with AUTO, OFF, or
+ * USE_SCENE_MODE, and any statistics or state updates
+ * collected from manual captures with OFF_KEEP_STATE will be
+ * discarded by the camera device.</p>
* @see CaptureRequest#CONTROL_MODE
*/
public static final int CONTROL_MODE_OFF_KEEP_STATE = 3;
@@ -1146,8 +1244,9 @@
/**
* <p>If face detection support exists, use face
* detection data for auto-focus, auto-white balance, and
- * auto-exposure routines. If face detection statistics are
- * disabled (i.e. {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} is set to OFF),
+ * auto-exposure routines.</p>
+ * <p>If face detection statistics are disabled
+ * (i.e. {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} is set to OFF),
* this should still operate correctly (but will not return
* face detection statistics to the framework).</p>
* <p>Unlike the other scene modes, {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
@@ -1163,8 +1262,8 @@
public static final int CONTROL_SCENE_MODE_FACE_PRIORITY = 1;
/**
- * <p>Optimized for photos of quickly moving objects.
- * Similar to SPORTS.</p>
+ * <p>Optimized for photos of quickly moving objects.</p>
+ * <p>Similar to SPORTS.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_ACTION = 2;
@@ -1233,8 +1332,8 @@
public static final int CONTROL_SCENE_MODE_FIREWORKS = 12;
/**
- * <p>Optimized for photos of quickly moving people.
- * Similar to ACTION.</p>
+ * <p>Optimized for photos of quickly moving people.</p>
+ * <p>Similar to ACTION.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_SPORTS = 13;
@@ -1266,11 +1365,13 @@
//
/**
+ * <p>Video stabilization is disabled.</p>
* @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
*/
public static final int CONTROL_VIDEO_STABILIZATION_MODE_OFF = 0;
/**
+ * <p>Video stabilization is enabled.</p>
* @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
*/
public static final int CONTROL_VIDEO_STABILIZATION_MODE_ON = 1;
@@ -1280,21 +1381,20 @@
//
/**
- * <p>No edge enhancement is applied</p>
+ * <p>No edge enhancement is applied.</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor
+ * <p>Apply edge enhancement at a quality level that does not slow down frame rate relative to sensor
* output</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_FAST = 1;
/**
- * <p>Frame rate may be reduced by high
- * quality</p>
+ * <p>Apply high-quality edge enhancement, at a cost of reducing output frame rate.</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_HIGH_QUALITY = 2;
@@ -1327,10 +1427,10 @@
//
/**
+ * <p>No hot pixel correction is applied.</p>
* <p>The frame rate must not be reduced relative to sensor raw output
* for this option.</p>
- * <p>No hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1338,10 +1438,9 @@
public static final int HOT_PIXEL_MODE_OFF = 0;
/**
- * <p>The frame rate must not be reduced relative to sensor raw output
- * for this option.</p>
- * <p>Hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>Hot pixel correction is applied, without reducing frame
+ * rate relative to sensor raw output.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1349,10 +1448,9 @@
public static final int HOT_PIXEL_MODE_FAST = 1;
/**
- * <p>The frame rate may be reduced relative to sensor raw output
- * for this option.</p>
- * <p>A high-quality hot pixel correction is applied.
- * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
+ * <p>High-quality hot pixel correction is applied, at a cost
+ * of reducing frame rate relative to sensor raw output.</p>
+ * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
* @see CaptureRequest#HOT_PIXEL_MODE
@@ -1380,21 +1478,21 @@
//
/**
- * <p>No noise reduction is applied</p>
+ * <p>No noise reduction is applied.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor
- * output</p>
+ * <p>Noise reduction is applied without reducing frame rate relative to sensor
+ * output.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_FAST = 1;
/**
- * <p>May slow down frame rate to provide highest
- * quality</p>
+ * <p>High-quality noise reduction is applied, at the cost of reducing frame rate
+ * relative to sensor output.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
@@ -1404,8 +1502,9 @@
//
/**
- * <p>Default. No test pattern mode is used, and the camera
+ * <p>No test pattern mode is used, and the camera
* device returns captures from the image sensor.</p>
+ * <p>This is the default if the key is not set.</p>
* @see CaptureRequest#SENSOR_TEST_PATTERN_MODE
*/
public static final int SENSOR_TEST_PATTERN_MODE_OFF = 0;
@@ -1509,19 +1608,21 @@
//
/**
- * <p>No lens shading correction is applied</p>
+ * <p>No lens shading correction is applied.</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_OFF = 0;
/**
- * <p>Must not slow down frame rate relative to sensor raw output</p>
+ * <p>Apply lens shading corrections, without slowing
+ * frame rate relative to sensor raw output</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_FAST = 1;
/**
- * <p>Frame rate may be reduced by high quality</p>
+ * <p>Apply high-quality lens shading correction, at the
+ * cost of reduced frame rate.</p>
* @see CaptureRequest#SHADING_MODE
*/
public static final int SHADING_MODE_HIGH_QUALITY = 2;
@@ -1531,20 +1632,28 @@
//
/**
+ * <p>Do not include face detection statistics in capture
+ * results.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_OFF = 0;
/**
- * <p>Optional Return rectangle and confidence
- * only</p>
+ * <p>Return face rectangle and confidence values only.</p>
+ * <p>In this mode, only android.statistics.faceRectangles and
+ * android.statistics.faceScores outputs are valid.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_SIMPLE = 1;
/**
- * <p>Optional Return all face
- * metadata</p>
+ * <p>Return all face
+ * metadata.</p>
+ * <p>In this mode,
+ * android.statistics.faceRectangles,
+ * android.statistics.faceScores,
+ * android.statistics.faceIds, and
+ * android.statistics.faceLandmarks outputs are valid.</p>
* @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
*/
public static final int STATISTICS_FACE_DETECT_MODE_FULL = 2;
@@ -1554,11 +1663,13 @@
//
/**
+ * <p>Do not include a lens shading map in the capture result.</p>
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
*/
public static final int STATISTICS_LENS_SHADING_MAP_MODE_OFF = 0;
/**
+ * <p>Include a lens shading map in the capture result.</p>
* @see CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE
*/
public static final int STATISTICS_LENS_SHADING_MAP_MODE_ON = 1;
@@ -1582,15 +1693,15 @@
public static final int TONEMAP_MODE_CONTRAST_CURVE = 0;
/**
- * <p>Advanced gamma mapping and color enhancement may be applied.</p>
- * <p>Should not slow down frame rate relative to raw sensor output.</p>
+ * <p>Advanced gamma mapping and color enhancement may be applied, without
+ * reducing frame rate compared to raw sensor output.</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_FAST = 1;
/**
- * <p>Advanced gamma mapping and color enhancement may be applied.</p>
- * <p>May slow down frame rate relative to raw sensor output.</p>
+ * <p>High-quality gamma mapping and color enhancement will be applied, at
+ * the cost of reduced frame rate compared to raw sensor output.</p>
* @see CaptureRequest#TONEMAP_MODE
*/
public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
@@ -1600,7 +1711,8 @@
//
/**
- * <p>AE is off or recently reset. When a camera device is opened, it starts in
+ * <p>AE is off or recently reset.</p>
+ * <p>When a camera device is opened, it starts in
* this state. This is a transient state, the camera device may skip reporting
* this state in capture result.</p>
* @see CaptureResult#CONTROL_AE_STATE
@@ -1609,7 +1721,8 @@
/**
* <p>AE doesn't yet have a good set of control values
- * for the current scene. This is a transient state, the camera device may skip
+ * for the current scene.</p>
+ * <p>This is a transient state, the camera device may skip
* reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
@@ -1638,11 +1751,13 @@
/**
* <p>AE has been asked to do a precapture sequence
- * (through the {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} START),
- * and is currently executing it. Once PRECAPTURE
- * completes, AE will transition to CONVERGED or
- * FLASH_REQUIRED as appropriate. This is a transient state, the
- * camera device may skip reporting this state in capture result.</p>
+ * and is currently executing it.</p>
+ * <p>Precapture can be triggered through setting
+ * {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} to START.</p>
+ * <p>Once PRECAPTURE completes, AE will transition to CONVERGED
+ * or FLASH_REQUIRED as appropriate. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
*
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
* @see CaptureResult#CONTROL_AE_STATE
@@ -1654,61 +1769,78 @@
//
/**
- * <p>AF off or has not yet tried to scan/been asked
- * to scan. When a camera device is opened, it starts in
- * this state. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AF is off or has not yet tried to scan/been asked
+ * to scan.</p>
+ * <p>When a camera device is opened, it starts in this
+ * state. This is a transient state, the camera device may
+ * skip reporting this state in capture
+ * result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_INACTIVE = 0;
/**
- * <p>if CONTINUOUS_* modes are supported. AF is
- * currently doing an AF scan initiated by a continuous
- * autofocus mode. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AF is currently performing an AF scan initiated the
+ * camera device in a continuous autofocus mode.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_SCAN = 1;
/**
- * <p>if CONTINUOUS_* modes are supported. AF currently
- * believes it is in focus, but may restart scanning at
- * any time. This is a transient state, the camera device may skip
- * reporting this state in capture result.</p>
+ * <p>AF currently believes it is in focus, but may
+ * restart scanning at any time.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_FOCUSED = 2;
/**
- * <p>if AUTO or MACRO modes are supported. AF is doing
- * an AF scan because it was triggered by AF trigger. This is a
- * transient state, the camera device may skip reporting
- * this state in capture result.</p>
+ * <p>AF is performing an AF scan because it was
+ * triggered by AF trigger.</p>
+ * <p>Only used by AUTO or MACRO AF modes. This is a transient
+ * state, the camera device may skip reporting this state in
+ * capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3;
/**
- * <p>if any AF mode besides OFF is supported. AF
- * believes it is focused correctly and is
- * locked.</p>
+ * <p>AF believes it is focused correctly and has locked
+ * focus.</p>
+ * <p>This state is reached only after an explicit START AF trigger has been
+ * sent ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}), when good focus has been obtained.</p>
+ * <p>The lens will remain stationary until the AF mode ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) is changed or
+ * a new AF trigger is sent to the camera device ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}).</p>
+ *
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AF_TRIGGER
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4;
/**
- * <p>if any AF mode besides OFF is supported. AF has
- * failed to focus successfully and is
- * locked.</p>
+ * <p>AF has failed to focus successfully and has locked
+ * focus.</p>
+ * <p>This state is reached only after an explicit START AF trigger has been
+ * sent ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}), when good focus cannot be obtained.</p>
+ * <p>The lens will remain stationary until the AF mode ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) is changed or
+ * a new AF trigger is sent to the camera device ({@link CaptureRequest#CONTROL_AF_TRIGGER android.control.afTrigger}).</p>
+ *
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AF_TRIGGER
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_NOT_FOCUSED_LOCKED = 5;
/**
- * <p>if CONTINUOUS_* modes are supported. AF finished a
- * passive scan without finding focus, and may restart
- * scanning at any time. This is a transient state, the camera
+ * <p>AF finished a passive scan without finding focus,
+ * and may restart scanning at any time.</p>
+ * <p>Only used by CONTINUOUS_* AF modes. This is a transient state, the camera
* device may skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
@@ -1719,16 +1851,19 @@
//
/**
- * <p>AWB is not in auto mode. When a camera device is opened, it
- * starts in this state. This is a transient state, the camera device may
- * skip reporting this state in capture result.</p>
+ * <p>AWB is not in auto mode, or has not yet started metering.</p>
+ * <p>When a camera device is opened, it starts in this
+ * state. This is a transient state, the camera device may
+ * skip reporting this state in capture
+ * result.</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
public static final int CONTROL_AWB_STATE_INACTIVE = 0;
/**
* <p>AWB doesn't yet have a good set of control
- * values for the current scene. This is a transient state, the camera device
+ * values for the current scene.</p>
+ * <p>This is a transient state, the camera device
* may skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
@@ -1776,8 +1911,9 @@
public static final int FLASH_STATE_FIRED = 3;
/**
- * <p>Flash partially illuminated this frame. This is usually due to the next
- * or previous frame having the flash fire, and the flash spilling into this capture
+ * <p>Flash partially illuminated this frame.</p>
+ * <p>This is usually due to the next or previous frame having
+ * the flash fire, and the flash spilling into this capture
* due to hardware limitations.</p>
* @see CaptureResult#FLASH_STATE
*/
@@ -1800,8 +1936,10 @@
public static final int LENS_STATE_STATIONARY = 0;
/**
- * <p>Any of the lens parameters ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
- * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is changing.</p>
+ * <p>One or several of the lens parameters
+ * ({@link CaptureRequest#LENS_FOCAL_LENGTH android.lens.focalLength}, {@link CaptureRequest#LENS_FOCUS_DISTANCE android.lens.focusDistance},
+ * {@link CaptureRequest#LENS_FILTER_DENSITY android.lens.filterDensity} or {@link CaptureRequest#LENS_APERTURE android.lens.aperture}) is
+ * currently changing.</p>
*
* @see CaptureRequest#LENS_APERTURE
* @see CaptureRequest#LENS_FILTER_DENSITY
@@ -1816,16 +1954,22 @@
//
/**
+ * <p>The camera device does not detect any flickering illumination
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_NONE = 0;
/**
+ * <p>The camera device detects illumination flickering at 50Hz
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_50HZ = 1;
/**
+ * <p>The camera device detects illumination flickering at 60Hz
+ * in the current scene.</p>
* @see CaptureResult#STATISTICS_SCENE_FLICKER
*/
public static final int STATISTICS_SCENE_FLICKER_60HZ = 2;
@@ -1835,8 +1979,8 @@
//
/**
- * <p>The current result is not yet fully synchronized to any request.
- * Synchronization is in progress, and reading metadata from this
+ * <p>The current result is not yet fully synchronized to any request.</p>
+ * <p>Synchronization is in progress, and reading metadata from this
* result may include a mix of data that have taken effect since the
* last synchronization time.</p>
* <p>In some future result, within {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} frames,
@@ -1851,10 +1995,10 @@
public static final int SYNC_FRAME_NUMBER_CONVERGING = -1;
/**
- * <p>The current result's synchronization status is unknown. The
- * result may have already converged, or it may be in progress.
- * Reading from this result may include some mix of settings from
- * past requests.</p>
+ * <p>The current result's synchronization status is unknown.</p>
+ * <p>The result may have already converged, or it may be in
+ * progress. Reading from this result may include some mix
+ * of settings from past requests.</p>
* <p>After a settings change, the new settings will eventually all
* take effect for the output buffers and results. However, this
* value will not change when that happens. Altering settings
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 0ff8cce..bf7bd37 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -733,8 +733,16 @@
* included at all in the request settings. When included and
* set to START, the camera device will trigger the autoexposure
* precapture metering sequence.</p>
- * <p>The effect of auto-exposure (AE) precapture trigger depends
- * on the current AE mode and state; see
+ * <p>The precapture sequence should triggered before starting a
+ * high-quality still capture for final metering decisions to
+ * be made, and for firing pre-capture flash pulses to estimate
+ * scene brightness and required final capture flash power, when
+ * the flash is enabled.</p>
+ * <p>Normally, this entry should be set to START for only a
+ * single request, and the application should wait until the
+ * sequence completes before starting a new one.</p>
+ * <p>The exact effect of auto-exposure (AE) precapture trigger
+ * depends on the current AE mode and state; see
* {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture state transition
* details.</p>
*
@@ -800,7 +808,11 @@
* autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
* <p>When set to CANCEL, the camera device will cancel any active trigger,
* and return to its initial AF state.</p>
- * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+ * <p>Generally, applications should set this entry to START or CANCEL for only a
+ * single capture, and then return it to IDLE (or not set at all). Specifying
+ * START for multiple captures in a row means restarting the AF operation over
+ * and over again.</p>
+ * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what the trigger means for each AF mode.</p>
*
* @see CaptureResult#CONTROL_AF_STATE
* @see #CONTROL_AF_TRIGGER_IDLE
@@ -813,9 +825,11 @@
/**
* <p>Whether auto-white balance (AWB) is currently locked to its
* latest calculated values.</p>
- * <p>Note that AWB lock is only meaningful for AUTO
- * mode; in other modes, AWB is already fixed to a specific
- * setting.</p>
+ * <p>Note that AWB lock is only meaningful when
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} is in the AUTO mode; in other modes,
+ * AWB is already fixed to a specific setting.</p>
+ *
+ * @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final Key<Boolean> CONTROL_AWB_LOCK =
new Key<Boolean>("android.control.awbLock", boolean.class);
@@ -825,17 +839,21 @@
* transform fields, and what its illumination target
* is.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
- * <p>When set to the ON mode, the camera device's auto white balance
+ * <p>When set to the ON mode, the camera device's auto-white balance
* routine is enabled, overriding the application's selected
* {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to the OFF mode, the camera device's auto white balance
+ * <p>When set to the OFF mode, the camera device's auto-white balance
* routine is disabled. The application manually controls the white
* balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
* and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to any other modes, the camera device's auto white balance
- * routine is disabled. The camera device uses each particular illumination
- * target for white balance adjustment.</p>
+ * <p>When set to any other modes, the camera device's auto-white
+ * balance routine is disabled. The camera device uses each
+ * particular illumination target for white balance
+ * adjustment. The application's values for
+ * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
+ * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -886,8 +904,8 @@
* strategy.</p>
* <p>This control (except for MANUAL) is only effective if
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
- * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
- * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
* contains MANUAL_SENSOR.</p>
*
* @see CaptureRequest#CONTROL_MODE
@@ -962,7 +980,9 @@
* <p>This is the mode that that is active when
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
* these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
- * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.
+ * The scene modes available for a given camera device are listed in
+ * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}.</p>
* <p>The interpretation and implementation of these scene modes is left
* to the implementor of the camera device. Their behavior will not be
* consistent across all devices, and any given device may only implement
@@ -970,6 +990,7 @@
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AF_MODE
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_AWB_MODE
* @see CaptureRequest#CONTROL_MODE
* @see #CONTROL_SCENE_MODE_DISABLED
@@ -996,6 +1017,8 @@
/**
* <p>Whether video stabilization is
* active.</p>
+ * <p>Video stabilization automatically translates and scales images from the camera
+ * in order to stabilize motion between consecutive frames.</p>
* <p>If enabled, video stabilization can modify the
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
* stabilized</p>
@@ -1110,14 +1133,14 @@
/**
* <p>Compression quality of the final JPEG
* image.</p>
- * <p>85-95 is typical usage range</p>
+ * <p>85-95 is typical usage range.</p>
*/
public static final Key<Byte> JPEG_QUALITY =
new Key<Byte>("android.jpeg.quality", byte.class);
/**
* <p>Compression quality of JPEG
- * thumbnail</p>
+ * thumbnail.</p>
*/
public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
@@ -1229,12 +1252,18 @@
/**
* <p>Sets whether the camera device uses optical image stabilization (OIS)
* when capturing images.</p>
- * <p>OIS is used to compensate for motion blur due to small movements of
- * the camera during capture. Unlike digital image stabilization, OIS makes
- * use of mechanical elements to stabilize the camera sensor, and thus
- * allows for longer exposure times before camera shake becomes
- * apparent.</p>
- * <p>This is not expected to be supported on most devices.</p>
+ * <p>OIS is used to compensate for motion blur due to small
+ * movements of the camera during capture. Unlike digital image
+ * stabilization ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}), OIS
+ * makes use of mechanical elements to stabilize the camera
+ * sensor, and thus allows for longer exposure times before
+ * camera shake becomes apparent.</p>
+ * <p>Not all devices will support OIS; see
+ * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
+ * available controls.</p>
+ *
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
* @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
* @see #LENS_OPTICAL_STABILIZATION_MODE_ON
*/
@@ -1242,16 +1271,15 @@
new Key<Integer>("android.lens.opticalStabilizationMode", int.class);
/**
- * <p>Mode of operation for the noise reduction.
- * algorithm</p>
+ * <p>Mode of operation for the noise reduction algorithm.</p>
* <p>Noise filtering control. OFF means no noise reduction
* will be applied by the camera device.</p>
- * <p>This must be set to a valid mode in
+ * <p>This must be set to a valid mode from
* {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
- * even if it slows down capture rate. FAST means the camera device should not
+ * even if it slows down capture rate. FAST means the camera device will not
* slow down capture rate when applying noise filtering.</p>
*
* @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
@@ -1435,7 +1463,7 @@
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
- * by android.sensor.* should be ignored. All other controls should
+ * by android.sensor.* will be ignored. All other controls should
* work as normal.</p>
* <p>For example, if manual flash is enabled, flash firing should still
* occur (and that the test pattern remain unmodified, since the flash
@@ -1490,7 +1518,7 @@
new Key<Integer>("android.shading.mode", int.class);
/**
- * <p>State of the face detector
+ * <p>Control for the face detector
* unit.</p>
* <p>Whether face detection is enabled, and whether it
* should output just the basic fields or the full set of
@@ -1508,7 +1536,7 @@
/**
* <p>Operating mode for hotpixel map generation.</p>
* <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.
- * If set to OFF, no hotpixel map should be returned.</p>
+ * If set to OFF, no hotpixel map will be returned.</p>
* <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -1521,7 +1549,7 @@
* <p>Whether the camera device will output the lens
* shading map in output result metadata.</p>
* <p>When set to ON,
- * android.statistics.lensShadingMap must be provided in
+ * android.statistics.lensShadingMap will be provided in
* the output result metadata.</p>
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ce3de1d..01fea54 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -579,8 +579,16 @@
* included at all in the request settings. When included and
* set to START, the camera device will trigger the autoexposure
* precapture metering sequence.</p>
- * <p>The effect of auto-exposure (AE) precapture trigger depends
- * on the current AE mode and state; see
+ * <p>The precapture sequence should triggered before starting a
+ * high-quality still capture for final metering decisions to
+ * be made, and for firing pre-capture flash pulses to estimate
+ * scene brightness and required final capture flash power, when
+ * the flash is enabled.</p>
+ * <p>Normally, this entry should be set to START for only a
+ * single request, and the application should wait until the
+ * sequence completes before starting a new one.</p>
+ * <p>The exact effect of auto-exposure (AE) precapture trigger
+ * depends on the current AE mode and state; see
* {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE precapture state transition
* details.</p>
*
@@ -592,7 +600,7 @@
new Key<Integer>("android.control.aePrecaptureTrigger", int.class);
/**
- * <p>Current state of auto-exposure (AE) algorithm.</p>
+ * <p>Current state of the auto-exposure (AE) algorithm.</p>
* <p>Switching between or enabling AE modes ({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}) always
* resets the AE state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
* or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -844,7 +852,11 @@
* autofocus algorithm. If autofocus is disabled, this trigger has no effect.</p>
* <p>When set to CANCEL, the camera device will cancel any active trigger,
* and return to its initial AF state.</p>
- * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what that means for each AF mode.</p>
+ * <p>Generally, applications should set this entry to START or CANCEL for only a
+ * single capture, and then return it to IDLE (or not set at all). Specifying
+ * START for multiple captures in a row means restarting the AF operation over
+ * and over again.</p>
+ * <p>See {@link CaptureResult#CONTROL_AF_STATE android.control.afState} for what the trigger means for each AF mode.</p>
*
* @see CaptureResult#CONTROL_AF_STATE
* @see #CONTROL_AF_TRIGGER_IDLE
@@ -1034,13 +1046,13 @@
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. If focus is good, Lens now locked</td>
+ * <td align="center">Immediate transition, if focus is good. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. if focus is bad, Lens now locked</td>
+ * <td align="center">Immediate transition, if focus is bad. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
@@ -1064,13 +1076,13 @@
* <td align="center">PASSIVE_FOCUSED</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. Lens now locked</td>
+ * <td align="center">Immediate transition, lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_UNFOCUSED</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Immediate trans. Lens now locked</td>
+ * <td align="center">Immediate transition, lens now locked</td>
* </tr>
* <tr>
* <td align="center">FOCUSED_LOCKED</td>
@@ -1137,13 +1149,13 @@
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">FOCUSED_LOCKED</td>
- * <td align="center">Eventual trans. once focus good, Lens now locked</td>
+ * <td align="center">Eventual transition once the focus is good. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
* <td align="center">AF_TRIGGER</td>
* <td align="center">NOT_FOCUSED_LOCKED</td>
- * <td align="center">Eventual trans. if cannot focus, Lens now locked</td>
+ * <td align="center">Eventual transition if cannot find focus. Lens now locked</td>
* </tr>
* <tr>
* <td align="center">PASSIVE_SCAN</td>
@@ -1254,9 +1266,11 @@
/**
* <p>Whether auto-white balance (AWB) is currently locked to its
* latest calculated values.</p>
- * <p>Note that AWB lock is only meaningful for AUTO
- * mode; in other modes, AWB is already fixed to a specific
- * setting.</p>
+ * <p>Note that AWB lock is only meaningful when
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} is in the AUTO mode; in other modes,
+ * AWB is already fixed to a specific setting.</p>
+ *
+ * @see CaptureRequest#CONTROL_AWB_MODE
*/
public static final Key<Boolean> CONTROL_AWB_LOCK =
new Key<Boolean>("android.control.awbLock", boolean.class);
@@ -1266,17 +1280,21 @@
* transform fields, and what its illumination target
* is.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
- * <p>When set to the ON mode, the camera device's auto white balance
+ * <p>When set to the ON mode, the camera device's auto-white balance
* routine is enabled, overriding the application's selected
* {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to the OFF mode, the camera device's auto white balance
+ * <p>When set to the OFF mode, the camera device's auto-white balance
* routine is disabled. The application manually controls the white
* balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
* and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
- * <p>When set to any other modes, the camera device's auto white balance
- * routine is disabled. The camera device uses each particular illumination
- * target for white balance adjustment.</p>
+ * <p>When set to any other modes, the camera device's auto-white
+ * balance routine is disabled. The camera device uses each
+ * particular illumination target for white balance
+ * adjustment. The application's values for
+ * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
+ * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
+ * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -1327,8 +1345,8 @@
* strategy.</p>
* <p>This control (except for MANUAL) is only effective if
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} != OFF</code> and any 3A routine is active.</p>
- * <p>ZERO_SHUTTER_LAG must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
- * contains ZSL. MANUAL must be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * <p>ZERO_SHUTTER_LAG will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
+ * contains ZSL. MANUAL will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}
* contains MANUAL_SENSOR.</p>
*
* @see CaptureRequest#CONTROL_MODE
@@ -1533,7 +1551,9 @@
* <p>This is the mode that that is active when
* <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code>. Aside from FACE_PRIORITY,
* these modes will disable {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode},
- * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.</p>
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode}, and {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} while in use.
+ * The scene modes available for a given camera device are listed in
+ * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}.</p>
* <p>The interpretation and implementation of these scene modes is left
* to the implementor of the camera device. Their behavior will not be
* consistent across all devices, and any given device may only implement
@@ -1541,6 +1561,7 @@
*
* @see CaptureRequest#CONTROL_AE_MODE
* @see CaptureRequest#CONTROL_AF_MODE
+ * @see CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES
* @see CaptureRequest#CONTROL_AWB_MODE
* @see CaptureRequest#CONTROL_MODE
* @see #CONTROL_SCENE_MODE_DISABLED
@@ -1567,6 +1588,8 @@
/**
* <p>Whether video stabilization is
* active.</p>
+ * <p>Video stabilization automatically translates and scales images from the camera
+ * in order to stabilize motion between consecutive frames.</p>
* <p>If enabled, video stabilization can modify the
* {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream
* stabilized</p>
@@ -1698,14 +1721,14 @@
/**
* <p>Compression quality of the final JPEG
* image.</p>
- * <p>85-95 is typical usage range</p>
+ * <p>85-95 is typical usage range.</p>
*/
public static final Key<Byte> JPEG_QUALITY =
new Key<Byte>("android.jpeg.quality", byte.class);
/**
* <p>Compression quality of JPEG
- * thumbnail</p>
+ * thumbnail.</p>
*/
public static final Key<Byte> JPEG_THUMBNAIL_QUALITY =
new Key<Byte>("android.jpeg.thumbnailQuality", byte.class);
@@ -1817,12 +1840,18 @@
/**
* <p>Sets whether the camera device uses optical image stabilization (OIS)
* when capturing images.</p>
- * <p>OIS is used to compensate for motion blur due to small movements of
- * the camera during capture. Unlike digital image stabilization, OIS makes
- * use of mechanical elements to stabilize the camera sensor, and thus
- * allows for longer exposure times before camera shake becomes
- * apparent.</p>
- * <p>This is not expected to be supported on most devices.</p>
+ * <p>OIS is used to compensate for motion blur due to small
+ * movements of the camera during capture. Unlike digital image
+ * stabilization ({@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode}), OIS
+ * makes use of mechanical elements to stabilize the camera
+ * sensor, and thus allows for longer exposure times before
+ * camera shake becomes apparent.</p>
+ * <p>Not all devices will support OIS; see
+ * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
+ * available controls.</p>
+ *
+ * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
+ * @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
* @see #LENS_OPTICAL_STABILIZATION_MODE_OFF
* @see #LENS_OPTICAL_STABILIZATION_MODE_ON
*/
@@ -1866,16 +1895,15 @@
new Key<Integer>("android.lens.state", int.class);
/**
- * <p>Mode of operation for the noise reduction.
- * algorithm</p>
+ * <p>Mode of operation for the noise reduction algorithm.</p>
* <p>Noise filtering control. OFF means no noise reduction
* will be applied by the camera device.</p>
- * <p>This must be set to a valid mode in
+ * <p>This must be set to a valid mode from
* {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
- * even if it slows down capture rate. FAST means the camera device should not
+ * even if it slows down capture rate. FAST means the camera device will not
* slow down capture rate when applying noise filtering.</p>
*
* @see CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES
@@ -2086,7 +2114,7 @@
/**
* <p>Time at start of exposure of first
- * row of the image sensor, in nanoseconds.</p>
+ * row of the image sensor active array, in nanoseconds.</p>
* <p>The timestamps are also included in all image
* buffers produced for the same capture, and will be identical
* on all the outputs. The timestamps measure time since an
@@ -2170,7 +2198,7 @@
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
- * by android.sensor.* should be ignored. All other controls should
+ * by android.sensor.* will be ignored. All other controls should
* work as normal.</p>
* <p>For example, if manual flash is enabled, flash firing should still
* occur (and that the test pattern remain unmodified, since the flash
@@ -2187,6 +2215,20 @@
new Key<Integer>("android.sensor.testPatternMode", int.class);
/**
+ * <p>Duration between the start of first row exposure
+ * and the start of last row exposure.</p>
+ * <p>This is the exposure time skew (in the unit of nanosecond) between the first and
+ * last row exposure start times. The first row and the last row are the first
+ * and last rows inside of the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
+ * <p>For typical camera sensors that use rolling shutters, this is also equivalent
+ * to the frame readout time.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ */
+ public static final Key<Long> SENSOR_ROLLING_SHUTTER_SKEW =
+ new Key<Long>("android.sensor.rollingShutterSkew", long.class);
+
+ /**
* <p>Quality of lens shading correction applied
* to the image data.</p>
* <p>When set to OFF mode, no lens shading correction will be applied by the
@@ -2225,7 +2267,7 @@
new Key<Integer>("android.shading.mode", int.class);
/**
- * <p>State of the face detector
+ * <p>Control for the face detector
* unit.</p>
* <p>Whether face detection is enabled, and whether it
* should output just the basic fields or the full set of
@@ -2241,9 +2283,13 @@
new Key<Integer>("android.statistics.faceDetectMode", int.class);
/**
- * <p>List of unique IDs for detected
- * faces</p>
- * <p>Only available if faceDetectMode == FULL</p>
+ * <p>List of unique IDs for detected faces.</p>
+ * <p>Each detected face is given a unique ID that is valid for as long as the face is visible
+ * to the camera device. A face that leaves the field of view and later returns may be
+ * assigned a new ID.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL</p>
+ *
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<int[]> STATISTICS_FACE_IDS =
@@ -2251,8 +2297,13 @@
/**
* <p>List of landmarks for detected
- * faces</p>
- * <p>Only available if faceDetectMode == FULL</p>
+ * faces.</p>
+ * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} == FULL</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<int[]> STATISTICS_FACE_LANDMARKS =
@@ -2260,8 +2311,13 @@
/**
* <p>List of the bounding rectangles for detected
- * faces</p>
- * <p>Only available if faceDetectMode != OFF</p>
+ * faces.</p>
+ * <p>The coordinate system is that of {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, with
+ * <code>(0, 0)</code> being the top-left pixel of the active array.</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<android.graphics.Rect[]> STATISTICS_FACE_RECTANGLES =
@@ -2270,8 +2326,9 @@
/**
* <p>List of the face confidence scores for
* detected faces</p>
- * <p>Only available if faceDetectMode != OFF. The value should be
- * meaningful (for example, setting 100 at all times is illegal).</p>
+ * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} != OFF.</p>
+ *
+ * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
* @hide
*/
public static final Key<byte[]> STATISTICS_FACE_SCORES =
@@ -2435,12 +2492,13 @@
* The camera device uses this entry to tell the application what the scene
* illuminant frequency is.</p>
* <p>When manual exposure control is enabled
- * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == OFF</code>),
- * the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't do the antibanding, and the
- * application can ensure it selects exposure times that do not cause banding
- * issues by looking into this metadata field. See {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode}
- * for more details.</p>
- * <p>Report NONE if there doesn't appear to be flickering illumination.</p>
+ * (<code>{@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} == OFF</code> or <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} ==
+ * OFF</code>), the {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} doesn't perform
+ * antibanding, and the application can ensure it selects
+ * exposure times that do not cause banding issues by looking
+ * into this metadata field. See
+ * {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} for more details.</p>
+ * <p>Reports NONE if there doesn't appear to be flickering illumination.</p>
*
* @see CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
* @see CaptureRequest#CONTROL_AE_MODE
@@ -2455,7 +2513,7 @@
/**
* <p>Operating mode for hotpixel map generation.</p>
* <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.
- * If set to OFF, no hotpixel map should be returned.</p>
+ * If set to OFF, no hotpixel map will be returned.</p>
* <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p>
*
* @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -2483,7 +2541,7 @@
* <p>Whether the camera device will output the lens
* shading map in output result metadata.</p>
* <p>When set to ON,
- * android.statistics.lensShadingMap must be provided in
+ * android.statistics.lensShadingMap will be provided in
* the output result metadata.</p>
* @see #STATISTICS_LENS_SHADING_MAP_MODE_OFF
* @see #STATISTICS_LENS_SHADING_MAP_MODE_ON
diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
index dd862b5..a6fc10f 100644
--- a/core/java/android/hardware/camera2/params/StreamConfiguration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -30,7 +30,8 @@
* Immutable class to store the available stream
* {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_CONFIGURATIONS configurations} to set up
* {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session}
- * with {@link CameraDevice#createCaptureSession}. <!-- TODO: link to input stream configuration -->
+ * with {@link CameraDevice#createCaptureSession}.
+ * <!-- TODO: link to input stream configuration -->
*
* <p>This is the authoritative list for all input/output formats (and sizes respectively
* for that format) that are supported by a camera device.</p>
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.aidl b/core/java/android/hardware/hdmi/HdmiPortInfo.aidl
new file mode 100644
index 0000000..157b5b3
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+parcelable HdmiPortInfo;
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
new file mode 100644
index 0000000..7b25f8a
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.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 android.hardware.hdmi;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A class to encapsulate HDMI port information. Contains the capability of the ports such as
+ * HDMI-CEC, MHL, ARC(Audio Return Channel), and physical address assigned to each port.
+ *
+ * @hide
+ */
+@SystemApi
+public final class HdmiPortInfo implements Parcelable {
+ /** HDMI port type: Input */
+ public static final int PORT_INPUT = 0;
+
+ /** HDMI port type: Output */
+ public static final int PORT_OUTPUT = 1;
+
+ private final int mId;
+ private final int mType;
+ private final int mAddress;
+ private final boolean mCecSupported;
+ private final boolean mArcSupported;
+ private final boolean mMhlSupported;
+
+ /**
+ * Constructor.
+ *
+ * @param id identifier assigned to each port. 1 for HDMI port 1
+ * @param type HDMI port input/output type
+ * @param address physical address of the port
+ * @param cec {@code true} if HDMI-CEC is supported on the port
+ * @param mhl {@code true} if MHL is supported on the port
+ * @param arc {@code true} if audio return channel is supported on the port
+ */
+ public HdmiPortInfo(int id, int type, int address, boolean cec, boolean mhl, boolean arc) {
+ mId = id;
+ mType = type;
+ mAddress = address;
+ mCecSupported = cec;
+ mArcSupported = arc;
+ mMhlSupported = mhl;
+ }
+
+ /**
+ * Returns the port id.
+ *
+ * @return port id
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the port type.
+ *
+ * @return port type
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * Returns the port address.
+ *
+ * @return port address
+ */
+ public int getAddress() {
+ return mAddress;
+ }
+
+ /**
+ * Returns {@code true} if the port supports HDMI-CEC signaling.
+ *
+ * @return {@code true} if the port supports HDMI-CEC signaling.
+ */
+ public boolean isCecSupported() {
+ return mCecSupported;
+ }
+
+ /**
+ * Returns {@code true} if the port supports MHL signaling.
+ *
+ * @return {@code true} if the port supports MHL signaling.
+ */
+ public boolean isMhlSupported() {
+ return mMhlSupported;
+ }
+
+ /**
+ * Returns {@code true} if the port supports audio return channel.
+ *
+ * @return {@code true} if the port supports audio return channel
+ */
+ public boolean isArcSupported() {
+ return mArcSupported;
+ }
+
+ /**
+ * Describe the kinds of special objects contained in this Parcelable's
+ * marshalled representation.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+
+ /**
+ * A helper class to deserialize {@link HdmiPortInfo} for a parcel.
+ */
+ public static final Parcelable.Creator<HdmiPortInfo> CREATOR =
+ new Parcelable.Creator<HdmiPortInfo>() {
+ @Override
+ public HdmiPortInfo createFromParcel(Parcel source) {
+ int id = source.readInt();
+ int type = source.readInt();
+ int address = source.readInt();
+ boolean cec = (source.readInt() == 1);
+ boolean arc = (source.readInt() == 1);
+ boolean mhl = (source.readInt() == 1);
+ return new HdmiPortInfo(id, type, address, cec, arc, mhl);
+ }
+
+ @Override
+ public HdmiPortInfo[] newArray(int size) {
+ return new HdmiPortInfo[size];
+ }
+ };
+
+ /**
+ * Serialize this object into a {@link Parcel}.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mId);
+ dest.writeInt(mType);
+ dest.writeInt(mAddress);
+ dest.writeInt(mCecSupported ? 1 : 0);
+ dest.writeInt(mArcSupported ? 1 : 0);
+ dest.writeInt(mMhlSupported ? 1 : 0);
+ }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 6dc4a4f..85af3d1 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -16,6 +16,8 @@
package android.hardware.hdmi;
import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.util.Log;
/**
* HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system
@@ -33,4 +35,46 @@
HdmiTvClient(IHdmiControlService service) {
mService = service;
}
+
+ // Factory method for HdmiTvClient.
+ // Declared package-private. Accessed by HdmiControlManager only.
+ static HdmiTvClient create(IHdmiControlService service) {
+ return new HdmiTvClient(service);
+ }
+
+ /**
+ * Callback interface used to get the result of {@link #deviceSelect}.
+ */
+ public interface SelectCallback {
+ /**
+ * Called when the operation is finished.
+ *
+ * @param result the result value of {@link #deviceSelect}
+ */
+ void onComplete(int result);
+ }
+
+ /**
+ * Select a CEC logical device to be a new active source.
+ *
+ * @param logicalAddress
+ * @param callback
+ */
+ public void deviceSelect(int logicalAddress, SelectCallback callback) {
+ // TODO: Replace SelectCallback with PartialResult.
+ try {
+ mService.deviceSelect(logicalAddress, getCallbackWrapper(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to select device: ", e);
+ }
+ }
+
+ private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
+ return new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ callback.onComplete(result);
+ }
+ };
+ }
}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 8da38e1..8d7c638 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -33,4 +33,5 @@
void queryDisplayStatus(IHdmiControlCallback callback);
void addHotplugEventListener(IHdmiHotplugEventListener listener);
void removeHotplugEventListener(IHdmiHotplugEventListener listener);
+ void deviceSelect(int logicalAddress, IHdmiControlCallback callback);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 27402668..ba31243 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -429,6 +429,11 @@
*/
public final static int INVALID_NET_ID = 0;
+ /**
+ * @hide
+ */
+ public final static int REQUEST_ID_UNSET = 0;
+
private final IConnectivityManager mService;
private final String mPackageName;
@@ -863,10 +868,10 @@
return -1;
}
- NetworkRequest request = removeRequestForFeature(netCap);
- if (request != null) {
+ NetworkCallback networkCallback = removeRequestForFeature(netCap);
+ if (networkCallback != null) {
Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature);
- releaseNetworkRequest(request);
+ unregisterNetworkCallback(networkCallback);
}
return 1;
}
@@ -883,8 +888,8 @@
* @hide
*/
public static void maybeMarkCapabilitiesRestricted(NetworkCapabilities nc) {
- for (Integer capability : nc.getNetworkCapabilities()) {
- switch (capability.intValue()) {
+ for (int capability : nc.getCapabilities()) {
+ switch (capability) {
case NetworkCapabilities.NET_CAPABILITY_CBS:
case NetworkCapabilities.NET_CAPABILITY_DUN:
case NetworkCapabilities.NET_CAPABILITY_EIMS:
@@ -903,7 +908,7 @@
}
// All the capabilities are typically provided by restricted networks.
// Conclude that this network is restricted.
- nc.removeNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
@@ -927,15 +932,14 @@
return null;
}
NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- netCap.addNetworkCapability(cap);
+ netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap);
maybeMarkCapabilitiesRestricted(netCap);
return netCap;
} else if (networkType == TYPE_WIFI) {
if ("p2p".equals(feature)) {
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
+ netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
maybeMarkCapabilitiesRestricted(netCap);
return netCap;
}
@@ -978,15 +982,15 @@
int expireSequenceNumber;
Network currentNetwork;
int delay = -1;
- NetworkCallbackListener networkCallbackListener = new NetworkCallbackListener() {
+ NetworkCallback networkCallback = new NetworkCallback() {
@Override
- public void onAvailable(NetworkRequest request, Network network) {
+ public void onAvailable(Network network) {
currentNetwork = network;
Log.d(TAG, "startUsingNetworkFeature got Network:" + network);
setProcessDefaultNetworkForHostResolution(network);
}
@Override
- public void onLost(NetworkRequest request, Network network) {
+ public void onLost(Network network) {
if (network.equals(currentNetwork)) {
currentNetwork = null;
setProcessDefaultNetworkForHostResolution(null);
@@ -1020,7 +1024,7 @@
if (l == null) return;
ourSeqNum = l.expireSequenceNumber;
if (l.expireSequenceNumber == sequenceNum) {
- releaseNetworkRequest(l.networkRequest);
+ unregisterNetworkCallback(l.networkCallback);
sLegacyRequests.remove(netCap);
}
}
@@ -1037,7 +1041,7 @@
l.networkCapabilities = netCap;
l.delay = delay;
l.expireSequenceNumber = 0;
- l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0,
+ l.networkRequest = sendRequestForNetwork(netCap, l.networkCallback, 0,
REQUEST, type);
if (l.networkRequest == null) return null;
sLegacyRequests.put(netCap, l);
@@ -1053,11 +1057,11 @@
}
}
- private NetworkRequest removeRequestForFeature(NetworkCapabilities netCap) {
+ private NetworkCallback removeRequestForFeature(NetworkCapabilities netCap) {
synchronized (sLegacyRequests) {
LegacyRequest l = sLegacyRequests.remove(netCap);
if (l == null) return null;
- return l.networkRequest;
+ return l.networkCallback;
}
}
@@ -1180,8 +1184,8 @@
}
/**
- * Callback for use with {@link ConnectivityManager#registerNetworkActiveListener} to
- * find out when the current network has gone in to a high power state.
+ * Callback for use with {@link ConnectivityManager#registerDefaultNetworkActiveListener}
+ * to find out when the system default network has gone in to a high power state.
*/
public interface OnNetworkActiveListener {
/**
@@ -1190,7 +1194,7 @@
* operations. Note that this listener only tells you when the network becomes
* active; if at any other time you want to know whether it is active (and thus okay
* to initiate network traffic), you can retrieve its instantaneous state with
- * {@link ConnectivityManager#isNetworkActive}.
+ * {@link ConnectivityManager#isDefaultNetworkActive}.
*/
public void onNetworkActive();
}
@@ -1211,13 +1215,18 @@
= new ArrayMap<OnNetworkActiveListener, INetworkActivityListener>();
/**
- * Start listening to reports when the data network is active, meaning it is
- * a good time to perform network traffic. Use {@link #isNetworkActive()}
- * to determine the current state of the network after registering the listener.
+ * Start listening to reports when the system's default data network is active, meaning it is
+ * a good time to perform network traffic. Use {@link #isDefaultNetworkActive()}
+ * to determine the current state of the system's default network after registering the
+ * listener.
+ * <p>
+ * If the process default network has been set with
+ * {@link ConnectivityManager#setProcessDefaultNetwork} this function will not
+ * reflect the process's default, but the system default.
*
* @param l The listener to be told when the network is active.
*/
- public void registerNetworkActiveListener(final OnNetworkActiveListener l) {
+ public void registerDefaultNetworkActiveListener(final OnNetworkActiveListener l) {
INetworkActivityListener rl = new INetworkActivityListener.Stub() {
@Override
public void onNetworkActive() throws RemoteException {
@@ -1234,11 +1243,11 @@
/**
* Remove network active listener previously registered with
- * {@link #registerNetworkActiveListener}.
+ * {@link #registerDefaultNetworkActiveListener}.
*
* @param l Previously registered listener.
*/
- public void unregisterNetworkActiveListener(OnNetworkActiveListener l) {
+ public void unregisterDefaultNetworkActiveListener(OnNetworkActiveListener l) {
INetworkActivityListener rl = mNetworkActivityListeners.get(l);
if (rl == null) {
throw new IllegalArgumentException("Listener not registered: " + l);
@@ -1257,7 +1266,7 @@
* this state. This method tells you whether right now is currently a good time to
* initiate network traffic, as the network is already active.
*/
- public boolean isNetworkActive() {
+ public boolean isDefaultNetworkActive() {
try {
return getNetworkManagementService().isNetworkActive();
} catch (RemoteException e) {
@@ -1889,7 +1898,7 @@
* Base class for NetworkRequest callbacks. Used for notifications about network
* changes. Should be extended by applications wanting notifications.
*/
- public static class NetworkCallbackListener {
+ public static class NetworkCallback {
/** @hide */
public static final int PRECHECK = 1;
/** @hide */
@@ -1912,78 +1921,68 @@
* Called whenever the framework connects to a network that it may use to
* satisfy this request
*/
- public void onPreCheck(NetworkRequest networkRequest, Network network) {}
+ public void onPreCheck(Network network) {}
/**
* Called when the framework connects and has declared new network ready for use.
+ * This callback may be called more than once if the {@link Network} that is
+ * satisfying the request changes.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
* @param network The {@link Network} of the satisfying network.
*/
- public void onAvailable(NetworkRequest networkRequest, Network network) {}
+ public void onAvailable(Network network) {}
/**
* Called when the network is about to be disconnected. Often paired with an
- * {@link NetworkCallbackListener#onAvailable} call with the new replacement network
+ * {@link NetworkCallback#onAvailable} call with the new replacement network
* for graceful handover. This may not be called if we have a hard loss
* (loss without warning). This may be followed by either a
- * {@link NetworkCallbackListener#onLost} call or a
- * {@link NetworkCallbackListener#onAvailable} call for this network depending
+ * {@link NetworkCallback#onLost} call or a
+ * {@link NetworkCallback#onAvailable} call for this network depending
* on whether we lose or regain it.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
- * @param network The {@link Network} of the failing network.
- * @param maxSecToLive The time in seconds the framework will attempt to keep the
- * network connected. Note that the network may suffers a
+ * @param network The {@link Network} that is about to be disconnected.
+ * @param maxMsToLive The time in ms the framework will attempt to keep the
+ * network connected. Note that the network may suffer a
* hard loss at any time.
*/
- public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {}
+ public void onLosing(Network network, int maxMsToLive) {}
/**
* Called when the framework has a hard loss of the network or when the
* graceful failure ends.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
* @param network The {@link Network} lost.
*/
- public void onLost(NetworkRequest networkRequest, Network network) {}
+ public void onLost(Network network) {}
/**
* Called if no network is found in the given timeout time. If no timeout is given,
* this will not be called.
* @hide
*/
- public void onUnavailable(NetworkRequest networkRequest) {}
+ public void onUnavailable() {}
/**
* Called when the network the framework connected to for this request
* changes capabilities but still satisfies the stated need.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
* @param network The {@link Network} whose capabilities have changed.
* @param networkCapabilities The new {@link NetworkCapabilities} for this network.
*/
- public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network,
+ public void onCapabilitiesChanged(Network network,
NetworkCapabilities networkCapabilities) {}
/**
* Called when the network the framework connected to for this request
* changes {@link LinkProperties}.
*
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
* @param network The {@link Network} whose link properties have changed.
* @param linkProperties The new {@link LinkProperties} for this network.
*/
- public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network,
- LinkProperties linkProperties) {}
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {}
- /**
- * Called when a {@link #releaseNetworkRequest} call concludes and the registered
- * callbacks will no longer be used.
- *
- * @param networkRequest The {@link NetworkRequest} used to initiate the request.
- */
- public void onReleased(NetworkRequest networkRequest) {}
+ private NetworkRequest networkRequest;
}
private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER;
@@ -2009,12 +2008,12 @@
private static final int EXPIRE_LEGACY_REQUEST = BASE + 10;
private class CallbackHandler extends Handler {
- private final HashMap<NetworkRequest, NetworkCallbackListener>mCallbackMap;
+ private final HashMap<NetworkRequest, NetworkCallback>mCallbackMap;
private final AtomicInteger mRefCount;
private static final String TAG = "ConnectivityManager.CallbackHandler";
private final ConnectivityManager mCm;
- CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallbackListener>callbackMap,
+ CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallback>callbackMap,
AtomicInteger refCount, ConnectivityManager cm) {
super(looper);
mCallbackMap = callbackMap;
@@ -2028,9 +2027,9 @@
switch (message.what) {
case CALLBACK_PRECHECK: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
- callbacks.onPreCheck(request, getNetwork(message));
+ callbacks.onPreCheck(getNetwork(message));
} else {
Log.e(TAG, "callback not found for PRECHECK message");
}
@@ -2038,9 +2037,9 @@
}
case CALLBACK_AVAILABLE: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
- callbacks.onAvailable(request, getNetwork(message));
+ callbacks.onAvailable(getNetwork(message));
} else {
Log.e(TAG, "callback not found for AVAILABLE message");
}
@@ -2048,9 +2047,9 @@
}
case CALLBACK_LOSING: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
- callbacks.onLosing(request, getNetwork(message), message.arg1);
+ callbacks.onLosing(getNetwork(message), message.arg1);
} else {
Log.e(TAG, "callback not found for LOSING message");
}
@@ -2058,9 +2057,9 @@
}
case CALLBACK_LOST: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
- callbacks.onLost(request, getNetwork(message));
+ callbacks.onLost(getNetwork(message));
} else {
Log.e(TAG, "callback not found for LOST message");
}
@@ -2068,12 +2067,12 @@
}
case CALLBACK_UNAVAIL: {
NetworkRequest req = (NetworkRequest)message.obj;
- NetworkCallbackListener callbacks = null;
+ NetworkCallback callbacks = null;
synchronized(mCallbackMap) {
callbacks = mCallbackMap.get(req);
}
if (callbacks != null) {
- callbacks.onUnavailable(req);
+ callbacks.onUnavailable();
} else {
Log.e(TAG, "callback not found for UNAVAIL message");
}
@@ -2081,12 +2080,12 @@
}
case CALLBACK_CAP_CHANGED: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
Network network = getNetwork(message);
NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
- callbacks.onNetworkCapabilitiesChanged(request, network, cap);
+ callbacks.onCapabilitiesChanged(network, cap);
} else {
Log.e(TAG, "callback not found for CHANGED message");
}
@@ -2094,12 +2093,12 @@
}
case CALLBACK_IP_CHANGED: {
NetworkRequest request = getNetworkRequest(message);
- NetworkCallbackListener callbacks = getCallbacks(request);
+ NetworkCallback callbacks = getCallbacks(request);
if (callbacks != null) {
Network network = getNetwork(message);
LinkProperties lp = mCm.getLinkProperties(network);
- callbacks.onLinkPropertiesChanged(request, network, lp);
+ callbacks.onLinkPropertiesChanged(network, lp);
} else {
Log.e(TAG, "callback not found for CHANGED message");
}
@@ -2107,20 +2106,19 @@
}
case CALLBACK_RELEASED: {
NetworkRequest req = (NetworkRequest)message.obj;
- NetworkCallbackListener callbacks = null;
+ NetworkCallback callbacks = null;
synchronized(mCallbackMap) {
callbacks = mCallbackMap.remove(req);
}
if (callbacks != null) {
- callbacks.onReleased(req);
+ synchronized(mRefCount) {
+ if (mRefCount.decrementAndGet() == 0) {
+ getLooper().quit();
+ }
+ }
} else {
Log.e(TAG, "callback not found for CANCELED message");
}
- synchronized(mRefCount) {
- if (mRefCount.decrementAndGet() == 0) {
- getLooper().quit();
- }
- }
break;
}
case CALLBACK_EXIT: {
@@ -2138,7 +2136,7 @@
private NetworkRequest getNetworkRequest(Message msg) {
return (NetworkRequest)(msg.obj);
}
- private NetworkCallbackListener getCallbacks(NetworkRequest req) {
+ private NetworkCallback getCallbacks(NetworkRequest req) {
synchronized(mCallbackMap) {
return mCallbackMap.get(req);
}
@@ -2146,7 +2144,7 @@
private Network getNetwork(Message msg) {
return new Network(msg.arg2);
}
- private NetworkCallbackListener removeCallbacks(Message msg) {
+ private NetworkCallback removeCallbacks(Message msg) {
NetworkRequest req = (NetworkRequest)msg.obj;
synchronized(mCallbackMap) {
return mCallbackMap.remove(req);
@@ -2154,19 +2152,19 @@
}
}
- private void addCallbackListener() {
+ private void incCallbackHandlerRefCount() {
synchronized(sCallbackRefCount) {
if (sCallbackRefCount.incrementAndGet() == 1) {
// TODO - switch this over to a ManagerThread or expire it when done
HandlerThread callbackThread = new HandlerThread("ConnectivityManager");
callbackThread.start();
sCallbackHandler = new CallbackHandler(callbackThread.getLooper(),
- sNetworkCallbackListener, sCallbackRefCount, this);
+ sNetworkCallback, sCallbackRefCount, this);
}
}
}
- private void removeCallbackListener() {
+ private void decCallbackHandlerRefCount() {
synchronized(sCallbackRefCount) {
if (sCallbackRefCount.decrementAndGet() == 0) {
sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget();
@@ -2175,8 +2173,8 @@
}
}
- static final HashMap<NetworkRequest, NetworkCallbackListener> sNetworkCallbackListener =
- new HashMap<NetworkRequest, NetworkCallbackListener>();
+ static final HashMap<NetworkRequest, NetworkCallback> sNetworkCallback =
+ new HashMap<NetworkRequest, NetworkCallback>();
static final AtomicInteger sCallbackRefCount = new AtomicInteger(0);
static CallbackHandler sCallbackHandler = null;
@@ -2184,51 +2182,48 @@
private final static int REQUEST = 2;
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener, int timeoutSec, int action,
+ NetworkCallback networkCallback, int timeoutSec, int action,
int legacyType) {
- NetworkRequest networkRequest = null;
- if (networkCallbackListener == null) {
- throw new IllegalArgumentException("null NetworkCallbackListener");
+ if (networkCallback == null) {
+ throw new IllegalArgumentException("null NetworkCallback");
}
if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
try {
- addCallbackListener();
+ incCallbackHandlerRefCount();
if (action == LISTEN) {
- networkRequest = mService.listenForNetwork(need, new Messenger(sCallbackHandler),
- new Binder());
+ networkCallback.networkRequest = mService.listenForNetwork(need,
+ new Messenger(sCallbackHandler), new Binder());
} else {
- networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler),
- timeoutSec, new Binder(), legacyType);
+ networkCallback.networkRequest = mService.requestNetwork(need,
+ new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
}
- if (networkRequest != null) {
- synchronized(sNetworkCallbackListener) {
- sNetworkCallbackListener.put(networkRequest, networkCallbackListener);
+ if (networkCallback.networkRequest != null) {
+ synchronized(sNetworkCallback) {
+ sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
}
}
} catch (RemoteException e) {}
- if (networkRequest == null) removeCallbackListener();
- return networkRequest;
+ if (networkCallback.networkRequest == null) decCallbackHandlerRefCount();
+ return networkCallback.networkRequest;
}
/**
* Request a network to satisfy a set of {@link NetworkCapabilities}.
*
* This {@link NetworkRequest} will live until released via
- * {@link #releaseNetworkRequest} or the calling application exits.
+ * {@link #unregisterNetworkCallback} or the calling application exits.
* Status of the request can be followed by listening to the various
- * callbacks described in {@link NetworkCallbackListener}. The {@link Network}
+ * callbacks described in {@link NetworkCallback}. The {@link Network}
* can be used to direct traffic to the network.
*
- * @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbackListener The {@link NetworkCallbackListener} to be utilized for this
- * request. Note the callbacks can be shared by multiple
- * requests and the NetworkRequest token utilized to
- * determine to which request the callback relates.
- * @return A {@link NetworkRequest} object identifying the request.
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this
+ * request. Note the callback must not be shared - they
+ * uniquely specify this request.
*/
- public NetworkRequest requestNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener) {
- return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, TYPE_NONE);
+ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
+ sendRequestForNetwork(request.networkCapabilities, networkCallback, 0,
+ REQUEST, TYPE_NONE);
}
/**
@@ -2236,53 +2231,53 @@
* by a timeout.
*
* This function behaves identically to the non-timedout version, but if a suitable
- * network is not found within the given time (in Seconds) the
- * {@link NetworkCallbackListener#unavailable} callback is called. The request must
+ * network is not found within the given time (in milliseconds) the
+ * {@link NetworkCallback#unavailable} callback is called. The request must
* still be released normally by calling {@link releaseNetworkRequest}.
- * @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbackListener The callbacks to be utilized for this request. Note
- * the callbacks can be shared by multiple requests and
- * the NetworkRequest token utilized to determine to which
- * request the callback relates.
- * @param timeoutSec The time in seconds to attempt looking for a suitable network
- * before {@link NetworkCallbackListener#unavailable} is called.
- * @return A {@link NetworkRequest} object identifying the request.
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The callbacks to be utilized for this request. Note
+ * the callbacks must not be shared - they uniquely specify
+ * this request.
+ * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+ * before {@link NetworkCallback#unavailable} is called.
* @hide
*/
- public NetworkRequest requestNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener, int timeoutSec) {
- return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST,
- TYPE_NONE);
+ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+ int timeoutMs) {
+ sendRequestForNetwork(request.networkCapabilities, networkCallback, timeoutMs,
+ REQUEST, TYPE_NONE);
}
/**
- * The maximum number of seconds the framework will look for a suitable network
+ * The maximum number of milliseconds the framework will look for a suitable network
* during a timeout-equiped call to {@link requestNetwork}.
* {@hide}
*/
- public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60;
+ public final static int MAX_NETWORK_REQUEST_TIMEOUT_MS = 100 * 60 * 1000;
/**
* The lookup key for a {@link Network} object included with the intent after
* succesfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ * @hide
*/
public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
/**
- * The lookup key for a {@link NetworkCapabilities} object included with the intent after
+ * The lookup key for a {@link NetworkRequest} object included with the intent after
* succesfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ * @hide
*/
- public static final String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES =
- "networkRequestNetworkCapabilities";
+ public static final String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST =
+ "networkRequestNetworkRequest";
/**
* Request a network to satisfy a set of {@link NetworkCapabilities}.
*
- * This function behavies identically to the callback-equiped version, but instead
- * of {@link NetworkCallbackListener} a {@link PendingIntent} is used. This means
+ * This function behavies identically to the version that takes a NetworkCallback, but instead
+ * of {@link NetworkCallback} a {@link PendingIntent} is used. This means
* the request may outlive the calling application and get called back when a suitable
* network is found.
* <p>
@@ -2291,10 +2286,10 @@
* <receiver> tag in an AndroidManifest.xml file
* <p>
* The operation Intent is delivered with two extras, a {@link Network} typed
- * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities}
- * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES} containing
+ * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkRequest}
+ * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_REQUEST} containing
* the original requests parameters. It is important to create a new,
- * {@link NetworkCallbackListener} based request before completing the processing of the
+ * {@link NetworkCallback} based request before completing the processing of the
* Intent to reserve the network or it will be released shortly after the Intent
* is processed.
* <p>
@@ -2302,51 +2297,49 @@
* two Intents defined by {@link Intent#filterEquals}), then it will be removed and
* replaced by this one, effectively releasing the previous {@link NetworkRequest}.
* <p>
- * The request may be released normally by calling {@link #releaseNetworkRequest}.
+ * The request may be released normally by calling {@link #unregisterNetworkCallback}.
*
- * @param need {@link NetworkCapabilities} required by this request.
+ * @param request {@link NetworkRequest} describing this request.
* @param operation Action to perform when the network is available (corresponds
- * to the {@link NetworkCallbackListener#onAvailable} call. Typically
+ * to the {@link NetworkCallback#onAvailable} call. Typically
* comes from {@link PendingIntent#getBroadcast}.
- * @return A {@link NetworkRequest} object identifying the request.
+ * @hide
*/
- public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) {
+ public void requestNetwork(NetworkRequest request, PendingIntent operation) {
try {
- return mService.pendingRequestForNetwork(need, operation);
+ mService.pendingRequestForNetwork(request.networkCapabilities, operation);
} catch (RemoteException e) {}
- return null;
}
/**
* Registers to receive notifications about all networks which satisfy the given
- * {@link NetworkCapabilities}. The callbacks will continue to be called until
- * either the application exits or the request is released using
- * {@link #releaseNetworkRequest}.
+ * {@link NetworkRequest}. The callbacks will continue to be called until
+ * either the application exits or {@link #unregisterNetworkCallback} is called
*
- * @param need {@link NetworkCapabilities} required by this request.
- * @param networkCallbackListener The {@link NetworkCallbackListener} to be called as suitable
- * networks change state.
- * @return A {@link NetworkRequest} object identifying the request.
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
+ * networks change state.
*/
- public NetworkRequest listenForNetwork(NetworkCapabilities need,
- NetworkCallbackListener networkCallbackListener) {
- return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, TYPE_NONE);
+ public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {
+ sendRequestForNetwork(request.networkCapabilities, networkCallback, 0, LISTEN, TYPE_NONE);
}
/**
- * Releases a {@link NetworkRequest} generated either through a {@link #requestNetwork}
- * or a {@link #listenForNetwork} call. The {@link NetworkCallbackListener} given in the
- * earlier call may continue receiving calls until the
- * {@link NetworkCallbackListener#onReleased} function is called, signifying the end
- * of the request.
+ * Unregisters callbacks about and possibly releases networks originating from
+ * {@link #requestNetwork} and {@link #registerNetworkCallback} calls. If the
+ * given {@code NetworkCallback} had previosuly been used with {@code #requestNetwork},
+ * any networks that had been connected to only to satisfy that request will be
+ * disconnected.
*
- * @param networkRequest The {@link NetworkRequest} generated by an earlier call to
- * {@link #requestNetwork} or {@link #listenForNetwork}.
+ * @param networkCallback The {@link NetworkCallback} used when making the request.
*/
- public void releaseNetworkRequest(NetworkRequest networkRequest) {
- if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest");
+ public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+ if (networkCallback == null || networkCallback.networkRequest == null ||
+ networkCallback.networkRequest.requestId == REQUEST_ID_UNSET) {
+ throw new IllegalArgumentException("Invalid NetworkCallback");
+ }
try {
- mService.releaseNetworkRequest(networkRequest);
+ mService.releaseNetworkRequest(networkCallback.networkRequest);
} catch (RemoteException e) {}
}
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index dfe0384..a14d13f 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -42,7 +42,7 @@
*
* Objects of this class are immutable.
*/
-public class IpPrefix implements Parcelable {
+public final class IpPrefix implements Parcelable {
private final byte[] address; // network byte order
private final int prefixLength;
@@ -139,7 +139,6 @@
/**
* Implement the Parcelable interface.
- * @hide
*/
public int describeContents() {
return 0;
@@ -147,7 +146,6 @@
/**
* Implement the Parcelable interface.
- * @hide
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeByteArray(address);
@@ -156,7 +154,6 @@
/**
* Implement the Parcelable interface.
- * @hide
*/
public static final Creator<IpPrefix> CREATOR =
new Creator<IpPrefix>() {
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index bb05936..8eefa0f 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -44,7 +44,7 @@
* does not affect live networks.
*
*/
-public class LinkProperties implements Parcelable {
+public final class LinkProperties implements Parcelable {
// The interface described by the network link.
private String mIfaceName;
private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
@@ -463,7 +463,6 @@
/**
* Implement the Parcelable interface
- * @hide
*/
public int describeContents() {
return 0;
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index d933f26..318aabe 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -29,8 +29,9 @@
/**
* Identifies a {@code Network}. This is supplied to applications via
- * {@link ConnectivityManager.NetworkCallbackListener} in response to
- * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}.
+ * {@link ConnectivityManager.NetworkCallback} in response to the active
+ * {@link ConnectivityManager#requestNetwork} or passive
+ * {@link ConnectivityManager#registerNetworkCallback} calls.
* It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
* through a targeted {@link SocketFactory} or process-wide via
* {@link ConnectivityManager#setProcessDefaultNetwork}.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 35274f1..fe96287 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -44,6 +44,9 @@
private static final String TAG = "NetworkCapabilities";
private static final boolean DBG = false;
+ /**
+ * @hide
+ */
public NetworkCapabilities() {
}
@@ -154,58 +157,64 @@
* Multiple capabilities may be applied sequentially. Note that when searching
* for a network to satisfy a request, all capabilities requested must be satisfied.
*
- * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+ * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+ * @return This NetworkCapability to facilitate chaining.
+ * @hide
*/
- public void addNetworkCapability(int networkCapability) {
- if (networkCapability < MIN_NET_CAPABILITY ||
- networkCapability > MAX_NET_CAPABILITY) {
+ public NetworkCapabilities addCapability(int capability) {
+ if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
throw new IllegalArgumentException("NetworkCapability out of range");
}
- mNetworkCapabilities |= 1 << networkCapability;
+ mNetworkCapabilities |= 1 << capability;
+ return this;
}
/**
* Removes (if found) the given capability from this {@code NetworkCapability} instance.
*
- * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+ * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+ * @return This NetworkCapability to facilitate chaining.
+ * @hide
*/
- public void removeNetworkCapability(int networkCapability) {
- if (networkCapability < MIN_NET_CAPABILITY ||
- networkCapability > MAX_NET_CAPABILITY) {
+ public NetworkCapabilities removeCapability(int capability) {
+ if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
throw new IllegalArgumentException("NetworkCapability out of range");
}
- mNetworkCapabilities &= ~(1 << networkCapability);
+ mNetworkCapabilities &= ~(1 << capability);
+ return this;
}
/**
* Gets all the capabilities set on this {@code NetworkCapability} instance.
*
- * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values
+ * @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values
* for this instance.
+ * @hide
*/
- public Collection<Integer> getNetworkCapabilities() {
+ public int[] getCapabilities() {
return enumerateBits(mNetworkCapabilities);
}
/**
* Tests for the presence of a capabilitity on this instance.
*
- * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
+ * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
* @return {@code true} if set on this instance.
*/
- public boolean hasCapability(int networkCapability) {
- if (networkCapability < MIN_NET_CAPABILITY ||
- networkCapability > MAX_NET_CAPABILITY) {
+ public boolean hasCapability(int capability) {
+ if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
return false;
}
- return ((mNetworkCapabilities & (1 << networkCapability)) != 0);
+ return ((mNetworkCapabilities & (1 << capability)) != 0);
}
- private Collection<Integer> enumerateBits(long val) {
- ArrayList<Integer> result = new ArrayList<Integer>();
+ private int[] enumerateBits(long val) {
+ int size = Long.bitCount(val);
+ int[] result = new int[size];
+ int index = 0;
int resource = 0;
while (val > 0) {
- if ((val & 1) == 1) result.add(resource);
+ if ((val & 1) == 1) result[index++] = resource;
val = val >> 1;
resource++;
}
@@ -265,33 +274,40 @@
* {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
*
* @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added.
+ * @return This NetworkCapability to facilitate chaining.
+ * @hide
*/
- public void addTransportType(int transportType) {
+ public NetworkCapabilities addTransportType(int transportType) {
if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
throw new IllegalArgumentException("TransportType out of range");
}
mTransportTypes |= 1 << transportType;
+ return this;
}
/**
* Removes (if found) the given transport from this {@code NetworkCapability} instance.
*
* @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed.
+ * @return This NetworkCapability to facilitate chaining.
+ * @hide
*/
- public void removeTransportType(int transportType) {
+ public NetworkCapabilities removeTransportType(int transportType) {
if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
throw new IllegalArgumentException("TransportType out of range");
}
mTransportTypes &= ~(1 << transportType);
+ return this;
}
/**
* Gets all the transports set on this {@code NetworkCapability} instance.
*
- * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values
+ * @return an array of {@code NetworkCapabilities.TRANSPORT_*} values
* for this instance.
+ * @hide
*/
- public Collection<Integer> getTransportTypes() {
+ public int[] getTransportTypes() {
return enumerateBits(mTransportTypes);
}
@@ -340,6 +356,7 @@
* fast backhauls and slow backhauls.
*
* @param upKbps the estimated first hop upstream (device to network) bandwidth.
+ * @hide
*/
public void setLinkUpstreamBandwidthKbps(int upKbps) {
mLinkUpBandwidthKbps = upKbps;
@@ -368,6 +385,7 @@
* fast backhauls and slow backhauls.
*
* @param downKbps the estimated first hop downstream (network to device) bandwidth.
+ * @hide
*/
public void setLinkDownstreamBandwidthKbps(int downKbps) {
mLinkDownBandwidthKbps = downKbps;
@@ -464,24 +482,22 @@
};
public String toString() {
- Collection<Integer> types = getTransportTypes();
- String transports = (types.size() > 0 ? " Transports: " : "");
- Iterator<Integer> i = types.iterator();
- while (i.hasNext()) {
- switch (i.next()) {
+ int[] types = getTransportTypes();
+ String transports = (types.length > 0 ? " Transports: " : "");
+ for (int i = 0; i < types.length;) {
+ switch (types[i]) {
case TRANSPORT_CELLULAR: transports += "CELLULAR"; break;
case TRANSPORT_WIFI: transports += "WIFI"; break;
case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break;
case TRANSPORT_ETHERNET: transports += "ETHERNET"; break;
}
- if (i.hasNext()) transports += "|";
+ if (++i < types.length) transports += "|";
}
- types = getNetworkCapabilities();
- String capabilities = (types.size() > 0 ? " Capabilities: " : "");
- i = types.iterator();
- while (i.hasNext()) {
- switch (i.next().intValue()) {
+ types = getCapabilities();
+ String capabilities = (types.length > 0 ? " Capabilities: " : "");
+ for (int i = 0; i < types.length; ) {
+ switch (types[i]) {
case NET_CAPABILITY_MMS: capabilities += "MMS"; break;
case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break;
case NET_CAPABILITY_DUN: capabilities += "DUN"; break;
@@ -497,7 +513,7 @@
case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break;
case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break;
}
- if (i.hasNext()) capabilities += "&";
+ if (++i < types.length) capabilities += "&";
}
String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" +
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 47377e9..36dc573 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -22,19 +22,14 @@
import java.util.concurrent.atomic.AtomicInteger;
/**
- * Defines a request for a network, made by calling {@link ConnectivityManager#requestNetwork}
- * or {@link ConnectivityManager#listenForNetwork}.
- *
- * This token records the {@link NetworkCapabilities} used to make the request and identifies
- * the request. It should be used to release the request via
- * {@link ConnectivityManager#releaseNetworkRequest} when the network is no longer desired.
+ * Defines a request for a network, made through {@link NetworkRequest.Builder} and used
+ * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes
+ * via {@link ConnectivityManager#registerNetworkCallback}.
*/
public class NetworkRequest implements Parcelable {
/**
- * The {@link NetworkCapabilities} that define this request. This should not be modified.
- * The networkCapabilities of the request are set when
- * {@link ConnectivityManager#requestNetwork} is called and the value is presented here
- * as a convenient reminder of what was requested.
+ * The {@link NetworkCapabilities} that define this request.
+ * @hide
*/
public final NetworkCapabilities networkCapabilities;
@@ -71,6 +66,95 @@
this.legacyType = that.legacyType;
}
+ /**
+ * Builder used to create {@link NetworkRequest} objects. Specify the Network features
+ * needed in terms of {@link NetworkCapabilities} features
+ */
+ public static class Builder {
+ private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities();
+
+ /**
+ * Default constructor for Builder.
+ */
+ public Builder() {}
+
+ /**
+ * Build {@link NetworkRequest} give the current set of capabilities.
+ */
+ public NetworkRequest build() {
+ return new NetworkRequest(mNetworkCapabilities, ConnectivityManager.TYPE_NONE,
+ ConnectivityManager.REQUEST_ID_UNSET);
+ }
+
+ /**
+ * Add the given capability requirement to this builder. These represent
+ * the requested network's required capabilities. Note that when searching
+ * for a network to satisfy a request, all capabilities requested must be
+ * satisfied. See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*}
+ * definitions.
+ *
+ * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add.
+ * @return The builder to facilitate chaining
+ * {@code builder.addCapability(...).addCapability();}.
+ */
+ public Builder addCapability(int capability) {
+ mNetworkCapabilities.addCapability(capability);
+ return this;
+ }
+
+ /**
+ * Removes (if found) the given capability from this builder instance.
+ *
+ * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to remove.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder removeCapability(int capability) {
+ mNetworkCapabilities.removeCapability(capability);
+ return this;
+ }
+
+ /**
+ * Adds the given transport requirement to this builder. These represent
+ * the set of allowed transports for the request. Only networks using one
+ * of these transports will satisfy the request. If no particular transports
+ * are required, none should be specified here. See {@link NetworkCapabilities}
+ * for {@code TRANSPORT_*} definitions.
+ *
+ * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to add.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder addTransportType(int transportType) {
+ mNetworkCapabilities.addTransportType(transportType);
+ return this;
+ }
+
+ /**
+ * Removes (if found) the given transport from this builder instance.
+ *
+ * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to remove.
+ * @return The builder to facilitate chaining.
+ */
+ public Builder removeTransportType(int transportType) {
+ mNetworkCapabilities.removeTransportType(transportType);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public Builder setLinkUpstreamBandwidthKbps(int upKbps) {
+ mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps);
+ return this;
+ }
+ /**
+ * @hide
+ */
+ public Builder setLinkDownstreamBandwidthKbps(int downKbps) {
+ mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps);
+ return this;
+ }
+ }
+
// implement the Parcelable interface
public int describeContents() {
return 0;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 8b42bcd..63d6cd3 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -46,7 +46,7 @@
* destination and gateway are both specified, they must be of the same address family
* (IPv4 or IPv6).
*/
-public class RouteInfo implements Parcelable {
+public final class RouteInfo implements Parcelable {
/**
* The IP destination address for this route.
* TODO: Make this an IpPrefix.
@@ -248,7 +248,7 @@
* Retrieves the gateway or next hop {@link InetAddress} for this route.
*
* @return {@link InetAddress} specifying the gateway or next hop. This may be
- & {@code null} for a directly-connected route."
+ * {@code null} for a directly-connected route."
*/
public InetAddress getGateway() {
return mGateway;
@@ -378,7 +378,6 @@
/**
* Implement the Parcelable interface
- * @hide
*/
public int describeContents() {
return 0;
@@ -386,7 +385,6 @@
/**
* Implement the Parcelable interface
- * @hide
*/
public void writeToParcel(Parcel dest, int flags) {
if (mDestination == null) {
@@ -409,7 +407,6 @@
/**
* Implement the Parcelable interface.
- * @hide
*/
public static final Creator<RouteInfo> CREATOR =
new Creator<RouteInfo>() {
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index cd47099..e77ef95 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -39,9 +39,6 @@
UserInfo getProfileParent(int userHandle);
UserInfo getUserInfo(int userHandle);
boolean isRestricted();
- void setGuestEnabled(boolean enable);
- boolean isGuestEnabled();
- void wipeUser(int userHandle);
int getUserSerialNumber(int userHandle);
int getUserHandle(int userSerialNumber);
Bundle getUserRestrictions(int userHandle);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 914c170..afbf983 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,7 +16,10 @@
package android.os;
+import android.util.SparseArray;
+
import java.io.PrintWriter;
+import java.util.HashMap;
/**
* Representation of a user on the device.
@@ -66,6 +69,8 @@
final int mHandle;
+ private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
+
/**
* Checks to see if the user id is the same for the two uids, i.e., they belong to the same
* user.
@@ -124,6 +129,18 @@
return getUserId(Binder.getCallingUid());
}
+ /** @hide */
+ public static final UserHandle getCallingUserHandle() {
+ int userId = getUserId(Binder.getCallingUid());
+ UserHandle userHandle = userHandles.get(userId);
+ // Intentionally not synchronized to save time
+ if (userHandle == null) {
+ userHandle = new UserHandle(userId);
+ userHandles.put(userId, userHandle);
+ }
+ return userHandle;
+ }
+
/**
* Returns the uid that is composed from the userId and the appId.
* @hide
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 91fbb9d..468cfe0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -25,6 +25,7 @@
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.provider.Settings;
import android.util.Log;
import com.android.internal.R;
@@ -361,6 +362,16 @@
}
/**
+ * Checks if the calling app is running as a guest user.
+ * @return whether the caller is a guest user.
+ * @hide
+ */
+ public boolean isGuestUser() {
+ UserInfo user = getUserInfo(UserHandle.myUserId());
+ return user != null ? user.isGuest() : false;
+ }
+
+ /**
* Return whether the given user is actively running. This means that
* the user is in the "started" state, not "stopped" -- it is currently
* allowed to run code through scheduled alarms, receiving broadcasts,
@@ -550,6 +561,21 @@
}
/**
+ * Creates a guest user and configures it.
+ * @param context an application context
+ * @param name the name to set for the user
+ * @hide
+ */
+ public UserInfo createGuest(Context context, String name) {
+ UserInfo guest = createUser(name, UserInfo.FLAG_GUEST);
+ if (guest != null) {
+ Settings.Secure.putStringForUser(context.getContentResolver(),
+ Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
+ }
+ return guest;
+ }
+
+ /**
* Creates a user with the specified name and options as a profile of another user.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
*
@@ -827,50 +853,6 @@
}
/**
- * Enable or disable the use of a guest account. If disabled, the existing guest account
- * will be wiped.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @param enable whether to enable a guest account.
- * @hide
- */
- public void setGuestEnabled(boolean enable) {
- try {
- mService.setGuestEnabled(enable);
- } catch (RemoteException re) {
- Log.w(TAG, "Could not change guest account availability to " + enable);
- }
- }
-
- /**
- * Checks if a guest user is enabled for this device.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @return whether a guest user is enabled
- * @hide
- */
- public boolean isGuestEnabled() {
- try {
- return mService.isGuestEnabled();
- } catch (RemoteException re) {
- Log.w(TAG, "Could not retrieve guest enabled state");
- return false;
- }
- }
-
- /**
- * Wipes all the data for a user, but doesn't remove the user.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
- * @param userHandle
- * @hide
- */
- public void wipeUser(int userHandle) {
- try {
- mService.wipeUser(userHandle);
- } catch (RemoteException re) {
- Log.w(TAG, "Could not wipe user " + userHandle);
- }
- }
-
- /**
* Returns the maximum number of users that can be created on this device. A return value
* of 1 means that it is a single user device.
* @hide
@@ -900,7 +882,9 @@
++switchableUserCount;
}
}
- return switchableUserCount > 1;
+ final boolean guestEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.GUEST_USER_ENABLED, 0) == 1;
+ return switchableUserCount > 1 || guestEnabled;
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1001677..2a5e9fd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4576,6 +4576,16 @@
public static final String DISPLAY_INTERCEPTED_NOTIFICATIONS = "display_intercepted_notifications";
/**
+ * If enabled, apps should try to skip any introductory hints on first launch. This might
+ * apply to users that are already familiar with the environment or temporary users, like
+ * guests.
+ * <p>
+ * Type : int (0 to show hints, 1 to skip showing hints)
+ * @hide
+ */
+ public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -6216,6 +6226,14 @@
public static final String DEVICE_NAME = "device_name";
/**
+ * Whether it should be possible to create a guest user on the device.
+ * <p>
+ * Type: int (0 for disabled, 1 for enabled)
+ * @hide
+ */
+ public static final String GUEST_USER_ENABLED = "guest_user_enabled";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -6529,6 +6547,53 @@
public static boolean putFloat(ContentResolver cr, String name, float value) {
return putString(cr, name, Float.toString(value));
}
+
+
+ /**
+ * Subscription to be used for voice call on a multi sim device. The supported values
+ * are 0 = SUB1, 1 = SUB2 and etc.
+ * @hide
+ */
+ public static final String MULTI_SIM_VOICE_CALL_SUBSCRIPTION = "multi_sim_voice_call";
+
+ /**
+ * Used to provide option to user to select subscription during dial.
+ * The supported values are 0 = disable or 1 = enable prompt.
+ * @hide
+ */
+ public static final String MULTI_SIM_VOICE_PROMPT = "multi_sim_voice_prompt";
+
+ /**
+ * Subscription to be used for data call on a multi sim device. The supported values
+ * are 0 = SUB1, 1 = SUB2 and etc.
+ * @hide
+ */
+ public static final String MULTI_SIM_DATA_CALL_SUBSCRIPTION = "multi_sim_data_call";
+
+ /**
+ * Subscription to be used for SMS on a multi sim device. The supported values
+ * are 0 = SUB1, 1 = SUB2 and etc.
+ * @hide
+ */
+ public static final String MULTI_SIM_SMS_SUBSCRIPTION = "multi_sim_sms";
+
+ /**
+ * Used to provide option to user to select subscription during send SMS.
+ * The value 1 - enable, 0 - disable
+ * @hide
+ */
+ public static final String MULTI_SIM_SMS_PROMPT = "multi_sim_sms_prompt";
+
+
+
+ /** User preferred subscriptions setting.
+ * This holds the details of the user selected subscription from the card and
+ * the activation status. Each settings string have the coma separated values
+ * iccId,appType,appId,activationStatus,3gppIndex,3gpp2Index
+ * @hide
+ */
+ public static final String[] MULTI_SIM_USER_PREFERRED_SUBS = {"user_preferred_sub1",
+ "user_preferred_sub2","user_preferred_sub3"};
}
/**
diff --git a/core/java/android/speech/tts/RequestConfigHelper.java b/core/java/android/speech/tts/RequestConfigHelper.java
index 3b5490b..bc65280 100644
--- a/core/java/android/speech/tts/RequestConfigHelper.java
+++ b/core/java/android/speech/tts/RequestConfigHelper.java
@@ -46,7 +46,8 @@
/**
* Score positively voices that exactly match the given locale
- * @param locale Reference locale. If null, the default locale will be used.
+ * @param locale Reference locale. If null, the system default locale for the
+ * current user will be used ({@link Locale#getDefault()}).
*/
public ExactLocaleMatcher(Locale locale) {
if (locale == null) {
@@ -70,7 +71,8 @@
/**
* Score positively voices with similar locale.
- * @param locale Reference locale. If null, default will be used.
+ * @param locale Reference locale. If null, the system default locale for the
+ * current user will be used ({@link Locale#getDefault()}).
*/
public LanguageMatcher(Locale locale) {
if (locale == null) {
@@ -164,10 +166,10 @@
}
/**
- * Get highest quality voice for the default locale.
+ * Get highest quality voice for the TTS default locale.
*
* Call {@link #highestQuality(EngineStatus, boolean, VoiceScorer)} with
- * {@link LanguageMatcher} set to device default locale.
+ * {@link LanguageMatcher} set to the {@link EngineStatus#getDefaultLocale()}.
*
* @param engineStatus
* Voices status received from a {@link TextToSpeechClient#getEngineStatus()} call.
@@ -179,7 +181,7 @@
public static RequestConfig highestQuality(EngineStatus engineStatus,
boolean hasToBeEmbedded) {
return highestQuality(engineStatus, hasToBeEmbedded,
- new LanguageMatcher(Locale.getDefault()));
+ new LanguageMatcher(engineStatus.getDefaultLocale()));
}
}
diff --git a/core/java/android/speech/tts/SynthesisRequestV2.java b/core/java/android/speech/tts/SynthesisRequestV2.java
index a42aa16..938458c9 100644
--- a/core/java/android/speech/tts/SynthesisRequestV2.java
+++ b/core/java/android/speech/tts/SynthesisRequestV2.java
@@ -167,9 +167,7 @@
}
};
- /**
- * @hide
- */
+ /** @hide */
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index 0c0be83..f726743 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -42,6 +42,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -357,9 +358,13 @@
/** Name of the TTS engine package */
private final String mPackageName;
- private EngineStatus(String packageName, List<VoiceInfo> voices) {
+ /** Engine default locale */
+ private final Locale mDefaultLocale;
+
+ private EngineStatus(String packageName, List<VoiceInfo> voices, Locale defaultLocale) {
this.mVoices = Collections.unmodifiableList(voices);
this.mPackageName = packageName;
+ this.mDefaultLocale = defaultLocale;
}
/**
@@ -375,6 +380,16 @@
public String getEnginePackage() {
return mPackageName;
}
+
+ /**
+ * Get the default locale to use for TTS with this TTS engine.
+ * Unless the user changed the TTS settings for this engine, the value returned should be
+ * the same as the system default locale for the current user
+ * ({@link Locale#getDefault()}).
+ */
+ public Locale getDefaultLocale() {
+ return mDefaultLocale;
+ }
}
/** Unique synthesis request identifier. */
@@ -638,7 +653,9 @@
return null;
}
- return new EngineStatus(mServiceConnection.getEngineName(), voices);
+ return new EngineStatus(mServiceConnection.getEngineName(), voices,
+ mEnginesHelper.getLocalePrefForEngine(
+ mServiceConnection.getEngineName()));
}
private class Connection implements ServiceConnection {
@@ -696,7 +713,9 @@
public void onVoicesInfoChange(List<VoiceInfo> voicesInfo) {
synchronized (mLock) {
mEngineStatus = new EngineStatus(mServiceConnection.getEngineName(),
- voicesInfo);
+ voicesInfo,
+ mEnginesHelper.getLocalePrefForEngine(
+ mServiceConnection.getEngineName()));
mMainHandler.obtainMessage(InternalHandler.WHAT_ENGINE_STATUS_CHANGED,
mEngineStatus).sendToTarget();
}
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 14a4024..20f3ad7 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -460,8 +460,8 @@
}
private String[] getSettingsLocale() {
- final String locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
- return TtsEngines.parseLocalePref(locale);
+ final Locale locale = mEngineHelper.getLocalePrefForEngine(mPackageName);
+ return TtsEngines.toOldLocaleStringFormat(locale);
}
private int getSecureSettingInt(String name, int defaultValue) {
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index 9b929a3..7474efe 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -28,6 +28,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+
import static android.provider.Settings.Secure.getString;
import android.provider.Settings;
@@ -42,8 +43,10 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.MissingResourceException;
/**
@@ -53,16 +56,52 @@
* Comments in this class the use the shorthand "system engines" for engines that
* are a part of the system image.
*
+ * This class is thread-safe/
+ *
* @hide
*/
public class TtsEngines {
private static final String TAG = "TtsEngines";
private static final boolean DBG = false;
- private static final String LOCALE_DELIMITER = "-";
+ /** Locale delimiter used by the old-style 3 char locale string format (like "eng-usa") */
+ private static final String LOCALE_DELIMITER_OLD = "-";
+
+ /** Locale delimiter used by the new-style locale string format (Locale.toString() results,
+ * like "en_US") */
+ private static final String LOCALE_DELIMITER_NEW = "_";
private final Context mContext;
+ /** Mapping of various language strings to the normalized Locale form */
+ private static final Map<String, String> sNormalizeLanguage;
+
+ /** Mapping of various country strings to the normalized Locale form */
+ private static final Map<String, String> sNormalizeCountry;
+
+ // Populate the sNormalize* maps
+ static {
+ HashMap<String, String> normalizeLanguage = new HashMap<String, String>();
+ for (String language : Locale.getISOLanguages()) {
+ try {
+ normalizeLanguage.put(new Locale(language).getISO3Language(), language);
+ } catch (MissingResourceException e) {
+ continue;
+ }
+ }
+ sNormalizeLanguage = Collections.unmodifiableMap(normalizeLanguage);
+
+ HashMap<String, String> normalizeCountry = new HashMap<String, String>();
+ for (String country : Locale.getISOCountries()) {
+ try {
+ normalizeCountry.put(new Locale("", country).getISO3Country(), country);
+ } catch (MissingResourceException e) {
+ continue;
+ }
+ }
+ sNormalizeCountry = Collections.unmodifiableMap(normalizeCountry);
+ }
+
public TtsEngines(Context ctx) {
mContext = ctx;
}
@@ -282,139 +321,139 @@
}
/**
- * Returns the locale string for a given TTS engine. Attempts to read the
+ * Returns the default locale for a given TTS engine. Attempts to read the
* value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
- * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
- * both these values are empty, the default phone locale is returned.
+ * default phone locale is returned.
*
* @param engineName the engine to return the locale for.
- * @return the locale string preference for this engine. Will be non null
- * and non empty.
+ * @return the locale preference for this engine. Will be non null.
*/
- public String getLocalePrefForEngine(String engineName) {
- String locale = parseEnginePrefFromList(
- getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
- engineName);
-
- if (TextUtils.isEmpty(locale)) {
- // The new style setting is unset, attempt to return the old style setting.
- locale = getV1Locale();
- }
-
- if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + locale);
-
- return locale;
+ public Locale getLocalePrefForEngine(String engineName) {
+ return getLocalePrefForEngine(engineName,
+ getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE));
}
/**
+ * Returns the default locale for a given TTS engine from given settings string. */
+ public Locale getLocalePrefForEngine(String engineName, String prefValue) {
+ String localeString = parseEnginePrefFromList(
+ prefValue,
+ engineName);
+
+ if (TextUtils.isEmpty(localeString)) {
+ // The new style setting is unset, attempt to return the old style setting.
+ return Locale.getDefault();
+ }
+
+ Locale result = parseLocaleString(localeString);
+ if (result == null) {
+ Log.w(TAG, "Failed to parse locale " + localeString + ", returning en_US instead");
+ result = Locale.US;
+ }
+
+ if (DBG) Log.d(TAG, "getLocalePrefForEngine(" + engineName + ")= " + result);
+
+ return result;
+ }
+
+
+ /**
* True if a given TTS engine uses the default phone locale as a default locale. Attempts to
- * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}, failing which the
- * old style value from {@link Settings.Secure#TTS_DEFAULT_LANG} is read. If
- * both these values are empty, this methods returns true.
+ * read the value from {@link Settings.Secure#TTS_DEFAULT_LOCALE}. If
+ * its value is empty, this methods returns true.
*
* @param engineName the engine to return the locale for.
*/
public boolean isLocaleSetToDefaultForEngine(String engineName) {
- return (TextUtils.isEmpty(parseEnginePrefFromList(
+ return TextUtils.isEmpty(parseEnginePrefFromList(
getString(mContext.getContentResolver(), Settings.Secure.TTS_DEFAULT_LOCALE),
- engineName)) &&
- TextUtils.isEmpty(
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.TTS_DEFAULT_LANG)));
+ engineName));
}
-
/**
- * Parses a locale preference value delimited by {@link #LOCALE_DELIMITER}.
- * Varies from {@link String#split} in that it will always return an array
- * of length 3 with non null values.
+ * Parses a locale encoded as a string, and tries its best to return a valid {@link Locale}
+ * object, even if the input string is encoded using the old-style 3 character format e.g.
+ * "deu-deu". At the end, we test if the resulting locale can return ISO3 language and
+ * country codes ({@link Locale#getISO3Language()} and {@link Locale#getISO3Country()}),
+ * if it fails to do so, we return null.
*/
- public static String[] parseLocalePref(String pref) {
- String[] returnVal = new String[] { "", "", ""};
- if (!TextUtils.isEmpty(pref)) {
- String[] split = pref.split(LOCALE_DELIMITER);
- System.arraycopy(split, 0, returnVal, 0, split.length);
+ public Locale parseLocaleString(String localeString) {
+ String language = "", country = "", variant = "";
+ if (!TextUtils.isEmpty(localeString)) {
+ String[] split = localeString.split(
+ "[" + LOCALE_DELIMITER_OLD + LOCALE_DELIMITER_NEW + "]");
+ language = split[0].toLowerCase();
+ if (split.length == 0) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object. Only" +
+ " separators");
+ return null;
+ }
+ if (split.length > 3) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object. Too" +
+ " many separators");
+ return null;
+ }
+ if (split.length >= 2) {
+ country = split[1].toUpperCase();
+ }
+ if (split.length >= 3) {
+ variant = split[2];
+ }
+
}
- if (DBG) Log.d(TAG, "parseLocalePref(" + returnVal[0] + "," + returnVal[1] +
- "," + returnVal[2] +")");
+ String normalizedLanguage = sNormalizeLanguage.get(language);
+ if (normalizedLanguage != null) {
+ language = normalizedLanguage;
+ }
- return returnVal;
+ String normalizedCountry= sNormalizeCountry.get(country);
+ if (normalizedCountry != null) {
+ country = normalizedCountry;
+ }
+
+ if (DBG) Log.d(TAG, "parseLocalePref(" + language + "," + country +
+ "," + variant +")");
+
+ Locale result = new Locale(language, country, variant);
+ try {
+ result.getISO3Language();
+ result.getISO3Country();
+ return result;
+ } catch(MissingResourceException e) {
+ Log.w(TAG, "Failed to convert " + localeString + " to a valid Locale object.");
+ return null;
+ }
}
/**
- * @return the old style locale string constructed from
- * {@link Settings.Secure#TTS_DEFAULT_LANG},
- * {@link Settings.Secure#TTS_DEFAULT_COUNTRY} and
- * {@link Settings.Secure#TTS_DEFAULT_VARIANT}. If no such locale is set,
- * then return the default phone locale.
- */
- private String getV1Locale() {
- final ContentResolver cr = mContext.getContentResolver();
-
- final String lang = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_LANG);
- final String country = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_COUNTRY);
- final String variant = Settings.Secure.getString(cr, Settings.Secure.TTS_DEFAULT_VARIANT);
-
- if (TextUtils.isEmpty(lang)) {
- return getDefaultLocale();
- }
-
- String v1Locale = lang;
- if (!TextUtils.isEmpty(country)) {
- v1Locale += LOCALE_DELIMITER + country;
- } else {
- return v1Locale;
- }
-
- if (!TextUtils.isEmpty(variant)) {
- v1Locale += LOCALE_DELIMITER + variant;
- }
-
- return v1Locale;
- }
-
- /**
- * Return the default device locale in form of 3 letter codes delimited by
- * {@link #LOCALE_DELIMITER}:
+ * Return the old-style string form of the locale. It consists of 3 letter codes:
* <ul>
- * <li> "ISO 639-2/T language code" if locale have no country entry</li>
- * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code "
- * if locale have no variant entry</li>
- * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code
- * {@link #LOCALE_DELIMITER} variant" if locale have variant entry</li>
+ * <li>"ISO 639-2/T language code" if the locale has no country entry</li>
+ * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country code"
+ * if the locale has no variant entry</li>
+ * <li> "ISO 639-2/T language code{@link #LOCALE_DELIMITER}ISO 3166 country
+ * code{@link #LOCALE_DELIMITER}variant" if the locale has a variant entry</li>
* </ul>
+ * If we fail to generate those codes using {@link Locale#getISO3Country()} and
+ * {@link Locale#getISO3Language()}, then we return new String[]{"eng","USA",""};
*/
- public String getDefaultLocale() {
- final Locale locale = Locale.getDefault();
-
+ static public String[] toOldLocaleStringFormat(Locale locale) {
+ String[] ret = new String[]{"","",""};
try {
// Note that the default locale might have an empty variant
// or language, and we take care that the construction is
// the same as {@link #getV1Locale} i.e no trailing delimiters
// or spaces.
- String defaultLocale = locale.getISO3Language();
- if (TextUtils.isEmpty(defaultLocale)) {
- Log.w(TAG, "Default locale is empty.");
- return "";
- }
+ ret[0] = locale.getISO3Language();
+ ret[1] = locale.getISO3Country();
+ ret[2] = locale.getVariant();
- if (!TextUtils.isEmpty(locale.getISO3Country())) {
- defaultLocale += LOCALE_DELIMITER + locale.getISO3Country();
- } else {
- // Do not allow locales of the form lang--variant with
- // an empty country.
- return defaultLocale;
- }
- if (!TextUtils.isEmpty(locale.getVariant())) {
- defaultLocale += LOCALE_DELIMITER + locale.getVariant();
- }
-
- return defaultLocale;
+ return ret;
} catch (MissingResourceException e) {
// Default locale does not have a ISO 3166 and/or ISO 639-2/T codes. Return the
// default "eng-usa" (that would be the result of Locale.getDefault() == Locale.US).
- return "eng-usa";
+ return new String[]{"eng","USA",""};
}
}
@@ -443,16 +482,21 @@
return null;
}
- public synchronized void updateLocalePrefForEngine(String name, String newLocale) {
+ /**
+ * Serialize the locale to a string and store it as a default locale for the given engine. If
+ * the passed locale is null, an empty string will be serialized; that empty string, when
+ * read back, will evaluate to {@link Locale#getDefault()}.
+ */
+ public synchronized void updateLocalePrefForEngine(String engineName, Locale newLocale) {
final String prefList = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.TTS_DEFAULT_LOCALE);
if (DBG) {
- Log.d(TAG, "updateLocalePrefForEngine(" + name + ", " + newLocale +
+ Log.d(TAG, "updateLocalePrefForEngine(" + engineName + ", " + newLocale +
"), originally: " + prefList);
}
final String newPrefList = updateValueInCommaSeparatedList(prefList,
- name, newLocale);
+ engineName, (newLocale != null) ? newLocale.toString() : "");
if (DBG) Log.d(TAG, "updateLocalePrefForEngine(), writing: " + newPrefList.toString());
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index f440853..1d9aa05 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -440,26 +440,10 @@
}
// Documentation from interface
- public SpannableStringBuilder replace(int start, int end,
+ public SpannableStringBuilder replace(final int start, final int end,
CharSequence tb, int tbstart, int tbend) {
checkRange("replace", start, end);
- // Sanity check
- if (start > end) {
- Log.w(TAG, "Bad arguments to #replace : "
- + "start = " + start + ", end = " + end);
- final int tmp = start;
- start = end;
- end = tmp;
- }
- if (tbstart > tbend) {
- Log.w(TAG, "Bad arguments to #replace : "
- + "tbstart = " + tbstart + ", tbend = " + tbend);
- final int tmp = tbstart;
- tbstart = tbend;
- tbend = tmp;
- }
-
int filtercount = mFilters.length;
for (int i = 0; i < filtercount; i++) {
CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index b5b9199..266a6fed 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -19,7 +19,6 @@
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import com.android.internal.util.VirtualRefBasePtr;
@@ -34,34 +33,18 @@
* @hide
*/
final class HardwareLayer {
- private static final int LAYER_TYPE_TEXTURE = 1;
- private static final int LAYER_TYPE_DISPLAY_LIST = 2;
-
private HardwareRenderer mRenderer;
private VirtualRefBasePtr mFinalizer;
- private RenderNode mDisplayList;
- private final int mLayerType;
- private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
+ private HardwareLayer(HardwareRenderer renderer, long deferredUpdater) {
if (renderer == null || deferredUpdater == 0) {
throw new IllegalArgumentException("Either hardware renderer: " + renderer
+ " or deferredUpdater: " + deferredUpdater + " is invalid");
}
mRenderer = renderer;
- mLayerType = type;
mFinalizer = new VirtualRefBasePtr(deferredUpdater);
}
- private void assertType(int type) {
- if (mLayerType != type) {
- throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
- }
- }
-
- boolean hasDisplayList() {
- return mDisplayList != null;
- }
-
/**
* Update the paint used when drawing this layer.
*
@@ -90,11 +73,6 @@
// Already destroyed
return;
}
-
- if (mDisplayList != null) {
- mDisplayList.destroyDisplayListData();
- mDisplayList = null;
- }
mRenderer.onLayerDestroyed(this);
mRenderer = null;
mFinalizer.release();
@@ -105,21 +83,6 @@
return mFinalizer.get();
}
- public RenderNode startRecording() {
- assertType(LAYER_TYPE_DISPLAY_LIST);
-
- if (mDisplayList == null) {
- mDisplayList = RenderNode.create("HardwareLayer");
- }
- return mDisplayList;
- }
-
- public void endRecording(Rect dirtyRect) {
- nUpdateRenderLayer(mFinalizer.get(), mDisplayList.getNativeDisplayList(),
- dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
- mRenderer.pushLayerUpdate(this);
- }
-
/**
* Copies this layer into the specified bitmap.
*
@@ -160,7 +123,6 @@
* Indicates that this layer has lost its texture.
*/
public void detachSurfaceTexture(final SurfaceTexture surface) {
- assertType(LAYER_TYPE_TEXTURE);
mRenderer.safelyRun(new Runnable() {
@Override
public void run() {
@@ -177,13 +139,11 @@
}
public void setSurfaceTexture(SurfaceTexture surface) {
- assertType(LAYER_TYPE_TEXTURE);
nSetSurfaceTexture(mFinalizer.get(), surface, false);
mRenderer.pushLayerUpdate(this);
}
public void updateSurfaceTexture() {
- assertType(LAYER_TYPE_TEXTURE);
nUpdateSurfaceTexture(mFinalizer.get());
mRenderer.pushLayerUpdate(this);
}
@@ -192,18 +152,13 @@
* This should only be used by HardwareRenderer! Do not call directly
*/
SurfaceTexture createSurfaceTexture() {
- assertType(LAYER_TYPE_TEXTURE);
SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.get()));
nSetSurfaceTexture(mFinalizer.get(), st, true);
return st;
}
static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
- return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
- }
-
- static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
- return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
+ return new HardwareLayer(renderer, layer);
}
private static native void nOnTextureDestroyed(long layerUpdater);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 592dec8..3de8144 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -374,16 +374,6 @@
abstract HardwareLayer createTextureLayer();
/**
- * Creates a new hardware layer.
- *
- * @param width The minimum width of the layer
- * @param height The minimum height of the layer
- *
- * @return A hardware layer
- */
- abstract HardwareLayer createDisplayListLayer(int width, int height);
-
- /**
* Creates a new {@link SurfaceTexture} that can be used to render into the
* specified hardware layer.
*
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index c32a2c9..fa5bd88 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -46,7 +46,7 @@
int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets);
void remove(IWindow window);
-
+
/**
* Change the parameters of a window. You supply the
* new parameters, it returns the new frame of the window on screen (the
@@ -109,7 +109,7 @@
* to optimize compositing of this part of the window.
*/
void setTransparentRegion(IWindow window, in Region region);
-
+
/**
* Tell the window manager about the content and visible insets of the
* given window, which can be used to adjust the <var>outContentInsets</var>
@@ -122,20 +122,20 @@
*/
void setInsets(IWindow window, int touchableInsets, in Rect contentInsets,
in Rect visibleInsets, in Region touchableRegion);
-
+
/**
* Return the current display size in which the window is being laid out,
* accounting for screen decorations around it.
*/
void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
-
+
void finishDrawing(IWindow window);
-
+
void setInTouchMode(boolean showFocus);
boolean getInTouchMode();
-
+
boolean performHapticFeedback(IWindow window, int effectId, boolean always);
-
+
/**
* Allocate the drag's thumbnail surface. Also assigns a token that identifies
* the drag to the OS and passes that as the return value. A return value of
@@ -150,11 +150,11 @@
boolean performDrag(IWindow window, IBinder dragToken, float touchX, float touchY,
float thumbCenterX, float thumbCenterY, in ClipData data);
- /**
- * Report the result of a drop action targeted to the given window.
- * consumed is 'true' when the drop was accepted by a valid recipient,
- * 'false' otherwise.
- */
+ /**
+ * Report the result of a drop action targeted to the given window.
+ * consumed is 'true' when the drop was accepted by a valid recipient,
+ * 'false' otherwise.
+ */
void reportDropResult(IWindow window, boolean consumed);
/**
@@ -174,12 +174,12 @@
* how big the increment is from one screen to another.
*/
void setWallpaperPosition(IBinder windowToken, float x, float y, float xstep, float ystep);
-
+
void wallpaperOffsetsComplete(IBinder window);
-
+
Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, in Bundle extras, boolean sync);
-
+
void wallpaperCommandComplete(IBinder window, in Bundle result);
void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
@@ -188,7 +188,7 @@
/**
* Notifies that a rectangle on the screen has been requested.
*/
- void onRectangleOnScreenRequested(IBinder token, in Rect rectangle, boolean immediate);
+ void onRectangleOnScreenRequested(IBinder token, in Rect rectangle);
IWindowId getWindowId(IBinder window);
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 4631b64..d86b699 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.graphics.Matrix;
import android.graphics.Outline;
+import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
@@ -322,11 +323,13 @@
* handled in the drawLayer operation directly (and more efficiently).
*
* @param caching true if the display list represents a hardware layer, false otherwise.
- *
- * @hide
*/
- public boolean setCaching(boolean caching) {
- return nSetCaching(mNativeRenderNode, caching);
+ public boolean setLayerType(int layerType) {
+ return nSetLayerType(mNativeRenderNode, layerType);
+ }
+
+ public boolean setLayerPaint(Paint paint) {
+ return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0);
}
/**
@@ -842,13 +845,6 @@
}
/**
- * Sets the scroll position, this is used for damage calculations
- */
- public void setScrollPosition(int x, int y) {
- nSetScrollPosition(mNativeRenderNode, x, y);
- }
-
- /**
* Outputs the display list to the log. This method exists for use by
* tools to output display lists for selected nodes to the log.
*
@@ -906,11 +902,11 @@
private static native boolean nSetRight(long renderNode, int right);
private static native boolean nSetTop(long renderNode, int top);
private static native boolean nSetLeft(long renderNode, int left);
- private static native void nSetScrollPosition(long renderNode, int scrollX, int scrollY);
private static native boolean nSetCameraDistance(long renderNode, float distance);
private static native boolean nSetPivotY(long renderNode, float pivotY);
private static native boolean nSetPivotX(long renderNode, float pivotX);
- private static native boolean nSetCaching(long renderNode, boolean caching);
+ private static native boolean nSetLayerType(long renderNode, int layerType);
+ private static native boolean nSetLayerPaint(long renderNode, long paint);
private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5cd3d62..79f19b5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -78,8 +78,8 @@
IBinder displayToken);
private static native int nativeGetActiveConfig(IBinder displayToken);
private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
- private static native void nativeBlankDisplay(IBinder displayToken);
- private static native void nativeUnblankDisplay(IBinder displayToken);
+ private static native void nativeSetDisplayPowerMode(
+ IBinder displayToken, int mode);
private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -209,6 +209,25 @@
*/
public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
+ /* Display power modes * /
+
+ /**
+ * Display power mode off: used while blanking the screen.
+ * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+ */
+ public static final int POWER_MODE_OFF = 0;
+
+ /**
+ * Display power mode doze: used while putting the screen into low power mode.
+ * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+ */
+ public static final int POWER_MODE_DOZE = 1;
+
+ /**
+ * Display power mode normal: used while unblanking the screen.
+ * Use only with {@link SurfaceControl#setDisplayPowerMode()}.
+ */
+ public static final int POWER_MODE_NORMAL = 2;
/**
@@ -487,18 +506,11 @@
}
}
- public static void unblankDisplay(IBinder displayToken) {
+ public static void setDisplayPowerMode(IBinder displayToken, int mode) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- nativeUnblankDisplay(displayToken);
- }
-
- public static void blankDisplay(IBinder displayToken) {
- if (displayToken == null) {
- throw new IllegalArgumentException("displayToken must not be null");
- }
- nativeBlankDisplay(displayToken);
+ nativeSetDisplayPowerMode(displayToken, mode);
}
public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 2a9f7d5..1f7eaa2 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -275,6 +275,11 @@
}
}
+ @Override
+ public void setLayerPaint(Paint paint) {
+ setLayerType(/* ignored */ 0, paint);
+ }
+
/**
* Always returns {@link #LAYER_TYPE_HARDWARE}.
*/
@@ -332,11 +337,6 @@
}
}
- @Override
- boolean destroyLayer(boolean valid) {
- return false;
- }
-
/**
* @hide
*/
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7bbe84e..2bfbd65 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -257,12 +257,6 @@
}
@Override
- HardwareLayer createDisplayListLayer(int width, int height) {
- long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
- return HardwareLayer.adoptDisplayListLayer(this, layer);
- }
-
- @Override
HardwareLayer createTextureLayer() {
long layer = nCreateTextureLayer(mNativeProxy);
return HardwareLayer.adoptTextureLayer(this, layer);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 69680c9..3aaedd6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -90,6 +90,7 @@
import com.android.internal.R;
import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -3472,8 +3473,6 @@
})
int mLayerType = LAYER_TYPE_NONE;
Paint mLayerPaint;
- Rect mLocalDirtyRect;
- private HardwareLayer mHardwareLayer;
/**
* Set to true when drawing cache is enabled and cannot be created.
@@ -4796,14 +4795,10 @@
* @param v previous or the next focus holder, or null if none
*/
private void manageFocusHotspot(boolean focused, View v) {
- if (mBackground == null) {
- return;
- }
-
final Rect r = new Rect();
if (!focused && v != null) {
v.getBoundsOnScreen(r);
- final int[] location = new int[2];
+ final int[] location = mAttachInfo.mTmpLocation;
getLocationOnScreen(location);
r.offset(-location[0], -location[1]);
} else {
@@ -4812,7 +4807,20 @@
final float x = r.exactCenterX();
final float y = r.exactCenterY();
- mBackground.setHotspot(x, y);
+ setDrawableHotspot(x, y);
+ }
+
+ /**
+ * Sets the hotspot position for this View's drawables.
+ *
+ * @param x hotspot x coordinate
+ * @param y hotspot y coordinate
+ * @hide
+ */
+ protected void setDrawableHotspot(float x, float y) {
+ if (mBackground != null) {
+ mBackground.setHotspot(x, y);
+ }
}
/**
@@ -6113,7 +6121,7 @@
// apply insets path and take things from there.
try {
mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
- return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
+ return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed();
} finally {
mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS;
}
@@ -6769,7 +6777,7 @@
*/
private void setPressed(boolean pressed, float x, float y) {
if (pressed) {
- setHotspot(x, y);
+ setDrawableHotspot(x, y);
}
setPressed(pressed);
@@ -9108,8 +9116,7 @@
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
// Not inside a scrolling container, so show the feedback right away
- setHotspot(x, y);
- setPressed(true);
+ setPressed(true, x, y);
checkForLongClick(0);
}
break;
@@ -9121,7 +9128,7 @@
break;
case MotionEvent.ACTION_MOVE:
- setHotspot(x, y);
+ setDrawableHotspot(x, y);
// Be lenient about moving outside of buttons
if (!pointInView(x, y, mTouchSlop)) {
@@ -9143,12 +9150,6 @@
return false;
}
- private void setHotspot(float x, float y) {
- if (mBackground != null) {
- mBackground.setHotspot(x, y);
- }
- }
-
/**
* @hide
*/
@@ -12938,7 +12939,6 @@
stopNestedScroll();
destroyDrawingCache();
- destroyLayer(false);
cleanupDraw();
mCurrentAnimation = null;
@@ -13416,30 +13416,32 @@
+ "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
}
- if (layerType == mLayerType) {
+ boolean typeChanged = mRenderNode.setLayerType(layerType);
+
+ if (!typeChanged) {
setLayerPaint(paint);
return;
}
// Destroy any previous software drawing cache if needed
- switch (mLayerType) {
- case LAYER_TYPE_HARDWARE:
- destroyLayer(false);
- // fall through - non-accelerated views may use software layer mechanism instead
- case LAYER_TYPE_SOFTWARE:
- destroyDrawingCache();
- break;
- default:
- break;
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
+ destroyDrawingCache();
+ invalidateParentCaches();
+ invalidate(true);
}
mLayerType = layerType;
- final boolean layerDisabled = mLayerType == LAYER_TYPE_NONE;
+ final boolean layerDisabled = (mLayerType == LAYER_TYPE_NONE);
mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
- mLocalDirtyRect = layerDisabled ? null : new Rect();
+ mRenderNode.setLayerPaint(mLayerPaint);
- invalidateParentCaches();
- invalidate(true);
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
+ // LAYER_TYPE_SOFTWARE is handled by View:draw(), so need to invalidate()
+ invalidateParentCaches();
+ invalidate(true);
+ } else {
+ invalidateViewProperty(false, false);
+ }
}
/**
@@ -13472,11 +13474,9 @@
if (layerType != LAYER_TYPE_NONE) {
mLayerPaint = paint == null ? new Paint() : paint;
if (layerType == LAYER_TYPE_HARDWARE) {
- HardwareLayer layer = getHardwareLayer();
- if (layer != null) {
- layer.setLayerPaint(mLayerPaint);
+ if (mRenderNode.setLayerPaint(mLayerPaint)) {
+ invalidateViewProperty(false, false);
}
- invalidateViewProperty(false, false);
} else {
invalidate();
}
@@ -13532,18 +13532,17 @@
throw new IllegalStateException("This view must be attached to a window first");
}
+ if (getWidth() == 0 || getHeight() == 0) {
+ return;
+ }
+
switch (mLayerType) {
case LAYER_TYPE_HARDWARE:
- getHardwareLayer();
- // TODO: We need a better way to handle this case
- // If views have registered pre-draw listeners they need
- // to be notified before we build the layer. Those listeners
- // may however rely on other events to happen first so we
- // cannot just invoke them here until they don't cancel the
- // current frame
- if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
- attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
- }
+ // The only part of a hardware layer we can build in response to
+ // this call is to ensure the display list is up to date.
+ // The actual rendering of the display list into the layer must
+ // be done at playback time
+ updateDisplayListIfDirty();
break;
case LAYER_TYPE_SOFTWARE:
buildDrawingCache(true);
@@ -13552,70 +13551,13 @@
}
/**
- * <p>Returns a hardware layer that can be used to draw this view again
- * without executing its draw method.</p>
+ * If this View draws with a HardwareLayer, returns it.
+ * Otherwise returns null
*
- * @return A HardwareLayer ready to render, or null if an error occurred.
+ * TODO: Only TextureView uses this, can we eliminate it?
*/
HardwareLayer getHardwareLayer() {
- if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null ||
- !mAttachInfo.mHardwareRenderer.isEnabled()) {
- return null;
- }
-
- final int width = mRight - mLeft;
- final int height = mBottom - mTop;
-
- if (width == 0 || height == 0) {
- return null;
- }
-
- if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
- if (mHardwareLayer == null) {
- mHardwareLayer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
- width, height);
- mLocalDirtyRect.set(0, 0, width, height);
- } else if (mHardwareLayer.isValid()) {
- // This should not be necessary but applications that change
- // the parameters of their background drawable without calling
- // this.setBackground(Drawable) can leave the view in a bad state
- // (for instance isOpaque() returns true, but the background is
- // not opaque.)
- computeOpaqueFlags();
-
- if (mHardwareLayer.prepare(width, height, isOpaque())) {
- mLocalDirtyRect.set(0, 0, width, height);
- }
- }
-
- mHardwareLayer.setLayerPaint(mLayerPaint);
- RenderNode displayList = mHardwareLayer.startRecording();
- updateDisplayListIfDirty(displayList, true);
- mHardwareLayer.endRecording(mLocalDirtyRect);
- mLocalDirtyRect.setEmpty();
- }
-
- return mHardwareLayer;
- }
-
- /**
- * Destroys this View's hardware layer if possible.
- *
- * @return True if the layer was destroyed, false otherwise.
- *
- * @see #setLayerType(int, android.graphics.Paint)
- * @see #LAYER_TYPE_HARDWARE
- */
- boolean destroyLayer(boolean valid) {
- if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
-
- invalidate(true);
- invalidateParentCaches();
- return true;
- }
- return false;
+ return null;
}
/**
@@ -13631,7 +13573,6 @@
*/
protected void destroyHardwareResources() {
resetDisplayList();
- destroyLayer(true);
}
/**
@@ -13726,33 +13667,19 @@
return !(mAttachInfo == null || mAttachInfo.mHardwareRenderer == null);
}
- /**
- * Returns a DisplayList. If the incoming displayList is null, one will be created.
- * Otherwise, the same display list will be returned (after having been rendered into
- * along the way, depending on the invalidation state of the view).
- *
- * @param renderNode The previous version of this displayList, could be null.
- * @param isLayer Whether the requester of the display list is a layer. If so,
- * the view will avoid creating a layer inside the resulting display list.
- * @return A new or reused DisplayList object.
- */
- private void updateDisplayListIfDirty(@NonNull RenderNode renderNode, boolean isLayer) {
- if (renderNode == null) {
- throw new IllegalArgumentException("RenderNode must not be null");
- }
+ private void updateDisplayListIfDirty() {
+ final RenderNode renderNode = mRenderNode;
if (!canHaveDisplayList()) {
// can't populate RenderNode, don't try
return;
}
- renderNode.setScrollPosition(mScrollX, mScrollY);
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
|| !renderNode.isValid()
- || (!isLayer && mRecreateDisplayList)) {
+ || (mRecreateDisplayList)) {
// Don't need to recreate the display list, just need to tell our
// children to restore/recreate theirs
if (renderNode.isValid()
- && !isLayer
&& !mRecreateDisplayList) {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
@@ -13761,13 +13688,10 @@
return; // no work needed
}
- if (!isLayer) {
- // If we got here, we're recreating it. Mark it as such to ensure that
- // we copy in child display lists into ours in drawChild()
- mRecreateDisplayList = true;
- }
+ // If we got here, we're recreating it. Mark it as such to ensure that
+ // we copy in child display lists into ours in drawChild()
+ mRecreateDisplayList = true;
- boolean caching = false;
int width = mRight - mLeft;
int height = mBottom - mTop;
int layerType = getLayerType();
@@ -13775,34 +13699,21 @@
final HardwareCanvas canvas = renderNode.start(width, height);
try {
- if (!isLayer && layerType != LAYER_TYPE_NONE) {
- if (layerType == LAYER_TYPE_HARDWARE) {
- final HardwareLayer layer = getHardwareLayer();
- if (layer != null && layer.isValid()) {
- canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
- } else {
- canvas.saveLayer(0, 0, mRight - mLeft, mBottom - mTop, mLayerPaint,
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
- Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- }
- caching = true;
- } else {
- buildDrawingCache(true);
- Bitmap cache = getDrawingCache(true);
- if (cache != null) {
- canvas.drawBitmap(cache, 0, 0, mLayerPaint);
- caching = true;
- }
+ final HardwareLayer layer = getHardwareLayer();
+ if (layer != null && layer.isValid()) {
+ canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
+ } else if (layerType == LAYER_TYPE_SOFTWARE) {
+ buildDrawingCache(true);
+ Bitmap cache = getDrawingCache(true);
+ if (cache != null) {
+ canvas.drawBitmap(cache, 0, 0, mLayerPaint);
}
} else {
-
computeScroll();
canvas.translate(-mScrollX, -mScrollY);
- if (!isLayer) {
- mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags &= ~PFLAG_DIRTY_MASK;
- }
+ mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
+ mPrivateFlags &= ~PFLAG_DIRTY_MASK;
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
@@ -13816,14 +13727,9 @@
}
} finally {
renderNode.end(canvas);
- renderNode.setCaching(caching);
- if (isLayer) {
- renderNode.setLeftTopRightBottom(0, 0, width, height);
- } else {
- setDisplayListProperties(renderNode);
- }
+ setDisplayListProperties(renderNode);
}
- } else if (!isLayer) {
+ } else {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
}
@@ -13838,7 +13744,7 @@
* @hide
*/
public RenderNode getDisplayList() {
- updateDisplayListIfDirty(mRenderNode, false);
+ updateDisplayListIfDirty();
return mRenderNode;
}
@@ -19858,6 +19764,11 @@
*/
final int[] mInvalidateChildLocation = new int[2];
+ /**
+ * Global to the view hierarchy used as a temporary for dealng with
+ * computing absolute on-screen location.
+ */
+ final int[] mTmpLocation = new int[2];
/**
* Global to the view hierarchy used as a temporary for dealing with
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2905851..a02e76b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4386,10 +4386,9 @@
// Make sure we do not set both flags at the same time
int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
- if (child.mLayerType != LAYER_TYPE_NONE) {
+ if (child.mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
- child.mLocalDirtyRect.union(dirty);
}
final int[] location = attachInfo.mInvalidateChildLocation;
@@ -4498,9 +4497,8 @@
location[CHILD_LEFT_INDEX] = left;
location[CHILD_TOP_INDEX] = top;
- if (mLayerType != LAYER_TYPE_NONE) {
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
- mLocalDirtyRect.union(dirty);
}
return mParent;
@@ -4517,9 +4515,8 @@
dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
}
- if (mLayerType != LAYER_TYPE_NONE) {
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
- mLocalDirtyRect.union(dirty);
}
return mParent;
@@ -4567,10 +4564,6 @@
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
- if (child.mLayerType != LAYER_TYPE_NONE) {
- child.mLocalDirtyRect.union(dirty);
- }
-
int left = child.mLeft;
int top = child.mTop;
if (!child.getMatrix().isIdentity()) {
@@ -4618,9 +4611,6 @@
if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
- if (mLayerType != LAYER_TYPE_NONE) {
- mLocalDirtyRect.union(dirty);
- }
if (!getMatrix().isIdentity()) {
transformRect(dirty);
}
@@ -5600,11 +5590,11 @@
@Override
public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
insets = super.dispatchApplyWindowInsets(insets);
- if (insets.hasInsets()) {
+ if (!insets.isConsumed()) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
insets = getChildAt(i).dispatchApplyWindowInsets(insets);
- if (!insets.hasInsets()) {
+ if (insets.isConsumed()) {
break;
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 76d5038..4cd1b25 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -631,27 +631,7 @@
}
void destroyHardwareLayers() {
- if (mThread != Thread.currentThread()) {
- if (mAttachInfo.mHardwareRenderer != null &&
- mAttachInfo.mHardwareRenderer.isEnabled()) {
- HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
- }
- } else {
- destroyHardwareLayer(mView);
- }
- }
-
- private static void destroyHardwareLayer(View view) {
- view.destroyLayer(true);
-
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
-
- int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- destroyHardwareLayer(group.getChildAt(i));
- }
- }
+ // TODO Implement
}
void flushHardwareLayerUpdates() {
@@ -1520,54 +1500,55 @@
disposeResizeBuffer();
- if (mResizeBuffer == null) {
- mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
- mWidth, mHeight);
- }
- mResizeBuffer.prepare(mWidth, mHeight, false);
- RenderNode layerRenderNode = mResizeBuffer.startRecording();
- HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
- try {
- final int restoreCount = layerCanvas.save();
-
- int yoff;
- final boolean scrolling = mScroller != null
- && mScroller.computeScrollOffset();
- if (scrolling) {
- yoff = mScroller.getCurrY();
- mScroller.abortAnimation();
- } else {
- yoff = mScrollY;
- }
-
- layerCanvas.translate(0, -yoff);
- if (mTranslator != null) {
- mTranslator.translateCanvas(layerCanvas);
- }
-
- RenderNode renderNode = mView.mRenderNode;
- if (renderNode != null && renderNode.isValid()) {
- layerCanvas.drawDisplayList(renderNode, null,
- RenderNode.FLAG_CLIP_CHILDREN);
- } else {
- mView.draw(layerCanvas);
- }
-
- drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
-
- mResizeBufferStartTime = SystemClock.uptimeMillis();
- mResizeBufferDuration = mView.getResources().getInteger(
- com.android.internal.R.integer.config_mediumAnimTime);
-
- layerCanvas.restoreToCount(restoreCount);
- layerRenderNode.end(layerCanvas);
- layerRenderNode.setCaching(true);
- layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
- mTempRect.set(0, 0, mWidth, mHeight);
- } finally {
- mResizeBuffer.endRecording(mTempRect);
- }
- mAttachInfo.mHardwareRenderer.flushLayerUpdates();
+// TODO: Again....
+// if (mResizeBuffer == null) {
+// mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
+// mWidth, mHeight);
+// }
+// mResizeBuffer.prepare(mWidth, mHeight, false);
+// RenderNode layerRenderNode = mResizeBuffer.startRecording();
+// HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
+// try {
+// final int restoreCount = layerCanvas.save();
+//
+// int yoff;
+// final boolean scrolling = mScroller != null
+// && mScroller.computeScrollOffset();
+// if (scrolling) {
+// yoff = mScroller.getCurrY();
+// mScroller.abortAnimation();
+// } else {
+// yoff = mScrollY;
+// }
+//
+// layerCanvas.translate(0, -yoff);
+// if (mTranslator != null) {
+// mTranslator.translateCanvas(layerCanvas);
+// }
+//
+// RenderNode renderNode = mView.mRenderNode;
+// if (renderNode != null && renderNode.isValid()) {
+// layerCanvas.drawDisplayList(renderNode, null,
+// RenderNode.FLAG_CLIP_CHILDREN);
+// } else {
+// mView.draw(layerCanvas);
+// }
+//
+// drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
+//
+// mResizeBufferStartTime = SystemClock.uptimeMillis();
+// mResizeBufferDuration = mView.getResources().getInteger(
+// com.android.internal.R.integer.config_mediumAnimTime);
+//
+// layerCanvas.restoreToCount(restoreCount);
+// layerRenderNode.end(layerCanvas);
+// layerRenderNode.setCaching(true);
+// layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
+// mTempRect.set(0, 0, mWidth, mHeight);
+// } finally {
+// mResizeBuffer.endRecording(mTempRect);
+// }
+// mAttachInfo.mHardwareRenderer.flushLayerUpdates();
}
mAttachInfo.mContentInsets.set(mPendingContentInsets);
if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
@@ -6215,7 +6196,7 @@
mTempRect.offset(0, -mCurScrollY);
mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
try {
- mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
+ mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
} catch (RemoteException re) {
/* ignore */
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index ecc4586..0120875 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1516,6 +1516,29 @@
public boolean getAllowExitTransitionOverlap() { return true; }
/**
+ * Returns the duration, in milliseconds, of the window background fade
+ * when transitioning into or away from an Activity when called with an Activity Transition.
+ * <p>When executing the enter transition, the background starts transparent
+ * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is
+ * 300 milliseconds.</p>
+ * @return The duration of the window background fade to opaque during enter transition.
+ * @see #getEnterTransition()
+ */
+ public long getTransitionBackgroundFadeDuration() { return 0; }
+
+ /**
+ * Sets the duration, in milliseconds, of the window background fade
+ * when transitioning into or away from an Activity when called with an Activity Transition.
+ * <p>When executing the enter transition, the background starts transparent
+ * and fades in. This requires {@link #FEATURE_CONTENT_TRANSITIONS}. The default is
+ * 300 milliseconds.</p>
+ * @param fadeDurationMillis The duration of the window background fade to or from opaque
+ * during enter transition.
+ * @see #setEnterTransition(android.transition.Transition)
+ */
+ public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { }
+
+ /**
* @return the color of the status bar.
*/
public abstract int getStatusBarColor();
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 7f89044..b721074 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -111,6 +111,7 @@
builder.append("type=").append(type);
builder.append(", layer=").append(layer);
builder.append(", token=").append(token);
+ builder.append(", bounds=").append(boundsInScreen);
builder.append(", parent=").append(parentToken);
builder.append(", focused=").append(focused);
builder.append(", children=").append(childTokens);
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 57e774e..1d2f1bf 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -35,6 +35,9 @@
private Rect mTempRect;
private boolean mIsRound;
+ private boolean mSystemWindowInsetsConsumed = false;
+ private boolean mWindowDecorInsetsConsumed = false;
+
private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
/**
@@ -43,7 +46,13 @@
* since it would allow them to inadvertently consume unknown insets by returning it.
* @hide
*/
- public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+ public static final WindowInsets CONSUMED;
+
+ static {
+ CONSUMED = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+ CONSUMED.mSystemWindowInsetsConsumed = true;
+ CONSUMED.mWindowDecorInsetsConsumed = true;
+ }
/** @hide */
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
@@ -52,13 +61,17 @@
/** @hide */
public WindowInsets(Rect systemWindowInsets, boolean isRound) {
- this(systemWindowInsets, EMPTY_RECT, isRound);
+ this(systemWindowInsets, null, isRound);
}
/** @hide */
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
- mSystemWindowInsets = systemWindowInsets;
- mWindowDecorInsets = windowDecorInsets;
+ mSystemWindowInsetsConsumed = systemWindowInsets == null;
+ mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
+
+ mWindowDecorInsetsConsumed = windowDecorInsets == null;
+ mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : windowDecorInsets;
+
mIsRound = isRound;
}
@@ -70,12 +83,14 @@
public WindowInsets(WindowInsets src) {
mSystemWindowInsets = src.mSystemWindowInsets;
mWindowDecorInsets = src.mWindowDecorInsets;
+ mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed;
+ mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
mIsRound = src.mIsRound;
}
/** @hide */
public WindowInsets(Rect systemWindowInsets) {
- this(systemWindowInsets, EMPTY_RECT);
+ this(systemWindowInsets, null);
}
/**
@@ -243,6 +258,24 @@
}
/**
+ * Check if these insets have been fully consumed.
+ *
+ * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
+ * have been called such that all insets have been set to zero. This affects propagation of
+ * insets through the view hierarchy; insets that have not been fully consumed will continue
+ * to propagate down to child views.</p>
+ *
+ * <p>The result of this method is equivalent to the return value of
+ * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
+ *
+ * @return true if the insets have been fully consumed.
+ * @hide Pending API
+ */
+ public boolean isConsumed() {
+ return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed;
+ }
+
+ /**
* Returns true if the associated window has a round shape.
*
* <p>A round window's left, top, right and bottom edges reach all the way to the
@@ -263,7 +296,8 @@
*/
public WindowInsets consumeSystemWindowInsets() {
final WindowInsets result = new WindowInsets(this);
- result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+ result.mSystemWindowInsets = EMPTY_RECT;
+ result.mSystemWindowInsetsConsumed = true;
return result;
}
@@ -281,10 +315,12 @@
boolean right, boolean bottom) {
if (left || top || right || bottom) {
final WindowInsets result = new WindowInsets(this);
- result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
+ result.mSystemWindowInsets = new Rect(
+ left ? 0 : mSystemWindowInsets.left,
top ? 0 : mSystemWindowInsets.top,
right ? 0 : mSystemWindowInsets.right,
bottom ? 0 : mSystemWindowInsets.bottom);
+ result.mSystemWindowInsetsConsumed = !hasSystemWindowInsets();
return result;
}
return this;
@@ -304,6 +340,7 @@
int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+ result.mSystemWindowInsetsConsumed = !hasSystemWindowInsets();
return result;
}
@@ -313,6 +350,7 @@
public WindowInsets consumeWindowDecorInsets() {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets.set(0, 0, 0, 0);
+ result.mWindowDecorInsetsConsumed = true;
return result;
}
@@ -327,6 +365,7 @@
top ? 0 : mWindowDecorInsets.top,
right ? 0 : mWindowDecorInsets.right,
bottom ? 0 : mWindowDecorInsets.bottom);
+ result.mWindowDecorInsetsConsumed = !hasWindowDecorInsets();
return result;
}
return this;
@@ -338,6 +377,7 @@
public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
final WindowInsets result = new WindowInsets(this);
result.mWindowDecorInsets = new Rect(left, top, right, bottom);
+ result.mWindowDecorInsetsConsumed = !hasWindowDecorInsets();
return result;
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 2b4677c..d426edc 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -605,21 +605,21 @@
public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation);
/**
- * Return whether the given window should forcibly hide everything
- * behind it. Typically returns true for the keyguard.
+ * Return whether the given window is forcibly hiding all windows except windows with
+ * FLAG_SHOW_WHEN_LOCKED set. Typically returns true for the keyguard.
*/
- public boolean doesForceHide(WindowManager.LayoutParams attrs);
+ public boolean isForceHiding(WindowManager.LayoutParams attrs);
/**
- * Return whether the given window can become one that passes doesForceHide() test.
+ * Return whether the given window can become one that passes isForceHiding() test.
* Typically returns true for the StatusBar.
*/
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs);
/**
* Determine if a window that is behind one that is force hiding
- * (as determined by {@link #doesForceHide}) should actually be hidden.
+ * (as determined by {@link #isForceHiding}) should actually be hidden.
* For example, typically returns false for the status bar. Be careful
* to return false for any window that you may hide yourself, since this
* will conflict with what you set.
@@ -830,13 +830,11 @@
* setting the window's frame, either here or in finishLayout().
*
* @param win The window being positioned.
- * @param attrs The LayoutParams of the window.
* @param attached For sub-windows, the window it is attached to; this
* window will already have had layoutWindow() called on it
* so you can use its Rect. Otherwise null.
*/
- public void layoutWindowLw(WindowState win,
- WindowManager.LayoutParams attrs, WindowState attached);
+ public void layoutWindowLw(WindowState win, WindowState attached);
/**
diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java
index c08f348..1c75f16 100644
--- a/core/java/android/view/animation/AccelerateInterpolator.java
+++ b/core/java/android/view/animation/AccelerateInterpolator.java
@@ -17,15 +17,18 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
- * An interpolator where the rate of change starts out slowly and
+ * An interpolator where the rate of change starts out slowly and
* and then accelerates.
*
*/
@@ -38,10 +41,10 @@
mFactor = 1.0f;
mDoubleFactor = 2.0;
}
-
+
/**
* Constructor
- *
+ *
* @param factor Degree to which the animation should be eased. Seting
* factor to 1.0f produces a y=x^2 parabola. Increasing factor above
* 1.0f exaggerates the ease-in effect (i.e., it starts even
@@ -51,17 +54,26 @@
mFactor = factor;
mDoubleFactor = 2 * mFactor;
}
-
+
public AccelerateInterpolator(Context context, AttributeSet attrs) {
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AccelerateInterpolator);
-
- mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator);
+ }
+
+ mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
mDoubleFactor = 2 * mFactor;
a.recycle();
}
-
+
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 1d1fa1e..af4e04f 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -20,6 +20,8 @@
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
@@ -143,7 +145,7 @@
*/
public static LayoutAnimationController loadLayoutAnimation(Context context, int id)
throws NotFoundException {
-
+
XmlResourceParser parser = null;
try {
parser = context.getResources().getAnimation(id);
@@ -201,7 +203,7 @@
/**
* Make an animation for objects becoming visible. Uses a slide and fade
* effect.
- *
+ *
* @param c Context for loading resources
* @param fromLeft is the object to be animated coming from the left
* @return The new animation
@@ -218,11 +220,11 @@
a.setStartTime(currentAnimationTimeMillis());
return a;
}
-
+
/**
* Make an animation for objects becoming invisible. Uses a slide and fade
* effect.
- *
+ *
* @param c Context for loading resources
* @param toRight is the object to be animated exiting to the right
* @return The new animation
@@ -234,17 +236,17 @@
} else {
a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left);
}
-
+
a.setInterpolator(new AccelerateInterpolator());
a.setStartTime(currentAnimationTimeMillis());
return a;
}
-
+
/**
* Make an animation for objects becoming visible. Uses a slide up and fade
* effect.
- *
+ *
* @param c Context for loading resources
* @return The new animation
*/
@@ -255,10 +257,10 @@
a.setStartTime(currentAnimationTimeMillis());
return a;
}
-
+
/**
* Loads an {@link Interpolator} object from a resource
- *
+ *
* @param context Application context used to access resources
* @param id The resource id of the animation to load
* @return The animation object reference by the specified id
@@ -268,7 +270,7 @@
XmlResourceParser parser = null;
try {
parser = context.getResources().getAnimation(id);
- return createInterpolatorFromXml(context, parser);
+ return createInterpolatorFromXml(context.getResources(), context.getTheme(), parser);
} catch (XmlPullParserException ex) {
NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
Integer.toHexString(id));
@@ -284,54 +286,84 @@
}
}
-
- private static Interpolator createInterpolatorFromXml(Context c, XmlPullParser parser)
+
+ /**
+ * Loads an {@link Interpolator} object from a resource
+ *
+ * @param res The resources
+ * @param id The resource id of the animation to load
+ * @return The interpolator object reference by the specified id
+ * @throws NotFoundException
+ * @hide
+ */
+ public static Interpolator loadInterpolator(Resources res, Theme theme, int id) throws NotFoundException {
+ XmlResourceParser parser = null;
+ try {
+ parser = res.getAnimation(id);
+ return createInterpolatorFromXml(res, theme, parser);
+ } catch (XmlPullParserException ex) {
+ NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
+ Integer.toHexString(id));
+ rnf.initCause(ex);
+ throw rnf;
+ } catch (IOException ex) {
+ NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" +
+ Integer.toHexString(id));
+ rnf.initCause(ex);
+ throw rnf;
+ } finally {
+ if (parser != null)
+ parser.close();
+ }
+
+ }
+
+ private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser)
throws XmlPullParserException, IOException {
-
+
Interpolator interpolator = null;
-
+
// Make sure we are on a start tag.
int type;
int depth = parser.getDepth();
- while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
- && type != XmlPullParser.END_DOCUMENT) {
+ while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
AttributeSet attrs = Xml.asAttributeSet(parser);
-
- String name = parser.getName();
-
-
+
+ String name = parser.getName();
+
if (name.equals("linearInterpolator")) {
- interpolator = new LinearInterpolator(c, attrs);
+ interpolator = new LinearInterpolator();
} else if (name.equals("accelerateInterpolator")) {
- interpolator = new AccelerateInterpolator(c, attrs);
+ interpolator = new AccelerateInterpolator(res, theme, attrs);
} else if (name.equals("decelerateInterpolator")) {
- interpolator = new DecelerateInterpolator(c, attrs);
- } else if (name.equals("accelerateDecelerateInterpolator")) {
- interpolator = new AccelerateDecelerateInterpolator(c, attrs);
- } else if (name.equals("cycleInterpolator")) {
- interpolator = new CycleInterpolator(c, attrs);
+ interpolator = new DecelerateInterpolator(res, theme, attrs);
+ } else if (name.equals("accelerateDecelerateInterpolator")) {
+ interpolator = new AccelerateDecelerateInterpolator();
+ } else if (name.equals("cycleInterpolator")) {
+ interpolator = new CycleInterpolator(res, theme, attrs);
} else if (name.equals("anticipateInterpolator")) {
- interpolator = new AnticipateInterpolator(c, attrs);
+ interpolator = new AnticipateInterpolator(res, theme, attrs);
} else if (name.equals("overshootInterpolator")) {
- interpolator = new OvershootInterpolator(c, attrs);
+ interpolator = new OvershootInterpolator(res, theme, attrs);
} else if (name.equals("anticipateOvershootInterpolator")) {
- interpolator = new AnticipateOvershootInterpolator(c, attrs);
+ interpolator = new AnticipateOvershootInterpolator(res, theme, attrs);
} else if (name.equals("bounceInterpolator")) {
- interpolator = new BounceInterpolator(c, attrs);
+ interpolator = new BounceInterpolator();
} else if (name.equals("pathInterpolator")) {
- interpolator = new PathInterpolator(c, attrs);
+ interpolator = new PathInterpolator(res, theme, attrs);
} else {
throw new RuntimeException("Unknown interpolator name: " + parser.getName());
}
}
-
+
return interpolator;
}
diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
index 83a8007..fe756bd 100644
--- a/core/java/android/view/animation/AnticipateInterpolator.java
+++ b/core/java/android/view/animation/AnticipateInterpolator.java
@@ -17,9 +17,12 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -45,11 +48,20 @@
}
public AnticipateInterpolator(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.AnticipateInterpolator);
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public AnticipateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.AnticipateInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator);
+ }
mTension =
- a.getFloat(com.android.internal.R.styleable.AnticipateInterpolator_tension, 2.0f);
+ a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);
a.recycle();
}
diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
index 1a8adfd..78e5acf 100644
--- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java
+++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
@@ -17,6 +17,8 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -62,7 +64,17 @@
}
public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator);
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public AnticipateOvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, AnticipateOvershootInterpolator);
+ }
mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java
index d1ebf05..3114aa3 100644
--- a/core/java/android/view/animation/CycleInterpolator.java
+++ b/core/java/android/view/animation/CycleInterpolator.java
@@ -17,9 +17,12 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -34,20 +37,29 @@
public CycleInterpolator(float cycles) {
mCycles = cycles;
}
-
+
public CycleInterpolator(Context context, AttributeSet attrs) {
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.CycleInterpolator);
-
- mCycles = a.getFloat(com.android.internal.R.styleable.CycleInterpolator_cycles, 1.0f);
-
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public CycleInterpolator(Resources resources, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.CycleInterpolator, 0, 0);
+ } else {
+ a = resources.obtainAttributes(attrs, R.styleable.CycleInterpolator);
+ }
+
+ mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f);
+
a.recycle();
}
-
+
public float getInterpolation(float input) {
return (float)(Math.sin(2 * mCycles * Math.PI * input));
}
-
+
private float mCycles;
/** @hide */
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index 0789a0e..674207c 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -17,15 +17,18 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.Resources.Theme;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
- * An interpolator where the rate of change starts out quickly and
+ * An interpolator where the rate of change starts out quickly and
* and then decelerates.
*
*/
@@ -36,7 +39,7 @@
/**
* Constructor
- *
+ *
* @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
* an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
* ease-out effect (i.e., it starts even faster and ends evens slower)
@@ -44,16 +47,25 @@
public DecelerateInterpolator(float factor) {
mFactor = factor;
}
-
+
public DecelerateInterpolator(Context context, AttributeSet attrs) {
- TypedArray a =
- context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.DecelerateInterpolator);
-
- mFactor = a.getFloat(com.android.internal.R.styleable.DecelerateInterpolator_factor, 1.0f);
-
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public DecelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.DecelerateInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.DecelerateInterpolator);
+ }
+
+ mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f);
+
a.recycle();
}
-
+
public float getInterpolation(float input) {
float result;
if (mFactor == 1.0f) {
@@ -63,7 +75,7 @@
}
return result;
}
-
+
private float mFactor = 1.0f;
/** @hide */
diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java
index a2466f1..d6c2808 100644
--- a/core/java/android/view/animation/OvershootInterpolator.java
+++ b/core/java/android/view/animation/OvershootInterpolator.java
@@ -17,9 +17,12 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import com.android.internal.R;
import com.android.internal.view.animation.HasNativeInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
@@ -46,11 +49,20 @@
}
public OvershootInterpolator(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.OvershootInterpolator);
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public OvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.OvershootInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.OvershootInterpolator);
+ }
mTension =
- a.getFloat(com.android.internal.R.styleable.OvershootInterpolator_tension, 2.0f);
+ a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
a.recycle();
}
diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java
index a369509..da12ffb 100644
--- a/core/java/android/view/animation/PathInterpolator.java
+++ b/core/java/android/view/animation/PathInterpolator.java
@@ -16,11 +16,15 @@
package android.view.animation;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.InflateException;
+import com.android.internal.R;
+
/**
* An interpolator that can traverse a Path that extends from <code>Point</code>
* <code>(0, 0)</code> to <code>(1, 1)</code>. The x coordinate along the <code>Path</code>
@@ -81,18 +85,33 @@
}
public PathInterpolator(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.PathInterpolator);
- if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX1)) {
+ this(context.getResources(), context.getTheme(), attrs);
+ }
+
+ /** @hide */
+ public PathInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+ TypedArray a;
+ if (theme != null) {
+ a = theme.obtainStyledAttributes(attrs, R.styleable.PathInterpolator, 0, 0);
+ } else {
+ a = res.obtainAttributes(attrs, R.styleable.PathInterpolator);
+ }
+ parseInterpolatorFromTypeArray(a);
+
+ a.recycle();
+ }
+
+ private void parseInterpolatorFromTypeArray(TypedArray a) {
+ if (!a.hasValue(R.styleable.PathInterpolator_controlX1)) {
throw new InflateException("pathInterpolator requires the controlX1 attribute");
- } else if (!a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY1)) {
+ } else if (!a.hasValue(R.styleable.PathInterpolator_controlY1)) {
throw new InflateException("pathInterpolator requires the controlY1 attribute");
}
- float x1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX1, 0);
- float y1 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY1, 0);
+ float x1 = a.getFloat(R.styleable.PathInterpolator_controlX1, 0);
+ float y1 = a.getFloat(R.styleable.PathInterpolator_controlY1, 0);
- boolean hasX2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlX2);
- boolean hasY2 = a.hasValue(com.android.internal.R.styleable.PathInterpolator_controlY2);
+ boolean hasX2 = a.hasValue(R.styleable.PathInterpolator_controlX2);
+ boolean hasY2 = a.hasValue(R.styleable.PathInterpolator_controlY2);
if (hasX2 != hasY2) {
throw new InflateException(
@@ -102,12 +121,10 @@
if (!hasX2) {
initQuad(x1, y1);
} else {
- float x2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlX2, 0);
- float y2 = a.getFloat(com.android.internal.R.styleable.PathInterpolator_controlY2, 0);
+ float x2 = a.getFloat(R.styleable.PathInterpolator_controlX2, 0);
+ float y2 = a.getFloat(R.styleable.PathInterpolator_controlY2, 0);
initCubic(x1, y1, x2, y2);
}
-
- a.recycle();
}
private void initQuad(float controlX, float controlY) {
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index fad6747..66f5f6c 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -186,12 +186,12 @@
/**
* Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe.
*/
- public static final class CursorAnchorInfoBuilder {
+ public static final class Builder {
/**
* Sets the text range of the selection. Calling this can be skipped if there is no
* selection.
*/
- public CursorAnchorInfoBuilder setSelectionRange(final int newStart, final int newEnd) {
+ public Builder setSelectionRange(final int newStart, final int newEnd) {
mSelectionStart = newStart;
mSelectionEnd = newEnd;
return this;
@@ -205,8 +205,7 @@
* @param index index where the composing text starts.
* @param composingText the entire composing text.
*/
- public CursorAnchorInfoBuilder setComposingText(final int index,
- final CharSequence composingText) {
+ public Builder setComposingText(final int index, final CharSequence composingText) {
mComposingTextStart = index;
if (composingText == null) {
mComposingText = null;
@@ -236,9 +235,8 @@
* that will be transformed with the transformation matrix when rendered on the screen. This
* should be calculated or compatible with {@link Layout#getLineBottom(int)}.
*/
- public CursorAnchorInfoBuilder setInsertionMarkerLocation(
- final float horizontalPosition, final float lineTop, final float lineBaseline,
- final float lineBottom){
+ public Builder setInsertionMarkerLocation(final float horizontalPosition,
+ final float lineTop, final float lineBaseline, final float lineBottom){
mInsertionMarkerHorizontal = horizontalPosition;
mInsertionMarkerTop = lineTop;
mInsertionMarkerBaseline = lineBaseline;
@@ -269,9 +267,8 @@
* @throws IllegalArgumentException If the index is a negative value, or not greater than
* all of the previously called indices.
*/
- public CursorAnchorInfoBuilder addCharacterRect(final int index,
- final float leadingEdgeX, final float leadingEdgeY, final float trailingEdgeX,
- final float trailingEdgeY) {
+ public Builder addCharacterRect(final int index, final float leadingEdgeX,
+ final float leadingEdgeY, final float trailingEdgeX, final float trailingEdgeY) {
if (index < 0) {
throw new IllegalArgumentException("index must not be a negative integer.");
}
@@ -289,7 +286,7 @@
* @param matrix transformation matrix from local coordinates into screen coordinates. null
* is interpreted as an identity matrix.
*/
- public CursorAnchorInfoBuilder setMatrix(final Matrix matrix) {
+ public Builder setMatrix(final Matrix matrix) {
mMatrix.set(matrix != null ? matrix : Matrix.IDENTITY_MATRIX);
return this;
}
@@ -297,7 +294,7 @@
/**
* @return {@link CursorAnchorInfo} using parameters in this
- * {@link CursorAnchorInfoBuilder}.
+ * {@link Builder}.
*/
public CursorAnchorInfo build() {
return new CursorAnchorInfo(this);
@@ -323,7 +320,7 @@
}
}
- private CursorAnchorInfo(final CursorAnchorInfoBuilder builder) {
+ private CursorAnchorInfo(final Builder builder) {
mSelectionStart = builder.mSelectionStart;
mSelectionEnd = builder.mSelectionEnd;
mComposingTextStart = builder.mComposingTextStart;
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
index 588b868..4a7f5fd 100644
--- a/core/java/android/webkit/ClientCertRequest.java
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -27,7 +27,7 @@
* such as the host name and the port number requesting the cert, the acceptable
* key types and the principals.
*
- * The user should call one of the interface methods to indicate how to deal
+ * The user should call one of the class methods to indicate how to deal
* with the client certificate request. All methods should be called on
* UI thread.
*
@@ -37,42 +37,45 @@
* {@link WebView#clearClientCertPreferences}.
*
*/
-public interface ClientCertRequest {
+public abstract class ClientCertRequest {
+
+ public ClientCertRequest() { }
+
/**
* Returns the acceptable types of asymmetric keys (can be null).
*/
- public String[] getKeyTypes();
+ public abstract String[] getKeyTypes();
/**
* Returns the acceptable certificate issuers for the certificate
* matching the private key (can be null).
*/
- public Principal[] getPrincipals();
+ public abstract Principal[] getPrincipals();
/**
* Returns the host name of the server requesting the certificate.
*/
- public String getHost();
+ public abstract String getHost();
/**
* Returns the port number of the server requesting the certificate.
*/
- public int getPort();
+ public abstract int getPort();
/**
* Proceed with the specified private key and client certificate chain.
* Remember the user's positive choice and use it for future requests.
*/
- public void proceed(PrivateKey privateKey, X509Certificate[] chain);
+ public abstract void proceed(PrivateKey privateKey, X509Certificate[] chain);
/**
* Ignore the request for now. Do not remember user's choice.
*/
- public void ignore();
+ public abstract void ignore();
/**
* Cancel this request. Remember the user's choice and use it for
* future requests.
*/
- public void cancel();
+ public abstract void cancel();
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 91ca7b4..482c7e8 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1486,11 +1486,11 @@
}
/**
- * Clears the client certificate preferences table stored in response
- * to proceeding/cancelling client cert requests. Note that webview
+ * Clears the client certificate preferences stored in response
+ * to proceeding/cancelling client cert requests. Note that Webview
* automatically clears these preferences when it receives a
- * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The client certificate
- * preferences are global for all Webviews.
+ * {@link KeyChain#ACTION_STORAGE_CHANGED} intent. The preferences are
+ * shared by all the webviews that are created by the embedder application.
*
* @param onCleared A runnable to be invoked when client certs are cleared.
* The embedder can pass null if not interested in the
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 43f623b..08931fe 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -255,6 +255,22 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ final Drawable progressDrawable = getProgressDrawable();
+ if (progressDrawable != null) {
+ progressDrawable.setHotspot(x, y);
+ }
+
+ final Drawable thumb = mThumb;
+ if (thumb != null) {
+ thumb.setHotspot(x, y);
+ }
+ }
+
@Override
public void invalidateDrawable(Drawable dr) {
super.invalidateDrawable(dr);
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 3ae9508..7113793 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -307,6 +307,16 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mCheckMarkDrawable != null) {
+ mCheckMarkDrawable.setHotspot(x, y);
+ }
+ }
+
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 6aff4f4..c934ad7 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -320,6 +320,16 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mButtonDrawable != null) {
+ mButtonDrawable.setHotspot(x, y);
+ }
+ }
+
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || who == mButtonDrawable;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 27d6b82..4467128 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -96,7 +96,6 @@
import android.view.WindowManager;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.CursorAnchorInfo;
-import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -3013,7 +3012,7 @@
* {@link InputMethodManager#isWatchingCursor(View)} returns false.
*/
private final class CursorAnchorInfoNotifier implements TextViewPositionListener {
- final CursorAnchorInfoBuilder mSelectionInfoBuilder = new CursorAnchorInfoBuilder();
+ final CursorAnchorInfo.Builder mSelectionInfoBuilder = new CursorAnchorInfo.Builder();
final int[] mTmpIntOffset = new int[2];
final Matrix mViewToScreenMatrix = new Matrix();
@@ -3037,7 +3036,7 @@
return;
}
- final CursorAnchorInfoBuilder builder = mSelectionInfoBuilder;
+ final CursorAnchorInfo.Builder builder = mSelectionInfoBuilder;
builder.reset();
final int selectionStart = mTextView.getSelectionStart();
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index b029328..01a6b8a 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -205,6 +205,16 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mForeground != null) {
+ mForeground.setHotspot(x, y);
+ }
+ }
+
/**
* Returns a set of layout parameters with a width of
* {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 572302a4..a40b85e 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1010,7 +1010,17 @@
}
}
- @Override
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mDrawable != null) {
+ mDrawable.setHotspot(x, y);
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index b49938c..af32f1c 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1144,6 +1144,20 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mProgressDrawable != null) {
+ mProgressDrawable.setHotspot(x, y);
+ }
+
+ if (mIndeterminateDrawable != null) {
+ mIndeterminateDrawable.setHotspot(x, y);
+ }
+ }
+
static class SavedState extends BaseSavedState {
int progress;
int secondaryProgress;
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 0c31496..14d782d 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -112,6 +112,16 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mOverlay != null) {
+ mOverlay.setHotspot(x, y);
+ }
+ }
+
/** This call has no effect anymore, as there is only one QuickContact mode */
@SuppressWarnings("unused")
public void setMode(int size) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index c5c6e64..03193a2 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -962,6 +962,20 @@
invalidate();
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ if (mThumbDrawable != null) {
+ mThumbDrawable.setHotspot(x, y);
+ }
+
+ if (mTrackDrawable != null) {
+ mTrackDrawable.setHotspot(x, y);
+ }
+ }
+
@Override
public void invalidateDrawable(Drawable drawable) {
super.invalidateDrawable(drawable);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 43c8dde..22f5e23 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2551,7 +2551,7 @@
r = c.getResources();
setRawTextSize(TypedValue.applyDimension(
- unit, size, r.getDisplayMetrics()));
+ unit, size, r.getDisplayMetrics()));
}
private void setRawTextSize(float size) {
@@ -3505,6 +3505,34 @@
}
}
+ /** @hide */
+ @Override
+ protected void setDrawableHotspot(float x, float y) {
+ super.setDrawableHotspot(x, y);
+
+ final Drawables dr = mDrawables;
+ if (dr != null) {
+ if (dr.mDrawableTop != null) {
+ dr.mDrawableTop.setHotspot(x, y);
+ }
+ if (dr.mDrawableBottom != null) {
+ dr.mDrawableBottom.setHotspot(x, y);
+ }
+ if (dr.mDrawableLeft != null) {
+ dr.mDrawableLeft.setHotspot(x, y);
+ }
+ if (dr.mDrawableRight != null) {
+ dr.mDrawableRight.setHotspot(x, y);
+ }
+ if (dr.mDrawableStart != null) {
+ dr.mDrawableStart.setHotspot(x, y);
+ }
+ if (dr.mDrawableEnd != null) {
+ dr.mDrawableEnd.setHotspot(x, y);
+ }
+ }
+ }
+
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
@@ -5842,7 +5870,6 @@
int end = text.partialEndOffset;
if (end > N) end = N;
removeParcelableSpans(content, start, end);
- // If start > end, content.replace will swap them before using them.
content.replace(start, end, text.text);
}
}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index cbd9a6a..4f1cd68 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -146,6 +146,8 @@
private ActionMenuPresenter mOuterActionMenuPresenter;
private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
+ private boolean mCollapsible;
+
public Toolbar(Context context) {
this(context, null);
}
@@ -969,6 +971,23 @@
return child.getMeasuredWidth() + hMargins;
}
+ /**
+ * Returns true if the Toolbar is collapsible and has no child views with a measured size > 0.
+ */
+ private boolean shouldCollapse() {
+ if (!mCollapsible) return false;
+
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ if (shouldLayout(child) && child.getMeasuredWidth() > 0 &&
+ child.getMeasuredHeight() > 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = 0;
@@ -1093,7 +1112,8 @@
final int measuredHeight = resolveSizeAndState(
Math.max(height, getSuggestedMinimumHeight()),
heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT);
- setMeasuredDimension(measuredWidth, measuredHeight);
+
+ setMeasuredDimension(measuredWidth, shouldCollapse() ? 0 : measuredHeight);
}
@Override
@@ -1490,6 +1510,16 @@
}
/**
+ * Force the toolbar to collapse to zero-height during measurement if
+ * it could be considered "empty" (no visible elements with nonzero measured size)
+ * @hide
+ */
+ public void setCollapsible(boolean collapsible) {
+ mCollapsible = collapsible;
+ requestLayout();
+ }
+
+ /**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
*/
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 8a9cb22..ea36e37 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -246,6 +247,13 @@
}
@Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ init(getContext());
+ requestApplyInsets();
+ }
+
+ @Override
public void onWindowSystemUiVisibilityChanged(int visible) {
super.onWindowSystemUiVisibilityChanged(visible);
pullChildren();
@@ -329,7 +337,7 @@
// insets in all cases, we need to know the measured size of the various action
// bar elements. onApplyWindowInsets() happens before the measure pass, so we can't
// do that here. Instead we will take this up in onMeasure().
- return WindowInsets.EMPTY;
+ return WindowInsets.CONSUMED;
}
@Override
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index b298d85..7fb2efd 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -424,7 +424,7 @@
@Override
public void setCollapsible(boolean collapsible) {
- // Ignore
+ mToolbar.setCollapsible(collapsible);
}
@Override
@@ -480,7 +480,7 @@
private void ensureSpinner() {
if (mSpinner == null) {
- mSpinner = new Spinner(getContext());
+ mSpinner = new Spinner(getContext(), null, R.attr.actionDropDownStyle);
Toolbar.LayoutParams lp = new Toolbar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL);
mSpinner.setLayoutParams(lp);
@@ -569,7 +569,7 @@
@Override
public void setNavigationIcon(int resId) {
- setNavigationIcon(mToolbar.getContext().getDrawable(resId));
+ setNavigationIcon(resId != 0 ? mToolbar.getContext().getDrawable(resId) : null);
}
@Override
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index ddcc396..c588942 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -52,7 +52,7 @@
jfieldID stringType;
jfieldID requiredPermission;
jfieldID maxDelay;
- jfieldID isWakeUpSensor;
+ jfieldID flags;
} gSensorOffsets;
@@ -81,7 +81,7 @@
sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
"Ljava/lang/String;");
sensorOffsets.maxDelay = _env->GetFieldID(sensorClass, "mMaxDelay", "I");
- sensorOffsets.isWakeUpSensor = _env->GetFieldID(sensorClass, "mWakeUpSensor", "Z");
+ sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags", "I");
}
static jint
@@ -117,7 +117,7 @@
env->SetObjectField(sensor, sensorOffsets.requiredPermission,
requiredPermission);
env->SetIntField(sensor, sensorOffsets.maxDelay, list->getMaxDelay());
- env->SetBooleanField(sensor, sensorOffsets.isWakeUpSensor, list->isWakeUpSensor());
+ env->SetIntField(sensor, sensorOffsets.flags, list->getFlags());
next++;
return size_t(next) < count ? next : 0;
}
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 64b077b..ace17ec 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -87,14 +87,6 @@
layer->updateTexImage();
}
-static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject clazz,
- jlong layerUpdaterPtr, jlong displayListPtr,
- jint left, jint top, jint right, jint bottom) {
- DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
- RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
- layer->setDisplayList(displayList, left, top, right, bottom);
-}
-
static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
jlong layerUpdaterPtr) {
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
@@ -126,7 +118,6 @@
{ "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V",
(void*) android_view_HardwareLayer_setSurfaceTexture },
{ "nUpdateSurfaceTexture", "(J)V", (void*) android_view_HardwareLayer_updateSurfaceTexture },
- { "nUpdateRenderLayer", "(JJIIII)V", (void*) android_view_HardwareLayer_updateRenderLayer },
{ "nGetLayer", "(J)J", (void*) android_view_HardwareLayer_getLayer },
{ "nGetTexName", "(J)I", (void*) android_view_HardwareLayer_getTexName },
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index e5f79f2..3ffde2d 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -87,9 +87,16 @@
// RenderProperties - setters
// ----------------------------------------------------------------------------
-static jboolean android_view_RenderNode_setCaching(JNIEnv* env,
- jobject clazz, jlong renderNodePtr, jboolean caching) {
- return SET_AND_DIRTY(setCaching, caching, RenderNode::GENERIC);
+static jboolean android_view_RenderNode_setLayerType(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, jint jlayerType) {
+ LayerType layerType = static_cast<LayerType>(jlayerType);
+ return SET_AND_DIRTY(mutateLayerProperties().setType, layerType, RenderNode::GENERIC);
+}
+
+static jboolean android_view_RenderNode_setLayerPaint(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, jlong paintPtr) {
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+ return SET_AND_DIRTY(mutateLayerProperties().setFromPaint, paint, RenderNode::GENERIC);
}
static jboolean android_view_RenderNode_setStaticMatrix(JNIEnv* env,
@@ -275,13 +282,6 @@
return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
}
-static void android_view_RenderNode_setScrollPosition(JNIEnv* env,
- jobject clazz, jlong renderNodePtr, jint scrollX, jint scrollY) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- SET_AND_DIRTY(setScrollX, scrollX, RenderNode::GENERIC);
- SET_AND_DIRTY(setScrollY, scrollY, RenderNode::GENERIC);
-}
-
// ----------------------------------------------------------------------------
// RenderProperties - getters
// ----------------------------------------------------------------------------
@@ -482,7 +482,8 @@
{ "nOutput", "(J)V", (void*) android_view_RenderNode_output },
{ "nGetDebugSize", "(J)I", (void*) android_view_RenderNode_getDebugSize },
- { "nSetCaching", "(JZ)Z", (void*) android_view_RenderNode_setCaching },
+ { "nSetLayerType", "(JI)Z", (void*) android_view_RenderNode_setLayerType },
+ { "nSetLayerPaint", "(JJ)Z", (void*) android_view_RenderNode_setLayerPaint },
{ "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix },
{ "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix },
{ "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds },
@@ -517,7 +518,6 @@
{ "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
{ "nOffsetLeftAndRight", "(JF)Z", (void*) android_view_RenderNode_offsetLeftAndRight },
{ "nOffsetTopAndBottom", "(JF)Z", (void*) android_view_RenderNode_offsetTopAndBottom },
- { "nSetScrollPosition", "(JII)V", (void*) android_view_RenderNode_setScrollPosition },
{ "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering },
{ "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8e6c4a0..c0d5221 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -412,20 +412,12 @@
return err == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
-static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
+static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenObj, jint mode) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return;
- ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
- SurfaceComposerClient::blankDisplay(token);
-}
-
-static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
- sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
- if (token == NULL) return;
-
- ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
- SurfaceComposerClient::unblankDisplay(token);
+ ALOGD_IF_SLOW(100, "Excessive delay in setPowerMode()");
+ SurfaceComposerClient::setDisplayPowerMode(token, mode);
}
static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
@@ -628,10 +620,6 @@
(void*)nativeGetActiveConfig },
{"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveConfig },
- {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
- (void*)nativeBlankDisplay },
- {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
- (void*)nativeUnblankDisplay },
{"nativeClearContentFrameStats", "(J)Z",
(void*)nativeClearContentFrameStats },
{"nativeGetContentFrameStats", "(JLandroid/view/WindowContentFrameStats;)Z",
@@ -640,6 +628,8 @@
(void*)nativeClearAnimationFrameStats },
{"nativeGetAnimationFrameStats", "(Landroid/view/WindowAnimationFrameStats;)Z",
(void*)nativeGetAnimationFrameStats },
+ {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
+ (void*)nativeSetDisplayPowerMode },
};
int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3067cdd0..edca101 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -123,10 +123,30 @@
<protected-broadcast
android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
<protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AG_EVENT" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.RESULT" />
+ <protected-broadcast
+ android:name="android.bluetooth.headsetclient.profile.action.LAST_VTAG" />
+ <protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED" />
<protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED" />
@@ -2643,6 +2663,13 @@
android:label="@string/permlab_provide_trust_agent"
android:description="@string/permdesc_provide_trust_agent" />
+ <!-- Allows an application to launch the trust agent settings activity.
+ @hide -->
+ <permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
+ android:protectionLevel="signatureOrSystem"
+ android:label="@string/permlab_launch_trust_agent_settings"
+ android:description="@string/permdesc_launch_trust_agent_settings" />
+
<!-- Must be required by an {@link
android.service.trust.TrustAgentService},
to ensure that only the system can bind to it. -->
diff --git a/core/res/assets/images/android-logo-mask.png b/core/res/assets/images/android-logo-mask.png
index 3078b28..ad40645 100644
--- a/core/res/assets/images/android-logo-mask.png
+++ b/core/res/assets/images/android-logo-mask.png
Binary files differ
diff --git a/core/res/assets/images/android-logo-shine.png b/core/res/assets/images/android-logo-shine.png
index add6796..cb65f22 100644
--- a/core/res/assets/images/android-logo-shine.png
+++ b/core/res/assets/images/android-logo-shine.png
Binary files differ
diff --git a/core/res/res/anim-land/task_close_enter.xml b/core/res/res/anim-land/task_close_enter.xml
deleted file mode 100644
index facc42b..0000000
--- a/core/res/res/anim-land/task_close_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400"/>
-
- <translate android:fromXDelta="-120%" android:toXDelta="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="300"
- android:duration="400" />
-
- <scale android:fromXScale=".5" android:toXScale="1.0"
- android:fromYScale=".5" android:toYScale="1.0"
- android:pivotY="50%p" android:pivotX="0%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_close_exit.xml b/core/res/res/anim-land/task_close_exit.xml
deleted file mode 100644
index e104c33..0000000
--- a/core/res/res/anim-land/task_close_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300"/>
-
- <translate android:fromXDelta="0" android:toXDelta="120%"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="300"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.5"
- android:fromYScale="1.0" android:toYScale="0.5"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotY="50%p" android:pivotX="100%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300" />
-
- <!-- This is needed to keep the animation running while task_open_enter completes -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:duration="700" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_enter.xml b/core/res/res/anim-land/task_open_enter.xml
deleted file mode 100644
index dc7c7a9..0000000
--- a/core/res/res/anim-land/task_open_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400"/>
-
- <translate android:fromXDelta="120%" android:toXDelta="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="300"
- android:duration="400" />
-
- <scale android:fromXScale=".5" android:toXScale="1.0"
- android:fromYScale=".5" android:toYScale="1.0"
- android:pivotY="50%p" android:pivotX="100%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="300"
- android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-land/task_open_exit.xml b/core/res/res/anim-land/task_open_exit.xml
deleted file mode 100644
index 701afa6..0000000
--- a/core/res/res/anim-land/task_open_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300"/>
-
- <translate android:fromXDelta="0" android:toXDelta="-120%"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="300"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.5"
- android:fromYScale="1.0" android:toYScale="0.5"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotY="50%p" android:pivotX="0%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="300" />
-
- <!-- This is needed to keep the animation running while task_open_enter completes -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:duration="700" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_enter.xml b/core/res/res/anim-sw720dp/task_close_enter.xml
deleted file mode 100644
index e25978b..0000000
--- a/core/res/res/anim-sw720dp/task_close_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="500"
- android:duration="400"/>
-
- <translate android:fromYDelta="-50%" android:toYDelta="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="500"
- android:duration="400" />
-
- <scale android:fromXScale=".8" android:toXScale="1.0"
- android:fromYScale=".8" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="0%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="500"
- android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_close_exit.xml b/core/res/res/anim-sw720dp/task_close_exit.xml
deleted file mode 100644
index 2d7e2a6..0000000
--- a/core/res/res/anim-sw720dp/task_close_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
-
- <translate android:fromYDelta="0" android:toYDelta="50%"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="350"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.8"
- android:fromYScale="1.0" android:toYScale="0.8"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="100%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="350" />
-
- <!-- This is needed to keep the animation running while task_close_enter completes -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:duration="900" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_enter.xml b/core/res/res/anim-sw720dp/task_open_enter.xml
deleted file mode 100644
index d583b6e..0000000
--- a/core/res/res/anim-sw720dp/task_open_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
-
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="500"
- android:duration="400"/>
-
- <translate android:fromYDelta="50%" android:toYDelta="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="500"
- android:duration="400" />
-
- <scale android:fromXScale=".8" android:toXScale="1.0"
- android:fromYScale=".8" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="100%p"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quad"
- android:startOffset="500"
- android:duration="400" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/anim-sw720dp/task_open_exit.xml b/core/res/res/anim-sw720dp/task_open_exit.xml
deleted file mode 100644
index dd25a0c..0000000
--- a/core/res/res/anim-sw720dp/task_open_exit.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
-
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="350"/>
-
- <translate android:fromYDelta="0" android:toYDelta="-50%"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="350"/>
-
- <scale android:fromXScale="1.0" android:toXScale="0.8"
- android:fromYScale="1.0" android:toYScale="0.8"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="0%p"
- android:interpolator="@interpolator/accelerate_quad"
- android:duration="350" />
-
- <!-- This is needed to keep the animation running while task_open_enter completes -->
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:duration="900" />
-</set>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..0c3c3b4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_blue.9.png b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
new file mode 100755
index 0000000..b991535
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_green.9.png b/core/res/res/drawable-hdpi/sim_dark_green.9.png
new file mode 100755
index 0000000..c8de61d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_orange.9.png b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
new file mode 100755
index 0000000..10347e8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_purple.9.png b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
new file mode 100755
index 0000000..ac4ee01
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_blue.9.png b/core/res/res/drawable-hdpi/sim_light_blue.9.png
new file mode 100755
index 0000000..b2c5581
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_green.9.png b/core/res/res/drawable-hdpi/sim_light_green.9.png
new file mode 100755
index 0000000..4d29c81
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_orange.9.png b/core/res/res/drawable-hdpi/sim_light_orange.9.png
new file mode 100755
index 0000000..68c6c2f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_purple.9.png b/core/res/res/drawable-hdpi/sim_light_purple.9.png
new file mode 100755
index 0000000..4deb8dc5
--- /dev/null
+++ b/core/res/res/drawable-hdpi/sim_light_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..8322ae3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_blue.9.png b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
new file mode 100755
index 0000000..d646a7f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_green.9.png b/core/res/res/drawable-mdpi/sim_dark_green.9.png
new file mode 100755
index 0000000..ee4ea0d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_orange.9.png b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
new file mode 100755
index 0000000..b394999
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_purple.9.png b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
new file mode 100755
index 0000000..459b5d69
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_blue.9.png b/core/res/res/drawable-mdpi/sim_light_blue.9.png
new file mode 100755
index 0000000..396ad70
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_blue.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_green.9.png b/core/res/res/drawable-mdpi/sim_light_green.9.png
new file mode 100755
index 0000000..a063174
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_green.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_orange.9.png b/core/res/res/drawable-mdpi/sim_light_orange.9.png
new file mode 100755
index 0000000..95ea88e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_orange.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_purple.9.png b/core/res/res/drawable-mdpi/sim_light_purple.9.png
new file mode 100755
index 0000000..b1bd35f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/sim_light_purple.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..e6c0047
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png b/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png
new file mode 100644
index 0000000..bb9debb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/dialog_background_mtrl_mult.9.png
Binary files differ
diff --git a/core/res/res/drawable/dialog_background_shadow_material.xml b/core/res/res/drawable/dialog_background_shadow_material.xml
new file mode 100644
index 0000000..0554920
--- /dev/null
+++ b/core/res/res/drawable/dialog_background_shadow_material.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/dialog_background_mtrl_mult"
+ android:tint="?attr/colorBackground"
+ android:tintMode="multiply" />
diff --git a/core/res/res/layout/dialog_custom_title_material.xml b/core/res/res/layout/dialog_custom_title_material.xml
index 1bb93eb..550b72e 100644
--- a/core/res/res/layout/dialog_custom_title_material.xml
+++ b/core/res/res/layout/dialog_custom_title_material.xml
@@ -23,6 +23,7 @@
android:fitsSystemWindows="true">
<FrameLayout android:id="@android:id/title_container"
android:layout_width="match_parent"
+ android:layout_height="?android:attr/windowTitleSize"
android:layout_weight="0"
android:gravity="center_vertical|start"
style="?android:attr/windowTitleBackgroundStyle" />
diff --git a/core/res/res/layout/dialog_title_material.xml b/core/res/res/layout/dialog_title_material.xml
index b92c1e7..918c8f1 100644
--- a/core/res/res/layout/dialog_title_material.xml
+++ b/core/res/res/layout/dialog_title_material.xml
@@ -22,7 +22,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
- <TextView android:id="@+id/alertTitle"
+ <TextView android:id="@+id/title"
style="?android:attr/windowTitleStyle"
android:singleLine="true"
android:ellipsize="end"
diff --git a/core/res/res/layout/preference_material.xml b/core/res/res/layout/preference_material.xml
index a4fe73d..a9599139 100644
--- a/core/res/res/layout/preference_material.xml
+++ b/core/res/res/layout/preference_material.xml
@@ -31,7 +31,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="58dip"
- android:gravity="left|center_vertical"
+ android:gravity="start|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+android:id/icon"
diff --git a/core/res/res/layout/subscription_item_layout.xml b/core/res/res/layout/subscription_item_layout.xml
new file mode 100755
index 0000000..9f8f2b3
--- /dev/null
+++ b/core/res/res/layout/subscription_item_layout.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright (C) 2014 MediaTek 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" >
+ <RelativeLayout
+ android:layout_width="48dip"
+ android:layout_height="32dip"
+ android:id="@+id/sub_color"
+ android:layout_marginEnd="6dip"
+ android:layout_centerVertical="true">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/sub_short_number"
+ android:layout_marginBottom="2dip"
+ android:layout_marginEnd="4dip"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentBottom="true"
+ android:textSize="12sp"
+ android:singleLine="true"
+ android:textColor="@android:color/white"
+ android:includeFontPadding="false"/>
+ </RelativeLayout>
+ <RelativeLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_centerVertical="true">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/sub_name"
+ android:singleLine="true"
+ android:ellipsize="none"
+ android:requiresFadingEdge="horizontal"
+ android:scrollHorizontally="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/sub_number"
+ android:layout_below="@+id/sub_name"
+ android:layout_alignStart="@+id/sub_name"
+ android:singleLine="true"
+ android:ellipsize="none"
+ android:requiresFadingEdge="horizontal"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"/>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/values-large/themes.xml b/core/res/res/values-large/themes.xml
deleted file mode 100644
index 8c8f86c..0000000
--- a/core/res/res/values-large/themes.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2010, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!--
-===============================================================
- PLEASE READ
-===============================================================
-
-The Holo themes must not be modified in order to pass CTS.
-Many related themes and styles depend on other values defined in this file.
-If you would like to provide custom themes and styles for your device,
-please see themes_device_defaults.xml.
-
-===============================================================
- PLEASE READ
-===============================================================
- -->
-<resources>
- <style name="Theme.Holo.DialogWhenLarge"
- parent="@android:style/Theme.Holo.Dialog.FixedSize">
- <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
- </style>
- <style name="Theme.Holo.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.Holo.Dialog.NoActionBar.FixedSize">
- <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
- </style>
- <style name="Theme.Holo.Light.DialogWhenLarge"
- parent="@android:style/Theme.Holo.Light.Dialog.FixedSize">
- </style>
- <style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.Holo.Light.Dialog.NoActionBar.FixedSize">
- </style>
-
- <style name="Theme.Material.DialogWhenLarge"
- parent="@android:style/Theme.Material.Dialog.FixedSize">
- <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
- </style>
- <style name="Theme.Material.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.Material.Dialog.NoActionBar.FixedSize">
- <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
- </style>
- <style name="Theme.Material.Light.DialogWhenLarge"
- parent="@android:style/Theme.Material.Light.Dialog.FixedSize">
- </style>
- <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.Material.Light.Dialog.NoActionBar.FixedSize">
- </style>
-</resources>
diff --git a/core/res/res/values-large/themes_device_defaults.xml b/core/res/res/values-large/themes_device_defaults.xml
index d57e827..d252c27 100644
--- a/core/res/res/values-large/themes_device_defaults.xml
+++ b/core/res/res/values-large/themes_device_defaults.xml
@@ -31,18 +31,12 @@
===============================================================
-->
<resources>
- <style name="Theme.DeviceDefault.DialogWhenLarge"
- parent="@android:style/Theme.DeviceDefault.Dialog.FixedSize">
+ <style name="Theme.DeviceDefault.DialogWhenLarge" parent="@style/Theme.DeviceDefault.Dialog.FixedSize">
<item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
</style>
- <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
+ <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
<item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
</style>
- <style name="Theme.DeviceDefault.Light.DialogWhenLarge"
- parent="@android:style/Theme.DeviceDefault.Light.Dialog.FixedSize">
- </style>
- <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
- </style>
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="@style/Theme.DeviceDefault.Light.Dialog.FixedSize" />
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize" />
</resources>
diff --git a/core/res/res/values-large/themes_holo.xml b/core/res/res/values-large/themes_holo.xml
new file mode 100644
index 0000000..3f03932
--- /dev/null
+++ b/core/res/res/values-large/themes_holo.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Holo themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+ <style name="Theme.Holo.DialogWhenLarge" parent="@style/Theme.Holo.Dialog.FixedSize">
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+ <style name="Theme.Holo.DialogWhenLarge.NoActionBar" parent="@style/Theme.Holo.Dialog.NoActionBar.FixedSize">
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+ <style name="Theme.Holo.Light.DialogWhenLarge" parent="@style/Theme.Holo.Light.Dialog.FixedSize" />
+ <style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Holo.Light.Dialog.NoActionBar.FixedSize" />
+</resources>
diff --git a/core/res/res/values-large/themes_material.xml b/core/res/res/values-large/themes_material.xml
new file mode 100644
index 0000000..2781608
--- /dev/null
+++ b/core/res/res/values-large/themes_material.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see themes_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+ <style name="Theme.Material.DialogWhenLarge" parent="@style/Theme.Material.Dialog.FixedSize">
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+ <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Dialog.NoActionBar.FixedSize">
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+ <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light.Dialog.FixedSize" />
+ <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.Dialog.NoActionBar.FixedSize" />
+</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2fea91e..5213896 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -496,6 +496,12 @@
<!-- Internal layout used internally for window decor -->
<attr name="windowActionBarFullscreenDecorLayout" format="reference" />
+ <!-- The duration, in milliseconds, of the window background fade duration
+ when transitioning into or away from an Activity when called with an
+ Activity Transition. Corresponds to
+ {@link android.view.Window#setTransitionBackgroundFadeDuration(long)}. -->
+ <attr name="windowTransitionBackgroundFadeDuration" format="integer"/>
+
<!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
@@ -1813,6 +1819,11 @@
Corresponds to {@link android.view.Window#setNavigationBarColor(int)}. -->
<attr name="navigationBarColor" format="color" />
+ <!-- The duration, in milliseconds, of the window background fade duration
+ when transitioning into or away from an Activity when called with an
+ Activity Transition. Corresponds to
+ {@link android.view.Window#setTransitionBackgroundFadeDuration(long)}. -->
+ <attr name="windowTransitionBackgroundFadeDuration" />
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -3859,8 +3870,11 @@
<attr name="inputType" />
</declare-styleable>
<declare-styleable name="PopupWindow">
+ <!-- The background to use for the popup window. -->
<attr name="popupBackground" format="reference|color" />
+ <!-- The animation style to use for the popup window. -->
<attr name="popupAnimationStyle" format="reference" />
+ <!-- Whether the popup window should overlap its anchor view. -->
<attr name="overlapAnchor" format="boolean" />
</declare-styleable>
<declare-styleable name="ViewAnimator">
@@ -4772,7 +4786,7 @@
</declare-styleable>
<!-- ========================== -->
- <!-- Vector drawable class -->
+ <!-- VectorDrawable class -->
<!-- ========================== -->
<eat-comment />
@@ -4792,7 +4806,7 @@
<attr name="height" />
</declare-styleable>
- <!-- Defines the group used in Vector Drawables. -->
+ <!-- Defines the group used in VectorDrawables. -->
<declare-styleable name="VectorDrawableGroup">
<!-- The Name of this group -->
<attr name="name" />
@@ -4814,7 +4828,7 @@
<attr name="alpha" />
</declare-styleable>
- <!-- Defines the path used in Vector Drawables. -->
+ <!-- Defines the path used in VectorDrawables. -->
<declare-styleable name="VectorDrawablePath">
<!-- The Name of this path -->
<attr name="name" />
@@ -4855,6 +4869,25 @@
</declare-styleable>
<!-- ========================== -->
+ <!-- AnimatedVectorDrawable class -->
+ <!-- ========================== -->
+ <eat-comment />
+
+ <!-- Define the AnimatedVectorDrawable. -->
+ <declare-styleable name="AnimatedVectorDrawable">
+ <!-- The static vector drawable. -->
+ <attr name="drawable" />
+ </declare-styleable>
+
+ <!-- Defines the target path or group used in the AnimatedVectorDrawable. -->
+ <declare-styleable name="AnimatedVectorDrawableTarget">
+ <!-- The name of this target path or group -->
+ <attr name="name" />
+ <!-- The animation for this target path or group -->
+ <attr name="animation" />
+ </declare-styleable>
+
+ <!-- ========================== -->
<!-- Animation class attributes -->
<!-- ========================== -->
<eat-comment />
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index fdbe0a0..7371d4e 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -27,10 +27,10 @@
<color name="bright_foreground_material_dark">@color/white</color>
<color name="bright_foreground_material_light">@color/black</color>
- <!-- Black 50% -->
- <color name="bright_foreground_disabled_material_dark">#80000000</color>
<!-- White 50% -->
- <color name="bright_foreground_disabled_material_light">#80ffffff</color>
+ <color name="bright_foreground_disabled_material_dark">#80ffffff</color>
+ <!-- Black 50% -->
+ <color name="bright_foreground_disabled_material_light">#80000000</color>
<color name="bright_foreground_inverse_material_dark">@color/bright_foreground_material_light</color>
<color name="bright_foreground_inverse_material_light">@color/bright_foreground_material_dark</color>
@@ -89,6 +89,9 @@
<color name="material_teal_A200">#ff18ffff</color>
<color name="material_teal_A400">#ff00e5ff</color>
+ <!-- Accent color used by Settings -->
+ <color name="material_dark_teal_A400">#ff009688</color>
+
<color name="material_green_100">#ffb7e1cd</color>
<color name="material_green_300">#ff57bb8a</color>
<color name="material_green_500">#ff0f9d58</color>
@@ -143,7 +146,10 @@
<color name="material_blue_grey_600">#ff546e7a</color>
<color name="material_blue_grey_700">#ff455a64</color>
<color name="material_blue_grey_800">#ff37474f</color>
+ <!-- Primary color used by Settings -->
<color name="material_blue_grey_900">#ff263238</color>
+ <!-- Primary dark color used by Settings -->
+ <color name="material_blue_grey_950">#ff21272b</color>
<color name="material_brown_100">#ffd7ccc8</color>
<color name="material_brown_300">#ffa1887f</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9ff9b11..a4f78bd 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -791,6 +791,19 @@
config_enableFusedLocationOverlay is false. -->
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
+ <!-- Whether to enable Hardware FLP overlay which allows Hardware FLP to be
+ replaced by an app at run-time. When disabled, only the
+ config_hardwareFlpPackageName package will be searched for Hardware Flp,
+ otherwise packages whose signature matches the signatures of
+ config_locationProviderPackageNames will be searched, and the service
+ with the highest version number will be picked. Anyone who wants to
+ disable the overlay mechanism can set it to false.
+ -->
+ <bool name="config_enableHardwareFlpOverlay" translatable="false">true</bool>
+ <!-- Package name providing Hardware Flp. Used only when
+ config_enableHardwareFlpOverlay is false. -->
+ <string name="config_hardwareFlpPackageName" translatable="false">com.android.location.fused</string>
+
<!-- Whether to enable geocoder overlay which allows geocoder to be replaced
by an app at run-time. When disabled, only the
config_geocoderProviderPackageName package will be searched for
@@ -1561,4 +1574,28 @@
<item>users</item>
</string-array>
+ <!-- default telephony hardware configuration for this platform.
+ -->
+ <!-- this string array should be overridden by the device to present a list
+ telephony hardware resource. this is used by the telephony device controller
+ (TDC) to offer the basic capabilities of the hardware to the telephony
+ framework
+ -->
+ <!-- an array of "[hardware type],[hardware-uuid],[state],[[hardware-type specific]]"
+ with, [[hardware-type specific]] in:
+ - "[[ril-model],[rat],[max-active-voice],[max-active-data],[max-active-standby]]"
+ for 'modem' hardware
+ - "[[associated-modem-uuid]]"
+ for 'sim' hardware.
+ refer to HardwareConfig in com.android.internal.telephony for specific details/values
+ those elements can carry.
+ -->
+ <string-array translatable="false" name="config_telephonyHardware">
+ <!-- modem -->
+ <item>"0,modem,0,0,0,1,1,1"</item>
+ <!-- sim -->
+ <item>"1,sim,0,modem"</item>
+ </string-array>
+
+
</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index be7e6c1..18e4574 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -15,6 +15,11 @@
-->
<resources>
+ <!-- Preference fragment padding, sides -->
+ <dimen name="preference_fragment_padding_side_material">0dp</dimen>
+
+ <dimen name="preference_screen_header_padding_side_material">0dp</dimen>
+
<!-- Default height of an action bar. -->
<dimen name="action_bar_default_height_material">56dp</dimen>
<!-- Default padding of an action bar. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2792c93..202c127 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2188,6 +2188,8 @@
<public type="attr" name="searchKeyphraseId" />
<public type="attr" name="searchKeyphrase" />
<public type="attr" name="searchKeyphraseSupportedLocales" />
+ <public type="attr" name="windowTransitionBackgroundFadeDuration" />
+ <public type="attr" name="overlapAnchor" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
@@ -2251,6 +2253,8 @@
<public type="style" name="TextAppearance.Material.Widget.TextView.PopupMenu" />
<public type="style" name="TextAppearance.Material.Widget.TextView.SpinnerItem" />
+ <public type="style" name="Theme.DeviceDefault.Settings" />
+
<public type="style" name="Theme.Material" />
<public type="style" name="Theme.Material.Dialog" />
<public type="style" name="Theme.Material.Dialog.MinWidth" />
@@ -2264,6 +2268,7 @@
<public type="style" name="Theme.Material.NoActionBar.Overscan" />
<public type="style" name="Theme.Material.NoActionBar.TranslucentDecor" />
<public type="style" name="Theme.Material.Panel" />
+ <public type="style" name="Theme.Material.Settings" />
<public type="style" name="Theme.Material.Voice" />
<public type="style" name="Theme.Material.Wallpaper" />
<public type="style" name="Theme.Material.Wallpaper.NoTitleBar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f1d9dc3..6e1b5ef 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -460,7 +460,7 @@
<string name="user_owner_label">Personal apps</string>
<!-- Label for a corporate profile in the intent forwarding app. -->
- <string name="managed_profile_label">Android for Work</string>
+ <string name="managed_profile_label">Android Work</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_costMoney">Services that cost you money</string>
@@ -3795,6 +3795,8 @@
<string name="permlab_provide_trust_agent">Provide a trust agent.</string>
<!-- Description of an application permission that lets it provide a trust agent. -->
<string name="permdesc_provide_trust_agent">Allows an application to provide a trust agent.</string>
+ <string name="permlab_launch_trust_agent_settings">Lunch trust agent settings menu.</string>
+ <string name="permdesc_launch_trust_agent_settings">Allows an application to lunch an activity that changes the trust agent behavior.</string>
<!-- Title of an application permission that lets it bind to a trust agent service. -->
<string name="permlab_bind_trust_agent_service">Bind to a trust agent service</string>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index a40835c..0c95149 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -37,8 +37,8 @@
</style>
<style name="PreferenceFragment.Material">
- <item name="paddingStart">@dimen/preference_fragment_padding_side</item>
- <item name="paddingEnd">@dimen/preference_fragment_padding_side</item>
+ <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
+ <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
</style>
<style name="Preference.Material.Information">
@@ -86,6 +86,38 @@
<item name="showDefault">true</item>
</style>
+ <!-- No margins or background by default. Could be different for x-large screens -->
+ <style name="PreferencePanel.Material">
+ </style>
+
+ <!-- The attributes are overridden here because the x-large or large resources may have
+ changed the margins and background in the parent PreferencePanel style. -->
+ <style name="PreferencePanel.Material.Dialog">
+ <item name="layout_marginStart">0dip</item>
+ <item name="layout_marginEnd">0dip</item>
+ <item name="layout_marginTop">0dip</item>
+ <item name="layout_marginBottom">0dip</item>
+ <item name="background">@null</item>
+ </style>
+
+ <style name="PreferenceHeaderPanel.Material">
+ <item name="layout_marginStart">@dimen/preference_screen_side_margin</item>
+ <item name="layout_marginEnd">@dimen/preference_screen_side_margin_negative</item>
+ <item name="paddingTop">@dimen/preference_screen_header_vertical_padding</item>
+ <item name="paddingBottom">@dimen/preference_screen_header_vertical_padding</item>
+ </style>
+
+ <style name="PreferenceHeaderList.Material">
+ <item name="paddingStart">@dimen/preference_screen_header_padding_side_material</item>
+ <item name="paddingEnd">@dimen/preference_screen_header_padding_side_material</item>
+ <item name="scrollbarStyle">@integer/preference_screen_header_scrollbarStyle</item>
+ </style>
+
+ <style name="PreferenceFragmentList.Material">
+ <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
+ <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
+ </style>
+
<!-- Begin Material theme styles -->
<!-- Text styles -->
@@ -344,8 +376,7 @@
<item name="android:textColor">#66000000</item>
</style>
- <style name="Widget.StatusBar.Material.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal">
- </style>
+ <style name="Widget.StatusBar.Material.ProgressBar" parent="Widget.Material.Light.ProgressBar.Horizontal" />
<style name="Widget.StatusBar.Material.ProgressBar.Media">
<item name="android:progressDrawable">@drawable/notification_material_media_progress</item>
@@ -625,6 +656,7 @@
<style name="Widget.Material.Spinner.DropDown.ActionBar">
<item name="background">@drawable/spinner_background_material</item>
+ <item name="overlapAnchor">true</item>
</style>
<style name="Widget.Material.TabWidget" parent="Widget.TabWidget">
@@ -963,12 +995,17 @@
<!-- Window title -->
<style name="WindowTitleBackground.Material">
<item name="background">@null</item>
+ <item name="paddingStart">16dp</item>
+ <item name="paddingEnd">16dp</item>
+ <item name="paddingTop">16dp</item>
</style>
<style name="WindowTitle.Material">
<item name="singleLine">true</item>
<item name="textAppearance">@style/TextAppearance.Material.WindowTitle</item>
<item name="shadowRadius">0</item>
+ <item name="ellipsize">end</item>
+ <item name="textAlignment">viewStart</item>
</style>
<style name="DialogWindowTitle.Material">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f2550ab..d69f60a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -999,6 +999,7 @@
<java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" />
<java-symbol type="array" name="config_callBarringMMI" />
<java-symbol type="array" name="config_globalActionsList" />
+ <java-symbol type="array" name="config_telephonyHardware" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="indicator_input_error" />
@@ -1122,6 +1123,15 @@
<java-symbol type="drawable" name="ic_corp_badge" />
<java-symbol type="drawable" name="ic_corp_icon_badge" />
+ <java-symbol type="drawable" name="sim_light_blue" />
+ <java-symbol type="drawable" name="sim_light_green" />
+ <java-symbol type="drawable" name="sim_light_orange" />
+ <java-symbol type="drawable" name="sim_light_purple" />
+ <java-symbol type="drawable" name="sim_dark_blue" />
+ <java-symbol type="drawable" name="sim_dark_green" />
+ <java-symbol type="drawable" name="sim_dark_orange" />
+ <java-symbol type="drawable" name="sim_dark_purple" />
+
<java-symbol type="layout" name="action_bar_home" />
<java-symbol type="layout" name="action_bar_title_item" />
<java-symbol type="layout" name="action_menu_item_layout" />
@@ -1462,6 +1472,7 @@
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
+ <java-symbol type="bool" name="config_enableHardwareFlpOverlay" />
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
<java-symbol type="bool" name="config_enableNetworkLocationOverlay" />
@@ -1553,6 +1564,7 @@
<java-symbol type="string" name="chooser_wallpaper" />
<java-symbol type="string" name="config_datause_iface" />
<java-symbol type="string" name="config_fusedLocationProviderPackageName" />
+ <java-symbol type="string" name="config_hardwareFlpPackageName" />
<java-symbol type="string" name="config_geocoderProviderPackageName" />
<java-symbol type="string" name="config_geofenceProviderPackageName" />
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 6b7d861..27c8754 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -555,4 +555,7 @@
<style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar" />
+ <!-- DeviceDefault theme for a window that should look like the Settings app. -->
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings" />
+
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 1304d2b..769c8a1 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -154,7 +154,7 @@
<item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@style/WindowTitle.Material</item>
- <item name="windowTitleSize">25dip</item>
+ <item name="windowTitleSize">@dimen/action_bar_default_height_material</item>
<item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
<item name="windowContentTransitions">false</item>
<item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
@@ -277,7 +277,6 @@
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
- <item name="preferenceFragmentPaddingSide">0dip</item>
<item name="preferenceCategoryStyle">@style/Preference.Material.Category</item>
<item name="preferenceStyle">@style/Preference.Material</item>
<item name="preferenceInformationStyle">@style/Preference.Material.Information</item>
@@ -288,6 +287,11 @@
<item name="editTextPreferenceStyle">@style/Preference.Material.DialogPreference.EditTextPreference</item>
<item name="ringtonePreferenceStyle">@style/Preference.Material.RingtonePreference</item>
<item name="preferenceLayoutChild">@layout/preference_child_material</item>
+ <item name="preferencePanelStyle">@style/PreferencePanel.Material</item>
+ <item name="preferenceHeaderPanelStyle">@style/PreferenceHeaderPanel.Material</item>
+ <item name="preferenceListStyle">@style/PreferenceHeaderList.Material</item>
+ <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
+ <item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side_material</item>
<item name="detailsElementBackground">?attr/colorBackground</item>
<!-- Search widget styles -->
@@ -503,7 +507,7 @@
<item name="windowContentOverlay">@drawable/ab_solid_shadow_material</item>
<item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@style/WindowTitle.Material</item>
- <item name="windowTitleSize">25dip</item>
+ <item name="windowTitleSize">@dimen/action_bar_default_height_material</item>
<item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
<item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
<item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
@@ -513,6 +517,9 @@
<item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
<item name="statusBarColor">?attr/colorPrimaryDark</item>
<item name="navigationBarColor">@color/black</item>
+ <item name="windowEnterTransition">@transition/fade</item>
+ <item name="windowSharedElementEnterTransition">@transition/move</item>
+ <item name="windowSharedElementExitTransition">@transition/move</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.Material.Light.Dialog</item>
@@ -622,7 +629,6 @@
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
- <item name="preferenceFragmentPaddingSide">0dip</item>
<item name="preferenceCategoryStyle">@style/Preference.Material.Category</item>
<item name="preferenceStyle">@style/Preference.Material</item>
<item name="preferenceInformationStyle">@style/Preference.Material.Information</item>
@@ -633,6 +639,11 @@
<item name="editTextPreferenceStyle">@style/Preference.Material.DialogPreference.EditTextPreference</item>
<item name="ringtonePreferenceStyle">@style/Preference.Material.RingtonePreference</item>
<item name="preferenceLayoutChild">@layout/preference_child_material</item>
+ <item name="preferencePanelStyle">@style/PreferencePanel.Material</item>
+ <item name="preferenceHeaderPanelStyle">@style/PreferenceHeaderPanel.Material</item>
+ <item name="preferenceListStyle">@style/PreferenceHeaderList.Material</item>
+ <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
+ <item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side_material</item>
<item name="detailsElementBackground">?attr/colorBackground</item>
<!-- PreferenceFrameLayout attributes -->
@@ -1006,7 +1017,7 @@
<style name="Theme.Material.Dialog">
<item name="windowFrame">@null</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
- <item name="windowBackground">@drawable/dialog_background_material</item>
+ <item name="windowBackground">@drawable/dialog_background_shadow_material</item>
<item name="windowIsFloating">true</item>
<item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
@@ -1102,18 +1113,15 @@
<!-- Theme for a window that will be displayed either full-screen on
smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
- <style name="Theme.Material.DialogWhenLarge" parent="@style/Theme.Material">
- </style>
+ <style name="Theme.Material.DialogWhenLarge" parent="@style/Theme.Material" />
<!-- Theme for a window without a title bar that will be displayed either
full-screen on smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
- <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.NoActionBar">
- </style>
+ <style name="Theme.Material.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.NoActionBar" />
<!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Material.Dialog.Presentation" parent="@style/Theme.Material.NoActionBar.Fullscreen">
- </style>
+ <style name="Theme.Material.Dialog.Presentation" parent="@style/Theme.Material.NoActionBar.Fullscreen" />
<!-- Light material dialog themes -->
@@ -1125,7 +1133,7 @@
<style name="Theme.Material.Light.Dialog">
<item name="windowFrame">@null</item>
<item name="windowTitleStyle">@style/DialogWindowTitle.Material.Light</item>
- <item name="windowBackground">?attr/colorBackground</item>
+ <item name="windowBackground">@drawable/dialog_background_shadow_material</item>
<item name="windowIsFloating">true</item>
<item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
@@ -1189,15 +1197,12 @@
<!-- Theme for a window that will be displayed either full-screen on
smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
- <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light">
- </style>
+ <style name="Theme.Material.Light.DialogWhenLarge" parent="@style/Theme.Material.Light" />
<!-- Theme for a window without an action bar that will be displayed either full-screen
on smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
- <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar"
- parent="@style/Theme.Material.Light.NoActionBar">
- </style>
+ <style name="Theme.Material.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.Material.Light.NoActionBar" />
<!-- Material light theme for alert dialog windows, which is used by the
{@link android.app.AlertDialog} class. This is basically a dialog
@@ -1219,8 +1224,7 @@
</style>
<!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" >
- </style>
+ <style name="Theme.Material.Light.Dialog.Presentation" parent="@style/Theme.Material.Light.NoActionBar.Fullscreen" />
<!-- Default material (dark) for windows that want to have the user's selected
wallpaper appear behind them. -->
@@ -1236,4 +1240,11 @@
<item name="windowNoTitle">true</item>
</style>
+ <!-- Default theme for Settings and activities launched from Settings. -->
+ <style name="Theme.Material.Settings" parent="@style/Theme.Material.Light.DarkActionBar">
+ <item name="colorPrimary">@color/material_blue_grey_900</item>
+ <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
+ <item name="colorAccent">@color/material_dark_teal_A400</item>
+ </style>
+
</resources>
diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java
index 814ecdd..7bc3974 100644
--- a/core/tests/coretests/src/android/net/LinkAddressTest.java
+++ b/core/tests/coretests/src/android/net/LinkAddressTest.java
@@ -30,6 +30,7 @@
import android.net.LinkAddress;
import android.os.Parcel;
import android.test.AndroidTestCase;
+import static android.test.MoreAsserts.assertNotEqual;
import android.test.suitebuilder.annotation.SmallTest;
import static android.system.OsConstants.IFA_F_DEPRECATED;
@@ -50,6 +51,17 @@
private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
+ public void testConstants() {
+ // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
+ assertNotEqual(0, RT_SCOPE_HOST);
+ assertNotEqual(0, RT_SCOPE_LINK);
+ assertNotEqual(0, RT_SCOPE_SITE);
+
+ assertNotEqual(0, IFA_F_DEPRECATED);
+ assertNotEqual(0, IFA_F_PERMANENT);
+ assertNotEqual(0, IFA_F_TENTATIVE);
+ }
+
public void testConstructors() throws SocketException {
LinkAddress address;
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
index 01283a6..c80d0bf 100644
--- a/core/tests/coretests/src/android/net/RouteInfoTest.java
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -71,17 +71,19 @@
}
public void testMatches() {
- class PatchedRouteInfo extends RouteInfo {
+ class PatchedRouteInfo {
+ private final RouteInfo mRouteInfo;
+
public PatchedRouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
- super(destination, gateway, iface);
+ mRouteInfo = new RouteInfo(destination, gateway, iface);
}
public boolean matches(InetAddress destination) {
- return super.matches(destination);
+ return mRouteInfo.matches(destination);
}
}
- RouteInfo r;
+ PatchedRouteInfo r;
r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
@@ -96,11 +98,11 @@
assertFalse(r.matches(Address("192.0.0.21")));
assertFalse(r.matches(Address("8.8.8.8")));
- RouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
+ PatchedRouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
assertFalse(ipv6Default.matches(Address("192.0.2.1")));
- RouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
+ PatchedRouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
assertTrue(ipv4Default.matches(Address("255.255.255.255")));
assertTrue(ipv4Default.matches(Address("192.0.2.1")));
assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
diff --git a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
index 7d72f3e..d850c7c 100644
--- a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
+++ b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
@@ -21,7 +21,7 @@
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.inputmethod.CursorAnchorInfo;
-import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
+import android.view.inputmethod.CursorAnchorInfo.Builder;
public class CursorAnchorInfoTest extends InstrumentationTestCase {
// null represents a character that is invisible, for example because it's overlapped by some
@@ -64,7 +64,7 @@
Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
- final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+ final Builder builder = new Builder();
builder.setSelectionRange(SELECTION_START, SELECTION_END)
.setComposingText(COMPOSING_TEXT_START, COMPOSING_TEXT)
.setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
@@ -148,7 +148,7 @@
final Matrix MATRIX3 = new Matrix();
MATRIX3.setTranslate(210.0f, 220.0f);
final Matrix matrix = new Matrix();
- final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+ final Builder builder = new Builder();
matrix.set(MATRIX1);
builder.setMatrix(matrix);
@@ -171,7 +171,7 @@
public void testBuilderAdd() throws Exception {
// A negative index should be rejected.
try {
- new CursorAnchorInfoBuilder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
+ new Builder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
} catch (IllegalArgumentException ex) {
assertTrue(true);
}
@@ -191,4 +191,3 @@
}
}
}
-
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 0a234aa..ff08312 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -564,7 +564,11 @@
<li><a href="<?cs var:toroot ?>guide/practices/tablets-and-handsets.html">
<span class="en">Supporting Tablets and Handsets</span>
</a></li>
-
+ <li>
+ <a href="<?cs var:toroot ?>guide/practices/verifying-apps-art.html">
+ <span class="en">Verifying App Behavior on ART</span>
+ </a>
+ </li>
</ul>
</li>
diff --git a/docs/html/guide/practices/verifying-apps-art.jd b/docs/html/guide/practices/verifying-apps-art.jd
new file mode 100644
index 0000000..0eedfaf
--- /dev/null
+++ b/docs/html/guide/practices/verifying-apps-art.jd
@@ -0,0 +1,296 @@
+page.title=Verifying App Behavior on the Android Runtime (ART)
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Quickview</h2>
+ <ul>
+ <li>The new Android runtime (ART) is available on some of the newest Android
+ devices, though all of them currently have Dalvik as the default
+ runtime.</li>
+ <li>App developers should make sure their apps are compatible with ART,
+ especially if you use JNI to run native code or if you use certain tools
+ that produce non-standard code (such as some obfuscators).</li>
+ </ul>
+
+ <h2 id="Contents">In this document</h2>
+ <ol>
+ <li><a href="#GC_Migration">Addressing Garbage Collection (GC) Issues</a></li>
+ <li><a href="#JNI_Issues">Preventing JNI Issues</a>
+ <ol>
+ <li><a href="#JNI_and_GC">Checking JNI code for garbage-collection
+ issues</a></li>
+ <li><a href="#Error_Handling">Error handling</a></li>
+ <li><a href="#Object_Model_Changes">Object model changes</a></li>
+ </ol>
+ </li>
+ <li><a href="#Stack_Size">Preventing Stack Size Issues</a></li>
+ <li><a href="#AOT_Fails">Fixing AOT Compilation Issues</a></li>
+ <li><a href="#Reporting_Problems">Reporting Problems</a></li>
+ </ol>
+ <h2>See also</h2>
+ <ol>
+ <li><a href="http://source.android.com/devices/tech/dalvik/art.html">Introducing ART</a></li>
+ <li><a
+href="http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html">Debugging
+Android JNI with CheckJNI</a></li>
+ </ol>
+</div>
+</div>
+
+<p>With Android 4.4, we are beginning to roll out a new Android runtime,
+<strong>ART</strong>. This runtime offers a number of new features that improve
+performance and smoothness of the Android platform and apps. (You can find more
+information about ART's new features in <a
+href="http://source.android.com/devices/tech/dalvik/art.html">Introducing
+ART</a>.)</p>
+
+<p>Currently, ART is available on a number of Android 4.4 devices, such as the
+Nexus 4, Nexus 5, Nexus 7, and Google Play edition devices.
+At this time, all devices still use Dalvik as the default runtime. We encourage
+you to test your apps for ART compatibility and to take advantage of ART's new
+features. However, for the time being, you should also take care to maintain
+compatibility with Dalvik.</p>
+
+<p>This document lets you know about things to watch for when migrating an
+existing app to be compatible with ART. Most apps should just work when
+running with ART. However, some techniques that work on Dalvik do not work on
+ART. This document discusses some of these issues.</p>
+
+<h2 id="GC_Migration">Addressing Garbage Collection (GC) Issues</h2>
+
+<p>Under Dalvik, apps frequently find it useful to explicitly call {@link
+java.lang.System#gc() System.gc()} to prompt garbage collection (GC). This should be
+far less necessary with ART, particularly if you're invoking garbage collection
+to prevent <a
+href="{@docRoot}/tools/debugging/debugging-memory.html#LogMessages"><code>GC_FOR_ALLOC</code></a>-type
+occurrences or to reduce fragmentation. You can verify which runtime is in use
+by calling {@link java.lang.System#getProperty(java.lang.String)
+System.getProperty("dalvik.vm.version")}. If ART is in use, the property's value
+is <code>"2.0.0"</code> or higher.</p>
+
+<p>Furthermore, a compacting garbage collector is under development in the <a
+href="https://source.android.com">Android Open-Source Project (AOSP)</a> to
+improve memory management. Because of this, you should avoid using techniques
+that are incompatible with compacting GC (such as saving pointers to object
+instance data). This is particularly important for apps that make use of the
+Java Native Interface (JNI). For more information, see <a
+href="#JNI_Issues">Preventing JNI Issues</a>.</p>
+
+<h2 id="JNI_Issues">Preventing JNI Issues</h2>
+
+<p>ART's JNI is somewhat stricter than Dalvik's. It is an especially good idea
+to use CheckJNI mode to catch common problems. If your app makes use of C/C++
+code, you should review the following article:</p>
+
+<p><a
+href="http://android-developers.blogspot.com/2011/07/debugging-android-jni-with-checkjni.html">Debugging
+Android JNI with CheckJNI</a></p>
+
+<h3 id="JNI_and_GC">Checking JNI code for garbage-collection issues</h3>
+
+<p>ART has a compacting garbage collector under development on the
+Android Open Source Project (AOSP). Once the compacting garbage collector is in
+use, objects may be moved in memory. If you use C/C++ code, do not
+perform operations that are incompatible with compacting GC. We have enhanced
+CheckJNI to identify some potential issues (as described in <a
+href="http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html">JNI
+Local Reference Changes in ICS</a>).</p>
+
+<p>One area to watch for in particular is the use of
+<code>Get...ArrayElements()</code> and <code>Release...ArrayElements()</code>
+functions. In runtimes with non-compacting GC, the
+<code>Get...ArrayElements()</code> functions typically return a reference to the
+actual memory backing the array object. If you make a change to one of the
+returned array elements, the array object is itself changed (and the arguments
+to <code>Release...ArrayElements()</code> are usually ignored). However, if
+compacting GC is in use, the <code>Get...ArrayElements()</code> functions may
+return a copy of the memory. If you misuse the reference when compacting GC is
+in use, this can lead to memory corruption or other problems. For example:</p>
+
+<ul>
+
+ <li>If you make any changes to the returned array elements, you must call the
+ appropriate <code>Release...ArrayElements()</code> function when you are done,
+ to make sure the changes you made are correctly copied back to the underlying
+ array object.</li>
+
+ <li>When you release the memory array elements, you must use the appropriate
+ mode, depending on what changes you made:
+
+ <ul>
+
+ <li>If you did not make any changes to the array elements, use
+ <code>JNI_ABORT</code> mode, which releases the memory without copying
+ changes back to the underlying array object.</li>
+
+ <li>If you made changes to the array, and do not need the reference any
+ more, use code <code>0</code> (which updates the array object and frees
+ the copy of the memory).</li>
+
+ <li>If you made changes to the array that you want to commit, and you want
+ to keep the copy of the array, use <code>JNI_COMMIT</code> (which updates
+ the underlying array object and retains the copy).</li>
+
+ </ul>
+
+ </li>
+
+ <li>When you call <code>Release...ArrayElements()</code>, return the same
+ pointer that was originally returned by <code>Get...ArrayElements()</code>. For
+ example, it's not safe to increment the original pointer (to scan through the
+ returned array elements) then pass the incremented pointer to
+ <code>Release...ArrayElements()</code>. Passing this modified pointer can cause
+ the wrong memory to be freed, resulting in memory corruption.</li>
+
+</ul>
+
+<h3 id="Error_Handling">Error handling</h3>
+
+<p>ART's JNI throws errors in a number of cases where Dalvik didn’t. (Once
+again, you can catch many such cases by testing with CheckJNI.)</p>
+
+<p>For example, if <code>RegisterNatives</code> is called with a method that
+does not exist (perhaps because the method was removed by a tool such as
+<strong>ProGuard</strong>), ART now properly throws {@link
+java.lang.NoSuchMethodError}:</p>
+
+<pre class="no-pretty-print">
+08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main
+08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError:
+ no static or non-static method
+ "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I"
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+ at java.lang.Runtime.nativeLoad(Native Method)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+ at java.lang.Runtime.doLoad(Runtime.java:421)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+ at java.lang.Runtime.loadLibrary(Runtime.java:362)
+08-12 17:09:41.082 13823 13823 E AndroidRuntime:
+ at java.lang.System.loadLibrary(System.java:526)
+</pre>
+
+<p>ART also logs an error (visible in logcat) if <code>RegisterNatives</code> is
+called with no methods:</p>
+
+<pre class="no-pretty-print">
+W/art ( 1234): JNI RegisterNativeMethods: attempt to register 0 native
+methods for <classname>
+</pre>
+
+<p>In addition, the JNI functions <code>GetFieldID()</code> and
+<code>GetStaticFieldID()</code> now properly throw {@link java.lang.NoSuchFieldError}
+instead of simply returning null. Similarly, <code>GetMethodID()</code> and
+<code>GetStaticMethodID()</code> now properly throw {@link java.lang.NoSuchMethodError}.
+This can lead to CheckJNI failures because of the unhandled exceptions or the
+exceptions being thrown to Java callers of native code. This makes it
+particularly important to test ART-compatible apps with CheckJNI mode.</p>
+
+<p>ART expects users of the JNI <code>CallNonvirtual...Method()</code> methods
+(such as <code>CallNonvirtualVoidMethod()</code>) to use the method's declaring
+class, not a subclass, as required by the JNI specification.</p>
+
+<h2 id="Stack_Size">Preventing Stack Size Issues</h2>
+
+<p>Dalvik had separate stacks for native and Java code, with a default Java
+stack size of 32KB and a default native stack size of 1MB. ART has a unified
+stack for better locality. Ordinarily, the ART {@link java.lang.Thread} stack
+size should be approximately the same as for Dalvik. However, if you explicitly
+set stack sizes, you may need to revisit those values for apps running in
+ART.</p>
+
+<ul>
+
+ <li>In Java, review calls to the {@link
+ java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable,
+ java.lang.String, long) Thread} constructor that specify an explicit stack
+ size. For example, you will need to increase the size if {@link
+ java.lang.StackOverflowError} occurs.</li>
+
+ <li>In C/C++, review use of <code>pthread_attr_setstack()</code> and
+ <code>pthread_attr_setstacksize()</code> for threads that also run Java code via
+ JNI. Here is an example of the error logged when an app attempts to call JNI
+ <code>AttachCurrentThread()</code> when the pthread size is too small:
+
+<pre class="no-pretty-print">F/art: art/runtime/thread.cc:435]
+ Attempt to attach a thread with a too-small stack (16384 bytes)</pre>
+ </li>
+
+</ul>
+
+<h2 id="Object_Model_Changes">Object model changes</h2>
+
+<p>Dalvik incorrectly allowed subclasses to override package-private methods.
+ART issues a warning in such cases:</p>
+
+<pre class="no-pretty-print">
+Before Android 4.1, method void com.foo.Bar.quux()
+would have incorrectly overridden the package-private method in
+com.quux.Quux
+</pre>
+
+<p>If you intend to override a class's method in a different package, declare the
+method as <code>public</code> or <code>protected</code>.</p>
+
+<p>{@link java.lang.Object} now has private fields. Apps that reflect on fields
+in their class hierarchies should be careful not to attempt to look at the
+fields of {@link java.lang.Object}. For example, if you are iterating up a class
+hierarchy as part of a serialization framework, stop when
+
+<pre>Class.getSuperclass() == java.lang.Object.class</pre>
+
+instead of continuing until the method returns <code>null</code>.</p>
+
+<p>Proxy {@link
+java.lang.reflect.InvocationHandler#invoke(java.lang.Object,java.lang.reflect.Method,java.lang.Object[])
+InvocationHandler.invoke()} now receives <code>null</code> if there are no
+arguments instead of an empty array. This behavior was documented previously but
+not correctly handled in Dalvik. Previous versions of <a
+href="https://code.google.com/p/mockito/">Mockito</a> have difficulties with
+this, so use an updated Mockito version when testing with ART.</p>
+
+<h2 id="AOT_Fails">Fixing AOT Compilation Issues</h2>
+
+<p>ART's Ahead-Of-Time (AOT) Java compilation should work for all standard Java
+code. Compilation is performed by ART's
+<code>dex2oat</code> tool; if you encounter any issues related to
+<code>dex2oat</code> at install time, let us know (see <a
+href="#Reporting_Problems">Reporting Problems</a>) so we can fix them as quickly
+as possible. A couple of issues to note:</p>
+
+<ul>
+
+ <li>ART does tighter bytecode verification at install time than Dalvik does.
+ Code produced by the Android build tools should be fine. However, some
+ post-processing tools (especially tools that perform obfuscation) may produce
+ invalid files that are tolerated by Dalvik but rejected by ART. We have been
+ working with tool vendors to find and fix such issues. In many cases, getting
+ the latest versions of your tools and regenerating the DEX files can fix these
+ problems.</li>
+
+ <li>Some typical problems that are flagged by the ART verifier include:
+ <ul>
+ <li>invalid control flow</li>
+ <li>unbalanced <code>moniterenter</code>/<code>moniterexit</code></li>
+ <li>0-length parameter type list size</li>
+ </ul>
+ </li>
+
+ <li>Some apps have dependencies on the installed <code>.odex</code> file
+ format in <code>/system/framework</code>, <code>/data/dalvik-cache</code>, or
+ in {@link dalvik.system.DexClassLoader}’s optimized output directory. These
+ files are now ELF files and not an extended form of DEX files. While ART tries
+ to follow the same naming and locking rules as Dalvik, apps should not depend
+ on the file format; the format is subject to change without notice.</li>
+
+
+
+<h2 id="Reporting_Problems">Reporting Problems</h2>
+
+<p>If you run into any issues that aren’t due to app JNI issues, report
+them via the Android Open Source Project Issue Tracker at <a
+href="https://code.google.com/p/android/issues/list">https://code.google.com/p/android/issues/list</a>.
+Include an <code>"adb bugreport"</code> and a link to the app in the Google
+Play store if available. Otherwise, if possible, attach an APK that reproduces
+the issue. Note that issues (including attachments) are publicly
+visible.</p>
diff --git a/docs/html/sdk/exploring.jd b/docs/html/sdk/exploring.jd
index 7749060..b34c1cf 100644
--- a/docs/html/sdk/exploring.jd
+++ b/docs/html/sdk/exploring.jd
@@ -5,163 +5,6 @@
@jd:body
-<p>The Android SDK is composed of modular packages that you can download separately using
-the Android SDK Manager. For example, when the SDK Tools are updated or a new version of
-the Android platform is released, you can use the SDK Manager to quickly download them to
-your environment. Simply follow the procedures described in <a
-href="{@docRoot}sdk/installing/adding-packages.html">Adding Platforms and Packages</a>.</p>
-
-<p>There are several different packages available for the Android SDK. The table below describes
-most of the available packages and where they're located once you download them.</p>
-
-
-<h2 id="Packages">Available Packages</h2>
-
-
-<table>
- <tr><th>Package</th><th>Description</th><th>File Location</th></tr>
- <tr>
- <td><a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools</a></td>
- <td>Contains tools for debugging and testing, plus other
-utilities that are required to develop an app. If you've just installed the SDK starter package,
-then you already have the latest version of this package. Make sure you keep this up to date.</td>
- <td>{@code <sdk>/tools/}</td></tr>
- <tr><td>SDK Platform-tools</td>
- <td>Contains platform-dependent tools for developing and debugging
-your application. These tools support the latest features of the Android platform and are typically
-updated only when a new platform becomes available. These tools are always backward compatible with
-older platforms, but you must be sure that you have the latest version of these tools when you
-install a new SDK platform.</td>
- <td>{@code <sdk>/platform-tools/}</td>
- </tr>
-
- <tr>
- <td>Documentation</td>
- <td>An offline copy of the latest documentation for the Android
-platform APIs.</td>
- <td>{@code <sdk>/docs/}</td>
- </tr>
- <tr><td>SDK Platform</td>
- <td>There's one SDK Platform available for each version of Android. It includes an {@code
-android.jar} file with a fully compliant Android library. In order to build an Android app, you must
-specify an SDK platform as your build target.</td>
- <td>{@code <sdk>/platforms/<android-version>/}</td>
- </tr>
- <tr>
- <td>System Images</td>
- <td>Each platform version offers one or more different system images (such as for ARM
-and x86). The Android emulator requires a system image to operate. You should always test your
-app on the latest version of Android and using the emulator with the latest system image is a
-good way to do so.</td>
- <td>{@code <sdk>/platforms/<android-version>/}</td>
- </tr>
- <tr>
- <td>Sources for Android SDK</td>
- <td>A copy of the Android platform source code that's useful for
-stepping through the code while debugging your app.</td>
- <td>{@code <sdk>/sources/}</td>
- </tr>
- <tr>
- <td><a href="{@docRoot}tools/samples/index.html">Samples for SDK</a></td>
- <td>A collection of sample apps that demonstrate a variety of the
-platform APIs. These are a great resource to browse Android app code. The API Demos app in
-particular provides a huge number of small demos you should explore.</td>
- <td>{@code <sdk>/platforms/<android-version>/samples/}</td>
- </tr>
- <tr>
- <td><a href="http://developers.google.com/android">Google APIs</a></td>
- <td>An SDK add-on that provides both a platform you can use to develop an app
-using special Google APIs and a system image for the emulator so you can test your app using the
-Google APIs.</td>
- <td>{@code <sdk>/add-ons/}</td>
- </tr>
-
- <tr>
- <td><a href="{@docRoot}tools/support-library/index.html">Android Support</a></td>
- <td>A static library you can include in your app sources in order to use powerful
-APIs that aren't available in the standard platform. For example, the support library
-contains versions of the {@link android.support.v4.app.Fragment} class that's compatible with
-Android 1.6 and higher (the class was originally introduced in Android 3.0) and the {@link
-android.support.v4.view.ViewPager} APIs that allow you to easily build a side-swipeable UI.</td>
- <td>{@code <sdk>/extras/android/support/}</td>
- </tr>
- <tr>
- <td><a href="{@docRoot}google/play/billing/index.html">Google Play Billing</a></td>
- <td>Provides the static libraries and samples that allow you to
-integrate billing services in your app with Google Play.</td>
- <td>{@code <sdk>/extras/google/}</td>
- </tr>
- <tr>
- <td><a href="{@docRoot}google/play/licensing/index.html">Google Play Licensing</a></td>
- <td>Provides the static libraries and samples that allow you to perform license verification for
-your app when distributing with Google Play.</td>
- <td>{@code <sdk>/extras/google/}</td>
- </tr>
-</table>
-
-<p>The above table is not comprehensive and you can <a
-href="#AddingSites">add new sites</a> to download additional packages from third-parties.</p>
-
-<p>In some cases, an SDK package may require a specific minimum revision of
-another package or SDK tool. For example, there may be a dependency between the ADT Plugin for
-Eclipse and
-the SDK Tools package. When you install the SDK Tools
-package, you should also upgrade to the required version of ADT (if you
-are developing in Eclipse). In this case, the major version number for your ADT plugin should
-always match the revision number of your SDK Tools (for example, ADT 8.x requires SDK Tools r8).
-</p>
-
-<p>The development tools will notify you with debug warnings if there is dependency that you need to
-address. The Android SDK Manager also enforces dependencies by requiring that you download any
-packages that are needed by those you have selected.</p>
-
-
-
-
-
-<h2 id="AddingSites">Adding New Sites</h2>
-
-<p>By default, <strong>Available Packages</strong> displays packages available from the
-<em>Android Repository</em> and <em>Third party Add-ons</em>. You can add other sites that host
-their own Android SDK add-ons, then download the SDK add-ons
-from those sites.</p>
-
-<p>For example, a mobile carrier or device manufacturer might offer additional
-API libraries that are supported by their own Android-powered devices. In order
-to develop using their libraries, you must install their Android SDK add-on, if it's not already
-available under <em>Third party Add-ons</em>. </p>
-
-<p>If a carrier or device manufacturer has hosted an SDK add-on repository file
-on their web site, follow these steps to add their site to the Android SDK
-Manager:</p>
-
-<ol>
- <li>Select <strong>Available Packages</strong> in the left panel.</li>
- <li>Click <strong>Add Add-on Site</strong> and enter the URL of the
-<code>repository.xml</code> file. Click <strong>OK</strong>.</li>
-</ol>
-<p>Any SDK packages available from the site will now be listed under a new item named
-<strong>User Add-ons</strong>.</p>
-
-
-
-
-<h2 id="troubleshooting">Troubleshooting</h2>
-
-<p><strong>Problems connecting to the SDK repository</strong></p>
-
-<p>If you are using the Android SDK Manager to download packages and are encountering
-connection problems, try connecting over http, rather than https. To switch the
-protocol used by the Android SDK Manager, follow these steps: </p>
-
-<ol>
- <li>With the Android SDK Manager window open, select "Settings" in the
- left pane. </li>
- <li>On the right, in the "Misc" section, check the checkbox labeled "Force
- https://... sources to be fetched using http://..." </li>
- <li>Click <strong>Save & Apply</strong>.</li>
-</ol>
-
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index e7f78e8..c6dbb90 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -206,12 +206,10 @@
<div id="next-steps" style="display:none;position:absolute;width:inherit">
- <p>Now that you've downloaded the Android SDK, you don't need to return here
- for SDK updates. The SDK tools allow you to
- install additional packages and future updates from the SDK Manager.</p>
- <p>For instructions about setting up your Android SDK for the first time,
- read <a id="next-link" href="{@docRoot}sdk/installing/bundle.html">Setting
- Up the ADT Bundle</a>.</p>
+ <p>You're just a few steps away from building apps for Android!</p>
+ <p>In a moment, you'll be redirected to <a
+ id="next-link" href="{@docRoot}sdk/installing/index.html">Installing the
+ Android SDK</a>.</p>
</div><!-- end next-steps -->
diff --git a/docs/html/sdk/installing/adding-packages.jd b/docs/html/sdk/installing/adding-packages.jd
index bba936e..c38c927 100644
--- a/docs/html/sdk/installing/adding-packages.jd
+++ b/docs/html/sdk/installing/adding-packages.jd
@@ -1,63 +1,222 @@
-page.title=Adding Platforms and Packages
+page.title=Adding SDK Packages
@jd:body
+<style>
+ol.large {
+ margin-left:0;
+}
+ol.large > li {
+ list-style-position: inside;
+ list-style-type:none;
+ margin:30px 0 0 0;
+ padding:30px 20px;
+ background:#eee;
+}
+ol.large > li:nth-child(odd) {
+}
+ol.large > li:before {
+ display:inline;
+ left:-40px;
+ float:left;
+ width:20px;
+ font-size:20px;
+ line-height:20px;
+}
+ol.large > li > h2 {
+ font-size:20px;
+ line-height:20px;
+ padding:0 0 0 20px;
+ margin:0 0 20px 0;
+ display:inline-block;
+ font-weight:normal;
+}
+ol.large > li:nth-child(1):before {
+ content:"1. ";
+}
+ol.large > li:nth-child(2):before {
+ content:"2. ";
+}
+ol.large > li:nth-child(3):before {
+ content:"3. ";
+}
+ol.large > li:nth-child(4):before {
+ content:"4. ";
+}
+ol.large > li:nth-child(5):before {
+ content:"5. ";
+}
+ol.large > li:nth-child(6):before {
+ content:"6. ";
+}
+</style>
-<p>The Android SDK separates tools, platforms, and other components into packages you can
- download using the Android SDK Manager. The original
-SDK package you've downloaded includes only the SDK Tools. To develop an Android app,
-you also need to download at least one Android platform and the latest SDK Platform-tools.</p>
-<ol>
-<li>Launch the SDK Manager.
-<p>If you've used the Windows installer to install the SDK tools, you should already have the
-Android SDK Manager open. Otherwise, you can launch the Android SDK Manager in one of the following
-ways:</p>
+<p>
+By default, the Android SDK does not include everything you need to start developing.
+The SDK separates tools, platforms, and other components into packages you can
+download as needed using the
+<a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>.
+So before you can start, there are a few packages you should add to your Android SDK.</p>
+
+<p>To start adding packages, launch the Android SDK Manager in one of the following ways:</p>
<ul>
- <li>On Windows, double-click the <code>SDK Manager.exe</code> file at the root of the Android
-SDK directory.</li>
- <li>On Mac or Linux, open a terminal and navigate to the <code>tools/</code> directory in the
-Android SDK, then execute <code>android sdk</code>.</li>
+ <li>In Eclipse or Android Studio, click <strong>SDK Manager</strong>
+<img src="{@docRoot}images/tools/sdk-manager-studio.png"
+style="vertical-align:bottom;margin:0;height:17px" /> in the toolbar.</li>
+ <li>If you're not using Eclipse or Android Studio:
+ <ul>
+ <li>Windows: Double-click the <code>SDK Manager.exe</code> file at the root of the Android
+ SDK directory.</li>
+ <li>Mac/Linux: Open a terminal and navigate to the <code>tools/</code> directory in the
+ Android SDK, then execute <code>android sdk</code>.</li>
+ </ul>
+ </li>
</ul>
+
+<ol class="large">
+<li>
+ <h2 class="norule">Get the latest SDK tools</h2>
+
+<img src="/images/sdk_manager_packages.png" alt="" width="350" style="float:right;margin-left:20px" />
+
+ <p>As a minimum when setting up the Android SDK,
+ you should download the latest tools and Android platform:</p>
+ <ol>
+ <li>Open the Tools directory and select:
+ <ul>
+ <li><strong>Android SDK Tools</strong></li>
+ <li><strong>Android SDK Platform-tools</strong></li>
+ <li><strong>Android SDK Build-tools</strong></li>
+ </ul>
+ </li>
+ <li>Open the first Android X.X folder (the latest version) and select:
+ <ul>
+ <li><strong>SDK Platform</strong></li>
+ <li>A system image for the emulator, such as <br>
+ <strong>ARM EABI v7a System Image</strong></li>
+ </ul>
+ </li>
+ <li>Click <strong>Install</strong>.</li>
+ </ol>
</li>
-<li>The SDK Manager shows all the SDK packages available for you to add to your Android SDK.
-As a minimum configuration for your SDK, we recommend you install the following:
-<ul>
- <li>The latest Tools packages (check the <strong>Tools</strong> folder).</li>
- <li>The latest version of Android (check the first <strong>Android</strong> folder).</li>
- <li>The Android Support Library (open the <strong>Extras</strong> folder and check
- <strong>Android Support Library</strong>).</li>
-</ul>
+<li>
+ <h2 class="norule">Get the support library for additional APIs</h2>
-<p>Once you've chosen your packages, click <strong>Install</strong>. The Android SDK Manager
-installs the selected packages into your Android SDK environment.</li>
+ <div class="sidebox">
+ <h3>Why use the support library?</h3>
+
+ <p>The support library is required for:</p>
+ <ul>
+ <li><a href="{@docRoot}wear/index.html">Android Wear</a></li>
+ <li><a href="{@docRoot}tv/index.html">Android TV</a></li>
+ <li><a href="{@docRoot}google/play-services/cast.html">Google Cast</a></li>
+ </ul>
+
+ <p>The support library also provides these popular APIs:</p>
+ <ul>
+ <li><a href="{@docRoot}reference/android/support/v4/widget/DrawerLayout.html">Navigation
+ drawer</a></li>
+ <li><a href="{@docRoot}reference/android/support/v4/view/ViewPager.html">Swipe views</a></li>
+ <li><a href="{@docRoot}reference/android/support/v7/app/ActionBar.html">Backward-compatible
+ action bar</a></li>
+ </ul>
+ </div>
+
+ <p>The <a href="{@docRoot}tools/support-library/features.html">Android Support Library</a>
+ provides an extended set of APIs that are compatible with most versions of Android.</p>
+
+ <p>To download the support library:</p>
+ <ol>
+ <li>Open the <strong>Extras</strong> directory and select:
+ <ul>
+ <li><strong>Android Support Repository</strong></li>
+ <li><strong>Android Support Library</strong></li>
+ </ul>
+ </li>
+ <li>Click <strong>Install</strong>.</li>
+ </ol>
+
+ <p> </p>
+ <p> </p>
+
+</li>
+
+
+<li>
+ <h2 class="norule">Get Google Play services for even more APIs</h2>
+
+ <div class="sidebox">
+ <h3>Why use Google Play services?</h3>
+
+ <p>The Google Play services APIs provide a variety of features and services for your Android
+ apps, such as:</p>
+ <ul>
+ <li><a href="{@docRoot}google/play-services/plus.html">User authentication</a></li>
+ <li><a href="{@docRoot}google/play-services/maps.html">Google Maps</a></li>
+ <li><a href="{@docRoot}google/play-services/cast.html">Google Cast</a></li>
+ <li><a href="{@docRoot}google/play-services/games.html">Games achievements and
+ leaderboards</a></li>
+ <li><a href="{@docRoot}google/play-services/index.html">And much more</a></li>
+ </ul>
+ </div>
+
+ <p>To develop with Google APIs, you need the Google Play services package:</p>
+ <ol>
+ <li>Open the <strong>Extras</strong> directory and select:
+ <ul>
+ <li><strong>Google Repository</strong></li>
+ <li><strong>Google Play services</strong></li>
+ </ul>
+ </li>
+ <li>Click <strong>Install</strong>.</li>
+ </ol>
+
+ <p class="note"><strong>Note:</strong> Google Play services APIs are not available on all
+ Android-powered devices, but are available on all devices with Google Play Store. To use these
+ APIs in the Android emulator, you must also install the the <strong>Google APIs</strong>
+ system image from the latest Android X.X directory in the SDK Manager.</p>
+</li>
+
+
+
+<li>
+ <h2 class="norule">Build something!</h2>
+
+<p>With the above packages now in your Android SDK, you're ready to build apps
+for Android. As new tools and other APIs become available, simply launch the SDK Manager
+ to download the new packages for your SDK.</p>
+
+<p>Here are a few options for how you should proceed:</p>
+
+<div class="cols" style="padding:10px 0">
+<div class="col-4">
+<h3>Get started</h3>
+<p>If you're new to Android development, learn the basics of Android apps by following
+the guide to <strong><a href="{@docRoot}training/basics/firstapp/index.html"
+>Building Your First App</a></strong>.</p>
+
+</div>
+<div class="col-4 box">
+<h3>Build for wearables</h3>
+<p>If you're ready to start building apps for Android wearables, see the guide to
+<strong><a href="{@docRoot}wear/preview/start.html">Building Apps for Android Wear</a></strong>.</p>
+
+</div>
+<div class="col-4 box">
+<h3>Use Google APIs</h3>
+<p>To start using Google APIs, such as Maps or
+Play Game services, see the guide to
+<strong><a href="{@docRoot}google/auth/api-client.html">Accessing Google Play Services
+APIs</a></strong>.</p>
+
+</div>
+</div><!-- end cols -->
+
+
+</li>
+
</ol>
-<p>With these packages installed, you're ready to start developing.
-To get started, read <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</p>
-
-<img src="/images/sdk_manager_packages.png" alt="" height="396" />
-<p class="img-caption"><strong>Figure 1.</strong> The Android SDK Manager shows the
-SDK packages that are available, already installed, or for which an update is available.</p>
-
-
-
-<h3>Additional information</h3>
-
-<ul>
- <li>For more information about using the SDK Manager and some of the available packages,
-see the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> document.</li>
- <li>This web site provides all information you need to develop Android apps, including <a
-href="{@docRoot}design/index.html">design guidelines</a>,
-<a href="{@docRoot}training/index.html">developer training</a>, <a
-href="{@docRoot}reference/packages.html">API reference</a>, and information
-about how you can <a href="{@docRoot}distribute/index.html">distribute your app</a>. We recommend
-you begin by reading <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</li>
- <li>For additional resources about developing and distributing your app, see the
-<a href="{@docRoot}support.html">Developer Support Resources</a>.</li>
-</ul>
-
diff --git a/docs/html/sdk/installing/bundle.jd b/docs/html/sdk/installing/bundle.jd
index 1f7da55..22bdd11 100644
--- a/docs/html/sdk/installing/bundle.jd
+++ b/docs/html/sdk/installing/bundle.jd
@@ -1,45 +1,3 @@
page.title=Setting Up the ADT Bundle
@jd:body
-
-
-<p>The ADT Bundle provides everything you need to start developing apps, including
-a version of the Eclipse IDE with built-in <b>ADT (Android Developer Tools)</b> to
-streamline your Android app development.
-If you haven't already, go download the <a href="{@docRoot}sdk/index.html"
->Android ADT Bundle</a>. (If you downloaded the SDK Tools only, for use with an
-existing IDE, you should instead read
-<a href="{@docRoot}sdk/installing/index.html">Setting Up an Existing IDE</a>.)</p>
-
-<h3>Install the SDK and Eclipse IDE</h3>
-<ol>
-<li>Unpack the ZIP file
-(named {@code adt-bundle-<os_platform>.zip}) and save it to an appropriate location,
-such as a "Development" directory in your home directory.</li>
-<li>Open the {@code adt-bundle-<os_platform>/eclipse/} directory and launch
-<strong>eclipse</strong>.</li>
-</ol>
-
-<p>That's it! The IDE is already loaded with the Android Developer Tools plugin and
-the SDK is ready to go. To start developing, read <a href="{@docRoot}training/basics/firstapp/index.html"
->Building Your First App</a>.</p>
-
-<p class="caution"><strong>Caution:</strong> Do not move any of the files or directories
-from the {@code adt-bundle-<os_platform>} directory. If you move the {@code eclipse}
-or {@code sdk} directory, ADT will not be able to locate the SDK and you'll
-need to manually update the ADT preferences.</p>
-
-<h3>Additional information</h3>
-
-<p>As you continue developing apps, you may need to install additional versions
-of Android for the emulator and other packages such as the library for
-Google Play In-app Billing. To install more packages, use
-the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p>
-
-<p>Everything you need to develop Android apps is on this web site, including <a
-href="{@docRoot}design/index.html">design guidelines</a>,
-<a href="{@docRoot}training/index.html">developer training</a>, <a
-href="{@docRoot}reference/packages.html">API reference</a>, and information
-about how you can <a href="{@docRoot}distribute/index.html">distribute your app</a>.
-For additional resources about developing and distributing your app, see the
-<a href="{@docRoot}support.html">Developer Support Resources</a>.</p>
\ No newline at end of file
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 6b63ba7..b6929bd 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -1,19 +1,213 @@
-page.title=Setting Up an Existing IDE
+page.title=Installing the Android SDK
@jd:body
-
-<p>You should have already downloaded the <a href="{@docRoot}sdk/index.html#ExistingIDE"
->Android SDK Tools</a>. (If you downloaded the ADT Bundle, you should instead read
-<a href="{@docRoot}sdk/installing/bundle.html">Setting Up the ADT Bundle</a>.)</p>
-
-<p>The SDK Tools package is not the complete SDK environment. It includes only the core SDK tools, which you can
-use to download the rest of the SDK packages (such as the latest system image).</p>
+<style>
+.paging-links {
+ margin:0 0 80px;
+}
+.paging-links .next-page-link {
+ right:initial;
+}
+.procedure-box {
+ padding:20px 20px 5px;
+ margin-bottom:1em;
+ background:#eee;
+}
+</style>
-<div id="win" class="docs" style="display:none">
-<h3>Getting started on Windows</h3>
+<!-- ################### ADT BUNDLE ####################### -->
+<div id="adt" heading="Installing the Eclipse ADT Bundle" style="display:none">
+
+
+<p>The Eclipse ADT Bundle provides everything you need to start developing apps, including
+the Android SDK tools and a version of the Eclipse IDE with built-in ADT
+(Android Developer Tools) to streamline your Android app development.</p>
+
+<p>If you didn't download the Eclipse ADT bundle, go <a href="{@docRoot}sdk/index.html"
+><b>download the Eclipse ADT bundle now</b></a>, or switch to the
+<a href="{@docRoot}sdk/installing/index.html?pkg=studio">Android Studio
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=tools">stand-alone SDK Tools
+install</a> instructions</i>.</p>
+
+<div class="procedure-box">
+<p><b>To set up the ADT Bundle:</b></p>
+<ol>
+<li>Unpack the ZIP file
+(named {@code adt-bundle-<os_platform>.zip}) and save it to an appropriate location,
+such as a "Development" directory in your home directory.</li>
+<li>Open the {@code adt-bundle-<os_platform>/eclipse/} directory and launch
+<strong>Eclipse</strong>.</li>
+</ol>
+
+<p class="caution"><strong>Caution:</strong> Do not move any of the files or directories
+from the {@code adt-bundle-<os_platform>} directory. If you move the {@code eclipse/}
+or {@code sdk/} directory, ADT will not be able to locate the SDK and you'll
+need to manually update the ADT preferences.</p>
+</div>
+
+<p>Eclipse with ADT is now ready and loaded with the Android developer tools, but there are still
+a couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################ END ADT BUNDLE ##################### -->
+
+
+
+
+
+
+<!-- ################ STUDIO ##################### -->
+<div id="studio" heading="Installing Android Studio" style="display:none">
+
+<p>Android Studio provides everything you need to start developing apps, including
+the Android SDK tools and the Android Studio IDE (powered by IntelliJ) to
+streamline your Android app development.</p>
+
+<p>If you didn't download Android Studio, go <a href="{@docRoot}sdk/installing/studio.html"
+><b>download Android Studio now</b></a>, or switch to the
+<a href="{@docRoot}sdk/installing/index.html?pkg=adt">Eclipse ADT
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=tools">stand-alone SDK Tools
+install</a> instructions.</p>
+
+
+<p>Before you set up Android Studio, be sure you have installed
+JDK 6 or greater (the JRE alone is not sufficient). To check if you
+have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
+If the JDK is not available or the version is lower than 6,
+<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html" class="external-link"
+>go download JDK</a>.</p>
+
+
+<div class="procedure-box">
+
+<p id="instructions-toggle"
+style="float:right;font-size:13px"><a href='' onclick='showAll();return false;'
+>[ Show instructions for all platforms ]</a></p>
+
+<div class="win docs" style="display:none">
+
+<p><b>To set up Android Studio on Windows:</b></p>
+ <ol>
+ <li>Launch the downloaded EXE file, {@code android-studio-bundle-<version>.exe}.</li>
+ <li>Follow the setup wizard to install Android Studio.
+
+ <p>On some Windows systems, the launcher script does not find where Java is installed.
+ If you encounter this problem,
+ you need to set an environment variable indicating the correct location.</p>
+ <p>Select <strong>Start menu > Computer > System Properties >
+ Advanced System Properties</strong>. Then open <strong>Advanced tab > Environment
+ Variables</strong> and add a new system variable <code>JAVA_HOME</code> that points to
+ your JDK folder, for example <code>C:\Program Files\Java\jdk1.7.0_21</code>.</p>
+ </p>
+ </li>
+
+ </ol>
+
+
+<p>The individual tools and
+other SDK packages are saved within the Android Studio application directory.
+To access the tools directly, use a terminal to navigate into the application and locate
+the {@code sdk/} directory. For example:</p>
+<p><code>\Users\<user>\AppData\Local\Android\android-studio\sdk\</code></p>
+
+
+
+</div><!-- end windows -->
+
+
+<div class="mac docs" style="display:none">
+
+<p><b>To set up Android Studio on Mac OSX:</b></p>
+ <ol>
+ <li>Open the downloaded DMG file, {@code android-studio-bundle-<version>.dmg}.</li>
+ <li>Drag and drop Android Studio into the Applications folder.
+ <p>
+ Depending on your security settings, when you attempt to open Android Studio, you might
+ see a warning that says the package is damaged and should be moved to the trash. If this
+ happens, go to <strong>System Preferences > Security & Privacy</strong> and under
+ <strong>Allow applications downloaded from</strong>, select <strong>Anywhere</strong>.
+ Then open Android Studio again.</p>
+ </li>
+ </ol>
+
+<p>The individual tools and
+other SDK packages are saved within the Android Studio application directory.
+To access the tools directly, use a terminal to navigate into the application and locate
+the {@code sdk/} directory. For example:</p>
+<p><code>/Applications/Android\ Studio.app/sdk/</code></p>
+
+
+</div><!-- end mac -->
+
+
+<div class="linux docs" style="display:none">
+
+<p><b>To set up Android Studio on Linux:</b></p>
+
+ <ol>
+ <li>Unpack the downloaded Tar file, {@code android-studio-bundle-<version>.tgz}, into an appropriate
+ location for your applications.
+ <li>To launch Android Studio, navigate to the {@code android-studio/bin/} directory
+ in a terminal and execute {@code studio.sh}.
+ <p>You may want to add {@code android-studio/bin/} to your PATH environmental
+ variable so that you can start Android Studio from any directory.</p>
+ </li>
+ </ol>
+
+</div><!-- end linux -->
+</div><!-- end procedure box -->
+
+<p>Android Studio is now ready and loaded with the Android developer tools, but there are still a
+couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################ END STUDIO ##################### -->
+
+
+
+
+
+
+
+
+
+<!-- ################ JUST SDK TOOLS ##################### -->
+<div id="tools" heading="Installing the Stand-alone SDK Tools" style="display:none">
+
+
+<p>The stand-alone SDK Tools package does not include a complete Android development environment.
+It includes only the core SDK tools, which you can access from a command line or with a plugin
+for your favorite IDE (if available).</p>
+
+<p>If you didn't download the SDK tools, go <a href="{@docRoot}sdk/index.html"
+><b>download the SDK now</b></a>,
+or switch to the <a href="{@docRoot}sdk/installing/index.html?pkg=adt">Eclipse ADT
+install</a> or <a href="{@docRoot}sdk/installing/index.html?pkg=studio">Android Studio
+install</a> instructions.</p>
+
+
+<div class="procedure-box">
+<p id="instructions-toggle"
+style="float:right;font-size:13px"><a href='' onclick='showAll();return false;'
+>[ Show instructions for all platforms ]</a></p>
+
+<div class="win docs" style="display:none">
+
+<p><b>To get started on Windows:</b></p>
+
<p>Your download package is an executable file that starts an installer. The installer checks your machine
for required tools, such as the proper Java SE Development Kit (JDK) and installs it if necessary.
The installer then saves the Android SDK Tools into a default location (or you can specify the location).</p>
@@ -21,15 +215,9 @@
<ol>
<li>Double-click the executable ({@code .exe} file) to start the install.</li>
<li>Make a note of the name and location in which it saves the SDK on your system—you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
the SDK tools from the command line.</li>
-<li>Once the installation completes, the installer offers to start the Android SDK Manager.
-If you'll be using Eclipse, <strong>do not</strong> start the Android SDK Manager,
-and instead move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>.
-<p>If you're using a different IDE,
-start the SDK Manager and read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</p>
+<li>Once the installation completes, the installer starts the Android SDK Manager.
</li>
</ol>
@@ -37,51 +225,37 @@
-<div id="mac" class="docs" style="display:none">
+<div class="mac docs" style="display:none">
-<h3>Getting started on Mac</h3>
+<p><b>To get started on Mac OSX:</b></p>
-<ol>
-<li>Unpack the ZIP file you've downloaded. By default, it's unpacked
+<p>Unpack the ZIP file you've downloaded. By default, it's unpacked
into a directory named <code>android-sdk-mac_x86</code>. Move it to an appropriate location on your machine,
-such as a "Development" directory in your home directory.
+such as a "Development" directory in your home directory.</p>
<p>Make a note of the name and location of the SDK directory on your system—you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
the SDK tools from the command line.</p>
-</li>
-<li>If you're using Eclipse, move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>. Otherwise, if you're using a different IDE,
-read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</li>
-</ol>
</div>
-<div id="linux" class="docs" style="display:none">
+<div class="linux docs" style="display:none">
-<h3>Getting started on Linux</h3>
+<p><b>To get started on Linux:</b></p>
-<ol>
-<li>Unpack the {@code .tgz} file you've downloaded. By default, the SDK files are unpacked
+<p>Unpack the {@code .tgz} file you've downloaded. By default, the SDK files are unpacked
into a directory named <code>android-sdk-linux_x86</code>. Move it to an appropriate location on your machine,
-such as a "Development" directory in your home directory.
+such as a "Development" directory in your home directory.</p>
<p>Make a note of the name and location of the SDK directory on your system—you will need to
-refer to the SDK directory later, when setting up the ADT plugin and when using
+refer to the SDK directory later when using
the SDK tools from the command line.</p>
-</li>
-<li>If you're using Eclipse, move on to <a href="{@docRoot}sdk/installing/installing-adt.html"
->Installing the Eclipse Plugin</a>. Otherwise, if you're using a different IDE,
-read <a href="{@docRoot}sdk/installing/adding-packages.html"
->Adding Platforms and Packages</a>.</li>
-</ol>
-<h5 id="Troubleshooting"><a href='' class="expandable"
+<h5 id="Troubleshooting" style="margin-bottom:15px"><a href='' class="expandable"
onclick="toggleExpandable(this,'#ubuntu-trouble');return false;"
>Troubleshooting Ubuntu</a></h5>
@@ -122,38 +296,129 @@
</div><!-- end ubuntu trouble -->
+</div><!-- end linux -->
+</div><!-- end procedure box -->
+
+
+<p>The Android SDK tools are now ready to begin developing apps, but there are still a
+couple packages you should add to make your Android SDK complete.</p>
+
+<p class="paging-links">
+<a href="{@docRoot}sdk/installing/adding-packages.html" class="next-page-link">
+Continue: Adding SDK Packages</a></p>
+
+
+</div>
+<!-- ################ END JUST TOOLS ##################### -->
+
+
+
+
+
+<!-- ################ DEFAULT ##################### -->
+<style>
+h3.large-link {
+ display:inline-block;
+ width:100%;
+ text-align:center;
+ border:1px solid #258aaf;
+ padding:10px 0;
+ color:inherit;
+}
+</style>
+
+<div id="default" style="display:none">
+
+<p>If you haven't already done so, <b><a href="{@docRoot}sdk/index.html">click here to download
+the Android SDK</a></b>. </p>
+
+<p>Otherwise, select which SDK package you want to install:</p>
+
+<div class="cols" style="margin-bottom:60px">
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=adt">
+<h3 class="large-link">Eclipse ADT</h3>
+</a>
</div>
-<p style="margin-top:2em;"><a href='' onclick='showAll();return false;'>Information for other platforms</a></p>
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=studio">
+<h3 class="large-link">Android Studio</h3></a>
+</div>
+
+<div class="col-4">
+<a href="{@docRoot}sdk/installing/index.html?pkg=tools">
+<h3 class="large-link">Stand-alone SDK Tools</h3></a>
+</div>
+</div>
+
+
+</div>
+<!-- ################ END DEFAULT ##################### -->
+
+
+
+
+
<script>
- var $osDocs;
- if (navigator.appVersion.indexOf("Win")!=-1) {
- $osDocs = $('#win');
- } else if (navigator.appVersion.indexOf("Mac")!=-1) {
- $osDocs = $('#mac');
- } else if (navigator.appVersion.indexOf("Linux")!=-1) {
- $osDocs = $('#linux');
- }
- if ($osDocs.length) {
- // reveal only the docs for this OS
- $osDocs.show();
- } else {
- // not running a compatible OS, so just show all the docs
- $('.docs').show();
- }
+// Show proper instructions based on downloaded SDK package
+var package = getUrlParam("pkg");
+if (package == "tools") {
+ // Show the SDK Tools (other IDE) instructions
+ $("h1").text($("#tools").attr('heading'));
+ $("#tools").show();
+} else if (package == "adt") {
+ // Show the ADT instructions
+ $("h1").text($("#adt").attr('heading'));
+ $("#adt").show();
+} else if (package == "studio") {
+ // Show the Android Studio instructions
+ $("h1").text($("#studio").attr('heading'));
+ $("#studio").show();
+} else {
+ // Show the default page content so user can select their setup
+ $("#default").show();
+}
- function showAll() {
- $('.docs').each(function() {
- if (!$(this).is(':visible')) {
- console.log('show')
- $(this).show();
- } else {
- console.log('hide')
- $(this).hide();
- $osDocs.show();
- }
- });
+// Show the proper instructions based on machine OS
+var $osDocs;
+if (navigator.appVersion.indexOf("Win")!=-1) {
+ $osDocs = $('.win');
+} else if (navigator.appVersion.indexOf("Mac")!=-1) {
+ $osDocs = $('.mac');
+} else if (navigator.appVersion.indexOf("Linux")!=-1) {
+ $osDocs = $('.linux');
+}
+
+if ($osDocs.length) {
+ // reveal only the docs for this OS
+ $osDocs.show();
+} else {
+ // not running a compatible OS, so just show all the docs
+ $('.docs').show();
+}
+
+
+/* Shows all the machine OS instructions */
+function showAll() {
+ $('.docs').show();
+ $("#instructions-toggle").hide();
+}
+
+/* Returns the value for the given URL parameter */
+function getUrlParam(param) {
+ var url = window.location.search.substring(1);
+ var variables = url.split('&');
+ for (var i = 0; i < variables.length; i++) {
+ var paramName = variables[i].split('=');
+ if (escape(paramName[0]) == param) {
+ return escape(paramName[1]);
+ }
}
+}
+
+
+
</script>
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 7bf366c..b23212d 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -15,19 +15,16 @@
UI, debug your app, and export signed (or unsigned) app packages (APKs) for distribution.
</p>
-<p>If you need to install Eclipse, you can download it from <a href=
-"http://www.eclipse.org/downloads/">eclipse.org/downloads/</a>.</p>
-
-
-<p class="note"><strong>Note:</strong> If you prefer to work in a different IDE, you do not need to
-install Eclipse or ADT. Instead, you can directly use the SDK tools to build and
-debug your application.</p>
+<p class="note"><strong>Note:</strong> You should install the ADT plugin
+only if you already have an Eclipse installation that you want to continue using. If you do not
+have Eclipse installed, you should instead <b><a href="{@docRoot}sdk/index.html">install
+the complete Android SDK</a></b>, which includes the latest IDE for Android developers.</p>
<h2 id="Download">Download the ADT Plugin</h2>
-
+<p>To add the ADT plugin to Eclipse:</p>
<ol>
<li>Start Eclipse, then select <strong>Help</strong> > <strong>Install New
Software</strong>.</li>
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 1b47f7f..7127ba6 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -7,7 +7,7 @@
<div style="position:relative;min-height:660px;">
-<h3 style="color:#f80">EARLY ACCESS PREVIEW</h3>
+<h3 style="color:#f80">BETA RELEASE</h3>
<div id="tos" style="position:absolute;display:none;width:inherit;">
<div class="col-13" style="margin:0;"> </div><!-- provides top margin for content -->
@@ -183,8 +183,6 @@
-
-
<div id="main">
<div class="figure" style="width:400px;margin-top:-20px">
@@ -298,7 +296,7 @@
Check for updates</strong>) to see whether an update is available.</p>
<p>If an update is not available,
-follow the <a href="#Installing">installation instructions</a> below and replace your existing
+click the button above to download and replace your existing
installation.</p>
<div class="caution">
@@ -311,100 +309,6 @@
the Android SDK Manager.</p>
</div>
-
-<h2 id="Installing">Installing Android Studio</h2>
-<p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you
-have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
-If JDK is not available or the version is lower than 6,
-<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">download
-JDK from here</a>.</p>
-<p>To install Android Studio:</p>
-<ol>
-<li>Download the <strong>Android Studio</strong> package from above.</li>
-<li>Install Android Studio and the SDK tools:
- <p><b>Windows:</b></p>
- <ol>
- <li>Launch the downloaded EXE file, {@code android-studio-bundle-<version>.exe}.</li>
- <li>Follow the setup wizard to install Android Studio.
-
- <div class="caution"><p><strong>Known issue:</strong>
- On some Windows systems, the launcher script does not find where Java is installed.
- If you encounter this problem,
- you need to set an environment variable indicating the correct location.</p>
- <p>Select <strong>Start menu > Computer > System Properties >
- Advanced System Properties</strong>. Then open <strong>Advanced tab > Environment
- Variables</strong> and add a new system variable <code>JAVA_HOME</code> that points to
- your JDK folder, for example <code>C:\Program Files\Java\jdk1.7.0_21</code>.</p>
- </div>
- </li>
-
- </ol>
- <p><b>Mac OS X:</b></p>
- <ol>
- <li>Open the downloaded DMG file, {@code android-studio-bundle-<version>.dmg}.</li>
- <li>Drag and drop Android Studio into the Applications folder.
-
- <div class="caution"><p><strong>Known issue:</strong>
- Depending on your security settings, when you attempt to open Android Studio, you might
- see a warning that says the package is damaged and should be moved to the trash. If this
- happens, go to <strong>System Preferences > Security & Privacy</strong> and under
- <strong>Allow applications downloaded from</strong>, select <strong>Anywhere</strong>.
- Then open Android Studio again.</p>
- </div>
- </li>
-
- </ol>
- <p><b>Linux:</b></p>
- <ol>
- <li>Unpack the downloaded Tar file, {@code android-studio-bundle-<version>.tgz}, into an appropriate
- location for your applications.
- <li>To launch Android Studio, navigate to the {@code android-studio/bin/} directory
- in a terminal and execute {@code studio.sh}.
- <p>You may want to add {@code android-studio/bin/} to your PATH environmental
- variable so that you can start Android Studio from any directory.</p>
- </li>
- </ol>
-</li>
-</ol>
-
-<p>That's it! You're ready to start developing apps with Android Studio.</p>
-
-<div class="note">
-<p><strong>Note:</strong> On Windows and Mac, the individual tools and
-other SDK packages are saved within the Android Studio application directory.
-To access the tools directly, use a terminal to navigate into the application and locate
-the {@code sdk/} directory. For example:</p>
-<p>Windows: <code>\Users\<user>\AppData\Local\Android\android-studio\sdk\</code></p>
-<p>Mac: <code>/Applications/Android\ Studio.app/sdk/</code></p>
-</div>
-
-<p>For a list of some known issues, see <a
-href="http://tools.android.com/knownissues">tools.android.com/knownissues</a>.</p>
-
-
-<h2 id="Start">Starting a Project</h2>
-
-<p>When you launch Android Studio for the first time, you'll see a Welcome
-screen that offers several ways to get started:</p>
-
-<ul>
- <li>To start building a new app, click <strong>New Project</strong>.
- <p>This starts the New Project wizard, which helps you set up a project using an app template.
- </li>
- <li>To import an existing Android app project, click <strong>Import Project</strong>.
- <p class="note"><strong>Note:</strong> If you previously developed your Android project
- with Eclipse, you should first use the new export feature in the ADT plugin to prepare
- your project with the new Gradle build system. For more information, read
- <a href="{@docRoot}sdk/installing/migrate.html">Migrating from Eclipse</a> and
- <a href="{@docRoot}sdk/installing/studio-build.html">Building Your Project with
- Gradle</a>.</p>
- </li>
-</ul>
-
-<p>For additional help using Android Studio, read <a
-href="{@docRoot}sdk/installing/studio-tips.html">Tips and Tricks</a>.</p>
-
-
<p>As you continue developing apps, you may need to install additional versions
of Android for the emulator and other packages such as the <a
href="{@docRoot}tools/support-library/index.html">Android Support Library</a>.
@@ -644,9 +548,13 @@
function onDownloadForRealz(link) {
if ($("input#agree").is(':checked')) {
- $("#tos").hide();
- $("#main").show();
- location.hash = "Updating";
+ $("h1").text('Now downloading Android Studio...');
+ $("#tos").slideUp();
+ $("#jd-content .jd-descr").fadeOut('slow', function() {
+ setTimeout(function() {
+ window.location = "/sdk/installing/index.html?pkg=studio";
+ }, 1000);
+ });
_gaq.push(['_trackEvent', 'SDK', 'Android Studio', $("#downloadForRealz").html()]);
return true;
} else {
diff --git a/docs/html/tools/help/sdk-manager.jd b/docs/html/tools/help/sdk-manager.jd
index 57271bb..b084237 100644
--- a/docs/html/tools/help/sdk-manager.jd
+++ b/docs/html/tools/help/sdk-manager.jd
@@ -3,7 +3,9 @@
<p>The Android SDK separates tools, platforms, and other components into packages you can
- download using the SDK Manager.</p>
+ download using the SDK Manager. For example, when the SDK Tools are updated or a new version of
+the Android platform is released, you can use the SDK Manager to quickly download them to
+your environment.</p>
<p>You can launch the SDK Manager in one of the following ways:</p>
<ul>
@@ -25,6 +27,14 @@
SDK packages that are available, already installed, or for which an update is available.</p>
+<p>There are several different packages available for the Android SDK. The table below describes
+most of the available packages and where they're located in your SDK directory
+once you download them.</p>
+
+
+
+
+
<h2 id="Recommended">Recommended Packages</h2>
<p>Here's an outline of the packages required and those we recommend you use:
@@ -69,3 +79,77 @@
<p class="note"><strong>Tip:</strong> For easy access to the SDK tools from a command line, add the
location of the SDK's <code>tools/</code> and
<code>platform-tools</code> to your <code>PATH</code> environment variable.</p>
+
+
+<p>The above list is not comprehensive and you can <a
+href="#AddingSites">add new sites</a> to download additional packages from third-parties.</p>
+
+<p>In some cases, an SDK package may require a specific minimum revision of
+another package or SDK tool.
+The development tools will notify you with warnings if there is dependency that you need to
+address. The Android SDK Manager also enforces dependencies by requiring that you download any
+packages that are needed by those you have selected.</p>
+
+
+
+
+
+<h2 id="AddingSites">Adding New Sites</h2>
+
+<p>By default, <strong>Available Packages</strong> displays packages available from the
+<em>Android Repository</em> and <em>Third party Add-ons</em>. You can add other sites that host
+their own Android SDK add-ons, then download the SDK add-ons
+from those sites.</p>
+
+<p>For example, a mobile carrier or device manufacturer might offer additional
+API libraries that are supported by their own Android-powered devices. In order
+to develop using their libraries, you must install their Android SDK add-on, if it's not already
+available under <em>Third party Add-ons</em>. </p>
+
+<p>If a carrier or device manufacturer has hosted an SDK add-on repository file
+on their web site, follow these steps to add their site to the Android SDK
+Manager:</p>
+
+<ol>
+ <li>Select <strong>Available Packages</strong> in the left panel.</li>
+ <li>Click <strong>Add Add-on Site</strong> and enter the URL of the
+<code>repository.xml</code> file. Click <strong>OK</strong>.</li>
+</ol>
+<p>Any SDK packages available from the site will now be listed under a new item named
+<strong>User Add-ons</strong>.</p>
+
+
+
+
+<h2 id="troubleshooting">Troubleshooting</h2>
+
+<p><strong>Problems connecting to the SDK repository</strong></p>
+
+<p>If you are using the Android SDK Manager to download packages and are encountering
+connection problems, try connecting over http, rather than https. To switch the
+protocol used by the Android SDK Manager, follow these steps: </p>
+
+<ol>
+ <li>With the Android SDK Manager window open, select "Settings" in the
+ left pane. </li>
+ <li>On the right, in the "Misc" section, check the checkbox labeled "Force
+ https://... sources to be fetched using http://..." </li>
+ <li>Click <strong>Save & Apply</strong>.</li>
+</ol>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index b29b87c..450a5c4 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -10,44 +10,32 @@
<div class="nav-section-header"><a href="<?cs var:toroot
?>sdk/index.html"><span class="en">Download</span></a></div>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/installing/bundle.html">
- <span class="en">Setting Up the ADT Bundle</span></a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/index.html">
+ <span class="en">Installing the SDK</span></a></li>
- <li class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>sdk/installing/index.html"><span class="en">Setting Up
- an Existing IDE</span></a></div>
- <ul>
- <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html">
- <span class="en">Installing the Eclipse Plugin</span></a></li>
- <li><a href="<?cs var:toroot ?>sdk/installing/adding-packages.html">
- <span class="en">Adding Platforms and Packages</span></a></li>
- </ul>
- </li>
-
- <li class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>sdk/installing/studio.html">Android Studio</a>
- </div>
- <ul>
- <li><a href="<?cs var:toroot ?>sdk/installing/migrate.html">
- Migrating from Eclipse</a></li>
- <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
- Tips and Tricks</a></li>
- <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 with Gradle</a></li>
- <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
- Debugging with Android Studio</a></li>
- </ul>
- </li>
- <li><a href="<?cs var:toroot ?>sdk/exploring.html">
- <span class="en">Exploring the SDK</span></a></li>
- <li><a href="<?cs var:toroot ?>tools/sdk/ndk/index.html">Download the NDK</a>
- </li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/adding-packages.html">
+ <span class="en">Adding SDK Packages</span></a></li>
</ul>
</li>
+
+
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>sdk/installing/studio.html">Android Studio</a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>sdk/installing/migrate.html">
+ Migrating from Eclipse</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html">
+ Tips and Tricks</a></li>
+ <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 with Gradle</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
+ Debugging with Android Studio</a></li>
+ </ul>
+ </li>
<li class="nav-section">
<div class="nav-section-header">
@@ -174,7 +162,13 @@
class="en">Tools Help</span></a></div>
<ul>
<li><a href="<?cs var:toroot ?>tools/help/adb.html">adb</a></li>
- <li><a href="<?cs var:toroot ?>tools/help/adt.html">ADT</a></li>
+ <li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/help/adt.html">ADT</a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>sdk/installing/installing-adt.html">
+ <span class="en">Installing the Eclipse Plugin</span></a></li>
+ </ul>
+ </li>
<li><a href="<?cs var:toroot ?>tools/help/android.html">android</a></li>
<li><a href="<?cs var:toroot ?>tools/help/avd-manager.html">AVD Manager</a></li>
<li><a href="<?cs var:toroot ?>tools/help/bmgr.html">bmgr</a>
@@ -244,6 +238,11 @@
</ul>
</li>
+ <li class="nav-section">
+ <div class="nav-section-header empty">
+ <a href="<?cs var:toroot ?>tools/sdk/ndk/index.html">NDK</a>
+ </div>
+ </li>
<li class="nav-section">
<div class="nav-section-header">
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index a5a074c..e1dec9d 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -537,4 +537,3 @@
}
}
}
-
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
new file mode 100644
index 0000000..968c0ec
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.graphics.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * AnimatedVectorDrawable can use ObjectAnimator and AnimatorSet to animate
+ * the property of the VectorDrawable.
+ *
+ * @hide
+ */
+public class AnimatedVectorDrawable extends Drawable implements Animatable {
+ private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName();
+
+ private static final String ANIMATED_VECTOR = "animated-vector";
+ private static final String TARGET = "target";
+
+ private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
+
+ private final AnimatedVectorDrawableState mAnimatedVectorState;
+
+
+ public AnimatedVectorDrawable() {
+ mAnimatedVectorState = new AnimatedVectorDrawableState(
+ new AnimatedVectorDrawableState(null));
+ }
+
+ private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
+ Theme theme) {
+ // TODO: Correctly handle the constant state for AVD.
+ mAnimatedVectorState = new AnimatedVectorDrawableState(state);
+ if (theme != null && canApplyTheme()) {
+ applyTheme(theme);
+ }
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ return null;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ mAnimatedVectorState.mVectorDrawable.draw(canvas);
+ if (isRunning()) {
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mAnimatedVectorState.mVectorDrawable.setBounds(bounds);
+ }
+
+ @Override
+ public int getAlpha() {
+ return mAnimatedVectorState.mVectorDrawable.getAlpha();
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mAnimatedVectorState.mVectorDrawable.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return mAnimatedVectorState.mVectorDrawable.getOpacity();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mAnimatedVectorState.mVectorDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mAnimatedVectorState.mVectorDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ final String tagName = parser.getName();
+ if (ANIMATED_VECTOR.equals(tagName)) {
+ final TypedArray a = obtainAttributes(res, theme, attrs,
+ R.styleable.AnimatedVectorDrawable);
+ int drawableRes = a.getResourceId(
+ R.styleable.AnimatedVectorDrawable_drawable, 0);
+ if (drawableRes != 0) {
+ mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable(
+ drawableRes);
+ }
+ a.recycle();
+ } else if (TARGET.equals(tagName)) {
+ final TypedArray a = obtainAttributes(res, theme, attrs,
+ R.styleable.AnimatedVectorDrawableTarget);
+ final String target = a.getString(
+ R.styleable.AnimatedVectorDrawableTarget_name);
+
+ int id = a.getResourceId(
+ R.styleable.AnimatedVectorDrawableTarget_animation, 0);
+ if (id != 0) {
+ Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id);
+ setupAnimatorsForTarget(target, objectAnimator);
+ }
+ a.recycle();
+ }
+ }
+
+ eventType = parser.next();
+ }
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return super.canApplyTheme() || mAnimatedVectorState != null
+ && mAnimatedVectorState.canApplyTheme();
+ }
+
+ @Override
+ public void applyTheme(Theme t) {
+ super.applyTheme(t);
+
+ final VectorDrawable vectorDrawable = mAnimatedVectorState.mVectorDrawable;
+ if (vectorDrawable != null && vectorDrawable.canApplyTheme()) {
+ vectorDrawable.applyTheme(t);
+ }
+ }
+
+ private static class AnimatedVectorDrawableState extends ConstantState {
+ int mChangingConfigurations;
+ VectorDrawable mVectorDrawable;
+ ArrayList<Animator> mAnimators;
+
+ public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
+ if (copy != null) {
+ mChangingConfigurations = copy.mChangingConfigurations;
+ // TODO: Make sure the constant state are handled correctly.
+ mVectorDrawable = new VectorDrawable();
+ mAnimators = new ArrayList<Animator>();
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new AnimatedVectorDrawable(this, null, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new AnimatedVectorDrawable(this, res, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res, Theme theme) {
+ return new AnimatedVectorDrawable(this, res, theme);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+
+ private void setupAnimatorsForTarget(String name, Animator animator) {
+ Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
+ animator.setTarget(target);
+ mAnimatedVectorState.mAnimators.add(animator);
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.v(LOGTAG, "add animator for target " + name + " " + animator);
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ if (animator.isRunning()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void start() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ if (animator.isPaused()) {
+ animator.resume();
+ } else if (!animator.isRunning()) {
+ animator.start();
+ }
+ }
+ invalidateSelf();
+ }
+
+ @Override
+ public void stop() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ animator.pause();
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 16548d0..1ee0224 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -91,10 +91,10 @@
@Override
public boolean setVisible(boolean visible, boolean restart) {
- boolean changed = super.setVisible(visible, restart);
+ final boolean changed = super.setVisible(visible, restart);
if (visible) {
if (changed || restart) {
- setFrame(0, true, restart || mCurFrame >= 0);
+ setFrame(0, true, mAnimating);
}
} else {
unscheduleSelf(this);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 18e8e52..6a7757b 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -209,7 +209,7 @@
* stored bounds of this drawable.
*
* @see #copyBounds()
- * @see #copyBounds(android.graphics.Rect)
+ * @see #copyBounds(android.graphics.Rect)
*/
public final Rect getBounds() {
if (mBounds == ZERO_BOUNDS_RECT) {
@@ -328,8 +328,8 @@
* that want to support animated drawables.
*
* @param cb The client's Callback implementation.
- *
- * @see #getCallback()
+ *
+ * @see #getCallback()
*/
public final void setCallback(Callback cb) {
mCallback = new WeakReference<Callback>(cb);
@@ -338,10 +338,10 @@
/**
* Return the current {@link Callback} implementation attached to this
* Drawable.
- *
+ *
* @return A {@link Callback} instance or null if no callback was set.
- *
- * @see #setCallback(android.graphics.drawable.Drawable.Callback)
+ *
+ * @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public Callback getCallback() {
if (mCallback != null) {
@@ -349,15 +349,15 @@
}
return null;
}
-
+
/**
* Use the current {@link Callback} implementation to have this Drawable
* redrawn. Does nothing if there is no Callback attached to the
* Drawable.
*
* @see Callback#invalidateDrawable
- * @see #getCallback()
- * @see #setCallback(android.graphics.drawable.Drawable.Callback)
+ * @see #getCallback()
+ * @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public void invalidateSelf() {
final Callback callback = getCallback();
@@ -931,7 +931,7 @@
Rects only to drop them on the floor.
*/
Rect pad = new Rect();
-
+
// Special stuff for compatibility mode: if the target density is not
// the same as the display density, but the resource -is- the same as
// the display density, then don't scale it down to the target density.
@@ -1040,6 +1040,8 @@
drawable = new GradientDrawable();
} else if (name.equals("vector")) {
drawable = new VectorDrawable();
+ } else if (name.equals("animated-vector")) {
+ drawable = new AnimatedVectorDrawable();
} else if (name.equals("scale")) {
drawable = new ScaleDrawable();
} else if (name.equals("clip")) {
@@ -1047,7 +1049,7 @@
} else if (name.equals("rotate")) {
drawable = new RotateDrawable();
} else if (name.equals("animated-rotate")) {
- drawable = new AnimatedRotateDrawable();
+ drawable = new AnimatedRotateDrawable();
} else if (name.equals("animation-list")) {
drawable = new AnimationDrawable();
} else if (name.equals("inset")) {
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 0d70e75..345400e 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -38,15 +38,18 @@
*/
class Ripple {
private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
- private static final TimeInterpolator DECEL_INTERPOLATOR = new DecelerateInterpolator(4);
+ private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator();
private static final float GLOBAL_SPEED = 1.0f;
private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED;
- private static final float WAVE_TOUCH_UP_ACCELERATION = 3096.0f * GLOBAL_SPEED;
- private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.9f / GLOBAL_SPEED;
- private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED;
+ private static final float WAVE_TOUCH_UP_ACCELERATION = 3400.0f * GLOBAL_SPEED;
+ private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED;
+ private static final float WAVE_OUTER_OPACITY_VELOCITY_MAX = 4.5f * GLOBAL_SPEED;
+ private static final float WAVE_OUTER_OPACITY_VELOCITY_MIN = 1.5f * GLOBAL_SPEED;
+ private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f;
+ private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f;
- private static final long RIPPLE_ENTER_DELAY = 100;
+ private static final long RIPPLE_ENTER_DELAY = 80;
// Hardware animators.
private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
@@ -311,7 +314,7 @@
public void enter() {
final int radiusDuration = (int)
(1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5);
- final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY);
+ final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY_MIN);
final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1);
radius.setAutoCancel(true);
@@ -355,7 +358,6 @@
*/
public void exit() {
cancelSoftwareAnimations();
-
final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius);
final float remaining;
if (mAnimRadius != null && mAnimRadius.isRunning()) {
@@ -368,13 +370,23 @@
+ WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5);
final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
+ // Scale the outer max opacity and opacity velocity based
+ // on the size of the outer radius
+
+ float outerSizeInfluence = MathUtils.constrain(
+ (mOuterRadius - WAVE_OUTER_SIZE_INFLUENCE_MIN * mDensity)
+ / (WAVE_OUTER_SIZE_INFLUENCE_MAX * mDensity), 0, 1);
+ float outerOpacityVelocity = MathUtils.lerp(WAVE_OUTER_OPACITY_VELOCITY_MIN,
+ WAVE_OUTER_OPACITY_VELOCITY_MAX, outerSizeInfluence);
+
// Determine at what time the inner and outer opacity intersect.
// inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
// outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
+
final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity)
- / (WAVE_OPACITY_DECAY_VELOCITY + WAVE_OUTER_OPACITY_VELOCITY) + 0.5f));
+ / (WAVE_OPACITY_DECAY_VELOCITY + outerOpacityVelocity) + 0.5f));
final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
- * WAVE_OUTER_OPACITY_VELOCITY / 1000) + 0.5f);
+ * outerOpacityVelocity * outerSizeInfluence / 1000) + 0.5f);
if (mCanUseHardware) {
exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
@@ -606,4 +618,14 @@
removeSelf();
}
};
+
+ /**
+ * Interpolator with a smooth log deceleration
+ */
+ private static final class LogInterpolator implements TimeInterpolator {
+ @Override
+ public float getInterpolation(float input) {
+ return 1 - (float) Math.pow(400, -input * 1.4);
+ }
+ }
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index c6c5b31..c531c22 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -27,6 +27,7 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -40,7 +41,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Stack;
/**
@@ -135,6 +135,8 @@
private final VectorDrawableState mVectorState;
+ private final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
+
public VectorDrawable() {
mVectorState = new VectorDrawableState(null);
}
@@ -147,6 +149,10 @@
}
}
+ Object getTargetByName(String name) {
+ return mVGTargetsMap.get(name);
+ }
+
@Override
public ConstantState getConstantState() {
return mVectorState;
@@ -162,6 +168,11 @@
}
@Override
+ public int getAlpha() {
+ return mVectorState.mVPathRenderer.getRootAlpha();
+ }
+
+ @Override
public void setAlpha(int alpha) {
if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
mVectorState.mVPathRenderer.setRootAlpha(alpha);
@@ -302,6 +313,9 @@
final VPath path = new VPath();
path.inflate(res, attrs, theme);
currentGroup.add(path);
+ if (path.getPathName() != null) {
+ mVGTargetsMap.put(path.getPathName(), path);
+ }
noPathTag = false;
} else if (SHAPE_SIZE.equals(tagName)) {
pathRenderer.parseSize(res, attrs);
@@ -314,6 +328,9 @@
newChildGroup.inflate(res, attrs, theme);
currentGroup.mChildGroupList.add(newChildGroup);
groupStack.push(newChildGroup);
+ if (newChildGroup.getGroupName() != null) {
+ mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup);
+ }
noGroupTag = false;
}
} else if (eventType == XmlPullParser.END_TAG) {
@@ -363,7 +380,7 @@
indent += " ";
}
// Print the current node
- Log.v(LOGTAG, indent + "current group is :" + currentGroup.getName()
+ Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName()
+ " rotation is " + currentGroup.mRotate);
Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString());
// Then print all the children
@@ -672,8 +689,7 @@
}
- private static class VGroup {
- private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
+ static class VGroup {
private final ArrayList<VPath> mPathList = new ArrayList<VPath>();
private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>();
@@ -694,10 +710,98 @@
private int[] mThemeAttrs;
- private String mName = null;
+ private String mGroupName = null;
- public String getName() {
- return mName;
+ /* Getter and Setter */
+ public float getRotation() {
+ return mRotate;
+ }
+
+ public void setRotation(float rotation) {
+ if (rotation != mRotate) {
+ mRotate = rotation;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getPivotX() {
+ return mPivotX;
+ }
+
+ public void setPivotX(float pivotX) {
+ if (pivotX != mPivotX) {
+ mPivotX = pivotX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getPivotY() {
+ return mPivotY;
+ }
+
+ public void setPivotY(float pivotY) {
+ if (pivotY != mPivotY) {
+ mPivotY = pivotY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getScaleX() {
+ return mScaleX;
+ }
+
+ public void setScaleX(float scaleX) {
+ if (scaleX != mScaleX) {
+ mScaleX = scaleX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getScaleY() {
+ return mScaleY;
+ }
+
+ public void setScaleY(float scaleY) {
+ if (scaleY != mScaleY) {
+ mScaleY = scaleY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getTranslateX() {
+ return mTranslateX;
+ }
+
+ public void setTranslateX(float translateX) {
+ if (translateX != mTranslateX) {
+ mTranslateX = translateX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getTranslateY() {
+ return mTranslateY;
+ }
+
+ public void setTranslateY(float translateY) {
+ if (translateY != mTranslateY) {
+ mTranslateY = translateY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getAlpha() {
+ return mGroupAlpha;
+ }
+
+ public void setAlpha(float groupAlpha) {
+ if (groupAlpha != mGroupAlpha) {
+ mGroupAlpha = groupAlpha;
+ }
+ }
+
+ public String getGroupName() {
+ return mGroupName;
}
public Matrix getLocalMatrix() {
@@ -705,8 +809,6 @@
}
public void add(VPath path) {
- String id = path.getID();
- mVGPathMap.put(id, path);
mPathList.add(path);
}
@@ -732,7 +834,7 @@
mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
updateLocalMatrix();
if (a.hasValue(R.styleable.VectorDrawableGroup_name)) {
- mName = a.getString(R.styleable.VectorDrawableGroup_name);
+ mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
}
a.recycle();
}
@@ -774,7 +876,7 @@
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) {
- mName = a.getString(R.styleable.VectorDrawableGroup_name);
+ mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) {
@@ -805,19 +907,15 @@
}
- private static class VPath {
- private static final int MAX_STATES = 10;
-
+ static class VPath {
private int[] mThemeAttrs;
int mStrokeColor = 0;
float mStrokeWidth = 0;
float mStrokeOpacity = Float.NaN;
-
int mFillColor = Color.BLACK;
int mFillRule;
float mFillOpacity = Float.NaN;
-
float mTrimPathStart = 0;
float mTrimPathEnd = 1;
float mTrimPathOffset = 0;
@@ -828,7 +926,7 @@
float mStrokeMiterlimit = 4;
private VNode[] mNode = null;
- private String mId;
+ private String mPathName;
public VPath() {
// Empty constructor.
@@ -841,8 +939,8 @@
}
}
- public String getID() {
- return mId;
+ public String getPathName() {
+ return mPathName;
}
private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
@@ -871,6 +969,71 @@
}
}
+ /* Setters and Getters */
+ int getStroke() {
+ return mStrokeColor;
+ }
+
+ void setStroke(int strokeColor) {
+ mStrokeColor = strokeColor;
+ }
+
+ float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ void setStrokeWidth(float strokeWidth) {
+ mStrokeWidth = strokeWidth;
+ }
+
+ float getStrokeOpacity() {
+ return mStrokeOpacity;
+ }
+
+ void setStrokeOpacity(float strokeOpacity) {
+ mStrokeOpacity = strokeOpacity;
+ }
+
+ int getFill() {
+ return mFillColor;
+ }
+
+ void setFill(int fillColor) {
+ mFillColor = fillColor;
+ }
+
+ float getFillOpacity() {
+ return mFillOpacity;
+ }
+
+ void setFillOpacity(float fillOpacity) {
+ mFillOpacity = fillOpacity;
+ }
+
+ float getTrimPathStart() {
+ return mTrimPathStart;
+ }
+
+ void setTrimPathStart(float trimPathStart) {
+ mTrimPathStart = trimPathStart;
+ }
+
+ float getTrimPathEnd() {
+ return mTrimPathEnd;
+ }
+
+ void setTrimPathEnd(float trimPathEnd) {
+ mTrimPathEnd = trimPathEnd;
+ }
+
+ float getTrimPathOffset() {
+ return mTrimPathOffset;
+ }
+
+ void setTrimPathOffset(float trimPathOffset) {
+ mTrimPathOffset = trimPathOffset;
+ }
+
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
final int[] themeAttrs = a.extractThemeAttrs();
@@ -883,7 +1046,7 @@
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
- mId = a.getString(R.styleable.VectorDrawablePath_name);
+ mPathName = a.getString(R.styleable.VectorDrawablePath_name);
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
@@ -966,7 +1129,7 @@
mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
- mId = a.getString(R.styleable.VectorDrawablePath_name);
+ mPathName = a.getString(R.styleable.VectorDrawablePath_name);
}
if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 8aa8c92..1cb87f2 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -26,8 +26,24 @@
namespace android {
namespace uirenderer {
+NullDamageAccumulator NullDamageAccumulator::sInstance;
+
+NullDamageAccumulator* NullDamageAccumulator::instance() {
+ return &sInstance;
+}
+
+enum TransformType {
+ TransformRenderNode,
+ TransformMatrix4,
+ TransformNone,
+};
+
struct DirtyStack {
- const RenderNode* node;
+ TransformType type;
+ union {
+ const RenderNode* renderNode;
+ const Matrix4* matrix4;
+ };
// When this frame is pop'd, this rect is mapped through the above transform
// and applied to the previous (aka parent) frame
SkRect pendingDirty;
@@ -42,7 +58,7 @@
mHead->prev = mHead;
}
-void DamageAccumulator::pushNode(const RenderNode* node) {
+void DamageAccumulator::pushCommon() {
if (!mHead->next) {
DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
nextFrame->next = 0;
@@ -50,42 +66,131 @@
mHead->next = nextFrame;
}
mHead = mHead->next;
- mHead->node = node;
mHead->pendingDirty.setEmpty();
}
-void DamageAccumulator::popNode() {
+void DamageAccumulator::pushTransform(const RenderNode* transform) {
+ pushCommon();
+ mHead->type = TransformRenderNode;
+ mHead->renderNode = transform;
+}
+
+void DamageAccumulator::pushTransform(const Matrix4* transform) {
+ pushCommon();
+ mHead->type = TransformMatrix4;
+ mHead->matrix4 = transform;
+}
+
+void DamageAccumulator::pushNullTransform() {
+ pushCommon();
+ mHead->type = TransformNone;
+}
+
+void DamageAccumulator::popTransform() {
LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
DirtyStack* dirtyFrame = mHead;
mHead = mHead->prev;
- if (!dirtyFrame->pendingDirty.isEmpty()) {
- SkRect mappedDirty;
- const RenderProperties& props = dirtyFrame->node->properties();
- const SkMatrix* transform = props.getTransformMatrix();
- if (transform && !transform->isIdentity()) {
- transform->mapRect(&mappedDirty, dirtyFrame->pendingDirty);
- } else {
- mappedDirty = dirtyFrame->pendingDirty;
+ switch (dirtyFrame->type) {
+ case TransformRenderNode:
+ applyRenderNodeTransform(dirtyFrame);
+ break;
+ case TransformMatrix4:
+ applyMatrix4Transform(dirtyFrame);
+ break;
+ case TransformNone:
+ mHead->pendingDirty.join(dirtyFrame->pendingDirty);
+ break;
+ }
+}
+
+static inline void mapRect(const Matrix4* matrix, const SkRect& in, SkRect* out) {
+ if (in.isEmpty()) return;
+ Rect temp(in);
+ matrix->mapRect(temp);
+ out->join(RECT_ARGS(temp));
+}
+
+void DamageAccumulator::applyMatrix4Transform(DirtyStack* frame) {
+ mapRect(frame->matrix4, frame->pendingDirty, &mHead->pendingDirty);
+}
+
+static inline void mapRect(const RenderProperties& props, const SkRect& in, SkRect* out) {
+ if (in.isEmpty()) return;
+ const SkMatrix* transform = props.getTransformMatrix();
+ SkRect temp(in);
+ if (transform && !transform->isIdentity()) {
+ transform->mapRect(&temp);
+ }
+ temp.offset(props.getLeft(), props.getTop());
+ out->join(temp);
+}
+
+static DirtyStack* findParentRenderNode(DirtyStack* frame) {
+ while (frame->prev != frame) {
+ frame = frame->prev;
+ if (frame->type == TransformRenderNode) {
+ return frame;
}
- if (CC_LIKELY(mHead->node)) {
- const RenderProperties& parentProps = mHead->node->properties();
- mappedDirty.offset(props.getLeft() - parentProps.getScrollX(),
- props.getTop() - parentProps.getScrollY());
- if (props.getClipToBounds()) {
- if (!mappedDirty.intersect(0, 0, parentProps.getWidth(), parentProps.getHeight())) {
- mappedDirty.setEmpty();
- }
+ }
+ return NULL;
+}
+
+static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
+ if (frame) {
+ while (frame->prev != frame) {
+ frame = frame->prev;
+ if (frame->type == TransformRenderNode
+ && frame->renderNode->hasProjectionReceiver()) {
+ return frame;
}
- if (CC_UNLIKELY(!MathUtils::isZero(props.getTranslationZ()))) {
- // TODO: Can we better bound the shadow damage area? For now
- // match the old damageShadowReceiver() path and just dirty
- // the entire parent bounds
- mappedDirty.join(0, 0, parentProps.getWidth(), parentProps.getHeight());
- }
- } else {
- mappedDirty.offset(props.getLeft(), props.getTop());
}
- dirty(mappedDirty.fLeft, mappedDirty.fTop, mappedDirty.fRight, mappedDirty.fBottom);
+ }
+ return NULL;
+}
+
+static void applyTransforms(DirtyStack* frame, DirtyStack* end) {
+ SkRect* rect = &frame->pendingDirty;
+ while (frame != end) {
+ if (frame->type == TransformRenderNode) {
+ mapRect(frame->renderNode->properties(), *rect, rect);
+ } else {
+ mapRect(frame->matrix4, *rect, rect);
+ }
+ frame = frame->prev;
+ }
+}
+
+void DamageAccumulator::applyRenderNodeTransform(DirtyStack* frame) {
+ if (frame->pendingDirty.isEmpty()) {
+ return;
+ }
+
+ const RenderProperties& props = frame->renderNode->properties();
+
+ // Perform clipping
+ if (props.getClipToBounds() && !frame->pendingDirty.isEmpty()) {
+ if (!frame->pendingDirty.intersect(0, 0, props.getWidth(), props.getHeight())) {
+ frame->pendingDirty.setEmpty();
+ }
+ }
+
+ // apply all transforms
+ mapRect(props, frame->pendingDirty, &mHead->pendingDirty);
+
+ // project backwards if necessary
+ if (props.getProjectBackwards() && !frame->pendingDirty.isEmpty()) {
+ // First, find our parent RenderNode:
+ DirtyStack* parentNode = findParentRenderNode(frame);
+ // Find our parent's projection receiver, which is what we project onto
+ DirtyStack* projectionReceiver = findProjectionReceiver(parentNode);
+ if (projectionReceiver) {
+ applyTransforms(frame, projectionReceiver);
+ projectionReceiver->pendingDirty.join(frame->pendingDirty);
+ } else {
+ ALOGW("Failed to find projection receiver? Dropping on the floor...");
+ }
+
+ frame->pendingDirty.setEmpty();
}
}
@@ -93,6 +198,10 @@
mHead->pendingDirty.join(left, top, right, bottom);
}
+void DamageAccumulator::peekAtDirty(SkRect* dest) {
+ *dest = mHead->pendingDirty;
+}
+
void DamageAccumulator::finish(SkRect* totalDirty) {
LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
// Root node never has a transform, so this is the fully mapped dirty rect
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index c62a351..fc9b41b 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -16,6 +16,7 @@
#ifndef DAMAGEACCUMULATOR_H
#define DAMAGEACCUMULATOR_H
+#include <cutils/compiler.h>
#include <utils/LinearAllocator.h>
#include <SkMatrix.h>
@@ -28,8 +29,21 @@
struct DirtyStack;
class RenderNode;
+class Matrix4;
-class DamageAccumulator {
+class IDamageAccumulator {
+public:
+ virtual void pushTransform(const RenderNode* transform) = 0;
+ virtual void pushTransform(const Matrix4* transform) = 0;
+ virtual void pushNullTransform() = 0;
+ virtual void popTransform() = 0;
+ virtual void dirty(float left, float top, float right, float bottom) = 0;
+ virtual void peekAtDirty(SkRect* dest) = 0;
+protected:
+ virtual ~IDamageAccumulator() {}
+};
+
+class DamageAccumulator : public IDamageAccumulator {
PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
public:
DamageAccumulator();
@@ -37,20 +51,52 @@
// Push a transform node onto the stack. This should be called prior
// to any dirty() calls. Subsequent calls to dirty()
- // will be affected by the node's transform when popNode() is called.
- void pushNode(const RenderNode* node);
+ // will be affected by the transform when popTransform() is called.
+ virtual void pushTransform(const RenderNode* transform);
+ virtual void pushTransform(const Matrix4* transform);
+ // This is used in combination with peekAtDirty to inspect the damage
+ // area of a subtree
+ virtual void pushNullTransform();
+
// Pops a transform node from the stack, propagating the dirty rect
- // up to the parent node.
- void popNode();
- void dirty(float left, float top, float right, float bottom);
+ // up to the parent node. Returns the IDamageTransform that was just applied
+ virtual void popTransform();
+
+ virtual void dirty(float left, float top, float right, float bottom);
+
+ // Returns the current dirty area, *NOT* transformed by pushed transforms
+ virtual void peekAtDirty(SkRect* dest);
void finish(SkRect* totalDirty);
private:
+ void pushCommon();
+ void applyMatrix4Transform(DirtyStack* frame);
+ void applyRenderNodeTransform(DirtyStack* frame);
+
LinearAllocator mAllocator;
DirtyStack* mHead;
};
+class NullDamageAccumulator : public IDamageAccumulator {
+ PREVENT_COPY_AND_ASSIGN(NullDamageAccumulator);
+public:
+ virtual void pushTransform(const RenderNode* transform) { }
+ virtual void pushTransform(const Matrix4* transform) { }
+ virtual void pushNullTransform() { }
+ virtual void popTransform() { }
+ virtual void dirty(float left, float top, float right, float bottom) { }
+ virtual void peekAtDirty(SkRect* dest) { dest->setEmpty(); }
+
+ ANDROID_API static NullDamageAccumulator* instance();
+
+private:
+ NullDamageAccumulator() {}
+ ~NullDamageAccumulator() {}
+
+ static NullDamageAccumulator sInstance;
+};
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index d494c4c..8e99b9a 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -27,8 +27,7 @@
}
DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
- : mDisplayList(0)
- , mSurfaceTexture(0)
+ : mSurfaceTexture(0)
, mTransform(0)
, mNeedsGLContextAttach(false)
, mUpdateTexImage(false)
@@ -41,7 +40,6 @@
mColorFilter = SkSafeRef(mLayer->getColorFilter());
mAlpha = mLayer->getAlpha();
mMode = mLayer->getMode();
- mDirtyRect.setEmpty();
if (!mDestroyer) {
mDestroyer = defaultLayerDestroyer;
@@ -60,37 +58,13 @@
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
-void DeferredLayerUpdater::setDisplayList(RenderNode* displayList,
- int left, int top, int right, int bottom) {
- mDisplayList = displayList;
- if (mDirtyRect.isEmpty()) {
- mDirtyRect.set(left, top, right, bottom);
- } else {
- mDirtyRect.unionWith(Rect(left, top, right, bottom));
- }
-}
-
bool DeferredLayerUpdater::apply(TreeInfo& info) {
bool success = true;
// These properties are applied the same to both layer types
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
- if (mDisplayList.get()) {
- if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
- success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
- }
- mLayer->setBlend(mBlend);
- // TODO: Use DamageAccumulator to get the damage area for the layer's
- // subtree to only update that part of the layer. Do this as part of
- // reworking layers to be a RenderProperty instead of a View-managed object
- mDirtyRect.set(0, 0, mWidth, mHeight);
- mDisplayList->prepareTree(info);
- mLayer->updateDeferred(mDisplayList.get(),
- mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
- mDirtyRect.setEmpty();
- mDisplayList = 0;
- } else if (mSurfaceTexture.get()) {
+ if (mSurfaceTexture.get()) {
if (mNeedsGLContextAttach) {
mNeedsGLContextAttach = false;
mSurfaceTexture->attachToContext(mLayer->getTexture());
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index b7cfe80..5082271 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -74,9 +74,6 @@
mTransform = matrix ? new SkMatrix(*matrix) : 0;
}
- ANDROID_API void setDisplayList(RenderNode* displayList,
- int left, int top, int right, int bottom);
-
ANDROID_API void setPaint(const SkPaint* paint);
ANDROID_API bool apply(TreeInfo& info);
@@ -94,11 +91,6 @@
int mAlpha;
SkXfermode::Mode mMode;
- // Layer type specific properties
- // displayList and surfaceTexture are mutually exclusive, only 1 may be set
- // dirtyRect is only valid if displayList is set
- sp<RenderNode> mDisplayList;
- Rect mDirtyRect;
sp<GLConsumer> mSurfaceTexture;
SkMatrix* mTransform;
bool mNeedsGLContextAttach;
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 2268386..9f2014f 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -417,6 +417,8 @@
}
void Matrix4::mapRect(Rect& r) const {
+ if (isIdentity()) return;
+
if (isSimple()) {
MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]);
MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index e33a001..1c5c578 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -147,6 +147,7 @@
data[kTranslateX] += x;
data[kTranslateY] += y;
data[kTranslateZ] += z;
+ mType |= kTypeUnknown;
} else {
// Doing a translation will only affect the translate bit of the type
// Save the type
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index c9921ba..59e15e1 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -975,11 +975,14 @@
// Bezier approximation
///////////////////////////////////////////////////////////////////////////////
+// Depth at which recursion is aborted
+#define ABORT_DEPTH 20
+
void PathTessellator::recursiveCubicBezierVertices(
float p1x, float p1y, float c1x, float c1y,
float p2x, float p2y, float c2x, float c2y,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
- Vector<Vertex>& outputVertices) {
+ Vector<Vertex>& outputVertices, int depth) {
float dx = p2x - p1x;
float dy = p2y - p1y;
float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
@@ -988,7 +991,7 @@
// multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
- if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
+ if (depth >= ABORT_DEPTH || d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
// below thresh, draw line by adding endpoint
pushToVector(outputVertices, p2x, p2y);
} else {
@@ -1012,11 +1015,11 @@
recursiveCubicBezierVertices(
p1x, p1y, p1c1x, p1c1y,
mx, my, p1c1c2x, p1c1c2y,
- sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
recursiveCubicBezierVertices(
mx, my, p2c1c2x, p2c1c2y,
p2x, p2y, p2c2x, p2c2y,
- sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
}
}
@@ -1025,12 +1028,12 @@
float bx, float by,
float cx, float cy,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
- Vector<Vertex>& outputVertices) {
+ Vector<Vertex>& outputVertices, int depth) {
float dx = bx - ax;
float dy = by - ay;
float d = (cx - bx) * dy - (cy - by) * dx;
- if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
+ if (depth >= ABORT_DEPTH || d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
// below thresh, draw line by adding endpoint
pushToVector(outputVertices, bx, by);
} else {
@@ -1044,9 +1047,9 @@
float my = (acy + bcy) * 0.5f;
recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
- sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
- sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices, depth + 1);
}
}
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index f033470..8ac9a3b 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -105,7 +105,7 @@
float bx, float by,
float cx, float cy,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
- Vector<Vertex> &outputVertices);
+ Vector<Vertex> &outputVertices, int depth = 0);
/*
endpoints p1, p2
@@ -117,7 +117,7 @@
float p2x, float p2y,
float c2x, float c2y,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
- Vector<Vertex> &outputVertices);
+ Vector<Vertex> &outputVertices, int depth = 0);
};
}; // namespace uirenderer
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index c2f6df8..378183a 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -15,6 +15,7 @@
*/
#define ATRACE_TAG ATRACE_TAG_VIEW
+#define LOG_TAG "RenderNode"
#include "RenderNode.h"
@@ -29,6 +30,8 @@
#include "Debug.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
+#include "LayerRenderer.h"
+#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
namespace android {
@@ -58,12 +61,14 @@
, mNeedsDisplayListDataSync(false)
, mDisplayListData(0)
, mStagingDisplayListData(0)
- , mNeedsAnimatorsSync(false) {
+ , mNeedsAnimatorsSync(false)
+ , mLayer(0) {
}
RenderNode::~RenderNode() {
delete mDisplayListData;
delete mStagingDisplayListData;
+ LayerRenderer::destroyLayerDeferred(mLayer);
}
void RenderNode::setStagingDisplayList(DisplayListData* data) {
@@ -111,36 +116,85 @@
prepareTreeImpl(info);
}
-static inline void pushNode(RenderNode* self, TreeInfo& info) {
- if (info.damageAccumulator) {
- info.damageAccumulator->pushNode(self);
- }
-}
-
-static inline void popNode(TreeInfo& info) {
- if (info.damageAccumulator) {
- info.damageAccumulator->popNode();
- }
-}
-
void RenderNode::damageSelf(TreeInfo& info) {
- if (info.damageAccumulator && isRenderable() && properties().getAlpha() > 0) {
- info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+ if (isRenderable() && properties().getAlpha() > 0) {
+ if (properties().getClipToBounds()) {
+ info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+ } else {
+ // Hope this is big enough?
+ // TODO: Get this from the display list ops or something
+ info.damageAccumulator->dirty(INT_MIN, INT_MIN, INT_MAX, INT_MAX);
+ }
+ }
+}
+
+void RenderNode::prepareLayer(TreeInfo& info) {
+ LayerType layerType = properties().layerProperties().type();
+ if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) {
+ // We push a null transform here as we don't care what the existing dirty
+ // area is, only what our display list dirty is as well as our children's
+ // dirty area
+ info.damageAccumulator->pushNullTransform();
+ }
+}
+
+void RenderNode::pushLayerUpdate(TreeInfo& info) {
+ LayerType layerType = properties().layerProperties().type();
+ // If we are not a layer OR we cannot be rendered (eg, view was detached)
+ // we need to destroy any Layers we may have had previously
+ if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) {
+ if (layerType == kLayerTypeRenderLayer) {
+ info.damageAccumulator->popTransform();
+ }
+ if (CC_UNLIKELY(mLayer)) {
+ LayerRenderer::destroyLayer(mLayer);
+ mLayer = NULL;
+ }
+ return;
+ }
+
+ if (!mLayer) {
+ mLayer = LayerRenderer::createRenderLayer(getWidth(), getHeight());
+ applyLayerPropertiesToLayer(info);
+ damageSelf(info);
+ } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
+ LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight());
+ damageSelf(info);
+ }
+
+ SkRect dirty;
+ info.damageAccumulator->peekAtDirty(&dirty);
+ info.damageAccumulator->popTransform();
+
+ if (!dirty.isEmpty()) {
+ mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
+ }
+ // This is not inside the above if because we may have called
+ // updateDeferred on a previous prepare pass that didn't have a renderer
+ if (info.renderer && mLayer->deferredUpdateScheduled) {
+ info.renderer->pushLayerUpdate(mLayer);
}
}
void RenderNode::prepareTreeImpl(TreeInfo& info) {
- pushNode(this, info);
+ info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
- pushStagingChanges(info);
+ pushStagingPropertiesChanges(info);
evaluateAnimations(info);
} else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
- pushStagingChanges(info);
+ pushStagingPropertiesChanges(info);
} else if (info.mode == TreeInfo::MODE_RT_ONLY) {
evaluateAnimations(info);
}
+
+ prepareLayer(info);
+ if (info.mode == TreeInfo::MODE_FULL) {
+ pushStagingDisplayListChanges(info);
+ }
prepareSubTree(info, mDisplayListData);
- popNode(info);
+ pushLayerUpdate(info);
+
+ info.damageAccumulator->popTransform();
}
class PushAnimatorsFunctor {
@@ -157,7 +211,7 @@
TreeInfo& mInfo;
};
-void RenderNode::pushStagingChanges(TreeInfo& info) {
+void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
// Push the animators first so that setupStartValueIfNecessary() is called
// before properties() is trampled by stagingProperties(), as they are
// required by some animators.
@@ -173,16 +227,29 @@
if (mDirtyPropertyFields) {
mDirtyPropertyFields = 0;
damageSelf(info);
- popNode(info);
+ info.damageAccumulator->popTransform();
mProperties = mStagingProperties;
- pushNode(this, info);
+ applyLayerPropertiesToLayer(info);
// We could try to be clever and only re-damage if the matrix changed.
// However, we don't need to worry about that. The cost of over-damaging
// here is only going to be a single additional map rect of this node
// plus a rect join(). The parent's transform (and up) will only be
// performed once.
+ info.damageAccumulator->pushTransform(this);
damageSelf(info);
}
+}
+
+void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
+ if (CC_LIKELY(!mLayer)) return;
+
+ const LayerProperties& props = properties().layerProperties();
+ mLayer->setAlpha(props.alpha(), props.xferMode());
+ mLayer->setColorFilter(props.colorFilter());
+ mLayer->setBlend(props.needsBlending());
+}
+
+void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
if (mNeedsDisplayListDataSync) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
@@ -217,7 +284,7 @@
// property push and just damage self before and after animators are run
damageSelf(info);
- popNode(info);
+ info.damageAccumulator->popTransform();
AnimateFunctor functor(this, info);
std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
@@ -226,7 +293,7 @@
mProperties.updateMatrix();
info.out.hasAnimations |= mAnimators.size();
- pushNode(this, info);
+ info.damageAccumulator->pushTransform(this);
damageSelf(info);
}
@@ -243,8 +310,11 @@
info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
}
for (size_t i = 0; i < subtree->children().size(); i++) {
- RenderNode* childNode = subtree->children()[i]->mDisplayList;
+ DrawDisplayListOp* op = subtree->children()[i];
+ RenderNode* childNode = op->mDisplayList;
+ info.damageAccumulator->pushTransform(&op->mTransformFromParent);
childNode->prepareTreeImpl(info);
+ info.damageAccumulator->popTransform();
}
}
}
@@ -276,9 +346,10 @@
renderer.concatMatrix(*properties().getTransformMatrix());
}
}
- bool clipToBoundsNeeded = properties().getCaching() ? false : properties().getClipToBounds();
+ const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
+ bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds();
if (properties().getAlpha() < 1) {
- if (properties().getCaching()) {
+ if (isLayer) {
renderer.setOverrideLayerAlpha(properties().getAlpha());
} else if (!properties().getHasOverlappingRendering()) {
renderer.scaleAlpha(properties().getAlpha());
@@ -693,8 +764,14 @@
*/
template <class T>
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
+ const bool drawLayer = (mLayer && (&renderer != mLayer->renderer));
+ // If we are updating the contents of mLayer, we don't want to apply any of
+ // the RenderNode's properties to this issueOperations pass. Those will all
+ // be applied when the layer is drawn, aka when this is true.
+ const bool useViewProperties = (!mLayer || drawLayer);
+
const int level = handler.level();
- if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
+ if (mDisplayListData->isEmpty() || (useViewProperties && properties().getAlpha() <= 0)) {
DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
return;
}
@@ -716,7 +793,9 @@
DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
- setViewProperties<T>(renderer, handler);
+ if (useViewProperties) {
+ setViewProperties<T>(renderer, handler);
+ }
bool quickRejected = properties().getClipToBounds()
&& renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
@@ -725,31 +804,36 @@
renderer.setClippingOutline(alloc, &(mProperties.getOutline()));
}
- Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
- buildZSortedChildList(zTranslatedNodes);
+ if (drawLayer) {
+ handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
+ renderer.getSaveCount() - 1, properties().getClipToBounds());
+ } else {
+ Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
+ buildZSortedChildList(zTranslatedNodes);
- // for 3d root, draw children with negative z values
- issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+ // for 3d root, draw children with negative z values
+ issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- const int saveCountOffset = renderer.getSaveCount() - 1;
- const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
- for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
- DisplayListOp *op = mDisplayListData->displayListOps[i];
+ DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+ const int saveCountOffset = renderer.getSaveCount() - 1;
+ const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
+ for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+ DisplayListOp *op = mDisplayListData->displayListOps[i];
-#if DEBUG_DISPLAY_LIST
- op->output(level + 1);
-#endif
- logBuffer.writeCommand(level, op->name());
- handler(op, saveCountOffset, properties().getClipToBounds());
+ #if DEBUG_DISPLAY_LIST
+ op->output(level + 1);
+ #endif
+ logBuffer.writeCommand(level, op->name());
+ handler(op, saveCountOffset, properties().getClipToBounds());
- if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
- issueOperationsOfProjectedChildren(renderer, handler);
+ if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
+ issueOperationsOfProjectedChildren(renderer, handler);
+ }
}
- }
- // for 3d root, draw children with positive z values
- issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ // for 3d root, draw children with positive z values
+ issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ }
}
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 393d4ea..b2fe849 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -39,6 +39,7 @@
#include <androidfw/ResourceTypes.h>
+#include "DamageAccumulator.h"
#include "Debug.h"
#include "Matrix.h"
#include "DeferredDisplayList.h"
@@ -125,6 +126,10 @@
return mDisplayListData && mDisplayListData->hasDrawOps;
}
+ bool hasProjectionReceiver() const {
+ return mDisplayListData && mDisplayListData->projectionReceiveIndex >= 0;
+ }
+
const char* getName() const {
return mName.string();
}
@@ -249,9 +254,13 @@
};
void prepareTreeImpl(TreeInfo& info);
- void pushStagingChanges(TreeInfo& info);
+ void pushStagingPropertiesChanges(TreeInfo& info);
+ void pushStagingDisplayListChanges(TreeInfo& info);
void evaluateAnimations(TreeInfo& info);
void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
+ void applyLayerPropertiesToLayer(TreeInfo& info);
+ void prepareLayer(TreeInfo& info);
+ void pushLayerUpdate(TreeInfo& info);
String8 mName;
@@ -267,6 +276,10 @@
std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+ // Owned by RT. Lifecycle is managed by prepareTree(), with the exception
+ // being in ~RenderNode() which may happen on any thread.
+ Layer* mLayer;
+
/**
* Draw time state - these properties are only set and used during rendering
*/
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 6163df5..8848b2f 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -21,16 +21,59 @@
#include <utils/Trace.h>
#include <SkCanvas.h>
+#include <SkColorFilter.h>
#include <SkMatrix.h>
#include <SkPath.h>
#include <SkPathOps.h>
#include "Matrix.h"
+#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
+LayerProperties::LayerProperties()
+ : mType(kLayerTypeNone)
+ , mColorFilter(NULL) {
+ reset();
+}
+
+LayerProperties::~LayerProperties() {
+ setType(kLayerTypeNone);
+}
+
+void LayerProperties::reset() {
+ mOpaque = false;
+ setFromPaint(NULL);
+}
+
+bool LayerProperties::setColorFilter(SkColorFilter* filter) {
+ if (mColorFilter == filter) return false;
+ SkRefCnt_SafeAssign(mColorFilter, filter);
+ return true;
+}
+
+bool LayerProperties::setFromPaint(const SkPaint* paint) {
+ bool changed = false;
+ SkXfermode::Mode mode;
+ int alpha;
+ OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+ changed |= setAlpha(static_cast<uint8_t>(alpha));
+ changed |= setXferMode(mode);
+ changed |= setColorFilter(paint ? paint->getColorFilter() : NULL);
+ return changed;
+}
+
+LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
+ setType(other.type());
+ setOpaque(other.opaque());
+ setAlpha(other.alpha());
+ setXferMode(other.xferMode());
+ setColorFilter(other.colorFilter());
+ return *this;
+}
+
RenderProperties::PrimitiveFields::PrimitiveFields()
: mClipToBounds(true)
, mProjectBackwards(false)
@@ -44,10 +87,8 @@
, mPivotX(0), mPivotY(0)
, mLeft(0), mTop(0), mRight(0), mBottom(0)
, mWidth(0), mHeight(0)
- , mScrollX(0), mScrollY(0)
, mPivotExplicitlySet(false)
- , mMatrixOrPivotDirty(false)
- , mCaching(false) {
+ , mMatrixOrPivotDirty(false) {
}
RenderProperties::ComputedFields::ComputedFields()
@@ -74,6 +115,7 @@
setStaticMatrix(other.getStaticMatrix());
setAnimationMatrix(other.getAnimationMatrix());
setCameraDistance(other.getCameraDistance());
+ mLayerProperties = other.layerProperties();
// Force recalculation of the matrix, since other's dirty bit may be clear
mPrimitiveFields.mMatrixOrPivotDirty = true;
@@ -104,9 +146,9 @@
}
}
- bool clipToBoundsNeeded = mPrimitiveFields.mCaching ? false : mPrimitiveFields.mClipToBounds;
+ bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds;
if (mPrimitiveFields.mAlpha < 1) {
- if (mPrimitiveFields.mCaching) {
+ if (layerProperties().type() != kLayerTypeNone) {
ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
} else if (!mPrimitiveFields.mHasOverlappingRendering) {
ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index c294f38..8c6cc9e 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -32,6 +32,7 @@
#include "Outline.h"
class SkBitmap;
+class SkColorFilter;
class SkPaint;
namespace android {
@@ -39,15 +40,95 @@
class Matrix4;
class RenderNode;
+class RenderProperties;
// The __VA_ARGS__ will be executed if a & b are not equal
#define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false)
#define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
+// Keep in sync with View.java:LAYER_TYPE_*
+enum LayerType {
+ kLayerTypeNone = 0,
+ // Although we cannot build the software layer directly (must be done at
+ // record time), this information is used when applying alpha.
+ kLayerTypeSoftware = 1,
+ kLayerTypeRenderLayer = 2,
+ // TODO: LayerTypeSurfaceTexture? Maybe?
+};
+
+class ANDROID_API LayerProperties {
+public:
+ bool setType(LayerType type) {
+ if (RP_SET(mType, type)) {
+ reset();
+ return true;
+ }
+ return false;
+ }
+
+ LayerType type() const {
+ return mType;
+ }
+
+ bool setOpaque(bool opaque) {
+ return RP_SET(mOpaque, opaque);
+ }
+
+ bool opaque() const {
+ return mOpaque;
+ }
+
+ bool setAlpha(uint8_t alpha) {
+ return RP_SET(mAlpha, alpha);
+ }
+
+ uint8_t alpha() const {
+ return mAlpha;
+ }
+
+ bool setXferMode(SkXfermode::Mode mode) {
+ return RP_SET(mMode, mode);
+ }
+
+ SkXfermode::Mode xferMode() const {
+ return mMode;
+ }
+
+ bool setColorFilter(SkColorFilter* filter);
+
+ SkColorFilter* colorFilter() const {
+ return mColorFilter;
+ }
+
+ // Sets alpha, xfermode, and colorfilter from an SkPaint
+ // paint may be NULL, in which case defaults will be set
+ bool setFromPaint(const SkPaint* paint);
+
+ bool needsBlending() const {
+ return !opaque() || alpha() < 255;
+ }
+
+ LayerProperties& operator=(const LayerProperties& other);
+
+private:
+ LayerProperties();
+ ~LayerProperties();
+ void reset();
+
+ friend class RenderProperties;
+
+ LayerType mType;
+ // Whether or not that Layer's content is opaque, doesn't include alpha
+ bool mOpaque;
+ uint8_t mAlpha;
+ SkXfermode::Mode mMode;
+ SkColorFilter* mColorFilter;
+};
+
/*
* Data structure that holds the properties for a RenderNode
*/
-class RenderProperties {
+class ANDROID_API RenderProperties {
public:
RenderProperties();
virtual ~RenderProperties();
@@ -366,26 +447,6 @@
return false;
}
- bool setScrollX(int scrollX) {
- return RP_SET(mPrimitiveFields.mScrollX, scrollX);
- }
-
- bool setScrollY(int scrollY) {
- return RP_SET(mPrimitiveFields.mScrollY, scrollY);
- }
-
- int getScrollX() const {
- return mPrimitiveFields.mScrollX;
- }
-
- int getScrollY() const {
- return mPrimitiveFields.mScrollY;
- }
-
- bool setCaching(bool caching) {
- return RP_SET(mPrimitiveFields.mCaching, caching);
- }
-
int getWidth() const {
return mPrimitiveFields.mWidth;
}
@@ -412,10 +473,6 @@
return mComputedFields.mTransformMatrix;
}
- bool getCaching() const {
- return mPrimitiveFields.mCaching;
- }
-
bool getClipToBounds() const {
return mPrimitiveFields.mClipToBounds;
}
@@ -438,7 +495,7 @@
void debugOutputProperties(const int level) const;
- ANDROID_API void updateMatrix();
+ void updateMatrix();
bool hasClippingPath() const {
return mPrimitiveFields.mRevealClip.willClip();
@@ -461,6 +518,14 @@
return mPrimitiveFields.mRevealClip;
}
+ const LayerProperties& layerProperties() const {
+ return mLayerProperties;
+ }
+
+ LayerProperties& mutateLayerProperties() {
+ return mLayerProperties;
+ }
+
private:
// Rendering properties
@@ -481,14 +546,13 @@
float mPivotX, mPivotY;
int mLeft, mTop, mRight, mBottom;
int mWidth, mHeight;
- int mScrollX, mScrollY;
bool mPivotExplicitlySet;
bool mMatrixOrPivotDirty;
- bool mCaching;
} mPrimitiveFields;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
+ LayerProperties mLayerProperties;
/**
* These fields are all generated from other properties and are not set directly.
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 41cc9d2..ef3d0d7 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -39,6 +39,7 @@
TessellationCache::Description::Description()
: type(kNone)
+ , aa(false)
, cap(SkPaint::kDefault_Cap)
, style(SkPaint::kFill_Style)
, strokeWidth(1.0f) {
@@ -47,6 +48,7 @@
TessellationCache::Description::Description(Type type)
: type(type)
+ , aa(false)
, cap(SkPaint::kDefault_Cap)
, style(SkPaint::kFill_Style)
, strokeWidth(1.0f) {
@@ -55,6 +57,7 @@
TessellationCache::Description::Description(Type type, const SkPaint* paint)
: type(type)
+ , aa(paint->isAntiAlias())
, cap(paint->getStrokeCap())
, style(paint->getStyle())
, strokeWidth(paint->getStrokeWidth()) {
@@ -63,6 +66,7 @@
hash_t TessellationCache::Description::hash() const {
uint32_t hash = JenkinsHashMix(0, type);
+ hash = JenkinsHashMix(hash, aa);
hash = JenkinsHashMix(hash, cap);
hash = JenkinsHashMix(hash, style);
hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
@@ -165,12 +169,12 @@
ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius)
- : drawTransform(drawTransform)
+ : drawTransform(*drawTransform)
, localClip(localClip)
, opaque(opaque)
- , casterPerimeter(casterPerimeter)
- , transformXY(transformXY)
- , transformZ(transformZ)
+ , casterPerimeter(*casterPerimeter)
+ , transformXY(*transformXY)
+ , transformZ(*transformZ)
, lightCenter(lightCenter)
, lightRadius(lightRadius) {
}
@@ -182,14 +186,19 @@
delete bufferPair;
}
- // Note - only the localClip is deep copied, since other pointers point at Allocator controlled
- // objects, which are safe for the entire frame
- const Matrix4* drawTransform;
+ /* Note - we deep copy all task parameters, because *even though* pointers into Allocator
+ * controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
+ * certain Allocators are destroyed before trim() is called to flush incomplete tasks.
+ *
+ * These deep copies could be avoided, long term, by cancelling or flushing outstanding tasks
+ * before tearning down single-frame LinearAllocators.
+ */
+ const Matrix4 drawTransform;
const Rect localClip;
bool opaque;
- const SkPath* casterPerimeter;
- const Matrix4* transformXY;
- const Matrix4* transformZ;
+ const SkPath casterPerimeter;
+ const Matrix4 transformXY;
+ const Matrix4 transformZ;
const Vector3 lightCenter;
const float lightRadius;
};
@@ -281,8 +290,8 @@
VertexBuffer* ambientBuffer = new VertexBuffer;
VertexBuffer* spotBuffer = new VertexBuffer;
- tessellateShadows(t->drawTransform, &t->localClip, t->opaque, t->casterPerimeter,
- t->transformXY, t->transformZ, t->lightCenter, t->lightRadius,
+ tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
+ &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
*ambientBuffer, *spotBuffer);
t->setResult(new TessellationCache::vertexBuffer_pair_t(ambientBuffer, spotBuffer));
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
index 8f37230..d4ff943 100644
--- a/libs/hwui/TessellationCache.h
+++ b/libs/hwui/TessellationCache.h
@@ -55,6 +55,7 @@
};
Type type;
+ bool aa;
SkPaint::Cap cap;
SkPaint::Style style;
float strokeWidth;
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 2096f98..0fc0cef 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -18,6 +18,7 @@
#include <utils/Timers.h>
+#include "DamageAccumulator.h"
#include "utils/Macros.h"
namespace android {
@@ -25,7 +26,7 @@
class BaseRenderNodeAnimator;
class AnimationListener;
-class DamageAccumulator;
+class OpenGLRenderer;
class AnimationHook {
public:
@@ -62,7 +63,8 @@
, frameTimeMs(0)
, animationHook(NULL)
, prepareTextures(mode == MODE_FULL)
- , damageAccumulator(0)
+ , damageAccumulator(NullDamageAccumulator::instance())
+ , renderer(0)
{}
const TraversalMode mode;
@@ -71,7 +73,11 @@
// TODO: Remove this? Currently this is used to signal to stop preparing
// textures if we run out of cache space.
bool prepareTextures;
- DamageAccumulator* damageAccumulator;
+ // Must not be null
+ IDamageAccumulator* damageAccumulator;
+ // The renderer that will be drawing the next frame. Use this to push any
+ // layer updates or similar. May be NULL.
+ OpenGLRenderer* renderer;
struct Out {
Out()
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8a5c857..440f965 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -440,6 +440,7 @@
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
info.damageAccumulator = &mDamageAccumulator;
+ info.renderer = mCanvas;
mRootRenderNode->prepareTree(info);
int runningBehind = 0;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index bdfdd21..797566f 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -130,9 +130,6 @@
mContext->processLayerUpdate(mLayers[i].get(), info);
}
mLayers.clear();
- if (info.out.hasAnimations) {
- // TODO: Uh... crap?
- }
mContext->prepareTree(info);
if (info.out.hasAnimations) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index ba6b214..6280fde 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2363,19 +2363,24 @@
if (rctlr == null) {
return false;
}
- IAudioService service = getService();
- final RemoteController.OnClientUpdateListener l = rctlr.getUpdateListener();
- final ComponentName listenerComponent = new ComponentName(mContext, l.getClass());
- try {
- int[] artworkDimensions = rctlr.getArtworkSize();
- boolean reg = service.registerRemoteController(rctlr.getRcDisplay(),
- artworkDimensions[0]/*w*/, artworkDimensions[1]/*h*/,
- listenerComponent);
- rctlr.setIsRegistered(reg);
- return reg;
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in registerRemoteController " + e);
- return false;
+ if (USE_SESSIONS) {
+ rctlr.startListeningToSessions();
+ return true;
+ } else {
+ IAudioService service = getService();
+ final RemoteController.OnClientUpdateListener l = rctlr.getUpdateListener();
+ final ComponentName listenerComponent = new ComponentName(mContext, l.getClass());
+ try {
+ int[] artworkDimensions = rctlr.getArtworkSize();
+ boolean reg = service.registerRemoteController(rctlr.getRcDisplay(),
+ artworkDimensions[0]/* w */, artworkDimensions[1]/* h */,
+ listenerComponent);
+ rctlr.setIsRegistered(reg);
+ return reg;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in registerRemoteController " + e);
+ return false;
+ }
}
}
@@ -2388,12 +2393,16 @@
if (rctlr == null) {
return;
}
- IAudioService service = getService();
- try {
- service.unregisterRemoteControlDisplay(rctlr.getRcDisplay());
- rctlr.setIsRegistered(false);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
+ if (USE_SESSIONS) {
+ rctlr.stopListeningToSessions();
+ } else {
+ IAudioService service = getService();
+ try {
+ service.unregisterRemoteControlDisplay(rctlr.getRcDisplay());
+ rctlr.setIsRegistered(false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e);
+ }
}
}
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 3711585..76c7299 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -19,11 +19,17 @@
import android.app.ActivityManager;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.IRemoteControlDisplay;
import android.media.MediaMetadataEditor;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -34,6 +40,7 @@
import android.view.KeyEvent;
import java.lang.ref.WeakReference;
+import java.util.List;
/**
* The RemoteController class is used to control media playback, display and update media metadata
@@ -56,6 +63,7 @@
private final static int TRANSPORT_UNKNOWN = 0;
private final static String TAG = "RemoteController";
private final static boolean DEBUG = false;
+ private final static boolean USE_SESSIONS = true;
private final static Object mGenLock = new Object();
private final static Object mInfoLock = new Object();
private final RcDisplay mRcd;
@@ -64,6 +72,11 @@
private final int mMaxBitmapDimension;
private MetadataEditor mMetadataEditor;
+ private MediaSessionManager mSessionManager;
+ private MediaSessionManager.SessionListener mSessionListener
+ = new TopTransportSessionListener();
+ private MediaController.Callback mSessionCb = new MediaControllerCallback();
+
/**
* Synchronized on mGenLock
*/
@@ -79,6 +92,8 @@
private int mArtworkWidth = -1;
private int mArtworkHeight = -1;
private boolean mEnabled = true;
+ // synchronized on mInfoLock, for USE_SESSION apis.
+ private MediaController mCurrentSession;
/**
* Class constructor.
@@ -123,6 +138,8 @@
mContext = context;
mRcd = new RcDisplay(this);
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mSessionManager = (MediaSessionManager) context
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
if (ActivityManager.isLowRamDeviceStatic()) {
mMaxBitmapDimension = MAX_BITMAP_DIMENSION;
@@ -194,8 +211,15 @@
* @hide
*/
public String getRemoteControlClientPackageName() {
- return mClientPendingIntentCurrent != null ?
- mClientPendingIntentCurrent.getCreatorPackage() : null;
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ return mCurrentSession != null ? mCurrentSession.getSessionInfo().getPackageName()
+ : null;
+ }
+ } else {
+ return mClientPendingIntentCurrent != null ?
+ mClientPendingIntentCurrent.getCreatorPackage() : null;
+ }
}
/**
@@ -215,22 +239,38 @@
* @see OnClientUpdateListener#onClientPlaybackStateUpdate(int, long, long, float)
*/
public long getEstimatedMediaPosition() {
- if (mLastPlaybackInfo != null) {
- if (!RemoteControlClient.playbackPositionShouldMove(mLastPlaybackInfo.mState)) {
- return mLastPlaybackInfo.mCurrentPosMs;
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ PlaybackState state = mCurrentSession.getPlaybackState();
+ if (state != null) {
+ return state.getPosition();
+ }
+ }
}
-
- // Take the current position at the time of state change and estimate.
- final long thenPos = mLastPlaybackInfo.mCurrentPosMs;
- if (thenPos < 0) {
- return -1;
+ } else {
+ final PlaybackInfo lastPlaybackInfo;
+ synchronized (mInfoLock) {
+ lastPlaybackInfo = mLastPlaybackInfo;
}
+ if (lastPlaybackInfo != null) {
+ if (!RemoteControlClient.playbackPositionShouldMove(lastPlaybackInfo.mState)) {
+ return lastPlaybackInfo.mCurrentPosMs;
+ }
- final long now = SystemClock.elapsedRealtime();
- final long then = mLastPlaybackInfo.mStateChangeTimeMs;
- final long sinceThen = now - then;
- final long scaledSinceThen = (long) (sinceThen * mLastPlaybackInfo.mSpeed);
- return thenPos + scaledSinceThen;
+ // Take the current position at the time of state change and
+ // estimate.
+ final long thenPos = lastPlaybackInfo.mCurrentPosMs;
+ if (thenPos < 0) {
+ return -1;
+ }
+
+ final long now = SystemClock.elapsedRealtime();
+ final long then = lastPlaybackInfo.mStateChangeTimeMs;
+ final long sinceThen = now - then;
+ final long scaledSinceThen = (long) (sinceThen * lastPlaybackInfo.mSpeed);
+ return thenPos + scaledSinceThen;
+ }
}
return -1;
}
@@ -267,30 +307,40 @@
if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
throw new IllegalArgumentException("not a media key event");
}
- final PendingIntent pi;
- synchronized(mInfoLock) {
- if (!mIsRegistered) {
- Log.e(TAG, "Cannot use sendMediaKeyEvent() from an unregistered RemoteController");
- return false;
- }
- if (!mEnabled) {
- Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController");
- return false;
- }
- pi = mClientPendingIntentCurrent;
- }
- if (pi != null) {
- Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
- intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
- try {
- pi.send(mContext, 0, intent);
- } catch (CanceledException e) {
- Log.e(TAG, "Error sending intent for media button down: ", e);
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ return mCurrentSession.dispatchMediaButtonEvent(keyEvent);
+ }
return false;
}
} else {
- Log.i(TAG, "No-op when sending key click, no receiver right now");
- return false;
+ final PendingIntent pi;
+ synchronized (mInfoLock) {
+ if (!mIsRegistered) {
+ Log.e(TAG,
+ "Cannot use sendMediaKeyEvent() from an unregistered RemoteController");
+ return false;
+ }
+ if (!mEnabled) {
+ Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController");
+ return false;
+ }
+ pi = mClientPendingIntentCurrent;
+ }
+ if (pi != null) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ try {
+ pi.send(mContext, 0, intent);
+ } catch (CanceledException e) {
+ Log.e(TAG, "Error sending intent for media button down: ", e);
+ return false;
+ }
+ } else {
+ Log.i(TAG, "No-op when sending key click, no receiver right now");
+ return false;
+ }
}
return true;
}
@@ -311,11 +361,19 @@
if (timeMs < 0) {
throw new IllegalArgumentException("illegal negative time value");
}
- final int genId;
- synchronized (mGenLock) {
- genId = mClientGenerationIdCurrent;
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ mCurrentSession.getTransportControls().seekTo(timeMs);
+ }
+ }
+ } else {
+ final int genId;
+ synchronized (mGenLock) {
+ genId = mClientGenerationIdCurrent;
+ }
+ mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
}
- mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs);
return true;
}
@@ -430,7 +488,6 @@
return editor;
}
-
/**
* A class to read the metadata published by a {@link RemoteControlClient}, or send a
* {@link RemoteControlClient} new values for keys that can be edited.
@@ -477,26 +534,41 @@
if (!mMetadataChanged) {
return;
}
- final int genId;
- synchronized(mGenLock) {
- genId = mClientGenerationIdCurrent;
- }
- synchronized(mInfoLock) {
- if (mEditorMetadata.containsKey(
- String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
- Rating rating = (Rating) getObject(
- MediaMetadataEditor.RATING_KEY_BY_USER, null);
- mAudioManager.updateRemoteControlClientMetadata(genId,
- MediaMetadataEditor.RATING_KEY_BY_USER,
- rating);
- } else {
- Log.e(TAG, "no metadata to apply");
+ if (USE_SESSIONS) {
+ synchronized (mInfoLock) {
+ if (mCurrentSession != null) {
+ if (mEditorMetadata.containsKey(
+ String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+ Rating rating = (Rating) getObject(
+ MediaMetadataEditor.RATING_KEY_BY_USER, null);
+ if (rating != null) {
+ mCurrentSession.getTransportControls().setRating(rating);
+ }
+ }
+ }
}
- // NOT setting mApplied to true as this type of MetadataEditor will be applied
- // multiple times, whenever the user of a RemoteController needs to change the
- // metadata (e.g. user changes the rating of a song more than once during playback)
- mApplied = false;
+ } else {
+ final int genId;
+ synchronized(mGenLock) {
+ genId = mClientGenerationIdCurrent;
+ }
+ synchronized(mInfoLock) {
+ if (mEditorMetadata.containsKey(
+ String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) {
+ Rating rating = (Rating) getObject(
+ MediaMetadataEditor.RATING_KEY_BY_USER, null);
+ mAudioManager.updateRemoteControlClientMetadata(genId,
+ MediaMetadataEditor.RATING_KEY_BY_USER,
+ rating);
+ } else {
+ Log.e(TAG, "no metadata to apply");
+ }
+ }
}
+ // NOT setting mApplied to true as this type of MetadataEditor will be applied
+ // multiple times, whenever the user of a RemoteController needs to change the
+ // metadata (e.g. user changes the rating of a song more than once during playback)
+ mApplied = false;
}
}
@@ -649,6 +721,46 @@
}
}
+ /**
+ * This receives updates when the current session changes. This is
+ * registered to receive the updates on the handler thread so it can call
+ * directly into the appropriate methods.
+ */
+ private class MediaControllerCallback extends MediaController.Callback {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ onNewPlaybackState(state);
+ }
+
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ onNewMediaMetadata(metadata);
+ }
+ }
+
+ /**
+ * Listens for changes to the active session stack and replaces the
+ * currently tracked session if it has changed.
+ */
+ private class TopTransportSessionListener extends MediaSessionManager.SessionListener {
+ @Override
+ public void onActiveSessionsChanged(List<MediaController> controllers) {
+ int size = controllers.size();
+ for (int i = 0; i < size; i++) {
+ MediaController controller = controllers.get(i);
+ long flags = controller.getFlags();
+ // We only care about sessions that handle transport controls,
+ // which will be true for apps using RCC
+ if ((flags & MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS) != 0) {
+ updateController(controller);
+ return;
+ }
+ }
+ updateController(null);
+ }
+
+ }
+
//==================================================
// Event handling
private final EventHandler mEventHandler;
@@ -658,6 +770,8 @@
private final static int MSG_NEW_METADATA = 3; // msg always has non-null obj parameter
private final static int MSG_CLIENT_CHANGE = 4;
private final static int MSG_DISPLAY_ENABLE = 5;
+ private final static int MSG_NEW_PLAYBACK_STATE = 6;
+ private final static int MSG_NEW_MEDIA_METADATA = 7;
private class EventHandler extends Handler {
@@ -686,12 +800,46 @@
case MSG_DISPLAY_ENABLE:
onDisplayEnable(msg.arg1 == 1);
break;
+ case MSG_NEW_PLAYBACK_STATE:
+ // same as new playback info but using new apis
+ onNewPlaybackState((PlaybackState) msg.obj);
+ break;
+ case MSG_NEW_MEDIA_METADATA:
+ onNewMediaMetadata((MediaMetadata) msg.obj);
+ break;
default:
Log.e(TAG, "unknown event " + msg.what);
}
}
}
+ /**
+ * @hide
+ */
+ void startListeningToSessions() {
+ final ComponentName listenerComponent = new ComponentName(mContext,
+ mOnClientUpdateListener.getClass());
+ mSessionManager.addActiveSessionsListener(mSessionListener, listenerComponent,
+ ActivityManager.getCurrentUser());
+ mSessionListener.onActiveSessionsChanged(mSessionManager
+ .getActiveSessions(listenerComponent));
+ if (DEBUG) {
+ Log.d(TAG, "Registered session listener with component " + listenerComponent
+ + " for user " + ActivityManager.getCurrentUser());
+ }
+ }
+
+ /**
+ * @hide
+ */
+ void stopListeningToSessions() {
+ mSessionManager.removeActiveSessionsListener(mSessionListener);
+ if (DEBUG) {
+ Log.d(TAG, "Unregistered session listener for user "
+ + ActivityManager.getCurrentUser());
+ }
+ }
+
/** If the msg is already queued, replace it with this one. */
private static final int SENDMSG_REPLACE = 0;
/** If the msg is already queued, ignore this one and leave the old. */
@@ -713,6 +861,7 @@
handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs);
}
+ ///////////// These calls are used by the old APIs with RCC and RCD //////////////////////
private void onNewPendingIntent(int genId, PendingIntent pi) {
synchronized(mGenLock) {
if (mClientGenerationIdCurrent != genId) {
@@ -848,6 +997,86 @@
}
}
+ ///////////// These calls are used by the new APIs with Sessions //////////////////////
+ private void updateController(MediaController controller) {
+ if (DEBUG) {
+ Log.d(TAG, "Updating controller to " + controller + " previous controller is "
+ + mCurrentSession);
+ }
+ synchronized (mInfoLock) {
+ if (controller == null) {
+ if (mCurrentSession != null) {
+ mCurrentSession.removeCallback(mSessionCb);
+ mCurrentSession = null;
+ sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
+ 0 /* genId */, 1 /* clearing */, null /* obj */, 0 /* delay */);
+ }
+ } else if (mCurrentSession == null
+ || !controller.getSessionInfo().getId()
+ .equals(mCurrentSession.getSessionInfo().getId())) {
+ if (mCurrentSession != null) {
+ mCurrentSession.removeCallback(mSessionCb);
+ }
+ sendMsg(mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE,
+ 0 /* genId */, 0 /* clearing */, null /* obj */, 0 /* delay */);
+ mCurrentSession = controller;
+ mCurrentSession.addCallback(mSessionCb, mEventHandler);
+
+ PlaybackState state = controller.getPlaybackState();
+ sendMsg(mEventHandler, MSG_NEW_PLAYBACK_STATE, SENDMSG_REPLACE,
+ 0 /* genId */, 0, state /* obj */, 0 /* delay */);
+
+ MediaMetadata metadata = controller.getMetadata();
+ sendMsg(mEventHandler, MSG_NEW_MEDIA_METADATA, SENDMSG_REPLACE,
+ 0 /* arg1 */, 0 /* arg2 */, metadata /* obj */, 0 /* delay */);
+ }
+ // else same controller, no need to update
+ }
+ }
+
+ private void onNewPlaybackState(PlaybackState state) {
+ final OnClientUpdateListener l;
+ synchronized (mInfoLock) {
+ l = this.mOnClientUpdateListener;
+ }
+ if (l != null) {
+ int playstate = state == null ? RemoteControlClient.PLAYSTATE_NONE : PlaybackState
+ .getRccStateFromState(state.getState());
+ if (state == null || state.getPosition() == PlaybackState.PLAYBACK_POSITION_UNKNOWN) {
+ l.onClientPlaybackStateUpdate(playstate);
+ } else {
+ l.onClientPlaybackStateUpdate(playstate, state.getLastPositionUpdateTime(),
+ state.getPosition(), state.getPlaybackRate());
+ }
+ if (state != null) {
+ l.onClientTransportControlUpdate(PlaybackState.getRccControlFlagsFromActions(state
+ .getActions()));
+ }
+ }
+ }
+
+ private void onNewMediaMetadata(MediaMetadata metadata) {
+ if (metadata == null) {
+ // RemoteController only handles non-null metadata
+ return;
+ }
+ final OnClientUpdateListener l;
+ final MetadataEditor metadataEditor;
+ // prepare the received Bundle to be used inside a MetadataEditor
+ synchronized(mInfoLock) {
+ l = mOnClientUpdateListener;
+ boolean canRate = mCurrentSession != null
+ && mCurrentSession.getRatingType() != Rating.RATING_NONE;
+ long editableKeys = canRate ? MediaMetadataEditor.RATING_KEY_BY_USER : 0;
+ Bundle legacyMetadata = MediaSessionLegacyHelper.getOldMetadata(metadata);
+ mMetadataEditor = new MetadataEditor(legacyMetadata, editableKeys);
+ metadataEditor = mMetadataEditor;
+ }
+ if (l != null) {
+ l.onClientMetadataUpdate(metadataEditor);
+ }
+ }
+
//==================================================
private static class PlaybackInfo {
int mState;
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 7c03907..f0cd785 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -37,6 +37,7 @@
boolean isTransportControlEnabled();
void showRoutePicker();
MediaSessionInfo getSessionInfo();
+ long getFlags();
// These commands are for the TransportController
void play();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 57a0a54..5ca7daa 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -57,6 +57,7 @@
private final Object mLock = new Object();
private boolean mCbRegistered = false;
+ private MediaSessionInfo mInfo;
private TransportControls mTransportController;
@@ -174,6 +175,21 @@
}
/**
+ * Get the flags for this session.
+ *
+ * @return The current set of flags for the session.
+ * @hide
+ */
+ public long getFlags() {
+ try {
+ return mSessionBinder.getFlags();
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling getFlags.", e);
+ }
+ return 0;
+ }
+
+ /**
* Adds a callback to receive updates from the Session. Updates will be
* posted on the caller's thread.
*
@@ -253,12 +269,14 @@
* @hide
*/
public MediaSessionInfo getSessionInfo() {
- try {
- return mSessionBinder.getSessionInfo();
- } catch (RemoteException e) {
- Log.e(TAG, "Error in getSessionInfo.", e);
+ if (mInfo == null) {
+ try {
+ mInfo = mSessionBinder.getSessionInfo();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in getSessionInfo.", e);
+ }
}
- return null;
+ return mInfo;
}
/*
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 099f601..801844f 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -20,6 +20,10 @@
import android.app.PendingIntent.CanceledException;
import android.content.Context;
import android.content.Intent;
+import android.media.MediaMetadata;
+import android.media.MediaMetadataEditor;
+import android.media.MediaMetadataRetriever;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.ArrayMap;
@@ -64,6 +68,88 @@
return sInstance;
}
+ public static Bundle getOldMetadata(MediaMetadata metadata) {
+ Bundle oldMetadata = new Bundle();
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUM),
+ metadata.getString(MediaMetadata.METADATA_KEY_ALBUM));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_ART)) {
+ oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+ metadata.getBitmap(MediaMetadata.METADATA_KEY_ART));
+ } else if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)) {
+ // Fall back to album art if the track art wasn't available
+ oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK),
+ metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ARTIST)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST),
+ metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ARTIST),
+ metadata.getString(MediaMetadata.METADATA_KEY_ARTIST));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_AUTHOR)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_AUTHOR),
+ metadata.getString(MediaMetadata.METADATA_KEY_AUTHOR));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_COMPILATION)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_COMPILATION),
+ metadata.getString(MediaMetadata.METADATA_KEY_COMPILATION));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_COMPOSER)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_COMPOSER),
+ metadata.getString(MediaMetadata.METADATA_KEY_COMPOSER));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_DATE)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DATE),
+ metadata.getString(MediaMetadata.METADATA_KEY_DATE));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_DISC_NUMBER)) {
+ oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER),
+ metadata.getLong(MediaMetadata.METADATA_KEY_DISC_NUMBER));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
+ oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DURATION),
+ metadata.getLong(MediaMetadata.METADATA_KEY_DURATION));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_GENRE)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_GENRE),
+ metadata.getString(MediaMetadata.METADATA_KEY_GENRE));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS)) {
+ oldMetadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS),
+ metadata.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_RATING)) {
+ oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.RATING_KEY_BY_OTHERS),
+ metadata.getRating(MediaMetadata.METADATA_KEY_RATING));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_USER_RATING)) {
+ oldMetadata.putParcelable(String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER),
+ metadata.getRating(MediaMetadata.METADATA_KEY_USER_RATING));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_TITLE)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_TITLE),
+ metadata.getString(MediaMetadata.METADATA_KEY_TITLE));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) {
+ oldMetadata.putLong(
+ String.valueOf(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER),
+ metadata.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_WRITER)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_WRITER),
+ metadata.getString(MediaMetadata.METADATA_KEY_WRITER));
+ }
+ if (metadata.containsKey(MediaMetadata.METADATA_KEY_YEAR)) {
+ oldMetadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_YEAR),
+ metadata.getString(MediaMetadata.METADATA_KEY_YEAR));
+ }
+ return oldMetadata;
+ }
+
public MediaSession getSession(PendingIntent pi) {
SessionHolder holder = mSessions.get(pi);
return holder == null ? null : holder.mSession;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 291bfc8..8eceee8 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -96,10 +96,13 @@
}
/**
- * Get a list of controllers for all ongoing sessions. This requires the
- * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
- * the calling app. You may also retrieve this list if your app is an
- * enabled notification listener using the
+ * Get a list of controllers for all ongoing sessions. The controllers will
+ * be provided in priority order with the most important controller at index
+ * 0.
+ * <p>
+ * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL
+ * permission be held by the calling app. You may also retrieve this list if
+ * your app is an enabled notification listener using the
* {@link NotificationListenerService} APIs, in which case you must pass the
* {@link ComponentName} of your enabled listener.
*
@@ -239,7 +242,8 @@
/**
* Called when the list of active sessions has changed. This can be due
* to a session being added or removed or the order of sessions
- * changing.
+ * changing. The controllers will be provided in priority order with the
+ * most important controller at index 0.
*
* @param controllers The updated list of controllers for the user that
* changed.
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index e09ac3f..3b3f249 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -432,6 +432,8 @@
return STATE_REWINDING;
case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
return STATE_SKIPPING_TO_PREVIOUS;
+ case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+ return STATE_SKIPPING_TO_NEXT;
case RemoteControlClient.PLAYSTATE_STOPPED:
return STATE_STOPPED;
default:
@@ -440,6 +442,41 @@
}
/**
+ * Get the {@link RemoteControlClient} state for the given
+ * {@link PlaybackState} state.
+ *
+ * @param state The state used by {@link PlaybackState}.
+ * @return The equivalent state used by {@link RemoteControlClient}.
+ * @hide
+ */
+ public static int getRccStateFromState(int state) {
+ switch (state) {
+ case STATE_BUFFERING:
+ return RemoteControlClient.PLAYSTATE_BUFFERING;
+ case STATE_ERROR:
+ return RemoteControlClient.PLAYSTATE_ERROR;
+ case STATE_FAST_FORWARDING:
+ return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
+ case STATE_NONE:
+ return RemoteControlClient.PLAYSTATE_NONE;
+ case STATE_PAUSED:
+ return RemoteControlClient.PLAYSTATE_PAUSED;
+ case STATE_PLAYING:
+ return RemoteControlClient.PLAYSTATE_PLAYING;
+ case STATE_REWINDING:
+ return RemoteControlClient.PLAYSTATE_REWINDING;
+ case STATE_SKIPPING_TO_PREVIOUS:
+ return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
+ case STATE_SKIPPING_TO_NEXT:
+ return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
+ case STATE_STOPPED:
+ return RemoteControlClient.PLAYSTATE_STOPPED;
+ default:
+ return -1;
+ }
+ }
+
+ /**
* @hide
*/
public static long getActionsFromRccControlFlags(int rccFlags) {
@@ -454,6 +491,21 @@
return actions;
}
+ /**
+ * @hide
+ */
+ public static int getRccControlFlagsFromActions(long actions) {
+ int rccFlags = 0;
+ long action = 1;
+ while (action <= actions && action < Integer.MAX_VALUE) {
+ if ((action & actions) != 0) {
+ rccFlags |= getRccFlagForAction(action);
+ }
+ action = action << 1;
+ }
+ return rccFlags;
+ }
+
private static long getActionForRccFlag(int flag) {
switch (flag) {
case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
@@ -480,6 +532,35 @@
return 0;
}
+ private static int getRccFlagForAction(long action) {
+ // We only care about the lower set of actions that can map to rcc
+ // flags.
+ int testAction = action < Integer.MAX_VALUE ? (int) action : 0;
+ switch (testAction) {
+ case (int) ACTION_SKIP_TO_PREVIOUS:
+ return RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
+ case (int) ACTION_REWIND:
+ return RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
+ case (int) ACTION_PLAY:
+ return RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
+ case (int) ACTION_PLAY_PAUSE:
+ return RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
+ case (int) ACTION_PAUSE:
+ return RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
+ case (int) ACTION_STOP:
+ return RemoteControlClient.FLAG_KEY_MEDIA_STOP;
+ case (int) ACTION_FAST_FORWARD:
+ return RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
+ case (int) ACTION_SKIP_TO_NEXT:
+ return RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
+ case (int) ACTION_SEEK_TO:
+ return RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
+ case (int) ACTION_SET_RATING:
+ return RemoteControlClient.FLAG_KEY_MEDIA_RATING;
+ }
+ return 0;
+ }
+
public static final Parcelable.Creator<PlaybackState> CREATOR
= new Parcelable.Creator<PlaybackState>() {
@Override
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 868c5bf..7b8f2ec 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -26,6 +26,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -223,6 +224,18 @@
return mService.loadLabel(pm);
}
+ /**
+ * Loads the user-displayed icon for this TV input service.
+ *
+ * @param pm Supplies a PackageManager used to load the TV input's resources.
+ * @return a Drawable containing the TV input's icon. If the TV input does not have
+ * an icon, application icon is returned. If it's unavailable too, system default is
+ * returned.
+ */
+ public Drawable loadIcon(PackageManager pm) {
+ return mService.serviceInfo.loadIcon(pm);
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index 3dd988e..a4d292a 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -104,7 +104,9 @@
int height;
meta->findInt32(kKeyWidth, &width);
meta->findInt32(kKeyHeight, &height);
- configBitmapSize(bm, getPrefConfig(k32Bit_SrcDepth, false), width, height);
+ configBitmapSize(
+ bm, SkColorTypeToBitmapConfig(getPrefColorType(k32Bit_SrcDepth, false)),
+ width, height);
// mode == DecodeBounds
if (mode == SkImageDecoder::kDecodeBounds_Mode) {
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 3f37ed1..b09bc2e 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -171,3 +171,8 @@
{
return static_cast<Sensor const*>(sensor)->getStringType().string();
}
+
+int ASensor_getReportingMode(ASensor const* sensor)
+{
+ return static_cast<Sensor const*>(sensor)->getReportingMode();
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 7918755..a8b49e2 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -130,6 +130,11 @@
}
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
private void updateOwnerInfo() {
String ownerInfo = getOwnerInfo();
if (!TextUtils.isEmpty(ownerInfo)) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index f71cafe..3e0d7e5 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -1735,10 +1735,12 @@
} else if (spinner == mOrientationSpinner) {
SpinnerItem<Integer> orientationItem = mOrientationSpinnerAdapter.getItem(position);
PrintAttributes attributes = mPrintJob.getAttributes();
- if (orientationItem.value == ORIENTATION_PORTRAIT) {
- attributes.copyFrom(attributes.asPortrait());
- } else {
- attributes.copyFrom(attributes.asLandscape());
+ if (mMediaSizeSpinner.getSelectedItem() != null) {
+ if (orientationItem.value == ORIENTATION_PORTRAIT) {
+ attributes.copyFrom(attributes.asPortrait());
+ } else {
+ attributes.copyFrom(attributes.asLandscape());
+ }
}
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 0e025a9..a92ab7e 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -195,4 +195,7 @@
<!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED -->
<bool name="def_wake_gesture_enabled">true</bool>
+ <!-- Default for Settings.Global.GUEST_USER_ENABLED -->
+ <bool name="def_guest_user_enabled">true</bool>
+
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 9b21ae4..09e6a94 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -70,7 +70,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 104;
+ private static final int DATABASE_VERSION = 105;
private Context mContext;
private int mUserHandle;
@@ -1677,6 +1677,24 @@
upgradeVersion = 104;
}
+ if (upgradeVersion < 105) {
+ if (mUserHandle == UserHandle.USER_OWNER) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+ + " VALUES(?,?);");
+ loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
+ R.bool.def_guest_user_enabled);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ }
+ upgradeVersion = 105;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -2410,6 +2428,8 @@
loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
+ loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
+ R.bool.def_guest_user_enabled);
// --- New global settings start here
} finally {
if (stmt != null) stmt.close();
diff --git a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
deleted file mode 100644
index e6af81e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
index 873ca7e..b28624f 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
index 9d3cf53..9ce434d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
index 288d36a..51dce69 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
index 266d34d..3f3e288 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
index 0298054..9856cbf 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
index 91e2edf..6910456 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
index 9ed15a7..e8c6ec6 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
index 6f2915b..06dcd20 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
index 3f3b692..240f536 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
index 3f7c4b0..e464347 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
index 956bb7c..f8b59e8 100644
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index 86e2947..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d8ab8ea..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
index a53aef1..1b578a6 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
index e1b2145..80ecaba 100644
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index dffc059..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index c0209b0..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
index 2d8f81d..c7bf2c7 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
index 61c6d11..278de42 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index a67ed6d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 6101333..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-hdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
index 90eece6..464831c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
index 382cf23..c24132c 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index ca1c8c4..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index cfef88d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-mdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
index a4b3b37..bc84f22 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
index ee5f623..f4e219e 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index ca3c541..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 78d4490..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
index 3d21350..ece2e37 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 40fbaec..d524dcf 100644
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 77bef31..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d79f5b7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw600dp-xxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
index 61b4569..373e84a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
index 1a0312b..e5a102a 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index d04916e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index d940d34..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
index 8715a11..6b19593 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
index 487a0b1..a5e0686 100644
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index a7cff47..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 0a60bb6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
deleted file mode 100644
index e865f4c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
index 225d924..f878093 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
index 7779d57..7780b16 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
index 37d17d2..343d0dd 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
index 5e70a07..8e9583b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
index 39a0c07..7d38703 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
index 5bbf3fe..6e186a3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
index 798f62f..12b4042 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
index f8e549a..e2a89c3 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
index c7fda96..311720b 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
index 3361e34..67e4ee7 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
index ed52bc3..dfef430 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
index b380327..de6d109 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
index 49df31b..7d0c3fbe 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
index ac45bcd..3baeb52 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
index 9fb4266..d5b48e8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
index 459d011..26d7e7b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
index e1cddde..c49198d 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
index e459f2c..2a21f29 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
index 0ec4d23..538d7d1 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
index 4dedcbe..eb8e80b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
index e55f2bf..1c2c35a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
index a39c3e5..eec613f 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
index 80e988f..1c0bad8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
index 4ef12b0d..1293fa8 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
index 8ef12a8..96a9cce 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
index c2977c0..9ffc80a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
index 60ec10e..aa9b57b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
index 8aa6e3a..b343522 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
index e272b62..f2f7b50 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
index bf68b22..383398c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
index 59ef663..53444ab 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
index cf3a5ff..4294937 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
index 2598954..7cb3ee4 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
index 66853db..b017946 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
index c46fd026..e8dd07c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
index 0e84d92..f396ea9 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
index 7e96395e..1b817cf 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
index cb94580..21b7a06 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
index 382ef39..676fc14 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
index 8d7be53..26f4ba9 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
index 613fba0..ea21b60 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
index 0511ad1..c7d77c2 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
index 77fe9b2..ae12cfd 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
index ae78eb0..8c27d45 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
index 5b446b1..c98827c 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png
deleted file mode 100644
index 83693c1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
index a2bb50a..ec2951d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
index 24897ce..5103190 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
index aaeeb1b..818aa4f 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
index ddee461..254f757 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
index 23a7997..f0de417 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
index 9f200c2..97f1526 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
index 43e9bc2..773fa94 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
index 5c0ba82..8a8e941 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
index b76a0ca..ad7dfc3 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png b/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png
deleted file mode 100644
index cebbb15..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/battery_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
index 79cfcee..77969b8 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
index 7959f65..b171f92 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
index c3bfcfb..ad35c65 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
index 64f6a22..d60229f 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
index 8fd36bc..8fffa8e 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
index 6f30e54..9215055 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
index 024ef8f..bcf7eb1 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
index 6e0b071..a261f85 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
index 9a56987..4c612f7 100644
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_power_low.xml b/packages/SystemUI/res/drawable/ic_power_low.xml
new file mode 100644
index 0000000..5bb7aba
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_power_low.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="24.0dp"
+ android:height="24.0dp"/>
+
+ <viewport
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM26.0,37.0l-4.0,0.0l0.0,-4.0l4.0,0.0L26.0,37.0zM26.0,30.0l-4.0,0.0L22.0,15.0l4.0,0.0L26.0,30.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_power_saver.xml b/packages/SystemUI/res/drawable/ic_power_saver.xml
new file mode 100644
index 0000000..26e7375
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_power_saver.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <size
+ android:width="24.0dp"
+ android:height="24.0dp"/>
+
+ <viewport
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
+
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M30.0,6.0L30.0,2.0L18.0,2.0l0.0,4.0l-8.0,0.0l0.0,40.0l28.0,0.0L38.0,6.0L30.0,6.0zM32.0,28.0l-6.0,0.0l0.0,6.0l-4.0,0.0l0.0,-6.0l-6.0,0.0l0.0,-4.0l6.0,0.0l0.0,-6.0l4.0,0.0l0.0,6.0l6.0,0.0L32.0,28.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/battery_low.xml b/packages/SystemUI/res/layout/battery_low.xml
deleted file mode 100644
index 2373355..0000000
--- a/packages/SystemUI/res/layout/battery_low.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/layout/keyguard.xml
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT 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/padding"
- android:orientation="vertical"
- android:gravity="center"
- android:padding="16dp"
- >
-
- <TextView android:id="@+id/subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:textColor="#ffffffff"
- android:gravity="start"
- android:text="@string/battery_low_subtitle"
- />
-
- <TextView android:id="@+id/level_percent"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:textColor="#ffffffff"
- android:gravity="start"
- android:paddingBottom="16dp"
- />
-
- <ImageView android:id="@+id/image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/battery_low_battery"
- />
-
-</LinearLayout>
-
-
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
index 84d64b9..e220a16 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
@@ -18,48 +18,13 @@
<com.android.systemui.statusbar.SpeedBumpView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:focusable="true"
- android:clickable="true"
+ android:layout_height="@dimen/speed_bump_height"
android:visibility="gone"
>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="@dimen/speed_bump_height_collapsed"
- android:layout_gravity="top"
- android:orientation="horizontal">
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/speedbump_line_left"
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:background="#6fdddddd"
- android:layout_gravity="center_vertical"/>
- <com.android.systemui.statusbar.SpeedBumpDotsLayout
- android:id="@+id/speed_bump_dots_layout"
- android:layout_width="34dp"
- android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:layout_height="match_parent"
- android:layout_weight="0"/>
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/speedbump_line_right"
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:background="#6fdddddd"
- android:layout_gravity="center_vertical"/>
- </LinearLayout>
- <TextView
- android:id="@+id/speed_bump_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="top|center_horizontal"
- android:fontFamily="sans-serif-condensed"
- android:textSize="15sp"
- android:singleLine="true"
- android:textColor="#eeeeee"
- android:visibility="invisible"
- android:text="@string/speed_bump_explanation"
- android:paddingTop="4dp" />
+ <com.android.systemui.statusbar.AlphaOptimizedView
+ android:id="@+id/speedbump_line"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="#6fdddddd"
+ android:layout_gravity="center_vertical"/>
</com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/layout/user_switcher_item.xml b/packages/SystemUI/res/layout/user_switcher_item.xml
index 43a85e7..8df2f5a 100644
--- a/packages/SystemUI/res/layout/user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/user_switcher_item.xml
@@ -21,10 +21,12 @@
android:layout_width="match_parent"
android:layout_height="64dp"
android:orientation="horizontal"
+ android:gravity="center_vertical"
tools:context=".settings.UserSwitcherDialog">
<ImageView
- android:layout_width="64dp"
- android:layout_height="match_parent"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="4dp"
android:id="@+id/user_picture"
tools:src="@drawable/dessert_zombiegingerbread"/>
<TextView
@@ -37,4 +39,11 @@
android:gravity="center_vertical"
tools:text="Hiroshi Lockheimer"
/>
+ <ImageView
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginEnd="4dp"
+ android:src="@*android:drawable/ic_menu_delete"
+ android:id="@+id/user_delete"
+ android:background="?android:attr/selectableItemBackground"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
index 1ce4983..6628f3b 100644
--- a/packages/SystemUI/res/values/arrays.xml
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -42,13 +42,11 @@
<!-- BatteryMeterView parameters -->
<array name="batterymeter_color_levels">
- <item>4</item>
<item>15</item>
<item>100</item>
</array>
<array name="batterymeter_color_values">
<item>#FFFF3300</item>
- <item>#FFFF3300</item>
<item>#FFFFFFFF</item>
</array>
<array name="batterymeter_bolt_points">
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index bb6f1a9..8c1a9c7 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -45,18 +45,6 @@
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
- <!-- The color of the red speed bump dot -->
- <color name="speed_bump_dot_red">#ffd50000</color>
-
- <!-- The color of the blue speed bump dot -->
- <color name="speed_bump_dot_blue">#ff2962ff</color>
-
- <!-- The color of the yellow speed bump dot -->
- <color name="speed_bump_dot_yellow">#ffffd600</color>
-
- <!-- The color of the green speed bump dot -->
- <color name="speed_bump_dot_green">#ff00c853</color>
-
<!-- The default recents task bar background color. -->
<color name="recents_task_bar_default_background_color">#e6444444</color>
<!-- The default recents task bar text color. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index fdf7f8d..5ffe3b3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -272,14 +272,8 @@
<!-- The minimum amount of top overscroll to go to the quick settings. -->
<dimen name="min_top_overscroll_to_qs">36dp</dimen>
- <!-- The height of the collapsed speed bump view. -->
- <dimen name="speed_bump_height_collapsed">24dp</dimen>
-
- <!-- The padding inset the explanation text needs compared to the collapsed height -->
- <dimen name="speed_bump_text_padding_inset">10dp</dimen>
-
- <!-- The height of the speed bump dots. -->
- <dimen name="speed_bump_dots_height">5dp</dimen>
+ <!-- The height of the speed bump view. -->
+ <dimen name="speed_bump_height">16dp</dimen>
<!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
<dimen name="collapsed_stack_height">94dp</dimen>
@@ -335,4 +329,7 @@
<!-- The width of the region on the left/right edge of the screen for performing the camera/
phone hints. -->
<dimen name="edge_tap_area_width">48dp</dimen>
+
+ <!-- the distance the panel moves up when starting the up motion on Keyguard -->
+ <dimen name="keyguard_panel_move_up_distance">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ed32795..e5499ee 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -59,25 +59,43 @@
<string name="status_bar_latest_events_title">Notifications</string>
<!-- When the battery is low, this is displayed to the user in a dialog. The title of the low battery alert. [CHAR LIMIT=NONE]-->
- <string name="battery_low_title">Connect charger</string>
-
- <!-- When the battery is low, this is displayed to the user in a dialog. The subtitle of the low battery alert. [CHAR LIMIT=NONE] -->
- <string name="battery_low_subtitle">The battery is getting low.</string>
+ <string name="battery_low_title">Battery is low</string>
<!-- A message that appears when the battery level is getting low in a dialog. This is
appened to the subtitle of the low battery alert. "number" is the percentage of battery
remaining [CHAR LIMIT=none]-->
<string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g> remaining</string>
+ <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]-->
+ <string name="battery_low_percent_format_saver_started"><xliff:g id="number">%d%%</xliff:g> remaining. Battery saver is on.</string>
+
<!-- A message that appears when a USB charger is plugged in and the device does not
support charging on it. That is, a charger that fits into the USB port and goes into
a wall socket, not into a computer. (This happens because some devices require more
current than the USB spec allows. [CHAR LIMIT=NONE] -->
<string name="invalid_charger">USB charging not supported.\nUse only the supplied charger.</string>
+ <!-- First line of invalid_charger, used in the notification form. [CHAR LIMIT=NONE]-->
+ <string name="invalid_charger_title">USB charging not supported.</string>
+
+ <!-- Second line of invalid_charger, used in the notification form. [CHAR LIMIT=NONE]-->
+ <string name="invalid_charger_text">Use only the supplied charger.</string>
+
<!-- When the battery is low, this is the label of the button to go to the
power usage activity to find out what drained the battery. [CHAR LIMIT=30] -->
- <string name="battery_low_why">Battery use</string>
+ <string name="battery_low_why">Settings</string>
+
+ <!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]-->
+ <string name="battery_saver_confirmation_title">Start battery saver?</string>
+
+ <!-- Battery saver confirmation dialog ok text [CHAR LIMIT=40]-->
+ <string name="battery_saver_confirmation_ok">Start</string>
+
+ <!-- Battery saver notification action [CHAR LIMIT=NONE]-->
+ <string name="battery_saver_start_action">Start battery saver</string>
+
+ <!-- Battery saver confirmation dialog text [CHAR LIMIT=NONE]-->
+ <string name="battery_saver_confirmation_text">To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in.</string>
<!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
<string name="status_bar_settings_settings_button">Settings</string>
@@ -596,6 +614,13 @@
<!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
<string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+ <!-- Related to user switcher --><skip/>
+ <!-- Name for the guest user -->
+ <string name="guest_nickname">Guest</string>
+
+ <!-- Label for adding a new guest -->
+ <string name="guest_new_guest">+ Guest</string>
+
<!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_minutes">
<item quantity="one">For one minute</item>
@@ -607,4 +632,13 @@
<item quantity="one">For one hour</item>
<item quantity="other">For %d hours</item>
</plurals>
+
+ <!-- Battery saver notification title. [CHAR LIMIT=60]-->
+ <string name="battery_saver_notification_title">Battery saver is on</string>
+
+ <!-- Battery saver notification text. [CHAR LIMIT=60] -->
+ <string name="battery_saver_notification_text">Device performance is reduced.</string>
+
+ <!-- Battery saver notification action text. [CHAR LIMIT=60] -->
+ <string name="battery_saver_notification_action_text">Open battery saver settings</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 19d06be..5e48258 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -25,8 +25,6 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.BatteryManager;
@@ -44,7 +42,6 @@
private static final boolean SHOW_100_PERCENT = false;
private static final int FULL = 96;
- private static final int EMPTY = 4;
private static final float SUBPIXEL = 0.4f; // inset rects for softer edges
private static final float BOLT_LEVEL_THRESHOLD = 0.3f; // opaque bolt below this fraction
@@ -58,6 +55,7 @@
private int mHeight;
private int mWidth;
private String mWarningString;
+ private final int mCriticalLevel;
private final int mChargeColor;
private final float[] mBoltPoints;
private final Path mBoltPath = new Path();
@@ -197,6 +195,8 @@
mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
context.getContentResolver(), "status_bar_show_battery_percent", 0);
mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
+ mCriticalLevel = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel);
mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFramePaint.setColor(frameColor);
@@ -303,7 +303,7 @@
if (level >= FULL) {
drawFrac = 1f;
- } else if (level <= EMPTY) {
+ } else if (level <= mCriticalLevel) {
drawFrac = 0f;
}
@@ -360,7 +360,7 @@
boolean pctOpaque = false;
float pctX = 0, pctY = 0;
String pctText = null;
- if (!tracker.plugged && level > EMPTY && mShowPercent
+ if (!tracker.plugged && level > mCriticalLevel && mShowPercent
&& !(tracker.level == 100 && !SHOW_100_PERCENT)) {
mTextPaint.setColor(getColorForLevel(level));
mTextPaint.setTextSize(height *
@@ -390,7 +390,7 @@
c.drawPath(mShapePath, mBatteryPaint);
if (!tracker.plugged) {
- if (level <= EMPTY) {
+ if (level <= mCriticalLevel) {
// draw the warning text
final float x = mWidth * 0.5f;
final float y = (mHeight + mWarningTextHeight) * 0.48f;
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
index feec87c..2943494 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
@@ -16,6 +16,7 @@
package com.android.systemui.power;
+import android.app.ActivityManagerNative;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
@@ -25,13 +26,13 @@
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Slog;
-import android.view.View;
+import android.view.ContextThemeWrapper;
import android.view.WindowManager;
-import android.widget.TextView;
import com.android.systemui.R;
@@ -46,13 +47,14 @@
private int mBatteryLevel;
private int mBucket;
private long mScreenOffTime;
+ private boolean mSaver;
+ private int mSaverTriggerLevel;
private AlertDialog mInvalidChargerDialog;
private AlertDialog mLowBatteryDialog;
- private TextView mBatteryLevelTextView;
public PowerDialogWarnings(Context context) {
- mContext = context;
+ mContext = new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light);
}
@Override
@@ -77,7 +79,7 @@
@Override
public void updateLowBatteryWarning() {
- if (mBatteryLevelTextView != null) {
+ if (mLowBatteryDialog != null) {
showLowBatteryWarning(false /*playSound*/);
}
}
@@ -93,27 +95,22 @@
@Override
public void showLowBatteryWarning(boolean playSound) {
Slog.i(TAG,
- ((mBatteryLevelTextView == null) ? "showing" : "updating")
+ ((mLowBatteryDialog == null) ? "showing" : "updating")
+ " low battery warning: level=" + mBatteryLevel
+ " [" + mBucket + "]");
- CharSequence levelText = mContext.getString(
- R.string.battery_low_percent_format, mBatteryLevel);
+ final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started
+ : R.string.battery_low_percent_format;
+ final CharSequence levelText = mContext.getString(textRes, mBatteryLevel);
- if (mBatteryLevelTextView != null) {
- mBatteryLevelTextView.setText(levelText);
+ if (mLowBatteryDialog != null) {
+ mLowBatteryDialog.setMessage(levelText);
} else {
- View v = View.inflate(mContext, R.layout.battery_low, null);
- mBatteryLevelTextView = (TextView)v.findViewById(R.id.level_percent);
-
- mBatteryLevelTextView.setText(levelText);
-
AlertDialog.Builder b = new AlertDialog.Builder(mContext);
- b.setCancelable(true);
- b.setTitle(R.string.battery_low_title);
- b.setView(v);
- b.setIconAttribute(android.R.attr.alertDialogIcon);
- b.setPositiveButton(android.R.string.ok, null);
+ b.setCancelable(true);
+ b.setTitle(R.string.battery_low_title);
+ b.setMessage(levelText);
+ b.setPositiveButton(android.R.string.ok, null);
final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@@ -125,6 +122,11 @@
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
+ try {
+ ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+ } catch (RemoteException e) {
+ // we tried
+ }
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
dismissLowBatteryWarning();
}
@@ -136,10 +138,9 @@
@Override
public void onDismiss(DialogInterface dialog) {
mLowBatteryDialog = null;
- mBatteryLevelTextView = null;
}
});
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
d.getWindow().getAttributes().privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
d.show();
@@ -198,21 +199,32 @@
dismissLowBatteryWarning();
AlertDialog.Builder b = new AlertDialog.Builder(mContext);
- b.setCancelable(true);
- b.setMessage(R.string.invalid_charger);
- b.setIconAttribute(android.R.attr.alertDialogIcon);
- b.setPositiveButton(android.R.string.ok, null);
+ b.setCancelable(true);
+ b.setTitle(R.string.invalid_charger_title);
+ b.setMessage(R.string.invalid_charger_text);
+ b.setPositiveButton(android.R.string.ok, null);
AlertDialog d = b.create();
d.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
mInvalidChargerDialog = null;
- mBatteryLevelTextView = null;
}
});
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ d.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
d.show();
mInvalidChargerDialog = d;
}
+
+ @Override
+ public void showSaverMode(boolean mode) {
+ mSaver = mode;
+ }
+
+ @Override
+ public void setSaverTrigger(int level) {
+ mSaverTriggerLevel = level;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
new file mode 100644
index 0000000..e8f3745
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.power;
+
+import android.app.AlertDialog;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import java.io.PrintWriter;
+
+public class PowerNotificationWarnings implements PowerUI.WarningsUI {
+ private static final String TAG = PowerUI.TAG + ".Notification";
+ private static final boolean DEBUG = PowerUI.DEBUG;
+
+ private static final String TAG_NOTIFICATION = "low_battery";
+ private static final int ID_NOTIFICATION = 100;
+ private static final int AUTO_DISMISS_MS = 10000;
+
+ private static final int SHOWING_NOTHING = 0;
+ private static final int SHOWING_WARNING = 1;
+ private static final int SHOWING_SAVER = 2;
+ private static final int SHOWING_INVALID_CHARGER = 3;
+ private static final String[] SHOWING_STRINGS = {
+ "SHOWING_NOTHING",
+ "SHOWING_WARNING",
+ "SHOWING_SAVER",
+ "SHOWING_INVALID_CHARGER",
+ };
+
+ private static final String ACTION_SHOW_FALLBACK_WARNING = "PNW.warningFallback";
+ private static final String ACTION_SHOW_FALLBACK_CHARGER = "PNW.chargerFallback";
+ private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
+ private static final String ACTION_START_SAVER = "PNW.startSaver";
+
+ private final Context mContext;
+ private final Context mLightContext;
+ private final NotificationManager mNoMan;
+ private final Handler mHandler = new Handler();
+ private final PowerDialogWarnings mFallbackDialogs;
+ private final Receiver mReceiver = new Receiver();
+ private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
+ private final Intent mOpenSaverSettings = settings(Settings.ACTION_BATTERY_SAVER_SETTINGS);
+
+ private int mBatteryLevel;
+ private int mBucket;
+ private long mScreenOffTime;
+ private int mShowing;
+
+ private boolean mSaver;
+ private int mSaverTriggerLevel;
+ private boolean mWarning;
+ private boolean mPlaySound;
+ private boolean mInvalidCharger;
+
+ public PowerNotificationWarnings(Context context) {
+ mContext = context;
+ mLightContext = new ContextThemeWrapper(mContext,
+ android.R.style.Theme_DeviceDefault_Light);
+ mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ mFallbackDialogs = new PowerDialogWarnings(context);
+ mReceiver.init();
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.print("mSaver="); pw.println(mSaver);
+ pw.print("mWarning="); pw.println(mWarning);
+ pw.print("mPlaySound="); pw.println(mPlaySound);
+ pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
+ pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
+ }
+
+ @Override
+ public void update(int batteryLevel, int bucket, long screenOffTime) {
+ mBatteryLevel = batteryLevel;
+ mBucket = bucket;
+ mScreenOffTime = screenOffTime;
+ mFallbackDialogs.update(batteryLevel, bucket, screenOffTime);
+ }
+
+ @Override
+ public void showSaverMode(boolean mode) {
+ mSaver = mode;
+ updateNotification();
+ }
+
+ @Override
+ public void setSaverTrigger(int level) {
+ mSaverTriggerLevel = level;
+ updateNotification();
+ }
+
+ private void updateNotification() {
+ Slog.d(TAG, "updateNotification mWarning=" + mWarning
+ + " mSaver=" + mSaver + " mInvalidCharger=" + mInvalidCharger);
+ if (mInvalidCharger) {
+ showInvalidChargerNotification();
+ mShowing = SHOWING_INVALID_CHARGER;
+ } else if (mWarning) {
+ showWarningNotification();
+ mShowing = SHOWING_WARNING;
+ } else if (mSaver) {
+ showSaverNotification();
+ mShowing = SHOWING_SAVER;
+ } else {
+ mNoMan.cancel(TAG_NOTIFICATION, ID_NOTIFICATION);
+ mShowing = SHOWING_NOTHING;
+ }
+ }
+
+ private void showInvalidChargerNotification() {
+ final Notification.Builder nb = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_power_low)
+ .setShowWhen(false)
+ .setOngoing(true)
+ .setContentTitle(mContext.getString(R.string.invalid_charger_title))
+ .setContentText(mContext.getString(R.string.invalid_charger_text))
+ .setPriority(Notification.PRIORITY_MAX)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_CHARGER), true);
+ final Notification n = nb.build();
+ if (n.headsUpContentView != null) {
+ n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
+ }
+ mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+ }
+
+ private void showWarningNotification() {
+ final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started
+ : R.string.battery_low_percent_format;
+ final Notification.Builder nb = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_power_low)
+ .setShowWhen(false)
+ .setContentTitle(mContext.getString(R.string.battery_low_title))
+ .setContentText(mContext.getString(textRes, mBatteryLevel))
+ .setOngoing(true)
+ .setPriority(Notification.PRIORITY_MAX)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setFullScreenIntent(pendingBroadcast(ACTION_SHOW_FALLBACK_WARNING), true);
+ if (hasBatterySettings()) {
+ nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
+ }
+ if (!mSaver && mSaverTriggerLevel <= 0) {
+ nb.addAction(R.drawable.ic_power_saver,
+ mContext.getString(R.string.battery_saver_start_action),
+ pendingBroadcast(ACTION_START_SAVER));
+ }
+ if (mPlaySound) {
+ attachLowBatterySound(nb);
+ }
+ final Notification n = nb.build();
+ if (n.headsUpContentView != null) {
+ n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
+ }
+ mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT);
+ }
+
+ private void showSaverNotification() {
+ final Notification.Builder nb = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_power_saver)
+ .setContentTitle(mContext.getString(R.string.battery_saver_notification_title))
+ .setContentText(mContext.getString(R.string.battery_saver_notification_text))
+ .setOngoing(true)
+ .setShowWhen(false)
+ .setCategory(Notification.CATEGORY_SYSTEM);
+ if (hasSaverSettings()) {
+ nb.addAction(0,
+ mContext.getString(R.string.battery_saver_notification_action_text),
+ pendingActivity(mOpenSaverSettings));
+ nb.setContentIntent(pendingActivity(mOpenSaverSettings));
+ }
+ mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT);
+ }
+
+ private PendingIntent pendingActivity(Intent intent) {
+ return PendingIntent.getActivityAsUser(mContext,
+ 0, intent, 0, null, UserHandle.CURRENT);
+ }
+
+ private PendingIntent pendingBroadcast(String action) {
+ return PendingIntent.getBroadcastAsUser(mContext,
+ 0, new Intent(action), 0, UserHandle.CURRENT);
+ }
+
+ private static Intent settings(String action) {
+ return new Intent(action).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_NO_HISTORY
+ | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ }
+
+ @Override
+ public boolean isInvalidChargerWarningShowing() {
+ return mInvalidCharger;
+ }
+
+ @Override
+ public void updateLowBatteryWarning() {
+ updateNotification();
+ mFallbackDialogs.updateLowBatteryWarning();
+ }
+
+ @Override
+ public void dismissLowBatteryWarning() {
+ Slog.i(TAG, "dismissing low battery warning: level=" + mBatteryLevel);
+ dismissLowBatteryNotification();
+ mFallbackDialogs.dismissLowBatteryWarning();
+ }
+
+ private void dismissLowBatteryNotification() {
+ Slog.i(TAG, "dismissing low battery notification");
+ mWarning = false;
+ updateNotification();
+ }
+
+ private boolean hasBatterySettings() {
+ return mOpenBatterySettings.resolveActivity(mContext.getPackageManager()) != null;
+ }
+
+ private boolean hasSaverSettings() {
+ return mOpenSaverSettings.resolveActivity(mContext.getPackageManager()) != null;
+ }
+
+ @Override
+ public void showLowBatteryWarning(boolean playSound) {
+ Slog.i(TAG,
+ "show low battery warning: level=" + mBatteryLevel
+ + " [" + mBucket + "]");
+ mPlaySound = playSound;
+ mWarning = true;
+ updateNotification();
+ mHandler.removeCallbacks(mDismissLowBatteryNotification);
+ mHandler.postDelayed(mDismissLowBatteryNotification, AUTO_DISMISS_MS);
+ }
+
+ private void attachLowBatterySound(Notification.Builder b) {
+ final ContentResolver cr = mContext.getContentResolver();
+
+ final int silenceAfter = Settings.Global.getInt(cr,
+ Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0);
+ final long offTime = SystemClock.elapsedRealtime() - mScreenOffTime;
+ if (silenceAfter > 0
+ && mScreenOffTime > 0
+ && offTime > silenceAfter) {
+ Slog.i(TAG, "screen off too long (" + offTime + "ms, limit " + silenceAfter
+ + "ms): not waking up the user with low battery sound");
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "playing low battery sound. pick-a-doop!"); // WOMP-WOMP is deprecated
+ }
+
+ if (Settings.Global.getInt(cr, Settings.Global.POWER_SOUNDS_ENABLED, 1) == 1) {
+ final String soundPath = Settings.Global.getString(cr,
+ Settings.Global.LOW_BATTERY_SOUND);
+ if (soundPath != null) {
+ final Uri soundUri = Uri.parse("file://" + soundPath);
+ if (soundUri != null) {
+ b.setSound(soundUri, AudioManager.STREAM_SYSTEM);
+ Slog.d(TAG, "playing sound " + soundUri);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dismissInvalidChargerWarning() {
+ dismissInvalidChargerNotification();
+ mFallbackDialogs.dismissInvalidChargerWarning();
+ }
+
+ private void dismissInvalidChargerNotification() {
+ Slog.i(TAG, "dismissing invalid charger notification");
+ mInvalidCharger = false;
+ updateNotification();
+ }
+
+ @Override
+ public void showInvalidChargerWarning() {
+ mInvalidCharger = true;
+ updateNotification();
+ }
+
+ private void showStartSaverConfirmation() {
+ final AlertDialog d = new AlertDialog.Builder(mLightContext)
+ .setTitle(R.string.battery_saver_confirmation_title)
+ .setMessage(R.string.battery_saver_confirmation_text)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverMode)
+ .create();
+
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ d.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ d.show();
+ }
+
+ private void setSaverSetting(boolean mode) {
+ final int val = mode ? 1 : 0;
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, val);
+ }
+
+ private final class Receiver extends BroadcastReceiver {
+
+ public void init() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_SHOW_FALLBACK_WARNING);
+ filter.addAction(ACTION_SHOW_FALLBACK_CHARGER);
+ filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
+ filter.addAction(ACTION_START_SAVER);
+ mContext.registerReceiver(this, filter, null, mHandler);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ Slog.i(TAG, "Received " + action);
+ if (action.equals(ACTION_SHOW_FALLBACK_WARNING)) {
+ dismissLowBatteryNotification();
+ mFallbackDialogs.showLowBatteryWarning(false /*playSound*/);
+ } else if (action.equals(ACTION_SHOW_FALLBACK_CHARGER)) {
+ dismissInvalidChargerNotification();
+ mFallbackDialogs.showInvalidChargerWarning();
+ } else if (action.equals(ACTION_SHOW_BATTERY_SETTINGS)) {
+ dismissLowBatteryNotification();
+ mContext.startActivityAsUser(mOpenBatterySettings, UserHandle.CURRENT);
+ } else if (action.equals(ACTION_START_SAVER)) {
+ dismissLowBatteryNotification();
+ showStartSaverConfirmation();
+ }
+ }
+ }
+
+ private final OnClickListener mStartSaverMode = new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ setSaverSetting(true);
+ }
+ });
+ }
+ };
+
+ private final Runnable mDismissLowBatteryNotification = new Runnable() {
+ @Override
+ public void run() {
+ dismissLowBatteryNotification();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 192ba57..1bb7edb 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
+import android.net.Uri;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.PowerManager;
@@ -38,13 +39,15 @@
public class PowerUI extends SystemUI {
static final String TAG = "PowerUI";
-
static final boolean DEBUG = false;
- private WarningsUI mWarnings;
private final Handler mHandler = new Handler();
+ private final SettingsObserver mObserver = new SettingsObserver(mHandler);
+ private final Receiver mReceiver = new Receiver();
+ private PowerManager mPowerManager;
+ private WarningsUI mWarnings;
private int mBatteryLevel = 100;
private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
private int mPlugType = 0;
@@ -56,10 +59,9 @@
private long mScreenOffTime = -1;
public void start() {
-
- final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mScreenOffTime = pm.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
- mWarnings = new PowerDialogWarnings(mContext);
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
+ mWarnings = new PowerNotificationWarnings(mContext);
ContentObserver obs = new ContentObserver(mHandler) {
@Override
@@ -72,13 +74,16 @@
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
false, obs, UserHandle.USER_ALL);
updateBatteryWarningLevels();
+ mReceiver.init();
+ mObserver.init();
+ }
- // Register for Intent broadcasts for...
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(Intent.ACTION_SCREEN_ON);
- mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
+ private void setSaverMode(boolean mode) {
+ mWarnings.showSaverMode(mode);
+ }
+
+ private void setSaverTrigger(int level) {
+ mWarnings.setSaverTrigger(level);
}
void updateBatteryWarningLevels() {
@@ -130,7 +135,23 @@
throw new RuntimeException("not possible!");
}
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ private final class Receiver extends BroadcastReceiver {
+
+ public void init() {
+ // Register for Intent broadcasts for...
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ mContext.registerReceiver(this, filter, null, mHandler);
+ updateSaverMode();
+ }
+
+ private void updateSaverMode() {
+ setSaverMode(mPowerManager.isPowerSaveMode());
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -191,6 +212,8 @@
mScreenOffTime = SystemClock.elapsedRealtime();
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
mScreenOffTime = -1;
+ } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
+ updateSaverMode();
} else {
Slog.w(TAG, "unknown intent: " + intent);
}
@@ -228,6 +251,8 @@
public interface WarningsUI {
void update(int batteryLevel, int bucket, long screenOffTime);
+ void setSaverTrigger(int level);
+ void showSaverMode(boolean mode);
void dismissLowBatteryWarning();
void showLowBatteryWarning(boolean playSound);
void dismissInvalidChargerWarning();
@@ -236,5 +261,29 @@
boolean isInvalidChargerWarningShowing();
void dump(PrintWriter pw);
}
+
+ private final class SettingsObserver extends ContentObserver {
+ private final Uri LOW_POWER_MODE_TRIGGER_LEVEL_URI =
+ Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL);
+
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void init() {
+ onChange(true, LOW_POWER_MODE_TRIGGER_LEVEL_URI);
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.registerContentObserver(LOW_POWER_MODE_TRIGGER_LEVEL_URI, false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (LOW_POWER_MODE_TRIGGER_LEVEL_URI.equals(uri)) {
+ final int level = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ setSaverTrigger(level);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 0fbbc6e0..8dcdcdb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -287,7 +287,7 @@
/** Updates each of the task animation rects. */
void updateAnimationRects() {
- if (mServiceIsBound && mBootCompleted) {
+ if (mServiceIsBound) {
Resources res = mContext.getResources();
int statusBarHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 1cc57ef..e554af7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -121,6 +121,7 @@
// Send a broadcast to hide recents
Intent intent = new Intent(RecentsService.ACTION_HIDE_RECENTS_ACTIVITY);
intent.setPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (msg.arg1 != 0) {
intent.putExtra(RecentsService.EXTRA_TRIGGERED_FROM_ALT_TAB, true);
}
@@ -129,6 +130,7 @@
// Send a broadcast to toggle recents
Intent intent = new Intent(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
intent.setPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
context.sendBroadcast(intent);
// Time this path
@@ -142,6 +144,7 @@
// Send a broadcast to start the enter animation
Intent intent = new Intent(RecentsService.ACTION_START_ENTER_ANIMATION);
intent.setPackage(context.getPackageName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
context.sendBroadcast(intent);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
index d67e7cb..a3b10f2 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserSwitcherHostView.java
@@ -21,8 +21,16 @@
import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -43,15 +51,18 @@
/**
* A quick and dirty view to show a user switcher.
*/
-public class UserSwitcherHostView extends FrameLayout implements ListView.OnItemClickListener {
+public class UserSwitcherHostView extends FrameLayout
+ implements ListView.OnItemClickListener, View.OnClickListener {
private static final String TAG = "UserSwitcherDialog";
private ArrayList<UserInfo> mUserInfo = new ArrayList<UserInfo>();
+ private UserInfo mGuestUser;
private Adapter mAdapter = new Adapter();
private UserManager mUserManager;
private Runnable mFinishRunnable;
private ListView mListView;
+ private boolean mGuestUserEnabled;
public UserSwitcherHostView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -60,6 +71,9 @@
return;
}
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+
+ mGuestUserEnabled = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.GUEST_USER_ENABLED, 0) == 1;
}
public UserSwitcherHostView(Context context, AttributeSet attrs) {
@@ -80,7 +94,39 @@
@Override
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
- int userId = mAdapter.getItem(position).id;
+ // Last item is the guest
+ if (position == mUserInfo.size()) {
+ postDelayed(new Runnable() {
+ public void run() {
+ switchToGuestUser();
+ }
+ }, 100);
+ } else {
+ final int userId = mAdapter.getItem(position).id;
+ postDelayed(new Runnable() {
+ public void run() {
+ switchUser(userId);
+ }
+ }, 100);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ // Delete was clicked
+ postDelayed(new Runnable() {
+ public void run() {
+ if (mGuestUser != null) {
+ switchUser(0);
+ mUserManager.removeUser(mGuestUser.id);
+ mGuestUser = null;
+ refreshUsers();
+ }
+ }
+ }, 100);
+ }
+
+ private void switchUser(int userId) {
try {
WindowManagerGlobal.getWindowManagerService().lockNow(null);
ActivityManagerNative.getDefault().switchUser(userId);
@@ -90,6 +136,15 @@
}
}
+ private void switchToGuestUser() {
+ if (mGuestUser == null) {
+ // No guest user. Create one.
+ mGuestUser = mUserManager.createGuest(mContext,
+ mContext.getResources().getString(R.string.guest_nickname));
+ }
+ switchUser(mGuestUser.id);
+ }
+
private void finish() {
if (mFinishRunnable != null) {
mFinishRunnable.run();
@@ -119,9 +174,12 @@
public void refreshUsers() {
mUserInfo.clear();
+ mGuestUser = null;
List<UserInfo> users = mUserManager.getUsers(true);
for (UserInfo user : users) {
- if (!user.isManagedProfile()) {
+ if (user.isGuest()) {
+ mGuestUser = user;
+ } else if (!user.isManagedProfile()) {
mUserInfo.add(user);
}
}
@@ -132,17 +190,25 @@
@Override
public int getCount() {
- return mUserInfo.size();
+ return mUserInfo.size() + (mGuestUserEnabled ? 1 : 0);
}
@Override
public UserInfo getItem(int position) {
- return mUserInfo.get(position);
+ if (position < mUserInfo.size()) {
+ return mUserInfo.get(position);
+ } else {
+ return mGuestUser;
+ }
}
@Override
public long getItemId(int position) {
- return getItem(position).serialNumber;
+ if (position < mUserInfo.size()) {
+ return getItem(position).serialNumber;
+ } else {
+ return mGuestUser != null ? mGuestUser.serialNumber : -1;
+ }
}
@Override
@@ -161,18 +227,46 @@
ViewHolder h = new ViewHolder();
h.name = (TextView) v.findViewById(R.id.user_name);
h.picture = (ImageView) v.findViewById(R.id.user_picture);
+ h.delete = (ImageView) v.findViewById(R.id.user_delete);
v.setTag(h);
return v;
}
private void bindView(ViewHolder h, UserInfo item) {
- h.name.setText(item.name);
- h.picture.setImageBitmap(mUserManager.getUserIcon(item.id));
+ if (item != null) {
+ h.name.setText(item.name);
+ h.picture.setImageBitmap(circularClip(mUserManager.getUserIcon(item.id)));
+ h.delete.setVisibility(item.isGuest() ? View.VISIBLE : View.GONE);
+ h.delete.setOnClickListener(UserSwitcherHostView.this);
+ if (item.isGuest()) {
+ h.picture.setImageResource(R.drawable.ic_account_circle);
+ }
+ } else {
+ h.name.setText(R.string.guest_new_guest);
+ h.picture.setImageResource(R.drawable.ic_account_circle);
+ h.delete.setVisibility(View.GONE);
+ }
+ }
+
+ private Bitmap circularClip(Bitmap input) {
+ if (input == null) {
+ return null;
+ }
+ Bitmap output = Bitmap.createBitmap(input.getWidth(),
+ input.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(output);
+ final Paint paint = new Paint();
+ paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
+ paint.setAntiAlias(true);
+ canvas.drawCircle(input.getWidth() / 2, input.getHeight() / 2, input.getWidth() / 2,
+ paint);
+ return output;
}
class ViewHolder {
TextView name;
ImageView picture;
+ ImageView delete;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index c00715a..20684a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -133,7 +133,6 @@
// for heads up notifications
protected HeadsUpNotificationView mHeadsUpNotificationView;
protected int mHeadsUpNotificationDecay;
- protected long mInterruptingNotificationTime;
// used to notify status bar for suppressing notification LED
protected boolean mPanelSlightlyVisible;
@@ -312,7 +311,8 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- if (mNotificationData.findByKey(sbn.getKey()) != null) {
+ if (mNotificationData.findByKey(sbn.getKey()) != null ||
+ isHeadsUp(sbn.getKey())) {
updateNotificationInternal(sbn, rankingMap);
} else {
addNotificationInternal(sbn, rankingMap);
@@ -469,6 +469,10 @@
// should be overridden
}
+ public boolean isHeadsUp(String key) {
+ return mHeadsUpNotificationView != null && mHeadsUpNotificationView.isShowing(key);
+ }
+
public boolean notificationIsForCurrentProfiles(StatusBarNotification n) {
final int thisUserId = mCurrentUserId;
final int notificationUserId = n.getUserId();
@@ -899,10 +903,7 @@
}
public boolean inflateViews(NotificationData.Entry entry, ViewGroup parent, boolean isHeadsUp) {
- int minHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
- int maxHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+ int maxHeight = mRowMaxHeight;
StatusBarNotification sbn = entry.notification;
RemoteViews contentView = sbn.getNotification().contentView;
RemoteViews bigContentView = sbn.getNotification().bigContentView;
@@ -1065,7 +1066,7 @@
}
}
entry.row = row;
- entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
+ entry.row.setHeightRange(mRowMinHeight, maxHeight);
entry.row.setOnActivatedListener(this);
entry.row.setIsBelowSpeedBump(isBelowSpeedBump(entry.notification));
entry.expanded = contentViewLocal;
@@ -1340,9 +1341,15 @@
public void updateNotificationInternal(StatusBarNotification notification, RankingMap ranking) {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
- final NotificationData.Entry oldEntry = mNotificationData.findByKey(notification.getKey());
+ final String key = notification.getKey();
+ boolean wasHeadsUp = isHeadsUp(key);
+ NotificationData.Entry oldEntry;
+ if (wasHeadsUp) {
+ oldEntry = mHeadsUpNotificationView.getEntry();
+ } else {
+ oldEntry = mNotificationData.findByKey(key);
+ }
if (oldEntry == null) {
- Log.w(TAG, "updateNotification for unknown key: " + notification.getKey());
return;
}
@@ -1408,61 +1415,99 @@
&& oldPublicContentView.getPackage() != null
&& oldPublicContentView.getPackage().equals(publicContentView.getPackage())
&& oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
-
-
boolean updateTicker = notification.getNotification().tickerText != null
&& !TextUtils.equals(notification.getNotification().tickerText,
oldEntry.notification.getNotification().tickerText);
+
+ final boolean shouldInterrupt = shouldInterrupt(notification);
+ final boolean alertAgain = alertAgain(oldEntry);
+ boolean updateSuccessful = false;
if (contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
&& publicUnchanged) {
- if (DEBUG) Log.d(TAG, "reusing notification for key: " + notification.getKey());
+ if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
oldEntry.notification = notification;
try {
- updateNotificationViews(oldEntry, notification);
-
- if (ENABLE_HEADS_UP && mHeadsUpNotificationView.getEntry() != null
- && oldNotification == mHeadsUpNotificationView.getEntry().notification) {
- if (!shouldInterrupt(notification)) {
- if (DEBUG) Log.d(TAG, "no longer interrupts!");
- scheduleHeadsUpClose();
- } else {
- if (DEBUG) Log.d(TAG, "updating the current heads up:" + notification);
- mHeadsUpNotificationView.getEntry().notification = notification;
- updateHeadsUpViews(mHeadsUpNotificationView.getEntry(), notification);
+ if (oldEntry.icon != null) {
+ // Update the icon
+ final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
+ notification.getUser(),
+ notification.getNotification().icon,
+ notification.getNotification().iconLevel,
+ notification.getNotification().number,
+ notification.getNotification().tickerText);
+ if (!oldEntry.icon.set(ic)) {
+ handleNotificationError(notification, "Couldn't update icon: " + ic);
+ return;
}
}
- // Update the icon.
- final StatusBarIcon ic = new StatusBarIcon(notification.getPackageName(),
- notification.getUser(),
- notification.getNotification().icon, notification.getNotification().iconLevel,
- notification.getNotification().number,
- notification.getNotification().tickerText);
- if (!oldEntry.icon.set(ic)) {
- handleNotificationError(notification, "Couldn't update icon: " + ic);
- return;
+ if (wasHeadsUp) {
+ if (shouldInterrupt) {
+ updateHeadsUpViews(oldEntry, notification);
+ if (alertAgain) {
+ resetHeadsUpDecayTimer();
+ }
+ } else {
+ // we updated the notification above, so release to build a new shade entry
+ mHeadsUpNotificationView.releaseAndClose();
+ return;
+ }
+ } else {
+ if (shouldInterrupt && alertAgain) {
+ removeNotificationViews(key, ranking);
+ addNotificationInternal(notification, ranking); //this will pop the headsup
+ } else {
+ updateNotificationViews(oldEntry, notification);
+ }
}
mNotificationData.updateRanking(ranking);
updateNotifications();
+ updateSuccessful = true;
}
catch (RuntimeException e) {
// It failed to add cleanly. Log, and remove the view from the panel.
Log.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e);
- removeNotificationViews(notification.getKey(), ranking);
- addNotificationViews(notification, ranking);
}
- } else {
- if (DEBUG) Log.d(TAG, "not reusing notification for key: " + notification.getKey());
- if (DEBUG) Log.d(TAG, "contents was " + (contentsUnchanged ? "unchanged" : "changed"));
- removeNotificationViews(notification.getKey(), ranking);
- addNotificationViews(notification, ranking); // will also replace the heads up
- final NotificationData.Entry newEntry = mNotificationData.findByKey(
- notification.getKey());
- final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
- if (userChangedExpansion) {
- boolean userExpanded = oldEntry.row.isUserExpanded();
- newEntry.row.setUserExpanded(userExpanded);
- newEntry.row.notifyHeightChanged();
+ }
+ if (!updateSuccessful) {
+ if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
+ if (wasHeadsUp) {
+ if (shouldInterrupt) {
+ if (DEBUG) Log.d(TAG, "rebuilding heads up for key: " + key);
+ Entry newEntry = new Entry(notification, null);
+ ViewGroup holder = mHeadsUpNotificationView.getHolder();
+ if (inflateViewsForHeadsUp(newEntry, holder)) {
+ mHeadsUpNotificationView.showNotification(newEntry);
+ if (alertAgain) {
+ resetHeadsUpDecayTimer();
+ }
+ } else {
+ Log.w(TAG, "Couldn't create new updated headsup for package "
+ + contentView.getPackage());
+ }
+ } else {
+ if (DEBUG) Log.d(TAG, "releasing heads up for key: " + key);
+ oldEntry.notification = notification;
+ mHeadsUpNotificationView.releaseAndClose();
+ return;
+ }
+ } else {
+ if (shouldInterrupt && alertAgain) {
+ if (DEBUG) Log.d(TAG, "reposting to invoke heads up for key: " + key);
+ removeNotificationViews(key, ranking);
+ addNotificationInternal(notification, ranking); //this will pop the headsup
+ } else {
+ if (DEBUG) Log.d(TAG, "rebuilding update in place for key: " + key);
+ removeNotificationViews(key, ranking);
+ addNotificationViews(notification, ranking);
+ final NotificationData.Entry newEntry = mNotificationData.findByKey(key);
+ final boolean userChangedExpansion = oldEntry.row.hasUserChangedExpansion();
+ if (userChangedExpansion) {
+ boolean userExpanded = oldEntry.row.isUserExpanded();
+ newEntry.row.setUserExpanded(userExpanded);
+ newEntry.row.notifyHeightChanged();
+ }
+ }
}
}
@@ -1542,6 +1587,12 @@
}
}
+ private boolean alertAgain(Entry entry) {
+ final StatusBarNotification sbn = entry.notification;
+ return entry == null || !entry.hasInterrupted()
+ || (sbn.getNotification().flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0;
+ }
+
protected boolean shouldInterrupt(StatusBarNotification sbn) {
Notification notification = sbn.getNotification();
// some predicates to make the boolean logic legible
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index c313c58..9921c55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -68,6 +68,10 @@
public void setInterruption() {
interruption = true;
}
+
+ public boolean hasInterrupted() {
+ return interruption;
+ }
}
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
deleted file mode 100644
index 1503072..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * An single dot of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
- */
-public class SpeedBumpDotView extends View {
-
- private final Paint mPaint = new Paint();
-
- public SpeedBumpDotView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mPaint.setAntiAlias(true);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- float radius = getWidth() / 2.0f;
- canvas.drawCircle(radius, radius, radius, mPaint);
- }
-
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-
- public void setColor(int color) {
- mPaint.setColor(color);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
deleted file mode 100644
index cac6327..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.view.View;
-import com.android.systemui.R;
-
-/**
- * The Algorithm of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout} which can be
- * queried for {@link * com.android.systemui.statusbar.SpeedBumpDotsState}
- */
-public class SpeedBumpDotsAlgorithm {
-
- private final float mDotRadius;
-
- public SpeedBumpDotsAlgorithm(Context context) {
- mDotRadius = context.getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height)
- / 2.0f;
- }
-
- public void getState(SpeedBumpDotsState resultState) {
-
- // First reset the current state and ensure that every View has a ViewState
- resultState.resetViewStates();
-
- SpeedBumpDotsLayout hostView = resultState.getHostView();
- boolean currentlyVisible = hostView.isCurrentlyVisible();
- resultState.setActiveState(currentlyVisible
- ? SpeedBumpDotsState.SHOWN
- : SpeedBumpDotsState.HIDDEN);
- int hostWidth = hostView.getWidth();
- float layoutWidth = hostWidth - 2 * mDotRadius;
- int childCount = hostView.getChildCount();
- float paddingBetween = layoutWidth / (childCount - 1);
- float centerY = hostView.getHeight() / 2.0f;
- for (int i = 0; i < childCount; i++) {
- View child = hostView.getChildAt(i);
- SpeedBumpDotsState.ViewState viewState = resultState.getViewStateForView(child);
- if (currentlyVisible) {
- float xTranslation = i * paddingBetween;
- viewState.xTranslation = xTranslation;
- viewState.yTranslation = calculateYTranslation(hostView, centerY, xTranslation,
- layoutWidth);
- } else {
- viewState.xTranslation = layoutWidth / 2;
- viewState.yTranslation = centerY - mDotRadius;
- }
- viewState.alpha = currentlyVisible ? 1.0f : 0.0f;
- viewState.scale = currentlyVisible ? 1.0f : 0.5f;
- }
- }
-
- private float calculateYTranslation(SpeedBumpDotsLayout hostView, float centerY,
- float xTranslation, float layoutWidth) {
- float t = hostView.getAnimationProgress();
- if (t == 0.0f || t == 1.0f) {
- return centerY - mDotRadius;
- }
- float damping = (0.5f -Math.abs(0.5f - t)) * 1.3f;
- float partialOffset = xTranslation / layoutWidth;
- float indentFactor = (float) (Math.sin((t + partialOffset * 1.5f) * - Math.PI) * damping);
- return (1.0f - indentFactor) * centerY - mDotRadius;
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
deleted file mode 100644
index ddf5215..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.animation.TimeAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import com.android.systemui.R;
-
-/**
- * A layout with a certain number of dots which are integrated in the
- * {@link com.android.systemui.statusbar.SpeedBumpView}
- */
-public class SpeedBumpDotsLayout extends ViewGroup {
-
- private static final float DOT_CLICK_ANIMATION_LENGTH = 300;
- private final int mDotSize;
- private final SpeedBumpDotsAlgorithm mAlgorithm = new SpeedBumpDotsAlgorithm(getContext());
- private final SpeedBumpDotsState mCurrentState = new SpeedBumpDotsState(this);
- private boolean mIsCurrentlyVisible = true;
- private final ValueAnimator mClickAnimator;
- private float mAnimationProgress;
- private ValueAnimator.AnimatorUpdateListener mClickUpdateListener
- = new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mAnimationProgress = animation.getAnimatedFraction();
- updateChildren();
- }
- };
-
- public SpeedBumpDotsLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- mDotSize = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
- createDots(context, attrs);
- mClickAnimator = TimeAnimator.ofFloat(0, DOT_CLICK_ANIMATION_LENGTH);
- mClickAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
- mClickAnimator.addUpdateListener(mClickUpdateListener);
- }
-
- private void createDots(Context context, AttributeSet attrs) {
- SpeedBumpDotView blueDot = new SpeedBumpDotView(context, attrs);
- blueDot.setColor(getResources().getColor(R.color.speed_bump_dot_blue));
- addView(blueDot);
-
- SpeedBumpDotView redDot = new SpeedBumpDotView(context, attrs);
- redDot.setColor(getResources().getColor(R.color.speed_bump_dot_red));
- addView(redDot);
-
- SpeedBumpDotView yellowDot = new SpeedBumpDotView(context, attrs);
- yellowDot.setColor(getResources().getColor(R.color.speed_bump_dot_yellow));
- addView(yellowDot);
-
- SpeedBumpDotView greenDot = new SpeedBumpDotView(context, attrs);
- greenDot.setColor(getResources().getColor(R.color.speed_bump_dot_green));
- addView(greenDot);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int childWidthSpec = MeasureSpec.makeMeasureSpec(mDotSize,
- MeasureSpec.getMode(widthMeasureSpec));
- int childHeightSpec = MeasureSpec.makeMeasureSpec(mDotSize,
- MeasureSpec.getMode(heightMeasureSpec));
- measureChildren(childWidthSpec, childHeightSpec);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- child.layout(0, 0, mDotSize, mDotSize);
- }
- if (changed) {
- updateChildren();
- }
- }
-
- private void updateChildren() {
- mAlgorithm.getState(mCurrentState);
- mCurrentState.apply();
- }
-
- public void performVisibilityAnimation(boolean visible) {
- if (mClickAnimator.isRunning()) {
- mClickAnimator.cancel();
- }
- mIsCurrentlyVisible = visible;
- mAlgorithm.getState(mCurrentState);
- mCurrentState.animateToState();
- }
-
- public void setInvisible() {
- mIsCurrentlyVisible = false;
- mAlgorithm.getState(mCurrentState);
- mCurrentState.apply();
- }
-
- public boolean isCurrentlyVisible() {
- return mIsCurrentlyVisible;
- }
-
- public void performDotClickAnimation() {
- if (mClickAnimator.isRunning()) {
- // don't perform an animation if it's running already
- return;
- }
- mClickAnimator.start();
- }
-
-
- public float getAnimationProgress() {
- return mAnimationProgress;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
deleted file mode 100644
index 4febab1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.view.View;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A state of a {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
- */
-public class SpeedBumpDotsState {
-
- public static final int HIDDEN = 1;
- public static final int SHOWN = 2;
- private static final int VISIBILITY_ANIMATION_DELAY_PER_ELEMENT = 80;
-
- private final SpeedBumpDotsLayout mHostView;
- private final HashMap<View, ViewState> mStateMap = new HashMap<View, ViewState>();
- private final Interpolator mFastOutSlowInInterpolator;
- private int mActiveState = 0;
-
- public SpeedBumpDotsState(SpeedBumpDotsLayout hostLayout) {
- mHostView = hostLayout;
- mFastOutSlowInInterpolator = AnimationUtils
- .loadInterpolator(hostLayout.getContext(),
- android.R.interpolator.fast_out_slow_in);
- }
-
- public SpeedBumpDotsLayout getHostView() {
- return mHostView;
- }
-
- public void resetViewStates() {
- int numChildren = mHostView.getChildCount();
- for (int i = 0; i < numChildren; i++) {
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
- if (viewState == null) {
- viewState = new ViewState();
- mStateMap.put(child, viewState);
- }
- }
- }
-
- public ViewState getViewStateForView(View requestedView) {
- return mStateMap.get(requestedView);
- }
-
- public void apply() {
- int childCount = mHostView.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
-
- child.setTranslationX(viewState.xTranslation);
- child.setTranslationY(viewState.yTranslation);
- child.setScaleX(viewState.scale);
- child.setScaleY(viewState.scale);
- child.setAlpha(viewState.alpha);
- }
- }
-
- public void animateToState() {
- int childCount = mHostView.getChildCount();
- int middleIndex = (childCount - 1) / 2;
- long delayPerElement = VISIBILITY_ANIMATION_DELAY_PER_ELEMENT;
- boolean isAppearing = getActiveState() == SHOWN;
- boolean isDisappearing = getActiveState() == HIDDEN;
- for (int i = 0; i < childCount; i++) {
- int delayIndex;
- if (i <= middleIndex) {
- delayIndex = i * 2;
- } else {
- int distToMiddle = i - middleIndex;
- delayIndex = (childCount - 1) - (distToMiddle - 1) * 2;
- }
- long startDelay = 0;
- if (isAppearing || isDisappearing) {
- if (isDisappearing) {
- delayIndex = childCount - 1 - delayIndex;
- }
- startDelay = delayIndex * delayPerElement;
- }
- View child = mHostView.getChildAt(i);
- ViewState viewState = mStateMap.get(child);
- child.animate().setInterpolator(mFastOutSlowInInterpolator)
- .setStartDelay(startDelay)
- .alpha(viewState.alpha)
- .translationX(viewState.xTranslation)
- .translationY(viewState.yTranslation)
- .scaleX(viewState.scale).scaleY(viewState.scale);
- }
- }
-
- public int getActiveState() {
- return mActiveState;
- }
-
- public void setActiveState(int mActiveState) {
- this.mActiveState = mActiveState;
- }
-
- public static class ViewState {
- float xTranslation;
- float yTranslation;
- float alpha;
- float scale;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
index 689d0e9..f80f0fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -16,71 +16,26 @@
package com.android.systemui.statusbar;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Outline;
import android.util.AttributeSet;
-import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import android.widget.TextView;
import com.android.systemui.R;
/**
* The view representing the separation between important and less important notifications
*/
-public class SpeedBumpView extends ExpandableView implements View.OnClickListener {
+public class SpeedBumpView extends ExpandableView {
- private final int mCollapsedHeight;
- private final int mDotsHeight;
- private final int mTextPaddingInset;
- private SpeedBumpDotsLayout mDots;
- private AlphaOptimizedView mLineLeft;
- private AlphaOptimizedView mLineRight;
- private boolean mIsExpanded;
- private boolean mDividerVisible = true;
- private ValueAnimator mCurrentAnimator;
+ private final int mSpeedBumpHeight;
+ private AlphaOptimizedView mLine;
+ private boolean mIsVisible = true;
private final Interpolator mFastOutSlowInInterpolator;
- private float mCenterX;
- private TextView mExplanationText;
- private boolean mExplanationTextVisible = false;
- private AnimatorListenerAdapter mHideExplanationListener = new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mCancelled) {
- mExplanationText.setVisibility(View.INVISIBLE);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- mCancelled = false;
- }
- };
- private Animator.AnimatorListener mAnimationFinishedListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mCurrentAnimator = null;
- }
- };
public SpeedBumpView(Context context, AttributeSet attrs) {
super(context, attrs);
- mCollapsedHeight = getResources()
- .getDimensionPixelSize(R.dimen.speed_bump_height_collapsed);
- mTextPaddingInset = getResources().getDimensionPixelSize(
- R.dimen.speed_bump_text_padding_inset);
- mDotsHeight = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
- setOnClickListener(this);
+ mSpeedBumpHeight = getResources()
+ .getDimensionPixelSize(R.dimen.speed_bump_height);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
}
@@ -88,111 +43,41 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mDots = (SpeedBumpDotsLayout) findViewById(R.id.speed_bump_dots_layout);
- mLineLeft = (AlphaOptimizedView) findViewById(R.id.speedbump_line_left);
- mLineRight = (AlphaOptimizedView) findViewById(R.id.speedbump_line_right);
- mExplanationText = (TextView) findViewById(R.id.speed_bump_text);
- resetExplanationText();
-
+ mLine = (AlphaOptimizedView) findViewById(R.id.speedbump_line);
}
@Override
protected int getInitialHeight() {
- return mCollapsedHeight;
+ return mSpeedBumpHeight;
}
@Override
public int getIntrinsicHeight() {
- if (mCurrentAnimator != null) {
- // expand animation is running
- return getActualHeight();
- }
- return mIsExpanded ? getHeight() : mCollapsedHeight;
+ return mSpeedBumpHeight;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- Outline outline = new Outline();
- mCenterX = getWidth() / 2;
- float centerY = getHeight() / 2;
- // TODO: hide outline better
- // Temporary workaround to hide outline on a transparent view
- int outlineLeft = (int) (mCenterX - getResources().getDisplayMetrics().densityDpi * 8);
- int outlineTop = (int) (centerY - mDotsHeight / 2);
- outline.setOval(outlineLeft, outlineTop, outlineLeft + mDotsHeight,
- outlineTop + mDotsHeight);
- setOutline(outline);
- mLineLeft.setPivotX(mLineLeft.getWidth());
- mLineLeft.setPivotY(mLineLeft.getHeight() / 2);
- mLineRight.setPivotX(0);
- mLineRight.setPivotY(mLineRight.getHeight() / 2);
+ mLine.setPivotX(mLine.getWidth() / 2);
+ mLine.setPivotY(mLine.getHeight() / 2);
+ setOutline(null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
- int height = mCollapsedHeight + mExplanationText.getMeasuredHeight() - mTextPaddingInset;
+ int height = mSpeedBumpHeight;
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
}
@Override
- public void onClick(View v) {
- if (mCurrentAnimator != null) {
- return;
- }
- int startValue = mIsExpanded ? getMaxHeight() : mCollapsedHeight;
- int endValue = mIsExpanded ? mCollapsedHeight : getMaxHeight();
- mCurrentAnimator = ValueAnimator.ofInt(startValue, endValue);
- mCurrentAnimator.setInterpolator(mFastOutSlowInInterpolator);
- mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- setActualHeight((int) animation.getAnimatedValue());
- }
- });
- mCurrentAnimator.addListener(mAnimationFinishedListener);
- mCurrentAnimator.start();
- mIsExpanded = !mIsExpanded;
- mDots.performDotClickAnimation();
- animateExplanationTextInternal(mIsExpanded);
- }
-
- private void animateExplanationTextInternal(boolean visible) {
- if (mExplanationTextVisible != visible) {
- float translationY = 0.0f;
- float scale = 0.5f;
- float alpha = 0.0f;
- boolean needsHideListener = true;
- if (visible) {
- mExplanationText.setVisibility(VISIBLE);
- translationY = mDots.getBottom() - mTextPaddingInset;
- scale = 1.0f;
- alpha = 1.0f;
- needsHideListener = false;
- }
- mExplanationText.animate().setInterpolator(mFastOutSlowInInterpolator)
- .alpha(alpha)
- .scaleX(scale)
- .scaleY(scale)
- .translationY(translationY)
- .setListener(needsHideListener ? mHideExplanationListener : null);
- mExplanationTextVisible = visible;
- }
- }
-
- @Override
public boolean isTransparent() {
return true;
}
public void performVisibilityAnimation(boolean nowVisible) {
animateDivider(nowVisible, null /* onFinishedRunnable */);
-
- // Animate explanation Text
- if (mIsExpanded) {
- animateExplanationTextInternal(nowVisible);
- }
}
/**
@@ -203,28 +88,16 @@
* finished.
*/
public void animateDivider(boolean nowVisible, Runnable onFinishedRunnable) {
- if (nowVisible != mDividerVisible) {
+ if (nowVisible != mIsVisible) {
// Animate dividers
float endValue = nowVisible ? 1.0f : 0.0f;
- float endTranslationXLeft = nowVisible ? 0.0f : mCenterX - mLineLeft.getRight();
- float endTranslationXRight = nowVisible ? 0.0f : mCenterX - mLineRight.getLeft();
- mLineLeft.animate()
+ mLine.animate()
.alpha(endValue)
.scaleX(endValue)
.scaleY(endValue)
- .translationX(endTranslationXLeft)
.setInterpolator(mFastOutSlowInInterpolator)
.withEndAction(onFinishedRunnable);
- mLineRight.animate()
- .alpha(endValue)
- .scaleX(endValue)
- .scaleY(endValue)
- .translationX(endTranslationXRight)
- .setInterpolator(mFastOutSlowInInterpolator);
-
- // Animate dots
- mDots.performVisibilityAnimation(nowVisible);
- mDividerVisible = nowVisible;
+ mIsVisible = nowVisible;
} else {
if (onFinishedRunnable != null) {
onFinishedRunnable.run();
@@ -233,34 +106,10 @@
}
public void setInvisible() {
- float endTranslationXLeft = mCenterX - mLineLeft.getRight();
- float endTranslationXRight = mCenterX - mLineRight.getLeft();
- mLineLeft.setAlpha(0.0f);
- mLineLeft.setScaleX(0.0f);
- mLineLeft.setScaleY(0.0f);
- mLineLeft.setTranslationX(endTranslationXLeft);
- mLineRight.setAlpha(0.0f);
- mLineRight.setScaleX(0.0f);
- mLineRight.setScaleY(0.0f);
- mLineRight.setTranslationX(endTranslationXRight);
- mDots.setInvisible();
- resetExplanationText();
-
- mDividerVisible = false;
- }
-
- public void collapse() {
- if (mIsExpanded) {
- setActualHeight(mCollapsedHeight);
- mIsExpanded = false;
- }
- resetExplanationText();
- }
-
- public void animateExplanationText(boolean nowVisible) {
- if (mIsExpanded) {
- animateExplanationTextInternal(nowVisible);
- }
+ mLine.setAlpha(0.0f);
+ mLine.setScaleX(0.0f);
+ mLine.setScaleY(0.0f);
+ mIsVisible = false;
}
@Override
@@ -272,17 +121,4 @@
public void performAddAnimation(long delay) {
performVisibilityAnimation(true);
}
-
- private void resetExplanationText() {
- mExplanationText.setTranslationY(0);
- mExplanationText.setVisibility(INVISIBLE);
- mExplanationText.setAlpha(0.0f);
- mExplanationText.setScaleX(0.5f);
- mExplanationText.setScaleY(0.5f);
- mExplanationTextVisible = false;
- }
-
- public boolean isExpanded() {
- return mIsExpanded;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 6a83a5e..db85b14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -88,13 +88,15 @@
public void run(Result result) {
int y = getClockY() - mKeyguardStatusHeight/2;
- float clockAdjustment = getClockYExpansionAdjustment();
+ float topAdjustment = getTopExpansionAdjustment();
float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier();
- result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier);
+ result.stackScrollerPaddingAdjustment = (int) (topAdjustment*topPaddingAdjMultiplier);
int clockNotificationsPadding = getClockNotificationsPadding()
+ result.stackScrollerPaddingAdjustment;
int padding = y + clockNotificationsPadding;
- y += clockAdjustment;
+ if (mNotificationCount == 0) {
+ y += topAdjustment;
+ }
result.clockY = y;
result.stackScrollerPadding = mKeyguardStatusHeight + padding;
result.clockAlpha = getClockAlpha(result.stackScrollerPadding
@@ -117,8 +119,8 @@
return (int) (getClockYFraction() * mHeight);
}
- private float getClockYExpansionAdjustment() {
- float rubberbandFactor = getClockYExpansionRubberbandFactor();
+ private float getTopExpansionAdjustment() {
+ float rubberbandFactor = getTopExpansionRubberbandFactor();
float value = (rubberbandFactor * (mMaxPanelHeight - mExpandedHeight));
float t = value / mMaxPanelHeight;
float slowedDownValue = -sSlowDownInterpolator.getInterpolation(t) * SLOW_DOWN_FACTOR
@@ -130,7 +132,7 @@
}
}
- private float getClockYExpansionRubberbandFactor() {
+ private float getTopExpansionRubberbandFactor() {
float t = getNotificationAmountT();
t = Math.min(t, 1.0f);
t = (float) Math.pow(t, 0.3f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
index e312d58..ca49408 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
@@ -246,7 +246,9 @@
private void startHintTranslationAnimations(float target, long duration,
Interpolator interpolator) {
ArrayList<View> targetViews = mCallback.getTranslationViews();
- for (View targetView : targetViews) {
+ int length = targetViews.size();
+ for (int i = 0; i < length; i++) {
+ View targetView = targetViews.get(i);
targetView.animate()
.setDuration(duration)
.setInterpolator(interpolator)
@@ -259,8 +261,16 @@
}
private void cancelAnimations() {
- ArrayList<View> targetViews = mCallback.getTranslationViews();
- for (View target : targetViews) {
+ ArrayList<View> translatingViews = mCallback.getTranslationViews();
+ int length = translatingViews.size();
+ for (int i = 0; i < length; i++) {
+ View target = translatingViews.get(i);
+ target.animate().cancel();
+ }
+ ArrayList<View> fadingViews = mCallback.getFadingViews();
+ length = fadingViews.size();
+ for (int i = 0; i < length; i++) {
+ View target = fadingViews.get(i);
target.animate().cancel();
}
View targetView = mTranslation > 0 ? mLeftIcon : mRightIcon;
@@ -291,6 +301,11 @@
// translation Animation
startTranslationAnimations(vel, target);
+ // fade animations
+ if (snapBack) {
+ startFadeInAnimations();
+ }
+
// animate left / right icon
startIconAnimation(vel, snapBack, target);
@@ -346,9 +361,20 @@
mSwipeAnimator = animator;
}
+ private void startFadeInAnimations() {
+ ArrayList<View> fadingViews = mCallback.getFadingViews();
+ int length = fadingViews.size();
+ for (int i = 0; i < length; i++) {
+ View targetView = fadingViews.get(i);
+ targetView.animate().alpha(1.0f);
+ }
+ }
+
private void startTranslationAnimations(float vel, float target) {
ArrayList<View> targetViews = mCallback.getTranslationViews();
- for (View targetView : targetViews) {
+ int length = targetViews.size();
+ for (int i = 0; i < length; i++) {
+ View targetView = targetViews.get(i);
ViewPropertyAnimator animator = targetView.animate();
mFlingAnimationUtils.apply(animator, mTranslation, target, vel);
animator.translationX(target);
@@ -375,8 +401,18 @@
translation = leftSwipePossible() ? translation : Math.min(0, translation);
if (translation != mTranslation || isReset) {
ArrayList<View> translatedViews = mCallback.getTranslationViews();
- for (View view : translatedViews) {
- view.setTranslationX(translation);
+ int length = translatedViews.size();
+ for (int i = 0; i < length; i++) {
+ View target = translatedViews.get(i);
+ target.setTranslationX(translation);
+ }
+ float targetAlpha = 1.0f - Math.abs(translation / mMinTranslationAmount);
+ targetAlpha = Math.max(0.0f, targetAlpha);
+ ArrayList<View> fadingViews = mCallback.getFadingViews();
+ length = fadingViews.size();
+ for (int i = 0; i < length; i++) {
+ View view = fadingViews.get(i);
+ view.setAlpha(targetAlpha);
}
if (translation == 0.0f) {
boolean animate = !isReset;
@@ -494,6 +530,8 @@
ArrayList<View> getTranslationViews();
+ ArrayList<View> getFadingViews();
+
View getLeftIcon();
View getCenterIcon();
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 34179cb..5c686fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -108,6 +108,7 @@
private KeyguardBottomAreaView mKeyguardBottomArea;
private boolean mBlockTouches;
private ArrayList<View> mSwipeTranslationViews = new ArrayList<>();
+ private ArrayList<View> mSwipeFadingViews = new ArrayList<>();
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -152,7 +153,7 @@
android.R.interpolator.fast_out_linear_in);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mSwipeTranslationViews.add(mNotificationStackScroller);
- mSwipeTranslationViews.add(mKeyguardStatusView);
+ mSwipeFadingViews.add(mKeyguardStatusView);
mPageSwiper = new KeyguardPageSwipeHelper(this, getContext());
}
@@ -695,6 +696,11 @@
}
@Override
+ protected boolean hasNotifications() {
+ return mNotificationStackScroller.getNotGoneChildCount() > 0;
+ }
+
+ @Override
protected int getMaxPanelHeight() {
// TODO: Figure out transition for collapsing when QS is open, adjust height here.
int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
@@ -958,6 +964,11 @@
}
@Override
+ public ArrayList<View> getFadingViews() {
+ return mSwipeFadingViews;
+ }
+
+ @Override
public View getLeftIcon() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL
? mKeyguardBottomArea.getCameraImageView()
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 1f3098d..08305dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -30,6 +30,8 @@
import android.view.ViewTreeObserver;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import com.android.systemui.R;
@@ -43,6 +45,8 @@
public static final boolean DEBUG = PanelBar.DEBUG;
public static final String TAG = PanelView.class.getSimpleName();
+ private static final long KEYGUARD_MOVE_UP_LENGTH = 300;
+
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
}
@@ -62,6 +66,9 @@
protected int mTouchSlop;
protected boolean mHintAnimationRunning;
private boolean mOverExpandedBeforeFling;
+ private boolean mKeyguardMovingUp;
+ private int mKeyguardMoveUpDistance;
+ private float mKeyguardFingerHeight;
private ValueAnimator mHeightAnimator;
private ObjectAnimator mPeekAnimator;
@@ -82,6 +89,8 @@
private Interpolator mLinearOutSlowInInterpolator;
private Interpolator mBounceInterpolator;
+ private Interpolator mKeyguardMoveUpInterpolator;
+ private final Interpolator mLinearInterpolator = new LinearInterpolator();
protected void onExpandingFinished() {
mBar.onExpandingFinished();
@@ -109,6 +118,7 @@
mLinearOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
mBounceInterpolator = new BounceInterpolator();
+ mKeyguardMoveUpInterpolator = new PathInterpolator(0.6f, 0f, 0.4f, 1f);
}
protected void loadDimens() {
@@ -120,6 +130,8 @@
mTouchSlop = configuration.getScaledTouchSlop();
mHintDistance = res.getDimension(R.dimen.hint_move_distance);
mEdgeTapAreaWidth = res.getDimensionPixelSize(R.dimen.edge_tap_area_width);
+ mKeyguardMoveUpDistance =
+ res.getDimensionPixelSize(R.dimen.keyguard_panel_move_up_distance);
}
private void trackMovement(MotionEvent event) {
@@ -217,8 +229,13 @@
mJustPeeked = false;
}
if (!mJustPeeked && (!waitForTouchSlop || mTracking)) {
- setExpandedHeightInternal(newHeight);
- mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
+ if (mStatusBar.getBarState() == StatusBarState.KEYGUARD &&
+ !hasNotifications()) {
+ setExpandedHeightKeyguard(newHeight);
+ } else {
+ setExpandedHeightInternal(newHeight);
+ mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
+ }
}
trackMovement(event);
@@ -247,10 +264,56 @@
return !waitForTouchSlop || mTracking;
}
+ protected abstract boolean hasNotifications();
+
+ private void setExpandedHeightKeyguard(float newHeight) {
+ mKeyguardFingerHeight = newHeight;
+ if (newHeight < getMaxPanelHeight() && !mKeyguardMovingUp) {
+ mKeyguardMovingUp = true;
+ ValueAnimator anim = createHeightAnimator(
+ getMaxPanelHeight() - mKeyguardMoveUpDistance);
+ anim.setDuration(KEYGUARD_MOVE_UP_LENGTH);
+ anim.setInterpolator(mKeyguardMoveUpInterpolator);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeightAnimator = null;
+ }
+ });
+ mHeightAnimator = anim;
+ anim.start();
+ postOnAnimationDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (mKeyguardFingerHeight < mExpandedHeight && mHeightAnimator != null
+ && mKeyguardMovingUp) {
+ mHeightAnimator.cancel();
+ float target = getMaxPanelHeight() - 1.75f * mKeyguardMoveUpDistance;
+ float diff = mExpandedHeight - target;
+ ValueAnimator anim = createHeightAnimator(target);
+ float velocity = 2.5f * mKeyguardMoveUpDistance /
+ (KEYGUARD_MOVE_UP_LENGTH / 1000f);
+ anim.setInterpolator(mLinearInterpolator);
+ anim.setDuration(Math.max(0, (long) (diff / velocity * 1000f)));
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeightAnimator = null;
+ }
+ });
+ mHeightAnimator = anim;
+ anim.start();
+ }
+ }
+ }, KEYGUARD_MOVE_UP_LENGTH / 2);
+ }
+ }
+
protected abstract boolean hasConflictingGestures();
protected void onTrackingStopped(boolean expand) {
mTracking = false;
+ mKeyguardMovingUp = false;
mBar.onTrackingStopped(PanelView.this, expand);
}
@@ -381,6 +444,9 @@
protected void fling(float vel, boolean expand) {
cancelPeek();
+ if (mHeightAnimator != null) {
+ mHeightAnimator.cancel();
+ }
float target = expand ? getMaxPanelHeight() : 0.0f;
if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) {
onExpandingFinished();
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 a2dbf75..b23992d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1068,8 +1068,6 @@
Entry interruptionCandidate = new Entry(notification, null);
ViewGroup holder = mHeadsUpNotificationView.getHolder();
if (inflateViewsForHeadsUp(interruptionCandidate, holder)) {
- mInterruptingNotificationTime = System.currentTimeMillis();
-
// 1. Populate mHeadsUpNotificationView
mHeadsUpNotificationView.showNotification(interruptionCandidate);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index d778ccb..0a48e34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -78,8 +78,10 @@
}
public boolean showNotification(NotificationData.Entry headsUp) {
- // bump any previous heads up back to the shade
- release();
+ if (mHeadsUp != null && headsUp != null && !mHeadsUp.key.equals(headsUp.key)) {
+ // bump any previous heads up back to the shade
+ release();
+ }
mHeadsUp = headsUp;
if (mContentHolder != null) {
@@ -101,6 +103,8 @@
mSwipeHelper.snapChild(mContentHolder, 1f);
mStartTouchTime = System.currentTimeMillis() + mTouchSensitivityDelay;
+ mHeadsUp.setInterruption();
+
// 2. Animate mHeadsUpNotificationView in
mBar.scheduleHeadsUpOpen();
@@ -110,6 +114,10 @@
return true;
}
+ public boolean isShowing(String key) {
+ return mHeadsUp != null && mHeadsUp.key.equals(key);
+ }
+
/** Discard the Heads Up notification. */
public void clear() {
mHeadsUp = null;
@@ -136,6 +144,11 @@
mHeadsUp = null;
}
+ public void releaseAndClose() {
+ release();
+ mBar.scheduleHeadsUpClose();
+ }
+
public NotificationData.Entry getEntry() {
return mHeadsUp;
}
@@ -378,4 +391,4 @@
return mConsuming;
}
}
-}
\ No newline at end of file
+}
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 e47f475..94472a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1723,7 +1723,6 @@
mStackScrollAlgorithm.setIsExpanded(isExpanded);
if (!isExpanded) {
mOwnScrollY = 0;
- mSpeedBumpView.collapse();
}
}
@@ -1792,7 +1791,6 @@
int newVisibility = visible ? VISIBLE : GONE;
mSpeedBumpView.setVisibility(newVisibility);
if (visible) {
- mSpeedBumpView.collapse();
// Make invisible to ensure that the appear animation is played.
mSpeedBumpView.setInvisible();
if (!mIsExpansionChanging) {
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 d6ff4fc..cbad9dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -186,7 +186,7 @@
if (!child.isTransparent()) {
// Only update the previous values if we are not transparent,
// otherwise we would clip to a transparent view.
- previousNotificationStart = newYTranslation + child.getClipTopAmount();
+ previousNotificationStart = newYTranslation + state.clipTopAmount;
previousNotificationEnd = newNotificationEnd;
previousNotificationIsSwiped = child.getTranslationX() != 0;
}
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 94cb16d..1ad4acc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -160,9 +160,8 @@
}
if(child instanceof SpeedBumpView) {
- float speedBumpEnd = newYTranslation + newHeight;
- performSpeedBumpAnimation(i, (SpeedBumpView) child, speedBumpEnd,
- newYTranslation);
+ float lineEnd = newYTranslation + newHeight / 2;
+ performSpeedBumpAnimation(i, (SpeedBumpView) child, lineEnd);
}
}
}
@@ -183,20 +182,12 @@
child.setClipBounds(mClipRect);
}
- private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd,
- float speedBumpStart) {
+ private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd) {
View nextChild = getNextChildNotGone(i);
if (nextChild != null) {
ViewState nextState = getViewStateForView(nextChild);
- boolean startIsAboveNext = nextState.yTranslation > speedBumpStart;
+ boolean startIsAboveNext = nextState.yTranslation > speedBumpEnd;
speedBump.animateDivider(startIsAboveNext, null /* onFinishedRunnable */);
-
- // handle expanded case
- if (speedBump.isExpanded()) {
- boolean endIsAboveNext = nextState.yTranslation > speedBumpEnd;
- speedBump.animateExplanationText(endIsAboveNext);
- }
-
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index a8645bc..5e1aa3b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -93,6 +93,7 @@
import android.view.ViewRootImpl;
import android.view.ViewStub;
import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -118,6 +119,9 @@
private final static String TAG = "PhoneWindow";
private final static boolean SWEEP_OPEN_MENU = false;
+
+ private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
+
/**
* Simple callback used by the context menu and its submenus. The options
* menu submenus do not use this (their behavior is more complex).
@@ -246,6 +250,7 @@
private Transition mSharedElementExitTransition;
private Boolean mAllowExitTransitionOverlap;
private Boolean mAllowEnterTransitionOverlap;
+ private long mBackgroundFadeDurationMillis = -1;
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -2627,15 +2632,15 @@
}
@Override
- protected boolean fitSystemWindows(Rect insets) {
- mFrameOffsets.set(insets);
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mFrameOffsets.set(insets.getSystemWindowInsets());
updateColorViews(insets);
- updateStatusGuard(insets);
+ insets = updateStatusGuard(insets);
updateNavigationGuard(insets);
if (getForeground() != null) {
drawableChanged();
}
- return super.fitSystemWindows(insets);
+ return insets;
}
@Override
@@ -2643,14 +2648,14 @@
return false;
}
- private void updateColorViews(Rect insets) {
+ private void updateColorViews(WindowInsets insets) {
if (mIsFloating || !ActivityManager.isHighEndGfx()) {
// No colors on floating windows or low end devices :(
return;
}
if (insets != null) {
- mLastTopInset = insets.top;
- mLastBottomInset = insets.bottom;
+ mLastTopInset = insets.getSystemWindowInsetTop();
+ mLastBottomInset = insets.getSystemWindowInsetBottom();
}
mStatusColorView = updateColorViewInt(mStatusColorView,
SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
@@ -2689,7 +2694,7 @@
return view;
}
- private void updateStatusGuard(Rect insets) {
+ private WindowInsets updateStatusGuard(WindowInsets insets) {
boolean showStatusGuard = false;
// Show the status guard when the non-overlay contextual action bar is showing
if (mActionModeView != null) {
@@ -2701,9 +2706,9 @@
&& mActionModeView.isShown();
if (nonOverlayShown) {
// set top margin to top insets, show status guard
- if (mlp.topMargin != insets.top) {
+ if (mlp.topMargin != insets.getSystemWindowInsetTop()) {
mlpChanged = true;
- mlp.topMargin = insets.top;
+ mlp.topMargin = insets.getSystemWindowInsetTop();
if (mStatusGuard == null) {
mStatusGuard = new View(mContext);
mStatusGuard.setBackgroundColor(mContext.getResources()
@@ -2719,7 +2724,8 @@
}
}
}
- insets.top = 0; // consume top insets
+ insets = insets.consumeSystemWindowInsets(
+ false, true /* top */, false, false);
showStatusGuard = true;
} else {
// reset top margin
@@ -2736,9 +2742,10 @@
if (mStatusGuard != null) {
mStatusGuard.setVisibility(showStatusGuard ? View.VISIBLE : View.GONE);
}
+ return insets;
}
- private void updateNavigationGuard(Rect insets) {
+ private void updateNavigationGuard(WindowInsets insets) {
// IMEs lay out below the nav bar, but the content view must not (for back compat)
if (getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
// prevent the content view from including the nav bar height
@@ -2746,7 +2753,7 @@
if (mContentParent.getLayoutParams() instanceof MarginLayoutParams) {
MarginLayoutParams mlp =
(MarginLayoutParams) mContentParent.getLayoutParams();
- mlp.bottomMargin = insets.bottom;
+ mlp.bottomMargin = insets.getSystemWindowInsetBottom();
mContentParent.setLayoutParams(mlp);
}
}
@@ -2756,11 +2763,11 @@
mNavigationGuard.setBackgroundColor(mContext.getResources()
.getColor(R.color.input_method_navigation_guard));
addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams(
- LayoutParams.MATCH_PARENT, insets.bottom,
+ LayoutParams.MATCH_PARENT, insets.getSystemWindowInsetBottom(),
Gravity.START | Gravity.BOTTOM));
} else {
LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams();
- lp.height = insets.bottom;
+ lp.height = insets.getSystemWindowInsetBottom();
mNavigationGuard.setLayoutParams(lp);
}
}
@@ -3419,6 +3426,12 @@
com.android.internal.R.styleable.
Window_windowAllowExitTransitionOverlap, true);
}
+ if (mBackgroundFadeDurationMillis < 0) {
+ mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
+ com.android.internal.R.styleable.
+ Window_windowTransitionBackgroundFadeDuration,
+ DEFAULT_BACKGROUND_FADE_DURATION_MS);
+ }
}
}
}
@@ -3825,6 +3838,20 @@
return (mAllowExitTransitionOverlap == null) ? true : mAllowExitTransitionOverlap;
}
+ @Override
+ public long getTransitionBackgroundFadeDuration() {
+ return (mBackgroundFadeDurationMillis < 0) ? DEFAULT_BACKGROUND_FADE_DURATION_MS
+ : mBackgroundFadeDurationMillis;
+ }
+
+ @Override
+ public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) {
+ if (fadeDurationMillis < 0) {
+ throw new IllegalArgumentException("negative durations are not allowed");
+ }
+ mBackgroundFadeDurationMillis = fadeDurationMillis;
+ }
+
private static final class DrawableFeatureState {
DrawableFeatureState(int _featureId) {
featureId = _featureId;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index cacf66b..5598972 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -306,6 +306,7 @@
boolean mSystemReady;
boolean mSystemBooted;
boolean mHdmiPlugged;
+ IUiModeManager mUiModeManager;
int mUiMode;
int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
int mLidOpenRotation;
@@ -435,6 +436,12 @@
* be done once per window. */
private WindowState mWinDismissingKeyguard;
+ /** The window that is currently showing "over" the keyguard. If there is an app window
+ * belonging to another app on top of this the keyguard shows. If there is a fullscreen
+ * app window under this, still dismiss the keyguard but don't show the app underneath. Show
+ * the wallpaper. */
+ private WindowState mWinShowWhenLocked;
+
boolean mShowingLockscreen;
boolean mShowingDream;
boolean mDreamingLockscreen;
@@ -1669,8 +1676,9 @@
}
@Override
- public boolean doesForceHide(WindowManager.LayoutParams attrs) {
- return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ public boolean isForceHiding(WindowManager.LayoutParams attrs) {
+ return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
+ (isKeyguardHostWindow(attrs) && isKeyguardSecureIncludingHidden());
}
@Override
@@ -3119,10 +3127,11 @@
/** {@inheritDoc} */
@Override
- public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
- WindowState attached) {
+ public void layoutWindowLw(WindowState win, WindowState attached) {
// we've already done the status bar
- if ((win == mStatusBar && !doesForceHide(attrs)) || win == mNavigationBar) {
+ final WindowManager.LayoutParams attrs = win.getAttrs();
+ if ((win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) == 0) ||
+ win == mNavigationBar) {
return;
}
final boolean isDefaultDisplay = win.isDefaultDisplay();
@@ -3603,12 +3612,12 @@
mDismissKeyguard = DISMISS_KEYGUARD_NONE;
mShowingLockscreen = false;
mShowingDream = false;
+ mWinShowWhenLocked = null;
}
/** {@inheritDoc} */
@Override
- public void applyPostLayoutPolicyLw(WindowState win,
- WindowManager.LayoutParams attrs) {
+ public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs) {
if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
+ win.isVisibleOrBehindKeyguardLw());
final int fl = PolicyControl.getWindowFlags(win, attrs);
@@ -3646,9 +3655,17 @@
final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
+ final boolean secureKeyguard = isKeyguardSecure();
if (appWindow) {
- if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) {
+ if (showWhenLocked || (dismissKeyguard && !secureKeyguard)) {
+ // Remove any previous windows with the same appToken.
mAppsToBeHidden.remove(win.getAppToken());
+ if (mAppsToBeHidden.isEmpty() && showWhenLocked &&
+ isKeyguardSecureIncludingHidden()) {
+ mWinShowWhenLocked = win;
+ mHideLockScreen = true;
+ mForceStatusBarFromKeyguard = false;
+ }
} else {
mAppsToBeHidden.add(win.getAppToken());
}
@@ -3670,13 +3687,18 @@
mDismissKeyguard = mWinDismissingKeyguard == win ?
DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
mWinDismissingKeyguard = win;
- mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure();
+ mForceStatusBarFromKeyguard = mShowingLockscreen && secureKeyguard;
}
}
if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
mAllowLockscreenWhenOn = true;
}
}
+
+ if (mWinShowWhenLocked != null &&
+ mWinShowWhenLocked.getAppToken() != win.getAppToken()) {
+ win.hideLw(false);
+ }
}
}
}
@@ -3684,6 +3706,16 @@
/** {@inheritDoc} */
@Override
public int finishPostLayoutPolicyLw() {
+ if (mWinShowWhenLocked != null &&
+ mWinShowWhenLocked != mTopFullscreenOpaqueWindowState) {
+ // A dialog is dismissing the keyguard. Put the wallpaper behind it and hide the
+ // fullscreen window.
+ // TODO: Make sure FLAG_SHOW_WALLPAPER is restored when dialog is dismissed. Or not.
+ mWinShowWhenLocked.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+ mTopFullscreenOpaqueWindowState.hideLw(false);
+ mTopFullscreenOpaqueWindowState = mWinShowWhenLocked;
+ }
+
int changes = 0;
boolean topIsFullscreen = false;
@@ -4086,11 +4118,6 @@
+ " policyFlags=" + Integer.toHexString(policyFlags));
}
- if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
- && event.getRepeatCount() == 0) {
- performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
- }
-
// Basic policy based on interactive state.
int result;
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
@@ -4113,6 +4140,10 @@
return result;
}
+ boolean useHapticFeedback = down
+ && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
+ && event.getRepeatCount() == 0;
+
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -4259,6 +4290,9 @@
case KeyEvent.KEYCODE_SLEEP: {
result &= ~ACTION_PASS_TO_USER;
+ if (!mPowerManager.isInteractive()) {
+ useHapticFeedback = false; // suppress feedback if already non-interactive
+ }
mPowerManager.goToSleep(event.getEventTime());
isWakeKey = false;
break;
@@ -4325,6 +4359,10 @@
}
}
+ if (useHapticFeedback) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+ }
+
if (isWakeKey) {
mPowerManager.wakeUp(event.getEventTime());
}
@@ -4639,6 +4677,11 @@
return mKeyguardDelegate.isSecure();
}
+ // Returns true if keyguard is currently locked whether or not it is currently hidden.
+ private boolean isKeyguardSecureIncludingHidden() {
+ return mKeyguardDelegate.isSecure() && mKeyguardDelegate.isShowing();
+ }
+
/** {@inheritDoc} */
public boolean inKeyguardRestrictedKeyInputMode() {
if (mKeyguardDelegate == null) return false;
@@ -4948,6 +4991,7 @@
mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
mKeyguardDelegate.onSystemReady();
+ updateUiMode();
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
@@ -5136,6 +5180,17 @@
}
}
+ void updateUiMode() {
+ if (mUiModeManager == null) {
+ mUiModeManager = IUiModeManager.Stub.asInterface(
+ ServiceManager.getService(Context.UI_MODE_SERVICE));
+ }
+ try {
+ mUiMode = mUiModeManager.getCurrentModeType();
+ } catch (RemoteException e) {
+ }
+ }
+
void updateRotation(boolean alwaysSendConfiguration) {
try {
//set orientation on WindowManager
@@ -5181,6 +5236,12 @@
if (ENABLE_DESK_DOCK_HOME_CAPTURE) {
intent = mDeskDockIntent;
}
+ } else if (mUiMode == Configuration.UI_MODE_TYPE_WATCH
+ && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK)) {
+ // Always launch dock home from home when watch is docked, if it exists.
+ intent = mDeskDockIntent;
}
if (intent == null) {
diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java
index 0e57232..c9bba69 100644
--- a/rs/java/android/renderscript/FieldPacker.java
+++ b/rs/java/android/renderscript/FieldPacker.java
@@ -233,6 +233,9 @@
if (obj != null) {
if (RenderScript.sPointerSize == 8) {
addI64(obj.getID(null));
+ addI64(0);
+ addI64(0);
+ addI64(0);
}
else {
addI32((int)obj.getID(null));
@@ -240,6 +243,9 @@
} else {
if (RenderScript.sPointerSize == 8) {
addI64(0);
+ addI64(0);
+ addI64(0);
+ addI64(0);
} else {
addI32(0);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index faa0c57..1be1572 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3302,7 +3302,7 @@
for (int i = 0; i < windowCount; i++) {
AccessibilityWindowInfo window = mWindows.get(i);
if (window.getId() == mActiveWindowId) {
- window.setActive(true);
+ window.setActive(true);
}
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9087726..00bda06 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -20,7 +20,6 @@
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
-import static android.net.ConnectivityManager.NetworkCallbackListener;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_DUMMY;
import static android.net.ConnectivityManager.TYPE_MOBILE;
@@ -630,8 +629,8 @@
if (DBG) log("ConnectivityService starting up");
NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
NetworkRequestInfo.REQUEST);
@@ -5410,7 +5409,7 @@
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, int timeoutSec, IBinder binder, int legacyType) {
+ Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
== false) {
enforceConnectivityInternalPermission();
@@ -5418,7 +5417,7 @@
enforceChangePermission();
}
- if (timeoutSec < 0 || timeoutSec > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_SEC) {
+ if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
throw new IllegalArgumentException("Bad timeout specified");
}
NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
@@ -5428,9 +5427,9 @@
NetworkRequestInfo.REQUEST);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
- if (timeoutSec > 0) {
+ if (timeoutMs > 0) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
- nri), timeoutSec * 1000);
+ nri), timeoutMs);
}
return networkRequest;
}
@@ -5694,7 +5693,7 @@
int a2 = 0;
switch (notificationType) {
case ConnectivityManager.CALLBACK_LOSING:
- a1 = 30; // TODO - read this from NetworkMonitor
+ a1 = 30 * 1000; // TODO - read this from NetworkMonitor
// fall through
case ConnectivityManager.CALLBACK_PRECHECK:
case ConnectivityManager.CALLBACK_AVAILABLE:
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 5eee396..10382ba 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -479,8 +479,8 @@
mContext,
mLocationHandler,
flpHardwareProvider.getLocationHardware(),
- com.android.internal.R.bool.config_enableFusedLocationOverlay,
- com.android.internal.R.string.config_fusedLocationProviderPackageName,
+ com.android.internal.R.bool.config_enableHardwareFlpOverlay,
+ com.android.internal.R.string.config_hardwareFlpPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
if(fusedProxy == null) {
Slog.e(TAG, "Unable to bind FusedProxy.");
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 362061e..d26f3fc 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -61,6 +61,7 @@
import android.os.SystemProperties;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -237,7 +238,9 @@
mThread = new Thread(mConnector, NETD_TAG);
mDaemonHandler = new Handler(FgThread.get().getLooper());
- mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) {
+ mPhoneStateListener = new PhoneStateListener(
+ SubscriptionManager.DEFAULT_SUB_ID, // FIXME: What Subscription should be used??
+ mDaemonHandler.getLooper()) {
public void onDataConnectionRealTimeInfoChanged(
DataConnectionRealTimeInfo dcRtInfo) {
notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index cfaf016..9d92421 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -33,10 +33,13 @@
import android.os.UserHandle;
import android.telephony.CellLocation;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
import android.telephony.TelephonyManager;
import android.telephony.DisconnectCause;
import android.telephony.PreciseCallState;
@@ -65,8 +68,9 @@
*/
class TelephonyRegistry extends ITelephonyRegistry.Stub {
private static final String TAG = "TelephonyRegistry";
- private static final boolean DBG = false;
- private static final boolean DBG_LOC = false;
+ private static final boolean DBG = false; // STOPSHIP if true
+ private static final boolean DBG_LOC = false; // STOPSHIP if true
+ private static final boolean VDBG = false; // STOPSHIP if true
private static class Record {
String pkgForDebug;
@@ -79,6 +83,10 @@
int events;
+ long subId;
+
+ boolean isLegacyApp;
+
@Override
public String toString() {
return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid +
@@ -94,41 +102,47 @@
private final IBatteryStats mBatteryStats;
- private int mCallState = TelephonyManager.CALL_STATE_IDLE;
+ private int mNumPhones;
- private String mCallIncomingNumber = "";
+ private int[] mCallState;
- private ServiceState mServiceState = new ServiceState();
+ private String[] mCallIncomingNumber;
- private SignalStrength mSignalStrength = new SignalStrength();
+ private ServiceState[] mServiceState;
- private boolean mMessageWaiting = false;
+ private SignalStrength[] mSignalStrength;
- private boolean mCallForwarding = false;
+ private boolean[] mMessageWaiting;
- private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
+ private boolean[] mCallForwarding;
- private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
+ private int[] mDataActivity;
- private boolean mDataConnectionPossible = false;
+ private int[] mDataConnectionState;
- private String mDataConnectionReason = "";
+ private boolean[] mDataConnectionPossible;
- private String mDataConnectionApn = "";
+ private String[] mDataConnectionReason;
+
+ private String[] mDataConnectionApn;
private ArrayList<String> mConnectedApns;
- private LinkProperties mDataConnectionLinkProperties;
+ private LinkProperties[] mDataConnectionLinkProperties;
- private NetworkCapabilities mDataConnectionNetworkCapabilities;
+ private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
- private Bundle mCellLocation = new Bundle();
+ private Bundle[] mCellLocation;
- private int mDataConnectionNetworkType;
+ private int[] mDataConnectionNetworkType;
private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
- private List<CellInfo> mCellInfo = null;
+ private ArrayList<List<CellInfo>> mCellInfo = null;
+
+ private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
+
+ private long mDefaultSubId;
private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
@@ -148,21 +162,40 @@
PhoneStateListener.LISTEN_CALL_STATE |
PhoneStateListener.LISTEN_DATA_ACTIVITY |
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
- PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+ PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
+ PhoneStateListener.LISTEN_VOLTE_STATE;;
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
private static final int MSG_USER_SWITCHED = 1;
+ private static final int MSG_UPDATE_DEFAULT_SUB = 2;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_USER_SWITCHED: {
- if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
- TelephonyRegistry.this.notifyCellLocation(mCellLocation);
+ Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
+ int numPhones = TelephonyManager.getDefault().getPhoneCount();
+ for (int sub = 0; sub < numPhones; sub++) {
+ TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]);
+ }
+ break;
+ }
+ case MSG_UPDATE_DEFAULT_SUB: {
+ Slog.d(TAG, "MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId);
+ // Default subscription id changed, update the changed default subscription
+ // id in all the legacy application listener records.
+ synchronized (mRecords) {
+ for (Record r : mRecords) {
+ // FIXME: Be sure we're using isLegacyApp correctly!
+ if (r.isLegacyApp == true) {
+ r.subId = mDefaultSubId;
+ }
+ }
+ }
break;
}
}
@@ -173,9 +206,14 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ Slog.d(TAG, "mBroadcastReceiver: action=" + action);
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
+ } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
+ mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ SubscriptionManager.getDefaultSubId());
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0));
}
}
};
@@ -190,13 +228,55 @@
TelephonyRegistry(Context context) {
CellLocation location = CellLocation.getEmpty();
+ mContext = context;
+ mBatteryStats = BatteryStatsService.getService();
+ mConnectedApns = new ArrayList<String>();
+
+ // Initialize default subscription to be used for single standby.
+ mDefaultSubId = SubscriptionManager.getDefaultSubId();
+
+ int numPhones = TelephonyManager.getDefault().getPhoneCount();
+ if (DBG) Slog.d(TAG, "TelephonyRegistor: ctor numPhones=" + numPhones);
+ mNumPhones = numPhones;
+ mCallState = new int[numPhones];
+ mDataActivity = new int[numPhones];
+ mDataConnectionState = new int[numPhones];
+ mDataConnectionNetworkType = new int[numPhones];
+ mCallIncomingNumber = new String[numPhones];
+ mServiceState = new ServiceState[numPhones];
+ mSignalStrength = new SignalStrength[numPhones];
+ mMessageWaiting = new boolean[numPhones];
+ mDataConnectionPossible = new boolean[numPhones];
+ mDataConnectionReason = new String[numPhones];
+ mDataConnectionApn = new String[numPhones];
+ mCallForwarding = new boolean[numPhones];
+ mCellLocation = new Bundle[numPhones];
+ mDataConnectionLinkProperties = new LinkProperties[numPhones];
+ mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
+ mCellInfo = new ArrayList<List<CellInfo>>();
+ for (int i = 0; i < numPhones; i++) {
+ mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
+ mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
+ mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+ mCallIncomingNumber[i] = "";
+ mServiceState[i] = new ServiceState();
+ mSignalStrength[i] = new SignalStrength();
+ mMessageWaiting[i] = false;
+ mCallForwarding[i] = false;
+ mDataConnectionPossible[i] = false;
+ mDataConnectionReason[i] = "";
+ mDataConnectionApn[i] = "";
+ mCellLocation[i] = new Bundle();
+ mCellInfo.add(i, null);
+ }
+
// Note that location can be null for non-phone builds like
// like the generic one.
if (location != null) {
- location.fillInNotifierBundle(mCellLocation);
+ for (int i = 0; i < numPhones; i++) {
+ location.fillInNotifierBundle(mCellLocation[i]);
+ }
}
- mContext = context;
- mBatteryStats = BatteryStatsService.getService();
mConnectedApns = new ArrayList<String>();
}
@@ -205,16 +285,31 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
+ Slog.d(TAG, "systemRunning register for intents");
mContext.registerReceiver(mBroadcastReceiver, filter);
}
@Override
public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
boolean notifyNow) {
+ listen(pkgForDebug, callback, events, notifyNow, mDefaultSubId, true);
+ }
+
+ @Override
+ public void listenUsingSubId(long subId, String pkgForDebug, IPhoneStateListener callback,
+ int events, boolean notifyNow) {
+ listen(pkgForDebug, callback, events, notifyNow, subId, false);
+ }
+
+ private void listen(String pkgForDebug, IPhoneStateListener callback, int events,
+ boolean notifyNow, long subId, boolean isLegacyApp) {
int callerUid = UserHandle.getCallingUserId();
int myUid = UserHandle.myUserId();
- if (DBG) {
+ if (VDBG) {
Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
+ + " notifyNow=" + notifyNow + " subId=" + subId
+ + " isLegacyApp=" + isLegacyApp
+ " myUid=" + myUid
+ " callerUid=" + callerUid);
}
@@ -239,22 +334,37 @@
r.callback = callback;
r.pkgForDebug = pkgForDebug;
r.callerUid = callerUid;
+ r.subId = subId;
+ r.isLegacyApp = isLegacyApp;
+ // Legacy applications pass invalid subId(-1), based on
+ // the received subId value update the isLegacyApp field
+ if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) {
+ r.subId = mDefaultSubId;
+ r.isLegacyApp = true; // FIXME: is this needed ??
+ }
+ if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+ r.subId = mDefaultSubId;
+ if (DBG) Slog.i(TAG, "listen: DEFAULT_SUB_ID");
+ }
mRecords.add(r);
if (DBG) Slog.i(TAG, "listen: add new record=" + r);
}
+ int phoneId = SubscriptionManager.getPhoneId(subId);
int send = events & (events ^ r.events);
r.events = events;
- if (notifyNow) {
+ if (notifyNow && validatePhoneId(phoneId)) {
if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try {
- r.callback.onServiceStateChanged(new ServiceState(mServiceState));
+ r.callback.onServiceStateChanged(
+ new ServiceState(mServiceState[phoneId]));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
try {
- int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
+ int gsmSignalStrength = mSignalStrength[phoneId]
+ .getGsmSignalStrength();
r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
: gsmSignalStrength));
} catch (RemoteException ex) {
@@ -263,51 +373,56 @@
}
if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
try {
- r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
+ r.callback.onMessageWaitingIndicatorChanged(
+ mMessageWaiting[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
try {
- r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
+ r.callback.onCallForwardingIndicatorChanged(
+ mCallForwarding[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
- if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
- r.callback.onCellLocationChanged(new Bundle(mCellLocation));
+ if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation = "
+ + mCellLocation[phoneId]);
+ r.callback.onCellLocationChanged(
+ new Bundle(mCellLocation[phoneId]));
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
try {
- r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
+ r.callback.onCallStateChanged(mCallState[phoneId],
+ mCallIncomingNumber[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
try {
- r.callback.onDataConnectionStateChanged(mDataConnectionState,
- mDataConnectionNetworkType);
+ r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+ mDataConnectionNetworkType[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
try {
- r.callback.onDataActivity(mDataActivity);
+ r.callback.onDataActivity(mDataActivity[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
try {
- r.callback.onSignalStrengthsChanged(mSignalStrength);
+ r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -321,8 +436,9 @@
}
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
- if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
- r.callback.onCellInfoChanged(mCellInfo);
+ if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo[" + phoneId + "] = "
+ + mCellInfo.get(phoneId));
+ r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -373,10 +489,10 @@
return;
}
synchronized (mRecords) {
- mCallState = state;
- mCallIncomingNumber = incomingNumber;
for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
+ if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+ (r.isLegacyApp == true)) {
+ // FIXME: why does isLegacyApp need to be true?
try {
r.callback.onCallStateChanged(state, incomingNumber);
} catch (RemoteException ex) {
@@ -386,82 +502,148 @@
}
handleRemoveListLocked();
}
- broadcastCallStateChanged(state, incomingNumber);
+ broadcastCallStateChanged(state, incomingNumber, mDefaultSubId);
}
- public void notifyServiceState(ServiceState state) {
+ public void notifyCallStateUsingSubId(long subId, int state, String incomingNumber) {
+ if (!checkNotifyPermission("notifyCallState()")) {
+ return;
+ }
+ if (VDBG) {
+ Slog.d(TAG, "notifyCallStateUsingSubId: subId=" + subId
+ + " state=" + state + " incomingNumber=" + incomingNumber);
+ }
+ synchronized (mRecords) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mCallState[phoneId] = state;
+ mCallIncomingNumber[phoneId] = incomingNumber;
+ for (Record r : mRecords) {
+ if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
+ (r.subId == subId) && (r.isLegacyApp == false)) {
+ // FIXME: why isLegacyApp false?
+ try {
+ r.callback.onCallStateChanged(state, incomingNumber);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ broadcastCallStateChanged(state, incomingNumber, subId);
+ }
+
+ public void notifyServiceState(ServiceState state) {
+ notifyServiceStateUsingSubId(mDefaultSubId, state);
+ }
+
+ public void notifyServiceStateUsingSubId(long subId, ServiceState state) {
if (!checkNotifyPermission("notifyServiceState()")){
return;
}
- long ident = Binder.clearCallingIdentity();
- try {
- mBatteryStats.notePhoneState(state.getState());
- } catch (RemoteException re) {
- // Can't do much
- } finally {
- Binder.restoreCallingIdentity(ident);
+ if (subId == SubscriptionManager.DEFAULT_SUB_ID) {
+ subId = mDefaultSubId;
+ Slog.d(TAG, "notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId);
+ }
+ if (VDBG) {
+ Slog.d(TAG, "notifyServiceStateUsingSubId: subId=" + subId
+ + " state=" + state);
}
synchronized (mRecords) {
- mServiceState = state;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
- try {
- r.callback.onServiceStateChanged(new ServiceState(state));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mServiceState[phoneId] = state;
+ for (Record r : mRecords) {
+ // FIXME: use DEFAULT_SUB_ID instead??
+ if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
+ (r.subId == subId)) {
+ try {
+ r.callback.onServiceStateChanged(new ServiceState(state));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
+ } else {
+ Slog.d(TAG, "notifyServiceStateUsingSubId: INVALID phoneId=" + phoneId);
}
handleRemoveListLocked();
}
- broadcastServiceStateChanged(state);
+ broadcastServiceStateChanged(state, subId);
}
public void notifySignalStrength(SignalStrength signalStrength) {
+ notifySignalStrengthUsingSubId(mDefaultSubId, signalStrength);
+ }
+
+ public void notifySignalStrengthUsingSubId(long subId, SignalStrength signalStrength) {
if (!checkNotifyPermission("notifySignalStrength()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifySignalStrengthUsingSubId: subId=" + subId
+ + " signalStrength=" + signalStrength);
+ }
synchronized (mRecords) {
- mSignalStrength = signalStrength;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
- try {
- r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mSignalStrength[phoneId] = signalStrength;
+ for (Record r : mRecords) {
+ if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
+ (r.subId == subId)){
+ try {
+ r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
- }
- if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
- try {
- int gsmSignalStrength = signalStrength.getGsmSignalStrength();
- r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
- : gsmSignalStrength));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
+ (r.subId == subId)) {
+ try {
+ int gsmSignalStrength = signalStrength.getGsmSignalStrength();
+ r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+ : gsmSignalStrength));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
handleRemoveListLocked();
}
- broadcastSignalStrengthChanged(signalStrength);
+ broadcastSignalStrengthChanged(signalStrength, subId);
}
public void notifyCellInfo(List<CellInfo> cellInfo) {
+ notifyCellInfoUsingSubId(mDefaultSubId, cellInfo);
+ }
+
+ public void notifyCellInfoUsingSubId(long subId, List<CellInfo> cellInfo) {
if (!checkNotifyPermission("notifyCellInfo()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyCellInfoUsingSubId: subId=" + subId
+ + " cellInfo=" + cellInfo);
+ }
synchronized (mRecords) {
- mCellInfo = cellInfo;
- for (Record r : mRecords) {
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
- try {
- if (DBG_LOC) {
- Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mCellInfo.set(phoneId, cellInfo);
+ for (Record r : mRecords) {
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)
+ && r.subId == subId) {
+ try {
+ if (DBG_LOC) {
+ Slog.d(TAG, "notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
+ }
+ r.callback.onCellInfoChanged(cellInfo);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
}
- r.callback.onCellInfoChanged(cellInfo);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
}
}
}
@@ -495,17 +677,29 @@
}
public void notifyMessageWaitingChanged(boolean mwi) {
+ notifyMessageWaitingChangedUsingSubId(mDefaultSubId, mwi);
+ }
+
+ public void notifyMessageWaitingChangedUsingSubId(long subId, boolean mwi) {
if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyMessageWaitingChangedUsingSubId: subId=" + subId
+ + " mwi=" + mwi);
+ }
synchronized (mRecords) {
- mMessageWaiting = mwi;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
- try {
- r.callback.onMessageWaitingIndicatorChanged(mwi);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mMessageWaiting[phoneId] = mwi;
+ for (Record r : mRecords) {
+ if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
+ (r.subId == subId)) {
+ try {
+ r.callback.onMessageWaitingIndicatorChanged(mwi);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
@@ -514,17 +708,29 @@
}
public void notifyCallForwardingChanged(boolean cfi) {
+ notifyCallForwardingChangedUsingSubId(mDefaultSubId, cfi);
+ }
+
+ public void notifyCallForwardingChangedUsingSubId(long subId, boolean cfi) {
if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyCallForwardingChangedUsingSubId: subId=" + subId
+ + " cfi=" + cfi);
+ }
synchronized (mRecords) {
- mCallForwarding = cfi;
- for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
- try {
- r.callback.onCallForwardingIndicatorChanged(cfi);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mCallForwarding[phoneId] = cfi;
+ for (Record r : mRecords) {
+ if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
+ (r.subId == subId)) {
+ try {
+ r.callback.onCallForwardingIndicatorChanged(cfi);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
}
@@ -533,11 +739,16 @@
}
public void notifyDataActivity(int state) {
+ notifyDataActivityUsingSubId(mDefaultSubId, state);
+ }
+
+ public void notifyDataActivityUsingSubId(long subId, int state) {
if (!checkNotifyPermission("notifyDataActivity()" )) {
return;
}
synchronized (mRecords) {
- mDataActivity = state;
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ mDataActivity[phoneId] = state;
for (Record r : mRecords) {
if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
try {
@@ -554,29 +765,40 @@
public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
+ notifyDataConnectionUsingSubId(mDefaultSubId, state, isDataConnectivityPossible,
+ reason, apn, apnType, linkProperties,
+ networkCapabilities, networkType, roaming);
+ }
+
+ public void notifyDataConnectionUsingSubId(long subId, int state,
+ boolean isDataConnectivityPossible, String reason, String apn, String apnType,
+ LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+ int networkType, boolean roaming) {
if (!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
- if (DBG) {
- Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
- + isDataConnectivityPossible + " reason='" + reason
+ if (VDBG) {
+ Slog.i(TAG, "notifyDataConnectionUsingSubId: subId=" + subId
+ + " state=" + state + " isDataConnectivityPossible=" + isDataConnectivityPossible
+ + " reason='" + reason
+ "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
+ " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
}
synchronized (mRecords) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
boolean modified = false;
if (state == TelephonyManager.DATA_CONNECTED) {
if (!mConnectedApns.contains(apnType)) {
mConnectedApns.add(apnType);
- if (mDataConnectionState != state) {
- mDataConnectionState = state;
+ if (mDataConnectionState[phoneId] != state) {
+ mDataConnectionState[phoneId] = state;
modified = true;
}
}
} else {
if (mConnectedApns.remove(apnType)) {
if (mConnectedApns.isEmpty()) {
- mDataConnectionState = state;
+ mDataConnectionState[phoneId] = state;
modified = true;
} else {
// leave mDataConnectionState as is and
@@ -584,25 +806,28 @@
}
}
}
- mDataConnectionPossible = isDataConnectivityPossible;
- mDataConnectionReason = reason;
- mDataConnectionLinkProperties = linkProperties;
- mDataConnectionNetworkCapabilities = networkCapabilities;
- if (mDataConnectionNetworkType != networkType) {
- mDataConnectionNetworkType = networkType;
+ mDataConnectionPossible[phoneId] = isDataConnectivityPossible;
+ mDataConnectionReason[phoneId] = reason;
+ mDataConnectionLinkProperties[phoneId] = linkProperties;
+ mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
+ if (mDataConnectionNetworkType[phoneId] != networkType) {
+ mDataConnectionNetworkType[phoneId] = networkType;
// need to tell registered listeners about the new network type
modified = true;
}
if (modified) {
if (DBG) {
- Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState
- + ", " + mDataConnectionNetworkType + ")");
+ Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
+ + ", " + mDataConnectionNetworkType[phoneId] + ")");
}
for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+ if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
+ (r.subId == subId)) {
try {
- r.callback.onDataConnectionStateChanged(mDataConnectionState,
- mDataConnectionNetworkType);
+ Slog.d(TAG,"Notify data connection state changed on sub: " +
+ subId);
+ r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+ mDataConnectionNetworkType[phoneId]);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -624,15 +849,24 @@
handleRemoveListLocked();
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
- apnType, linkProperties, networkCapabilities, roaming);
+ apnType, linkProperties, networkCapabilities, roaming, subId);
broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
linkProperties, "");
}
public void notifyDataConnectionFailed(String reason, String apnType) {
+ notifyDataConnectionFailedUsingSubId(mDefaultSubId, reason, apnType);
+ }
+
+ public void notifyDataConnectionFailedUsingSubId(long subId,
+ String reason, String apnType) {
if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyDataConnectionFailedUsingSubId: subId=" + subId
+ + " reason=" + reason + " apnType=" + apnType);
+ }
synchronized (mRecords) {
mPreciseDataConnectionState = new PreciseDataConnectionState(
TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -648,29 +882,42 @@
}
handleRemoveListLocked();
}
- broadcastDataConnectionFailed(reason, apnType);
+ broadcastDataConnectionFailed(reason, apnType, subId);
broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
}
public void notifyCellLocation(Bundle cellLocation) {
+ notifyCellLocationUsingSubId(mDefaultSubId, cellLocation);
+ }
+
+ public void notifyCellLocationUsingSubId(long subId, Bundle cellLocation) {
+ Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+ + " cellLocation=" + cellLocation);
if (!checkNotifyPermission("notifyCellLocation()")) {
return;
}
+ if (VDBG) {
+ Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId
+ + " cellLocation=" + cellLocation);
+ }
synchronized (mRecords) {
- mCellLocation = cellLocation;
- for (Record r : mRecords) {
- if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
- try {
- if (DBG_LOC) {
- Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation
- + " r=" + r);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (validatePhoneId(phoneId)) {
+ mCellLocation[phoneId] = cellLocation;
+ for (Record r : mRecords) {
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)
+ && r.subId == subId) {
+ try {
+ if (DBG_LOC) {
+ Slog.d(TAG, "notifyCellLocation: cellLocation=" + cellLocation
+ + " r=" + r);
+ }
+ r.callback.onCellLocationChanged(new Bundle(cellLocation));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
}
- r.callback.onCellLocationChanged(new Bundle(cellLocation));
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
}
-
}
}
handleRemoveListLocked();
@@ -771,6 +1018,26 @@
TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
}
+ public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
+ if (!checkNotifyPermission("notifyVoLteServiceStateChanged()")) {
+ return;
+ }
+ synchronized (mRecords) {
+ mVoLteServiceState = lteState;
+ for (Record r : mRecords) {
+ if ((r.events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) {
+ try {
+ r.callback.onVoLteServiceStateChanged(
+ new VoLteServiceState(mVoLteServiceState));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -810,15 +1077,26 @@
// the legacy intent broadcasting
//
- private void broadcastServiceStateChanged(ServiceState state) {
+ private void broadcastServiceStateChanged(ServiceState state, long subId) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.notePhoneState(state.getState());
+ } catch (RemoteException re) {
+ // Can't do much
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
Bundle data = new Bundle();
state.fillInNotifierBundle(data);
intent.putExtras(data);
+ // Pass the subscription along with the intent.
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
+ private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) {
long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.notePhoneSignalStrength(signalStrength);
@@ -833,10 +1111,11 @@
Bundle data = new Bundle();
signalStrength.fillInNotifierBundle(data);
intent.putExtras(data);
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastCallStateChanged(int state, String incomingNumber) {
+ private void broadcastCallStateChanged(int state, String incomingNumber, long subId) {
long ident = Binder.clearCallingIdentity();
try {
if (state == TelephonyManager.CALL_STATE_IDLE) {
@@ -856,6 +1135,7 @@
if (!TextUtils.isEmpty(incomingNumber)) {
intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
}
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.READ_PHONE_STATE);
}
@@ -863,7 +1143,7 @@
private void broadcastDataConnectionStateChanged(int state,
boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
- NetworkCapabilities networkCapabilities, boolean roaming) {
+ NetworkCapabilities networkCapabilities, boolean roaming, long subId) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -890,13 +1170,16 @@
intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastDataConnectionFailed(String reason, String apnType) {
+ private void broadcastDataConnectionFailed(String reason, String apnType,
+ long subId) {
Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -989,4 +1272,10 @@
}
return valid;
}
+
+ private boolean validatePhoneId(int phoneId) {
+ boolean valid = (phoneId >= 0) && (phoneId < mNumPhones);
+ if (VDBG) Slog.d(TAG, "validatePhoneId: " + valid);
+ return valid;
+ }
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index b2aaf74..e152ebe 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -537,13 +537,16 @@
}
@Override
- public AuthenticatorDescription[] getAuthenticatorTypes() {
+ public AuthenticatorDescription[] getAuthenticatorTypes(int userId) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getAuthenticatorTypes: "
+ + "for user id " + userId
+ "caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
- final int userId = UserHandle.getCallingUserId();
+ // Only allow the system process to read accounts of other users
+ enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ + " trying get authenticator types for " + userId);
final long identityToken = clearCallingIdentity();
try {
Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
@@ -562,6 +565,16 @@
}
}
+ private void enforceCrossUserPermission(int userId, String errorMessage) {
+ if (userId != UserHandle.getCallingUserId()
+ && Binder.getCallingUid() != Process.myUid()
+ && mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(errorMessage);
+ }
+ }
+
@Override
public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1567,14 +1580,8 @@
final Account account, final Bundle options, final boolean expectActivityLaunch,
int userId) {
// Only allow the system process to read accounts of other users
- if (userId != UserHandle.getCallingUserId()
- && Binder.getCallingUid() != Process.myUid()
- && mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("User " + UserHandle.getCallingUserId()
+ enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ " trying to confirm account credentials for " + userId);
- }
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "confirmCredentials: " + account
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 03ce530..d7cf7b1 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -32,11 +32,11 @@
import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_APP;
-import static com.android.server.am.ActivityStackSupervisor.DEBUG_CONTAINERS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_SCREENSHOTS;
import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
@@ -1406,7 +1406,7 @@
ActivityRecord parent = mActivityContainer.mParentActivity;
if ((parent != null && parent.state != ActivityState.RESUMED) ||
- !mActivityContainer.isAttachedLocked()) {
+ !mActivityContainer.isAttached()) {
// Do not resume this stack if its parent is not resumed.
// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false;
@@ -2678,14 +2678,11 @@
|| prevState == ActivityState.INITIALIZING) {
// If this activity is already stopped, we can just finish
// it right now.
- r.makeFinishing();
- boolean activityRemoved = destroyActivityLocked(r, true, oomAdj, "finish-imm");
+ boolean activityRemoved = destroyActivityLocked(r, true,
+ oomAdj, "finish-imm");
if (activityRemoved) {
mStackSupervisor.resumeTopActivitiesLocked();
}
- if (DEBUG_CONTAINERS) Slog.d(TAG,
- "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
- " destroy returned removed=" + activityRemoved);
return activityRemoved ? null : r;
}
@@ -3048,7 +3045,6 @@
if (r != null) {
mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
}
- if (DEBUG_CONTAINERS) Slog.d(TAG, "activityDestroyedLocked: r=" + r);
if (isInStackLocked(token) != null) {
if (r.state == ActivityState.DESTROYING) {
@@ -3808,7 +3804,7 @@
mStacks.remove(this);
mStacks.add(0, this);
}
- mActivityContainer.onTaskListEmptyLocked();
+ mActivityContainer.onTaskListEmpty();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 545a9f7..c4cdbd7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -241,7 +241,7 @@
// TODO: Add listener for removal of references.
/** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
- private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
+ SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
/** Mapping from displayId to display current state */
private final SparseArray<ActivityDisplay> mActivityDisplays =
@@ -2257,10 +2257,8 @@
ActivityContainer createActivityContainer(ActivityRecord parentActivity,
IActivityContainerCallback callback) {
- ActivityContainer activityContainer =
- new VirtualActivityContainer(parentActivity, callback);
+ ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback);
mActivityContainers.put(activityContainer.mStackId, activityContainer);
- if (DEBUG_CONTAINERS) Slog.d(TAG, "createActivityContainer: " + activityContainer);
parentActivity.mChildContainers.add(activityContainer);
return activityContainer;
}
@@ -2269,8 +2267,6 @@
final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers;
for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) {
ActivityContainer container = childStacks.remove(containerNdx);
- if (DEBUG_CONTAINERS) Slog.d(TAG, "removeChildActivityContainers: removing " +
- container);
container.release();
}
}
@@ -2278,8 +2274,11 @@
void deleteActivityContainer(IActivityContainer container) {
ActivityContainer activityContainer = (ActivityContainer)container;
if (activityContainer != null) {
- if (DEBUG_CONTAINERS) Slog.d(TAG, "deleteActivityContainer: ",
- new RuntimeException("here").fillInStackTrace());
+ activityContainer.mStack.finishAllActivitiesLocked();
+ final ActivityRecord parent = activityContainer.mParentActivity;
+ if (parent != null) {
+ parent.mChildContainers.remove(activityContainer);
+ }
final int stackId = activityContainer.mStackId;
mActivityContainers.remove(stackId);
mWindowManager.removeStack(stackId);
@@ -3131,13 +3130,6 @@
}
}
} break;
- case CONTAINER_TASK_LIST_EMPTY_TIMEOUT: {
- synchronized (mService) {
- Slog.w(TAG, "Timeout waiting for all activities in task to finish. " +
- msg.obj);
- ((ActivityContainer) msg.obj).onTaskListEmptyLocked();
- }
- } break;
}
}
}
@@ -3194,10 +3186,8 @@
@Override
public int getDisplayId() {
- synchronized (mService) {
- if (mActivityDisplay != null) {
- return mActivityDisplay.mDisplayId;
- }
+ if (mActivityDisplay != null) {
+ return mActivityDisplay.mDisplayId;
}
return -1;
}
@@ -3206,12 +3196,10 @@
public boolean injectEvent(InputEvent event) {
final long origId = Binder.clearCallingIdentity();
try {
- synchronized (mService) {
- if (mActivityDisplay != null) {
- return mInputManagerInternal.injectInputEvent(event,
- mActivityDisplay.mDisplayId,
- InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
- }
+ if (mActivityDisplay != null) {
+ return mInputManagerInternal.injectInputEvent(event,
+ mActivityDisplay.mDisplayId,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
return false;
} finally {
@@ -3221,16 +3209,10 @@
@Override
public void release() {
- synchronized (mService) {
- if (mContainerState == CONTAINER_STATE_FINISHING) {
- return;
- }
- mContainerState = CONTAINER_STATE_FINISHING;
- final Message msg =
- mHandler.obtainMessage(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
- mHandler.sendMessageDelayed(msg, 1000);
- mStack.finishAllActivitiesLocked();
- }
+ mContainerState = CONTAINER_STATE_FINISHING;
+ mStack.finishAllActivitiesLocked();
+ detachLocked();
+ mWindowManager.removeStack(mStackId);
}
private void detachLocked() {
@@ -3321,17 +3303,15 @@
return ActivityStackSupervisor.this;
}
- boolean isAttachedLocked() {
+ boolean isAttached() {
return mActivityDisplay != null;
}
void getBounds(Point outBounds) {
- synchronized (mService) {
- if (mActivityDisplay != null) {
- mActivityDisplay.getBounds(outBounds);
- } else {
- outBounds.set(0, 0);
- }
+ if (mActivityDisplay != null) {
+ mActivityDisplay.getBounds(outBounds);
+ } else {
+ outBounds.set(0, 0);
}
}
@@ -3354,12 +3334,7 @@
return true;
}
- void onTaskListEmptyLocked() {
- mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
- if (!mStack.isHomeStack()) {
- detachLocked();
- deleteActivityContainer(this);
- }
+ void onTaskListEmpty() {
mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
}
@@ -3378,7 +3353,7 @@
mParentActivity = parent;
mCallback = callback;
mContainerState = CONTAINER_STATE_NO_SURFACE;
- mIdString = "VirtualActivityContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+ mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
}
@Override
@@ -3424,22 +3399,22 @@
}
}
- setSurfaceIfReadyLocked();
+ setSurfaceIfReady();
if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
+ virtualActivityDisplay);
}
@Override
- boolean isAttachedLocked() {
- return mSurface != null && super.isAttachedLocked();
+ boolean isAttached() {
+ return mSurface != null && super.isAttached();
}
@Override
void setDrawn() {
synchronized (mService) {
mDrawn = true;
- setSurfaceIfReadyLocked();
+ setSurfaceIfReady();
}
}
@@ -3449,8 +3424,8 @@
return false;
}
- private void setSurfaceIfReadyLocked() {
- if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
+ private void setSurfaceIfReady() {
+ if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
" mContainerState=" + mContainerState + " mSurface=" + mSurface);
if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 7f43e43..e80aecd 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -111,12 +111,15 @@
}
}
- static boolean shouldBlank(int state) {
- return state == Display.STATE_OFF;
- }
-
- static boolean shouldUnblank(int state) {
- return state == Display.STATE_ON || state == Display.STATE_DOZING;
+ static int getPowerModeForState(int state) {
+ switch (state) {
+ case Display.STATE_OFF:
+ return SurfaceControl.POWER_MODE_OFF;
+ case Display.STATE_DOZING:
+ return SurfaceControl.POWER_MODE_DOZE;
+ default:
+ return SurfaceControl.POWER_MODE_NORMAL;
+ }
}
private final class LocalDisplayDevice extends DisplayDevice {
@@ -204,11 +207,8 @@
@Override
public void requestDisplayStateLocked(int state) {
if (mState != state) {
- if (shouldBlank(state) && !shouldBlank(mState)) {
- SurfaceControl.blankDisplay(getDisplayTokenLocked());
- } else if (shouldUnblank(state) && !shouldUnblank(mState)) {
- SurfaceControl.unblankDisplay(getDisplayTokenLocked());
- }
+ SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(),
+ getPowerModeForState(state));
mState = state;
updateDeviceInfoLocked();
}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
new file mode 100644
index 0000000..32bcb69
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.annotation.Nullable;
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Handles CEC command <Active Source>.
+ *
+ * <p>Used by feature actions that need to handle the command in their flow.
+ */
+final class ActiveSourceHandler {
+ private static final String TAG = "ActiveSourceHandler";
+
+ private final HdmiControlService mService;
+ private final int mSourceAddress;
+ private final int mSourcePath;
+ @Nullable private final IHdmiControlCallback mCallback;
+
+ static ActiveSourceHandler create(HdmiControlService service, int sourceAddress,
+ int sourcePath, IHdmiControlCallback callback) {
+ if (service == null) {
+ Slog.e(TAG, "Wrong arguments");
+ return null;
+ }
+ return new ActiveSourceHandler(service, sourceAddress, sourcePath, callback);
+ }
+
+ private ActiveSourceHandler(HdmiControlService service, int sourceAddress, int sourcePath,
+ IHdmiControlCallback callback) {
+ mService = service;
+ mSourceAddress = sourceAddress;
+ mSourcePath = sourcePath;
+ mCallback = callback;
+ }
+
+ /**
+ * Handles the incoming active source command.
+ *
+ * @param deviceLogicalAddress logical address of the device to be the active source
+ * @param routingPath routing path of the device to be the active source
+ */
+ void process(int deviceLogicalAddress, int routingPath) {
+ if (mSourcePath == routingPath && mService.getActiveSource() == mSourceAddress) {
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ return;
+ }
+ HdmiCecDeviceInfo device = mService.getDeviceInfo(deviceLogicalAddress);
+ if (device == null) {
+ // TODO: Start new device action (Device Discovery) sequence 5.
+ }
+
+ if (!mService.isInPresetInstallationMode()) {
+ int prevActiveInput = mService.getActiveInput();
+ mService.updateActiveDevice(deviceLogicalAddress, routingPath);
+ if (prevActiveInput != mService.getActiveInput()) {
+ // TODO: change port input here.
+ }
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ } else {
+ // TV is in a mode that should keep its current source/input from
+ // being changed for its operation. Reclaim the active source
+ // or switch the port back to the one used for the current mode.
+ if (mService.getActiveSource() == mSourceAddress) {
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(mSourceAddress, mSourcePath);
+ mService.sendCecCommand(activeSource);
+ mService.updateActiveDevice(deviceLogicalAddress, routingPath);
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ } else {
+ int activePath = mService.getActivePath();
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(mSourceAddress,
+ routingPath, activePath));
+ // TODO: Start port select action here
+ // PortSelectAction action = new PortSelectAction(mService, mSourceAddress,
+ // activePath, mCallback);
+ // mService.addActionAndStart(action);
+ }
+ }
+ }
+
+ private void invokeCallback(int result) {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.onComplete(result);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Callback failed:" + e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
new file mode 100644
index 0000000..f170de0
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.os.RemoteException;
+import android.util.Slog;
+
+/**
+ * Handles an action that selects a logical device as a new active source.
+ *
+ * Triggered by {@link HdmiTvClient}, attempts to select the given target device
+ * for a new active source. It does its best to wake up the target in standby mode
+ * before issuing the command >Set Stream path<.
+ */
+final class DeviceSelectAction extends FeatureAction {
+ private static final String TAG = "DeviceSelect";
+
+ // Time in milliseconds we wait for the device power status to switch to 'Standby'
+ private static final int TIMEOUT_TRANSIT_TO_STANDBY_MS = 5 * 1000;
+
+ // Time in milliseconds we wait for the device power status to turn to 'On'.
+ private static final int TIMEOUT_POWER_ON_MS = 5 * 1000;
+
+ // Time in milliseconds we wait for <Active Source>.
+ private static final int TIMEOUT_ACTIVE_SOURCE_MS = 20 * 1000;
+
+ // The number of times we try to wake up the target device before we give up
+ // and just send <Set Stream Path>.
+ private static final int LOOP_COUNTER_MAX = 20;
+
+ // State in which we wait for <Report Power Status> to come in response to the command
+ // <Give Device Power Status> we have sent.
+ private static final int STATE_WAIT_FOR_REPORT_POWER_STATUS = 1;
+
+ // State in which we wait for the device power status to switch to 'Standby'.
+ // We wait till the status becomes 'Standby' before we send <Set Stream Path>
+ // to wake up the device again.
+ private static final int STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY = 2;
+
+ // State in which we wait for the device power status to switch to 'on'. We wait
+ // maximum 100 seconds (20 * 5) before we give up and just send <Set Stream Path>.
+ private static final int STATE_WAIT_FOR_DEVICE_POWER_ON = 3;
+
+ // State in which we wait for the <Active Source> in response to the command
+ // <Set Stream Path> we have sent. We wait as much as TIMEOUT_ACTIVE_SOURCE_MS
+ // before we give up and mark the action as failure.
+ private static final int STATE_WAIT_FOR_ACTIVE_SOURCE = 4;
+
+ private final HdmiCecDeviceInfo mTarget;
+ private final IHdmiControlCallback mCallback;
+ private final int mSourcePath;
+
+ private int mPowerStatusCounter = 0;
+
+ /**
+ * Constructor.
+ *
+ * @param service {@link HdmiControlService} instance
+ * @param sourceAddress logical address of TV initiating this action
+ * @param sourcePath physical address of TV
+ * @param target target logical device that will be a new active source
+ * @param callback callback object
+ */
+ public DeviceSelectAction(HdmiControlService service, int sourceAddress, int sourcePath,
+ HdmiCecDeviceInfo target, IHdmiControlCallback callback) {
+ super(service, sourceAddress);
+ mCallback = callback;
+ mSourcePath = sourcePath;
+ mTarget = target;
+ }
+
+ @Override
+ public boolean start() {
+ // TODO: Call the logic that display a banner saying the select action got started.
+ queryDevicePowerStatus();
+ return true;
+ }
+
+ private void queryDevicePowerStatus() {
+ sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
+ mSourceAddress, mTarget.getLogicalAddress()));
+ mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
+ addTimer(mState, TIMEOUT_MS);
+ }
+
+ @Override
+ public boolean processCommand(HdmiCecMessage cmd) {
+ if (cmd.getSource() != mTarget.getLogicalAddress()) {
+ return false;
+ }
+ int opcode = cmd.getOpcode();
+ byte[] params = cmd.getParams();
+
+ switch (mState) {
+ case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+ if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS && params.length == 1) {
+ return handleReportPowerStatus(params[0]);
+ }
+ return false;
+ case STATE_WAIT_FOR_ACTIVE_SOURCE:
+ if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE && params.length == 2) {
+ int activePath = HdmiUtils.twoBytesToInt(params);
+ ActiveSourceHandler.create(mService, mSourceAddress, mSourcePath, mCallback)
+ .process(cmd.getSource(), activePath);
+ finish();
+ return true;
+ }
+ return false;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ private boolean handleReportPowerStatus(int powerStatus) {
+ // TODO: Check TV's own status which might have been updated during the action.
+ // If in 'Standby' or 'Transit to standby', remove the banner
+ // and stop this action. Otherwise, send <Set Stream Path>
+ switch (powerStatus) {
+ case HdmiCec.POWER_STATUS_ON:
+ sendSetStreamPath();
+ return true;
+ case HdmiCec.POWER_STATUS_TRANSIENT_TO_STANDBY:
+ if (mPowerStatusCounter < 4) {
+ mState = STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY;
+ addTimer(mState, TIMEOUT_TRANSIT_TO_STANDBY_MS);
+ } else {
+ sendSetStreamPath();
+ }
+ return true;
+ case HdmiCec.POWER_STATUS_STANDBY:
+ if (mPowerStatusCounter == 0) {
+ turnOnDevice();
+ } else {
+ sendSetStreamPath();
+ }
+ return true;
+ case HdmiCec.POWER_STATUS_TRANSIENT_TO_ON:
+ if (mPowerStatusCounter < LOOP_COUNTER_MAX) {
+ mState = STATE_WAIT_FOR_DEVICE_POWER_ON;
+ addTimer(mState, TIMEOUT_POWER_ON_MS);
+ } else {
+ sendSetStreamPath();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void turnOnDevice() {
+ sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER);
+ sendRemoteKeyCommand(HdmiConstants.UI_COMMAND_POWER_ON_FUNCTION);
+ mState = STATE_WAIT_FOR_DEVICE_POWER_ON;
+ addTimer(mState, TIMEOUT_POWER_ON_MS);
+ }
+
+ private void sendSetStreamPath() {
+ sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(
+ mSourceAddress, mTarget.getPhysicalAddress()));
+ mState = STATE_WAIT_FOR_ACTIVE_SOURCE;
+ addTimer(mState, TIMEOUT_ACTIVE_SOURCE_MS);
+ }
+
+ private void sendRemoteKeyCommand(int keyCode) {
+ sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(mSourceAddress,
+ mTarget.getLogicalAddress(), keyCode));
+ sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(mSourceAddress,
+ mTarget.getLogicalAddress()));
+ }
+
+ @Override
+ public void handleTimerEvent(int timeoutState) {
+ if (mState != timeoutState) {
+ Slog.w(TAG, "Timer in a wrong state. Ignored.");
+ return;
+ }
+ switch (mState) {
+ case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+ sendSetStreamPath();
+ break;
+ case STATE_WAIT_FOR_DEVICE_TO_TRANSIT_TO_STANDBY:
+ case STATE_WAIT_FOR_DEVICE_POWER_ON:
+ mPowerStatusCounter++;
+ queryDevicePowerStatus();
+ break;
+ case STATE_WAIT_FOR_ACTIVE_SOURCE:
+ // TODO: Remove the banner
+ // Display banner "Communication failed. Please check your cable or connection"
+ invokeCallback(HdmiCec.RESULT_TIMEOUT);
+ finish();
+ break;
+ }
+ }
+
+ private void invokeCallback(int result) {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.onComplete(result);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Callback failed:" + e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java
index 0ba7773..ae272b4 100644
--- a/services/core/java/com/android/server/hdmi/FeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/FeatureAction.java
@@ -46,8 +46,9 @@
// Timer handler message used for timeout event
protected static final int MSG_TIMEOUT = 100;
- // Default timeout for the incoming command to arrive in response to a request
- protected static final int TIMEOUT_MS = 1000;
+ // Default timeout for the incoming command to arrive in response to a request.
+ // TODO: Consider reading this value from configuration to allow customization.
+ protected static final int TIMEOUT_MS = 2000;
// Default state used in common by all the feature actions.
protected static final int STATE_NONE = 0;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index f869424..a0c635d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -19,6 +19,7 @@
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiPortInfo;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
@@ -308,6 +309,10 @@
return mDeviceInfos.get(logicalAddress);
}
+ HdmiPortInfo[] getPortInfos() {
+ return nativeGetPortInfos(mNativePtr);
+ }
+
/**
* Return the locally hosted logical device of a given type.
*
@@ -641,8 +646,8 @@
private static native int nativeGetPhysicalAddress(long controllerPtr);
private static native int nativeGetVersion(long controllerPtr);
private static native int nativeGetVendorId(long controllerPtr);
+ private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
private static native void nativeSetOption(long controllerPtr, int flag, int value);
private static native void nativeSetAudioReturnChannel(long controllerPtr, boolean flag);
private static native boolean nativeIsConnected(long controllerPtr, int port);
-
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 8bd81ea..6394fe7 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -16,8 +16,11 @@
package com.android.server.hdmi;
+import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
+import android.os.RemoteException;
import android.util.Slog;
import java.util.Locale;
@@ -55,6 +58,31 @@
}
}
+ /**
+ * Performs the action 'device select', or 'one touch play' initiated by TV.
+ *
+ * @param targetAddress logical address of the device to select
+ * @param callback callback object to report the result with
+ */
+ void deviceSelect(int targetAddress, IHdmiControlCallback callback) {
+ HdmiCecDeviceInfo targetDevice = mService.getDeviceInfo(targetAddress);
+ if (targetDevice == null) {
+ invokeCallback(callback, HdmiCec.RESULT_TARGET_NOT_AVAILABLE);
+ return;
+ }
+ mService.removeAction(DeviceSelectAction.class);
+ mService.addAndStartAction(new DeviceSelectAction(mService, mAddress,
+ mService.getPhysicalAddress(), targetDevice, callback));
+ }
+
+ private static void invokeCallback(IHdmiControlCallback callback, int result) {
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Invoking callback failed:" + e);
+ }
+ }
+
@Override
protected boolean handleGetMenuLanguage(HdmiCecMessage message) {
HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand(
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 1fcb32f..8dbfd85 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -270,6 +270,38 @@
}
/**
+ * Build <Set Stream Path> command.
+ *
+ * <p>This is a broadcast message sent to all devices on the bus.
+ *
+ * @param src source address of command
+ * @param streamPath physical address of the device to start streaming
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildSetStreamPath(int src, int streamPath) {
+ return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_SET_STREAM_PATH,
+ physicalAddressToParam(streamPath));
+ }
+
+ /**
+ * Build <Routing Change> command.
+ *
+ * <p>This is a broadcast message sent to all devices on the bus.
+ *
+ * @param src source address of command
+ * @param oldPath physical address of the currently active routing path
+ * @param newPath physical address of the new active routing path
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildRoutingChange(int src, int oldPath, int newPath) {
+ byte[] param = new byte[] {
+ (byte) ((oldPath >> 8) & 0xFF), (byte) (oldPath & 0xFF),
+ (byte) ((newPath >> 8) & 0xFF), (byte) (newPath & 0xFF)
+ };
+ return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ROUTING_CHANGE, param);
+ }
+
+ /**
* Build <Give Device Power Status> command.
*
* @param src source address of command
diff --git a/services/core/java/com/android/server/hdmi/HdmiConstants.java b/services/core/java/com/android/server/hdmi/HdmiConstants.java
index 54b5dcb..8f319ea 100644
--- a/services/core/java/com/android/server/hdmi/HdmiConstants.java
+++ b/services/core/java/com/android/server/hdmi/HdmiConstants.java
@@ -39,9 +39,15 @@
// Constants related to UI Command Codes.
// Refer to CEC Table 30 in HDMI Spec v1.4b.
+ static final int UI_COMMAND_POWER = 0x40;
static final int UI_COMMAND_MUTE = 0x43;
static final int UI_COMMAND_MUTE_FUNCTION = 0x65;
static final int UI_COMMAND_RESTORE_VOLUME_FUNCTION = 0x66;
+ static final int UI_COMMAND_POWER_ON_FUNCTION = 0x6D;
+
+ // Bit mask used to get the routing path of the top level device.
+ // When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0.
+ static final int ROUTING_PATH_TOP_MASK = 0xF000;
// Flags used for setOption to CEC HAL.
/**
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index d41da30..0d7ac8d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -21,6 +21,7 @@
import android.hardware.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.hdmi.IHdmiHotplugEventListener;
@@ -40,6 +41,7 @@
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -105,9 +107,8 @@
// Used to synchronize the access to the service.
private final Object mLock = new Object();
- // Type of logical devices hosted in the system.
- @GuardedBy("mLock")
- private final int[] mLocalDevices;
+ // Type of logical devices hosted in the system. Stored in the unmodifiable list.
+ private final List<Integer> mLocalDevices;
// List of listeners registered by callers that want to get notified of
// hotplug events.
@@ -117,6 +118,9 @@
private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
new ArrayList<>();
+ // Handler running on service thread. It's used to run a task in service thread.
+ private final Handler mHandler = new Handler();
+
private final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache();
@Nullable
@@ -125,6 +129,25 @@
@Nullable
private HdmiMhlController mMhlController;
+ // HDMI port information. Stored in the unmodifiable list to keep the static information
+ // from being modified.
+ private List<HdmiPortInfo> mPortInfo;
+
+ // Logical address of the active source.
+ @GuardedBy("mLock")
+ private int mActiveSource;
+
+ // Active routing path. Physical address of the active source but not all the time, such as
+ // when the new active source does not claim itself to be one.
+ @GuardedBy("mLock")
+ private int mActiveRoutingPath;
+
+ // Set to true while the service is in normal mode. While set to false, no input change is
+ // allowed. Used for situations where input change can confuse users such as channel auto-scan,
+ // system upgrade, etc., a.k.a. "prohibit mode".
+ @GuardedBy("mLock")
+ private boolean mInputChangeEnabled;
+
@GuardedBy("mLock")
// Whether ARC is "enabled" or not.
// TODO: it may need to hold lock if it's accessed from others.
@@ -134,13 +157,12 @@
// Whether SystemAudioMode is "On" or not.
private boolean mSystemAudioMode;
- // Handler running on service thread. It's used to run a task in service thread.
- private final Handler mHandler = new Handler();
-
public HdmiControlService(Context context) {
super(context);
- mLocalDevices = getContext().getResources().getIntArray(
- com.android.internal.R.array.config_hdmiCecLogicalDeviceType);
+ mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray(
+ com.android.internal.R.array.config_hdmiCecLogicalDeviceType));
+ // TODO: Get control flag from persistent storage
+ mInputChangeEnabled = true;
}
@Override
@@ -158,14 +180,14 @@
if (mMhlController == null) {
Slog.i(TAG, "Device does not support MHL-control.");
}
-
+ mPortInfo = initPortInfo();
publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
// TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and
// start to monitor the preference value and invoke SystemAudioActionFromTv if needed.
}
- private void initializeLocalDevices(final int[] deviceTypes) {
+ private void initializeLocalDevices(final List<Integer> deviceTypes) {
// A container for [Logical Address, Local device info].
final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>();
final SparseIntArray finished = new SparseIntArray();
@@ -189,7 +211,7 @@
// Once finish address allocation for all devices, notify
// it to each device.
- if (deviceTypes.length == finished.size()) {
+ if (deviceTypes.size() == finished.size()) {
notifyAddressAllocated(devices);
}
}
@@ -205,6 +227,66 @@
}
}
+ // Initialize HDMI port information. Combine the information from CEC and MHL HAL and
+ // keep them in one place.
+ private List<HdmiPortInfo> initPortInfo() {
+ HdmiPortInfo[] cecPortInfo = null;
+
+ // CEC HAL provides majority of the info while MHL does only MHL support flag for
+ // each port. Return empty array if CEC HAL didn't provide the info.
+ if (mCecController != null) {
+ cecPortInfo = mCecController.getPortInfos();
+ }
+ if (cecPortInfo == null) {
+ return Collections.emptyList();
+ }
+
+ HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0];
+ if (mMhlController != null) {
+ // TODO: Implement plumbing logic to get MHL port information.
+ // mhlPortInfo = mMhlController.getPortInfos();
+ }
+
+ // Use the id (port number) to find the matched info between CEC and MHL to combine them
+ // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found.
+ ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length);
+ for (int i = 0; i < cecPortInfo.length; ++i) {
+ HdmiPortInfo cec = cecPortInfo[i];
+ int id = cec.getId();
+ boolean mhlInfoFound = false;
+ for (HdmiPortInfo mhl : mhlPortInfo) {
+ if (id == mhl.getId()) {
+ result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(),
+ cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported()));
+ mhlInfoFound = true;
+ break;
+ }
+ }
+ if (!mhlInfoFound) {
+ result.add(cec);
+ }
+ }
+
+ return Collections.unmodifiableList(result);
+ }
+
+ /**
+ * Returns HDMI port information for the given port id.
+ *
+ * @param portId HDMI port id
+ * @return {@link HdmiPortInfo} for the given port
+ */
+ HdmiPortInfo getPortInfo(int portId) {
+ // mPortInfo is an unmodifiable list and the only reference to its inner list.
+ // No lock is necessary.
+ for (HdmiPortInfo info : mPortInfo) {
+ if (portId == info.getId()) {
+ return info;
+ }
+ }
+ return null;
+ }
+
/**
* Returns {@link Looper} for IO operation.
*
@@ -224,6 +306,41 @@
return mHandler.getLooper();
}
+ int getActiveSource() {
+ synchronized (mLock) {
+ return mActiveSource;
+ }
+ }
+
+ int getActivePath() {
+ synchronized (mLock) {
+ return mActiveRoutingPath;
+ }
+ }
+
+ /**
+ * Returns the path (physical address) of the device at the top of the currently active
+ * routing path. Used to get the corresponding port address of the HDMI input of the TV.
+ */
+ int getActiveInput() {
+ synchronized (mLock) {
+ return mActiveRoutingPath & HdmiConstants.ROUTING_PATH_TOP_MASK;
+ }
+ }
+
+ void updateActiveDevice(int logicalAddress, int physicalAddress) {
+ synchronized (mLock) {
+ mActiveSource = logicalAddress;
+ mActiveRoutingPath = physicalAddress;
+ }
+ }
+
+ void setInputChangeEnabled(boolean enabled) {
+ synchronized (mLock) {
+ mInputChangeEnabled = enabled;
+ }
+ }
+
/**
* Returns physical address of the device.
*/
@@ -238,6 +355,11 @@
return mCecController.getVendorId();
}
+ HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) {
+ assertRunOnServiceThread();
+ return mCecController.getDeviceInfo(logicalAddress);
+ }
+
/**
* Returns version of CEC.
*/
@@ -256,6 +378,24 @@
}
/**
+ * Returns the {@link HdmiCecDeviceInfo} instance whose physical address matches
+ * the given routing path. CEC devices use routing path for its physical address to
+ * describe the hierarchy of the devices in the network.
+ *
+ * @param path routing path or physical address
+ * @return {@link HdmiCecDeviceInfo} if the matched info is found; otherwise null
+ */
+ HdmiCecDeviceInfo getDeviceInfoByPath(int path) {
+ assertRunOnServiceThread();
+ for (HdmiCecDeviceInfo info : mCecController.getDeviceInfoList(false)) {
+ if (info.getPhysicalAddress() == path) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
* Add and start a new {@link FeatureAction} to the action queue.
*
* @param action {@link FeatureAction} to add and start
@@ -304,7 +444,7 @@
}
// Remove all actions matched with the given Class type.
- private <T extends FeatureAction> void removeAction(final Class<T> clazz) {
+ <T extends FeatureAction> void removeAction(final Class<T> clazz) {
removeActionExcept(clazz, null);
}
@@ -569,12 +709,34 @@
@Override
public int[] getSupportedTypes() {
enforceAccessPermission();
- synchronized (mLock) {
- return mLocalDevices;
+ // mLocalDevices is an unmodifiable list - no lock necesary.
+ int[] localDevices = new int[mLocalDevices.size()];
+ for (int i = 0; i < localDevices.length; ++i) {
+ localDevices[i] = mLocalDevices.get(i);
}
+ return localDevices;
}
@Override
+ public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ HdmiCecLocalDeviceTv tv =
+ (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV);
+ if (tv == null) {
+ Slog.w(TAG, "Local playback device not available");
+ invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
+ return;
+ }
+ tv.deviceSelect(logicalAddress, callback);
+ }
+ });
+ }
+
+
+ @Override
public void oneTouchPlay(final IHdmiControlCallback callback) {
enforceAccessPermission();
runOnServiceThread(new Runnable() {
@@ -710,8 +872,9 @@
}
boolean isInPresetInstallationMode() {
- // TODO: Implement this.
- return false;
+ synchronized (mLock) {
+ return !mInputChangeEnabled;
+ }
}
/**
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index ca09fe6..b534377 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -20,6 +20,10 @@
import android.hardware.hdmi.HdmiCecMessage;
import android.util.Slog;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
* Various utilities to handle HDMI CEC messages.
*/
@@ -73,6 +77,22 @@
}
/**
+ * Convert integer array to list of {@link Integer}.
+ *
+ * <p>The result is immutable.
+ *
+ * @param is integer array
+ * @return {@link List} instance containing the elements in the given array
+ */
+ static List<Integer> asImmutableList(final int[] is) {
+ ArrayList<Integer> list = new ArrayList<>(is.length);
+ for (int type : is) {
+ list.add(type);
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /**
* Assemble two bytes into single integer value.
*
* @param data to be assembled
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
new file mode 100644
index 0000000..26048d2
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 java.util.concurrent.TimeUnit;
+
+import android.hardware.hdmi.IHdmiControlCallback;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecDeviceInfo;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+/**
+ * Feature action for routing control. Exchanges routing-related commands with other devices
+ * to determine the new active source.
+ *
+ * <p>This action is initiated by various cases:
+ * <ul>
+ * <li> Manual TV input switching
+ * <li> Routing change of a CEC switch other than TV
+ * <li> New CEC device at the tail of the active routing path
+ * <li> Removed CEC device from the active routing path
+ * <li> Routing at CEC enable time
+ * </ul>
+ */
+public class RoutingControlAction extends FeatureAction {
+ private static final String TAG = "RoutingControlAction";
+
+ // State in which we wait for <Routing Information> to arrive. If timed out, we use the
+ // latest routing path to set the new active source.
+ private final static int STATE_WAIT_FOR_ROUTING_INFORMATION = 1;
+
+ // State in which we wait for <Report Power Status> in response to <Give Device Power Status>
+ // we have sent. If the response tells us the device power is on, we send <Set Stream Path>
+ // to make it the active source. Otherwise we do not send <Set Stream Path>, and possibly
+ // just show the blank screen.
+ private final static int STATE_WAIT_FOR_REPORT_POWER_STATUS = 2;
+
+ // Time out in millseconds used for <Routing Information>
+ private static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000;
+
+ // Time out in milliseconds used for <Report Power Status>
+ private static final int TIMEOUT_REPORT_POWER_STATUS_MS = 1000;
+
+ private final IHdmiControlCallback mCallback;
+
+ // The latest routing path. Updated by each <Routing Information> from CEC switches.
+ private int mCurrentRoutingPath;
+
+ RoutingControlAction(HdmiControlService service, int sourceAddress, int portId,
+ IHdmiControlCallback callback) {
+ super(service, sourceAddress);
+ mCallback = callback;
+ mCurrentRoutingPath = portToPath(portId);
+ }
+
+ @Override
+ public boolean start() {
+ mState = STATE_WAIT_FOR_ROUTING_INFORMATION;
+ addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
+ return true;
+ }
+
+ @Override
+ public boolean processCommand(HdmiCecMessage cmd) {
+ int opcode = cmd.getOpcode();
+ byte[] params = cmd.getParams();
+ if (mState == STATE_WAIT_FOR_ROUTING_INFORMATION
+ && opcode == HdmiCec.MESSAGE_ROUTING_INFORMATION) {
+ // Keep updating the physicalAddress as we receive <Routing Information>.
+ // If the routing path doesn't belong to the currently active one, we should
+ // ignore it since it might have come from other, routing change sequence.
+ int routingPath = HdmiUtils.twoBytesToInt(params);
+ if (isInActiveRoutingPath(mCurrentRoutingPath, routingPath)) {
+ return true;
+ }
+ mCurrentRoutingPath = routingPath;
+ // Stop possible previous routing change sequence if in progress.
+ mService.removeAction(RoutingControlAction.class);
+ addTimer(mState, TIMEOUT_ROUTING_INFORMATION_MS);
+ return true;
+ } else if (mState == STATE_WAIT_FOR_REPORT_POWER_STATUS
+ && opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
+ handleReportPowerStatus(cmd.getParams()[0]);
+ return true;
+ }
+ return false;
+ }
+
+ private void handleReportPowerStatus(int devicePowerStatus) {
+ int tvPowerStatus = getTvPowerStatus();
+ if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) {
+ if (isPowerStatusOnOrTransientToOn(devicePowerStatus)) {
+ sendSetStreamPath();
+ } else {
+ // The whole action should be stopped here if the device is in standby mode.
+ // We don't attempt to wake it up by sending <Set Stream Path>.
+ }
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ finish();
+ } else {
+ // TV is going into standby mode.
+ // TODO: Figure out what to do.
+ }
+ }
+
+ private int getTvPowerStatus() {
+ // TODO: Obtain TV power status.
+ return HdmiCec.POWER_STATUS_ON;
+ }
+
+ private static boolean isPowerStatusOnOrTransientToOn(int status) {
+ return status == HdmiCec.POWER_STATUS_ON || status == HdmiCec.POWER_STATUS_TRANSIENT_TO_ON;
+ }
+
+ private void sendSetStreamPath() {
+ sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(mSourceAddress, mCurrentRoutingPath));
+ }
+
+ private static boolean isInActiveRoutingPath(int activePath, int newPath) {
+ // Check each nibble of the currently active path and the new path till the position
+ // where the active nibble is not zero. For (activePath, newPath),
+ // (1.1.0.0, 1.0.0.0) -> true, new path is a parent
+ // (1.2.1.0, 1.2.1.2) -> true, new path is a descendant
+ // (1.1.0.0, 1.2.0.0) -> false, new path is a sibling
+ // (1.0.0.0, 2.0.0.0) -> false, in a completely different path
+ for (int i = 12; i >= 0; i -= 4) {
+ int nibbleActive = (activePath >> i) & 0xF;
+ if (nibbleActive == 0) {
+ break;
+ }
+ int nibbleNew = (newPath >> i) & 0xF;
+ if (nibbleNew == 0) {
+ break;
+ }
+ if (nibbleActive != nibbleNew) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void handleTimerEvent(int timeoutState) {
+ if (mState != timeoutState || mState == STATE_NONE) {
+ Slog.w("CEC", "Timer in a wrong state. Ignored.");
+ return;
+ }
+ switch (timeoutState) {
+ case STATE_WAIT_FOR_ROUTING_INFORMATION:
+ HdmiCecDeviceInfo device = mService.getDeviceInfoByPath(mCurrentRoutingPath);
+ if (device == null) {
+ maybeChangeActiveInput(pathToPort(mCurrentRoutingPath));
+ } else {
+ // TODO: Also check followings and then proceed:
+ // if routing change was neither triggered by TV at CEC enable time, nor
+ // at the detection of new device at the end of the active routing path, nor
+ // by TV power on with HDMI input as the active signal source.
+ int deviceLogicalAddress = device.getLogicalAddress();
+ queryDevicePowerStatus(deviceLogicalAddress, new SendMessageCallback() {
+ @Override
+ public void onSendCompleted(int error) {
+ handlDevicePowerStatusAckResult(error == HdmiCec.RESULT_SUCCESS);
+ }
+ });
+ }
+ return;
+ case STATE_WAIT_FOR_REPORT_POWER_STATUS:
+ int tvPowerStatus = getTvPowerStatus();
+ if (isPowerStatusOnOrTransientToOn(tvPowerStatus)) {
+ if (!maybeChangeActiveInput(pathToPort(mCurrentRoutingPath))) {
+ sendSetStreamPath();
+ }
+ }
+ invokeCallback(HdmiCec.RESULT_SUCCESS);
+ finish();
+ return;
+ }
+ }
+
+ // Called whenever an HDMI input of the TV shall become the active input.
+ private boolean maybeChangeActiveInput(int inputPortPath) {
+ if (mService.getActiveInput() == inputPortPath) {
+ return false;
+ }
+ // TODO: Remember the currently active input
+ // if PAP/PIP is active, move the focus to the right window, otherwise switch
+ // the port.
+ // Show the OSD input change banner.
+ return true;
+ }
+
+ private void queryDevicePowerStatus(int address, SendMessageCallback callback) {
+ sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(mSourceAddress, address),
+ callback);
+ }
+
+ private void handlDevicePowerStatusAckResult(boolean acked) {
+ if (acked) {
+ mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
+ addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS);
+ } else {
+ maybeChangeActiveInput(pathToPort(mCurrentRoutingPath));
+ }
+ }
+
+ // Get the address of the TV port to which the given path is connected.
+ private static int pathToPort(int path) {
+ return path & HdmiConstants.ROUTING_PATH_TOP_MASK;
+ }
+
+ // Given the HDMI port id, return the port address.
+ private int portToPath(int portId) {
+ return mService.getPortInfo(portId).getAddress();
+ }
+
+ private void invokeCallback(int result) {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.onComplete(result);
+ } catch (RemoteException e) {
+ // Do nothing.
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 92b643c..534faba3 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -481,11 +481,10 @@
*/
private void closeAndCleanupJobH(boolean reschedule) {
removeMessages(MSG_TIMEOUT);
+ mCompletedListener.onJobCompleted(mRunningJob, reschedule);
synchronized (mLock) {
mWakeLock.release();
mContext.unbindService(JobServiceContext.this);
- mCompletedListener.onJobCompleted(mRunningJob, reschedule);
-
mWakeLock = null;
mRunningJob = null;
mParams = null;
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 5f22b34..4ac26c1 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -262,16 +262,23 @@
@Override
public void run() {
final long startElapsed = SystemClock.elapsedRealtime();
+ List<JobStatus> mStoreCopy = new ArrayList<JobStatus>();
synchronized (JobStore.this) {
- writeJobsMapImpl();
+ // Copy over the jobs so we can release the lock before writing.
+ for (JobStatus jobStatus : mJobSet) {
+ JobStatus copy = new JobStatus(jobStatus.getJob(), jobStatus.getUid(),
+ jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed());
+ mStoreCopy.add(copy);
+ }
}
+ writeJobsMapImpl(mStoreCopy);
if (JobSchedulerService.DEBUG) {
Slog.v(TAG, "Finished writing, took " + (SystemClock.elapsedRealtime()
- startElapsed) + "ms");
}
}
- private void writeJobsMapImpl() {
+ private void writeJobsMapImpl(List<JobStatus> jobList) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmlSerializer out = new FastXmlSerializer();
@@ -281,8 +288,7 @@
out.startTag(null, "job-info");
out.attribute(null, "version", Integer.toString(JOBS_FILE_VERSION));
- for (int i = 0; i < mJobSet.size(); i++) {
- final JobStatus jobStatus = mJobSet.valueAt(i);
+ for (JobStatus jobStatus : jobList) {
if (DEBUG) {
Slog.d(TAG, "Saving job " + jobStatus.getJobId());
}
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 7e79ff7..daba0d9 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -197,4 +197,4 @@
+ ", UM=" + js.hasUnmeteredConstraint());
}
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 835b094..9ae8aed 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -949,6 +949,11 @@
}
@Override
+ public long getFlags() {
+ return mFlags;
+ }
+
+ @Override
public void play() throws RemoteException {
mSessionCb.play();
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 50a32c4..b95db9c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -18,6 +18,7 @@
import android.app.AlarmManager;
import android.app.AppOpsManager;
+import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -88,6 +89,10 @@
private static final Set<String> ALARM_PACKAGES = new HashSet<String>(Arrays.asList(
"com.google.android.deskclock"
));
+ private static final Set<String> SYSTEM_PACKAGES = new HashSet<String>(Arrays.asList(
+ "android",
+ "com.android.systemui"
+ ));
public ZenModeHelper(Context context, Handler handler) {
mContext = context;
@@ -130,6 +135,9 @@
// notifications never transition from not intercepted to intercepted
return false;
}
+ if (isSystem(record)) {
+ return false;
+ }
if (isAlarm(record)) {
return false;
}
@@ -239,6 +247,11 @@
}
}
+ private boolean isSystem(NotificationRecord record) {
+ return SYSTEM_PACKAGES.contains(record.sbn.getPackageName())
+ && Notification.CATEGORY_SYSTEM.equals(record.getNotification().category);
+ }
+
private boolean isAlarm(NotificationRecord record) {
return ALARM_PACKAGES.contains(record.sbn.getPackageName());
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6cfcbdc..49502b6 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10266,7 +10266,7 @@
synchronized (mPackages) {
// Check whether the newly-scanned package wants to define an already-defined perm
int N = pkg.permissions.size();
- for (int i = 0; i < N; i++) {
+ for (int i = N-1; i >= 0; i--) {
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm.info.name);
if (bp != null) {
@@ -10274,13 +10274,23 @@
// also includes the "updating the same package" case, of course.
if (compareSignatures(bp.packageSetting.signatures.mSignatures,
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
- Slog.w(TAG, "Package " + pkg.packageName
- + " attempting to redeclare permission " + perm.info.name
- + " already owned by " + bp.sourcePackage);
- res.returnCode = PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
- res.origPermission = perm.info.name;
- res.origPackage = bp.sourcePackage;
- return;
+ // If the owning package is the system itself, we log but allow
+ // install to proceed; we fail the install on all other permission
+ // redefinitions.
+ if (!bp.sourcePackage.equals("android")) {
+ Slog.w(TAG, "Package " + pkg.packageName
+ + " attempting to redeclare permission " + perm.info.name
+ + " already owned by " + bp.sourcePackage);
+ res.returnCode = PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
+ res.origPermission = perm.info.name;
+ res.origPackage = bp.sourcePackage;
+ return;
+ } else {
+ Slog.w(TAG, "Package " + pkg.packageName
+ + " attempting to redeclare system permission "
+ + perm.info.name + "; ignoring new declaration");
+ pkg.permissions.remove(i);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b7bc2e1..b941657 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -161,7 +161,6 @@
private final SparseBooleanArray mRemovingUserIds = new SparseBooleanArray();
private int[] mUserIds;
- private boolean mGuestEnabled;
private int mNextSerialNumber;
private int mUserVersion = 0;
@@ -427,43 +426,6 @@
}
}
- @Override
- public void setGuestEnabled(boolean enable) {
- checkManageUsersPermission("enable guest users");
- synchronized (mPackagesLock) {
- if (mGuestEnabled != enable) {
- mGuestEnabled = enable;
- // Erase any guest user that currently exists
- for (int i = 0; i < mUsers.size(); i++) {
- UserInfo user = mUsers.valueAt(i);
- if (!user.partial && user.isGuest()) {
- if (!enable) {
- removeUser(user.id);
- }
- return;
- }
- }
- // No guest was found
- if (enable) {
- createUser("Guest", UserInfo.FLAG_GUEST);
- }
- }
- }
- }
-
- @Override
- public boolean isGuestEnabled() {
- synchronized (mPackagesLock) {
- return mGuestEnabled;
- }
- }
-
- @Override
- public void wipeUser(int userHandle) {
- checkManageUsersPermission("wipe user");
- // TODO:
- }
-
public void makeInitialized(int userId) {
checkManageUsersPermission("makeInitialized");
synchronized (mPackagesLock) {
@@ -583,7 +545,6 @@
}
private void readUserListLocked() {
- mGuestEnabled = false;
if (!mUserListFile.exists()) {
fallbackToSingleUserLocked();
return;
@@ -625,9 +586,6 @@
if (user != null) {
mUsers.put(user.id, user);
- if (user.isGuest()) {
- mGuestEnabled = true;
- }
if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
mNextSerialNumber = user.id + 1;
}
@@ -1146,7 +1104,7 @@
final UserInfo user;
synchronized (mPackagesLock) {
user = mUsers.get(userHandle);
- if (userHandle == 0 || user == null) {
+ if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
return false;
}
mRemovingUserIds.put(userHandle, true);
diff --git a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
index 55dd4ab..24318df 100644
--- a/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -42,6 +42,7 @@
private static final String seappContextsPath = "seapp_contexts";
private static final String versionPath = "selinux_version";
private static final String macPermissionsPath = "mac_permissions.xml";
+ private static final String serviceContextsPath = "service_contexts";
public SELinuxPolicyInstallReceiver() {
super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
@@ -65,6 +66,9 @@
new File(contexts, sepolicyPath).renameTo(
new File(contexts, sepolicyPath + "_backup"));
+
+ new File(contexts, serviceContextsPath).renameTo(
+ new File(contexts, serviceContextsPath + "_backup"));
}
private void copyUpdate(File contexts) {
@@ -74,6 +78,7 @@
new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath));
new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath));
new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath));
+ new File(updateDir, serviceContextsPath).renameTo(new File(contexts, serviceContextsPath));
}
private int readInt(BufferedInputStream reader) throws IOException {
@@ -85,13 +90,14 @@
}
private int[] readChunkLengths(BufferedInputStream bundle) throws IOException {
- int[] chunks = new int[6];
+ int[] chunks = new int[7];
chunks[0] = readInt(bundle);
chunks[1] = readInt(bundle);
chunks[2] = readInt(bundle);
chunks[3] = readInt(bundle);
chunks[4] = readInt(bundle);
chunks[5] = readInt(bundle);
+ chunks[6] = readInt(bundle);
return chunks;
}
@@ -112,6 +118,7 @@
installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[3]);
installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[4]);
installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[5]);
+ installFile(new File(updateDir, serviceContextsPath), stream, chunkLengths[6]);
} finally {
IoUtils.closeQuietly(stream);
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 95cfa243..6cb6b76 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -44,6 +44,7 @@
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
+import android.view.ViewConfiguration;
import android.view.WindowInfo;
import android.view.WindowManager;
import android.view.WindowManagerInternal.MagnificationCallbacks;
@@ -113,13 +114,13 @@
mDisplayMagnifier.setMagnificationSpecLocked(spec);
}
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
- public void onRectangleOnScreenRequestedLocked(Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
if (mDisplayMagnifier != null) {
- mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle, immediate);
+ mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
}
// Not relevant for the window observer.
}
@@ -129,7 +130,7 @@
mDisplayMagnifier.onWindowLayersChangedLocked();
}
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
@@ -138,7 +139,7 @@
mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
}
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
@@ -154,7 +155,7 @@
mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
}
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
@@ -162,16 +163,16 @@
// Not relevant for the display magnifier.
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
- public void onSomeWindowResizedOrMoved() {
+ public void onSomeWindowResizedOrMovedLocked() {
// Not relevant for the display magnifier.
if (mWindowsForAccessibilityObserver != null) {
- mWindowsForAccessibilityObserver.computeChangedWindows();
+ mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
}
}
@@ -256,7 +257,7 @@
mWindowManagerService.scheduleAnimationLocked();
}
- public void onRectangleOnScreenRequestedLocked(Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
if (DEBUG_RECTANGLE_REQUESTED) {
Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
}
@@ -889,21 +890,45 @@
private final WindowsForAccessibilityCallback mCallback;
+ private final long mRecurringAccessibilityEventsIntervalMillis;
+
public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
WindowsForAccessibilityCallback callback) {
mContext = windowManagerService.mContext;
mWindowManagerService = windowManagerService;
mCallback = callback;
mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
+ mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
+ .getSendRecurringAccessibilityEventsInterval();
computeChangedWindows();
}
+ public void scheduleComputeChangedWindowsLocked() {
+ // If focus changed, compute changed windows immediately as the focused window
+ // is used by the accessibility manager service to determine the active window.
+ if (mWindowManagerService.mCurrentFocus != null
+ && mWindowManagerService.mCurrentFocus != mWindowManagerService.mLastFocus) {
+ mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
+ computeChangedWindows();
+ } else if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
+ mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
+ mRecurringAccessibilityEventsIntervalMillis);
+ }
+ }
+
public void computeChangedWindows() {
if (DEBUG) {
Slog.i(LOG_TAG, "computeChangedWindows()");
}
synchronized (mWindowManagerService.mWindowMap) {
+ // Do not send the windows if there is no current focus as
+ // the window manager is still looking for where to put it.
+ // We will do the work when we get a focus change callback.
+ if (mWindowManagerService.mCurrentFocus == null) {
+ return;
+ }
+
WindowManager windowManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getRealSize(mTempPoint);
@@ -921,37 +946,21 @@
Set<IBinder> addedWindows = mTempBinderSet;
addedWindows.clear();
+ boolean focusedWindowAdded = false;
+
final int visibleWindowCount = visibleWindows.size();
for (int i = visibleWindowCount - 1; i >= 0; i--) {
WindowState windowState = visibleWindows.valueAt(i);
- // Compute the window touchable frame as shown on the screen.
- // Get the touchable frame.
- Region touchableRegion = mTempRegion1;
- windowState.getTouchableRegion(touchableRegion);
- Rect touchableFrame = mTempRect;
- touchableRegion.getBounds(touchableFrame);
-
- // Move to origin as all transforms are captured by the matrix.
- RectF windowFrame = mTempRectF;
- windowFrame.set(touchableFrame);
- windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
-
- // Map the frame to get what appears on the screen.
- Matrix matrix = mTempMatrix;
- populateTransformationMatrixLocked(windowState, matrix);
- matrix.mapRect(windowFrame);
-
- // Got the bounds.
+ // Compute the bounds in the screen.
Rect boundsInScreen = mTempRect;
- boundsInScreen.set((int) windowFrame.left, (int) windowFrame.top,
- (int) windowFrame.right, (int) windowFrame.bottom);
+ computeWindowBoundsInScreen(windowState, boundsInScreen);
final int flags = windowState.mAttrs.flags;
// If the window is not touchable, do not report it but take into account
// the space it takes since the content behind it cannot be touched.
- if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) == 1) {
+ if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
unaccountedSpace.op(boundsInScreen, unaccountedSpace,
Region.Op.DIFFERENCE);
continue;
@@ -965,33 +974,12 @@
// Add windows of certain types not covered by modal windows.
if (isReportedWindowType(windowState.mAttrs.type)) {
// Add the window to the ones to be reported.
- WindowInfo window = WindowInfo.obtain();
- window.type = windowState.mAttrs.type;
- window.layer = windowState.mLayer;
- window.token = windowState.mClient.asBinder();
-
+ WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
addedWindows.add(window.token);
-
- WindowState attachedWindow = windowState.mAttachedWindow;
- if (attachedWindow != null) {
- window.parentToken = attachedWindow.mClient.asBinder();
- }
-
- window.focused = windowState.isFocused();
- window.boundsInScreen.set(boundsInScreen);
-
- final int childCount = windowState.mChildWindows.size();
- if (childCount > 0) {
- if (window.childTokens == null) {
- window.childTokens = new ArrayList<IBinder>();
- }
- for (int j = 0; j < childCount; j++) {
- WindowState child = windowState.mChildWindows.get(j);
- window.childTokens.add(child.mClient.asBinder());
- }
- }
-
windows.add(window);
+ if (windowState.isFocused()) {
+ focusedWindowAdded = true;
+ }
}
// Account for the space this window takes.
@@ -1010,6 +998,25 @@
}
}
+ // Always report the focused window.
+ if (!focusedWindowAdded) {
+ for (int i = visibleWindowCount - 1; i >= 0; i--) {
+ WindowState windowState = visibleWindows.valueAt(i);
+ if (windowState.isFocused()) {
+ // Compute the bounds in the screen.
+ Rect boundsInScreen = mTempRect;
+ computeWindowBoundsInScreen(windowState, boundsInScreen);
+
+ // Add the window to the ones to be reported.
+ WindowInfo window = obtainPopulatedWindowInfo(windowState,
+ boundsInScreen);
+ addedWindows.add(window.token);
+ windows.add(window);
+ break;
+ }
+ }
+ }
+
// Remove child/parent references to windows that were not added.
final int windowCount = windows.size();
for (int i = 0; i < windowCount; i++) {
@@ -1072,6 +1079,57 @@
}
}
+ private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
+ // Get the touchable frame.
+ Region touchableRegion = mTempRegion1;
+ windowState.getTouchableRegion(touchableRegion);
+ Rect touchableFrame = mTempRect;
+ touchableRegion.getBounds(touchableFrame);
+
+ // Move to origin as all transforms are captured by the matrix.
+ RectF windowFrame = mTempRectF;
+ windowFrame.set(touchableFrame);
+ windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
+
+ // Map the frame to get what appears on the screen.
+ Matrix matrix = mTempMatrix;
+ populateTransformationMatrixLocked(windowState, matrix);
+ matrix.mapRect(windowFrame);
+
+ // Got the bounds.
+ outBounds.set((int) windowFrame.left, (int) windowFrame.top,
+ (int) windowFrame.right, (int) windowFrame.bottom);
+ }
+
+ private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
+ Rect boundsInScreen) {
+ WindowInfo window = WindowInfo.obtain();
+ window.type = windowState.mAttrs.type;
+ window.layer = windowState.mLayer;
+ window.token = windowState.mClient.asBinder();
+
+ WindowState attachedWindow = windowState.mAttachedWindow;
+ if (attachedWindow != null) {
+ window.parentToken = attachedWindow.mClient.asBinder();
+ }
+
+ window.focused = windowState.isFocused();
+ window.boundsInScreen.set(boundsInScreen);
+
+ final int childCount = windowState.mChildWindows.size();
+ if (childCount > 0) {
+ if (window.childTokens == null) {
+ window.childTokens = new ArrayList<IBinder>();
+ }
+ for (int j = 0; j < childCount; j++) {
+ WindowState child = windowState.mChildWindows.get(j);
+ window.childTokens.add(child.mClient.asBinder());
+ }
+ }
+
+ return window;
+ }
+
private void cacheWindows(List<WindowInfo> windows) {
final int oldWindowCount = mOldWindows.size();
for (int i = oldWindowCount - 1; i >= 0; i--) {
@@ -1088,10 +1146,10 @@
if (oldWindow == newWindow) {
return false;
}
- if (oldWindow == null && newWindow != null) {
+ if (oldWindow == null) {
return true;
}
- if (oldWindow != null && newWindow == null) {
+ if (newWindow == null) {
return true;
}
if (oldWindow.type != newWindow.type) {
@@ -1160,7 +1218,8 @@
}
private class MyHandler extends Handler {
- public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 1;
+ public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
+ public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 2;
public MyHandler(Looper looper) {
super(looper, null, false);
@@ -1170,6 +1229,10 @@
@SuppressWarnings("unchecked")
public void handleMessage(Message message) {
switch (message.what) {
+ case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
+ computeChangedWindows();
+ } break;
+
case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
List<WindowInfo> windows = (List<WindowInfo>) message.obj;
mCallback.onWindowsForAccessibilityChanged(windows);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 3200b54..b4cf2ae 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -446,11 +446,11 @@
}
}
- public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
synchronized(mService.mWindowMap) {
final long identity = Binder.clearCallingIdentity();
try {
- mService.onRectangleOnScreenRequested(token, rectangle, immediate);
+ mService.onRectangleOnScreenRequested(token, rectangle);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a354c45..dfb1200 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -154,7 +154,8 @@
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- if (windows.get(winNdx).mWinAnimator.isAnimating()) {
+ final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
+ if (winAnimator.isAnimating() && !winAnimator.isDummyAnimation()) {
return true;
}
}
@@ -236,9 +237,22 @@
void detachDisplay() {
EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
+
+ boolean doAnotherLayoutPass = false;
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- mService.tmpRemoveTaskWindowsLocked(mTasks.get(taskNdx));
+ final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
+ for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
+ final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
+ for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
+ mService.removeWindowInnerLocked(null, appWindows.get(winNdx));
+ doAnotherLayoutPass = true;
+ }
+ }
}
+ if (doAnotherLayoutPass) {
+ mService.requestTraversalLocked();
+ }
+
mAnimationBackgroundSurface.destroySurface();
mAnimationBackgroundSurface = null;
mDimLayer.destroySurface();
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 008d2fc..45326f7 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -19,6 +19,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
@@ -227,7 +228,7 @@
continue;
}
final WindowStateAnimator winAnimator = win.mWinAnimator;
- if (mPolicy.doesForceHide(win.mAttrs)) {
+ if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
if (!winAnimator.mAnimating) {
// Create a new animation to delay until keyguard is gone on its own.
winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
@@ -268,7 +269,7 @@
}
}
- if (mPolicy.doesForceHide(win.mAttrs)) {
+ if (mPolicy.isForceHiding(win.mAttrs)) {
if (!wasAnimating && nowAnimating) {
if (WindowManagerService.DEBUG_ANIM ||
WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 93a763a..2d8a34b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2529,7 +2529,7 @@
Binder.restoreCallingIdentity(origId);
}
- private void removeWindowInnerLocked(Session session, WindowState win) {
+ void removeWindowInnerLocked(Session session, WindowState win) {
if (win.mRemoved) {
// Nothing to do.
return;
@@ -2811,14 +2811,13 @@
performLayoutAndPlaceSurfacesLocked();
}
- public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
synchronized (mWindowMap) {
if (mAccessibilityController != null) {
WindowState window = mWindowMap.get(token);
//TODO (multidisplay): Magnification is supported only for the default display.
if (window != null && window.getDisplayId() == Display.DEFAULT_DISPLAY) {
- mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle,
- immediate);
+ mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle);
}
}
}
@@ -8443,7 +8442,7 @@
}
win.mLayoutNeeded = false;
win.prelayout();
- mPolicy.layoutWindowLw(win, win.mAttrs, null);
+ mPolicy.layoutWindowLw(win, null);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame="
+ win.mFrame + " mContainingFrame="
@@ -8495,7 +8494,7 @@
}
win.mLayoutNeeded = false;
win.prelayout();
- mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+ mPolicy.layoutWindowLw(win, win.mAttachedWindow);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame="
+ win.mFrame + " mContainingFrame="
@@ -9231,7 +9230,7 @@
//TODO (multidisplay): Accessibility supported only for the default display.
if (mAccessibilityController != null
&& displayId == Display.DEFAULT_DISPLAY) {
- mAccessibilityController.onSomeWindowResizedOrMoved();
+ mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
try {
@@ -9872,7 +9871,9 @@
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
- if (mAccessibilityController != null) {
+ // TODO(multidisplay): Accessibilty supported only of default desiplay.
+ if (mAccessibilityController != null
+ && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
mAccessibilityController.onWindowFocusChangedLocked();
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fe771dc..7003c8c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -728,8 +728,11 @@
}
public DisplayContent getDisplayContent() {
- return mAppToken == null || mNotOnAppsDisplay ?
- mDisplayContent : getStack().getDisplayContent();
+ if (mAppToken == null || mNotOnAppsDisplay) {
+ return mDisplayContent;
+ }
+ final TaskStack stack = getStack();
+ return stack == null ? mDisplayContent : stack.getDisplayContent();
}
public int getDisplayId() {
@@ -1364,7 +1367,7 @@
//TODO (multidisplay): Accessibility supported only for the default display.
if (mService.mAccessibilityController != null
&& getDisplayId() == Display.DEFAULT_DISPLAY) {
- mService.mAccessibilityController.onSomeWindowResizedOrMoved();
+ mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
}
mOverscanInsetsChanged = false;
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index cbc853d..0f919d1 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -57,6 +57,8 @@
int getVersion();
// Get vendor id used for vendor command.
uint32_t getVendorId();
+ // Get Port information on all the HDMI ports.
+ jobjectArray getPortInfos();
// Set a flag and its value.
void setOption(int flag, int value);
// Set audio return channel status.
@@ -69,6 +71,7 @@
}
private:
+ static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
static void onReceived(const hdmi_event_t* event, void* arg);
hdmi_cec_device_t* mDevice;
@@ -209,11 +212,11 @@
}
int HdmiCecController::getPhysicalAddress() {
- uint16_t physicalAddress = 0xFFFF;
- if (mDevice->get_physical_address(mDevice, &physicalAddress) == 0) {
- return physicalAddress;
+ uint16_t addr;
+ if (!mDevice->get_physical_address(mDevice, &addr)) {
+ return addr;
}
- return -1;
+ return INVALID_PHYSICAL_ADDRESS;
}
int HdmiCecController::getVersion() {
@@ -228,6 +231,34 @@
return vendorId;
}
+jobjectArray HdmiCecController::getPortInfos() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo");
+ if (hdmiPortInfo == NULL) {
+ return NULL;
+ }
+ jmethodID ctor = env->GetMethodID(hdmiPortInfo, "<init>", "(IIIZZZ)V");
+ if (ctor == NULL) {
+ return NULL;
+ }
+ hdmi_port_info* ports;
+ int numPorts;
+ mDevice->get_port_info(mDevice, &ports, &numPorts);
+ jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL);
+
+ // MHL support field will be obtained from MHL HAL. Leave it to false.
+ jboolean mhlSupported = (jboolean) 0;
+ for (int i = 0; i < numPorts; ++i) {
+ hdmi_port_info* info = &ports[i];
+ jboolean cecSupported = (jboolean) info->cec_supported;
+ jboolean arcSupported = (jboolean) info->arc_supported;
+ jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_num, info->type,
+ info->physical_address, cecSupported, mhlSupported, arcSupported);
+ env->SetObjectArrayElement(res, i, infoObj);
+ }
+ return res;
+}
+
void HdmiCecController::setOption(int flag, int value) {
mDevice->set_option(mDevice, flag, value);
}
@@ -242,7 +273,6 @@
return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
}
-
// static
void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
HdmiCecController* controller = static_cast<HdmiCecController*>(arg);
@@ -311,58 +341,50 @@
return controller->sendMessage(message);
}
-static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz,
- jlong controllerPtr, jint logicalAddress) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
- return controller->addLogicalAddress(
- static_cast<cec_logical_address_t>(logicalAddress));
+static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
+ jint logicalAddress) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress));
}
-static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz,
- jlong controllerPtr) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
controller->clearLogicaladdress();
}
-static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz,
- jlong controllerPtr) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
return controller->getPhysicalAddress();
}
-static jint nativeGetVersion(JNIEnv* env, jclass clazz,
- jlong controllerPtr) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+static jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
return controller->getVersion();
}
static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
return controller->getVendorId();
}
-static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag,
- jint value) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
+ return controller->getPortInfos();
+}
+
+static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
controller->setOption(flag, value);
}
static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
jboolean enabled) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
controller->setAudioReturnChannel(enabled == JNI_TRUE);
}
static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
- HdmiCecController* controller =
- reinterpret_cast<HdmiCecController*>(controllerPtr);
+ HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
}
@@ -377,6 +399,9 @@
{ "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress },
{ "nativeGetVersion", "(J)I", (void *) nativeGetVersion },
{ "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId },
+ { "nativeGetPortInfos",
+ "(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
+ (void *) nativeGetPortInfos },
{ "nativeSetOption", "(JII)V", (void *) nativeSetOption },
{ "nativeSetAudioReturnChannel", "(JZ)V", (void *) nativeSetAudioReturnChannel },
{ "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
@@ -385,8 +410,7 @@
#define CLASS_PATH "com/android/server/hdmi/HdmiCecController"
int register_android_server_hdmi_HdmiCecController(JNIEnv* env) {
- int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods,
- NELEM(sMethods));
+ int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
return 0;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 29d6f7e..4574caf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -32,6 +32,7 @@
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
+import android.app.IActivityManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -839,15 +840,23 @@
sendAdminCommandLocked(admin, action, null);
}
+ void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
+ sendAdminCommandLocked(admin, action, null, result);
+ }
+
/**
* Send an update to one specific admin, get notified when that admin returns a result.
*/
- void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
+ void sendAdminCommandLocked(ActiveAdmin admin, String action, Bundle adminExtras,
+ BroadcastReceiver result) {
Intent intent = new Intent(action);
intent.setComponent(admin.info.getComponent());
if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
intent.putExtra("expiration", admin.passwordExpirationDate);
}
+ if (adminExtras != null) {
+ intent.putExtras(adminExtras);
+ }
if (result != null) {
mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
null, result, mHandler, Activity.RESULT_OK, null, null);
@@ -1375,6 +1384,11 @@
if (!mHasFeature) {
return;
}
+ setActiveAdmin(adminReceiver, refreshing, userHandle, null);
+ }
+
+ private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
+ Bundle onEnableData) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
enforceCrossUserPermission(userHandle);
@@ -1411,7 +1425,8 @@
policy.mAdminList.set(replaceIndex, newAdmin);
}
saveSettingsLocked(userHandle);
- sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
+ sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+ onEnableData, null);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -3498,6 +3513,36 @@
}
@Override
+ public UserHandle createAndInitializeUser(ComponentName who, String name,
+ String ownerName, ComponentName profileOwnerComponent, Bundle adminExtras) {
+ UserHandle user = createUser(who, name);
+ long id = Binder.clearCallingIdentity();
+ try {
+ String profileOwnerPkg = profileOwnerComponent.getPackageName();
+ final IPackageManager ipm = AppGlobals.getPackageManager();
+ IActivityManager activityManager = ActivityManagerNative.getDefault();
+
+ try {
+ // Install the profile owner if not present.
+ if (!ipm.isPackageAvailable(profileOwnerPkg, user.getIdentifier())) {
+ ipm.installExistingPackageAsUser(profileOwnerPkg, user.getIdentifier());
+ }
+
+ // Start user in background.
+ activityManager.startUserInBackground(user.getIdentifier());
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
+ }
+
+ setActiveAdmin(profileOwnerComponent, true, user.getIdentifier(), adminExtras);
+ setProfileOwner(profileOwnerPkg, ownerName, user.getIdentifier());
+ return user;
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ }
+
+ @Override
public boolean removeUser(ComponentName who, UserHandle userHandle) {
synchronized (this) {
if (who == null) {
diff --git a/telecomm/java/android/telecomm/CallCapabilities.java b/telecomm/java/android/telecomm/CallCapabilities.java
index b2b33a3..5aff19c 100644
--- a/telecomm/java/android/telecomm/CallCapabilities.java
+++ b/telecomm/java/android/telecomm/CallCapabilities.java
@@ -17,7 +17,7 @@
package android.telecomm;
/** Defines actions a call currently supports. */
-public class CallCapabilities {
+public final class CallCapabilities {
/** Call can currently be put on hold or unheld. */
public static final int HOLD = 0x00000001;
@@ -27,24 +27,60 @@
/** Call can currently be merged. */
public static final int MERGE_CALLS = 0x00000004;
- /* Call can currently be swapped with another call. */
+ /** Call can currently be swapped with another call. */
public static final int SWAP_CALLS = 0x00000008;
- /* Call currently supports adding another call to this one. */
+ /** Call currently supports adding another call to this one. */
public static final int ADD_CALL = 0x00000010;
- /* Call supports responding via text option. */
+ /** Call supports responding via text option. */
public static final int RESPOND_VIA_TEXT = 0x00000020;
- /* Call can be muted. */
+ /** Call can be muted. */
public static final int MUTE = 0x00000040;
- /* Call supports generic conference mode. */
+ /** Call supports generic conference mode. */
public static final int GENERIC_CONFERENCE = 0x00000080;
- /* Call currently supports switch between connections. */
+ /** Call currently supports switch between connections. */
public static final int CONNECTION_HANDOFF = 0x00000100;
public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
| RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE | CONNECTION_HANDOFF;
+
+ public static String toString(int capabilities) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[Capabilities:");
+ if ((capabilities & HOLD) != 0) {
+ builder.append(" HOLD");
+ }
+ if ((capabilities & SUPPORT_HOLD) != 0) {
+ builder.append(" SUPPORT_HOLD");
+ }
+ if ((capabilities & MERGE_CALLS) != 0) {
+ builder.append(" MERGE_CALLS");
+ }
+ if ((capabilities & SWAP_CALLS) != 0) {
+ builder.append(" SWAP_CALLS");
+ }
+ if ((capabilities & ADD_CALL) != 0) {
+ builder.append(" ADD_CALL");
+ }
+ if ((capabilities & RESPOND_VIA_TEXT) != 0) {
+ builder.append(" RESPOND_VIA_TEXT");
+ }
+ if ((capabilities & MUTE) != 0) {
+ builder.append(" MUTE");
+ }
+ if ((capabilities & GENERIC_CONFERENCE) != 0) {
+ builder.append(" GENERIC_CONFERENCE");
+ }
+ if ((capabilities & CONNECTION_HANDOFF) != 0) {
+ builder.append(" HANDOFF");
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ private CallCapabilities() {}
}
diff --git a/telecomm/java/android/telecomm/CallService.java b/telecomm/java/android/telecomm/CallService.java
index a254459..0b5981c 100644
--- a/telecomm/java/android/telecomm/CallService.java
+++ b/telecomm/java/android/telecomm/CallService.java
@@ -61,7 +61,7 @@
private static final int MSG_ON_AUDIO_STATE_CHANGED = 11;
private static final int MSG_PLAY_DTMF_TONE = 12;
private static final int MSG_STOP_DTMF_TONE = 13;
- private static final int MSG_ADD_TO_CONFERENCE = 14;
+ private static final int MSG_CONFERENCE = 14;
private static final int MSG_SPLIT_FROM_CONFERENCE = 15;
private static final int MSG_ON_POST_DIAL_CONTINUE = 16;
@@ -128,24 +128,12 @@
case MSG_STOP_DTMF_TONE:
stopDtmfTone((String) msg.obj);
break;
- case MSG_ADD_TO_CONFERENCE: {
- SomeArgs args = (SomeArgs) msg.obj;
- try {
- @SuppressWarnings("unchecked")
- List<String> callIds = (List<String>) args.arg2;
- String conferenceCallId = (String) args.arg1;
- addToConference(conferenceCallId, callIds);
- } finally {
- args.recycle();
- }
- break;
- }
- case MSG_SPLIT_FROM_CONFERENCE: {
+ case MSG_CONFERENCE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
String conferenceCallId = (String) args.arg1;
String callId = (String) args.arg2;
- splitFromConference(conferenceCallId, callId);
+ conference(conferenceCallId, callId);
} finally {
args.recycle();
}
@@ -162,6 +150,9 @@
}
break;
}
+ case MSG_SPLIT_FROM_CONFERENCE:
+ splitFromConference((String) msg.obj);
+ break;
default:
break;
}
@@ -245,19 +236,16 @@
}
@Override
- public void addToConference(String conferenceCallId, List<String> callsToConference) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = conferenceCallId;
- args.arg2 = callsToConference;
- mMessageHandler.obtainMessage(MSG_ADD_TO_CONFERENCE, args).sendToTarget();
- }
-
- @Override
- public void splitFromConference(String conferenceCallId, String callId) {
+ public void conference(String conferenceCallId, String callId) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = conferenceCallId;
args.arg2 = callId;
- mMessageHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, args).sendToTarget();
+ mMessageHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
+ }
+
+ @Override
+ public void splitFromConference(String callId) {
+ mMessageHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, callId).sendToTarget();
}
@Override
@@ -424,24 +412,22 @@
public abstract void onAudioStateChanged(String activeCallId, CallAudioState audioState);
/**
- * Adds the specified calls to the specified conference call.
+ * Conferences the specified call.
*
* @param conferenceCallId The unique ID of the conference call onto which the specified calls
* should be added.
- * @param callIds The calls to add to the conference call.
+ * @param callId The call to conference.
* @hide
*/
- public abstract void addToConference(String conferenceCallId, List<String> callIds);
+ public abstract void conference(String conferenceCallId, String callId);
/**
- * Removes the specified call from the specified conference call. This is a no-op if the call
- * is not already part of the conference call.
+ * Removes the specified call from a conference call.
*
- * @param conferenceCallId The conference call.
* @param callId The call to remove from the conference call
* @hide
*/
- public abstract void splitFromConference(String conferenceCallId, String callId);
+ public abstract void splitFromConference(String callId);
public void onPostDialContinue(String callId, boolean proceed) {}
public void onPostDialWait(Connection conn, String remaining) {}
diff --git a/telecomm/java/android/telecomm/CallServiceAdapter.java b/telecomm/java/android/telecomm/CallServiceAdapter.java
index 8c3ddad..0ba8161 100644
--- a/telecomm/java/android/telecomm/CallServiceAdapter.java
+++ b/telecomm/java/android/telecomm/CallServiceAdapter.java
@@ -179,12 +179,12 @@
* Indicates that the specified call can conference with any of the specified list of calls.
*
* @param callId The unique ID of the call.
- * @param conferenceCapableCallIds The unique IDs of the calls which can be conferenced.
+ * @param canConference Specified whether or not the call can be conferenced.
* @hide
*/
- public void setCanConferenceWith(String callId, List<String> conferenceCapableCallIds) {
+ public void setCanConference(String callId, boolean canConference) {
try {
- mAdapter.setCanConferenceWith(callId, conferenceCapableCallIds);
+ mAdapter.setCanConference(callId, canConference);
} catch (RemoteException ignored) {
}
}
@@ -193,13 +193,14 @@
* Indicates whether or not the specified call is currently conferenced into the specified
* conference call.
*
- * @param conferenceCallId The unique ID of the conference call.
* @param callId The unique ID of the call being conferenced.
+ * @param conferenceCallId The unique ID of the conference call. Null if call is not
+ * conferenced.
* @hide
*/
- public void setIsConferenced(String conferenceCallId, String callId, boolean isConferenced) {
+ public void setIsConferenced(String callId, String conferenceCallId) {
try {
- mAdapter.setIsConferenced(conferenceCallId, callId, isConferenced);
+ mAdapter.setIsConferenced(callId, conferenceCallId);
} catch (RemoteException ignored) {
}
}
@@ -236,4 +237,16 @@
} catch (RemoteException e) {
}
}
+
+ /**
+ * Indicates that a new conference call has been created.
+ *
+ * @param callId The unique ID of the conference call.
+ */
+ public void addConferenceCall(String callId) {
+ try {
+ mAdapter.addConferenceCall(callId, null);
+ } catch (RemoteException ignored) {
+ }
+ }
}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index 344814f..7aee770 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -19,7 +19,10 @@
import android.net.Uri;
import android.os.Bundle;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -35,6 +38,8 @@
void onDisconnected(Connection c, int cause, String message);
void onRequestingRingback(Connection c, boolean ringback);
void onDestroyed(Connection c);
+ void onConferenceCapableChanged(Connection c, boolean isConferenceCapable);
+ void onParentConnectionChanged(Connection c, Connection parent);
}
public static class ListenerBase implements Listener {
@@ -65,6 +70,14 @@
/** {@inheritDoc} */
@Override
public void onRequestingRingback(Connection c, boolean ringback) {}
+
+ /** ${inheritDoc} */
+ @Override
+ public void onConferenceCapableChanged(Connection c, boolean isConferenceCapable) {}
+
+ /** ${inheritDoc} */
+ @Override
+ public void onParentConnectionChanged(Connection c, Connection parent) {}
}
public final class State {
@@ -79,10 +92,14 @@
}
private final Set<Listener> mListeners = new HashSet<>();
+ private final List<Connection> mChildConnections = new ArrayList<>();
+
private int mState = State.NEW;
private CallAudioState mCallAudioState;
private Uri mHandle;
private boolean mRequestingRingback = false;
+ private boolean mIsConferenceCapable = false;
+ private Connection mParentConnection;
/**
* Create a new Connection.
@@ -176,6 +193,16 @@
}
/**
+ * Separates this Connection from a parent connection.
+ *
+ * @hide
+ */
+ public final void separate() {
+ Log.d(this, "separate");
+ onSeparate();
+ }
+
+ /**
* Abort this Connection. The Connection will immediately transition to
* the {@link State#DISCONNECTED} state, and send no notifications of this
* or any other future events.
@@ -240,6 +267,14 @@
}
/**
+ * TODO(santoscordon): Needs updated documentation.
+ */
+ public final void conference() {
+ Log.d(this, "conference");
+ onConference();
+ }
+
+ /**
* Inform this Connection that the state of its audio output has been changed externally.
*
* @param state The new audio state.
@@ -274,7 +309,7 @@
}
/**
- * @return Whether this connection is requesting that the system play a ringback tone
+ * Returns whether this connection is requesting that the system play a ringback tone
* on its behalf.
*/
public boolean isRequestingRingback() {
@@ -282,6 +317,38 @@
}
/**
+ * Returns whether this connection is a conference connection (has child connections).
+ */
+ public boolean isConferenceConnection() {
+ return !mChildConnections.isEmpty();
+ }
+
+ public void setParentConnection(Connection parentConnection) {
+ Log.d(this, "parenting %s to %s", this, parentConnection);
+ if (mParentConnection != parentConnection) {
+ if (mParentConnection != null) {
+ mParentConnection.removeChild(this);
+ }
+ mParentConnection = parentConnection;
+ if (mParentConnection != null) {
+ mParentConnection.addChild(this);
+ // do something if the child connections goes down to ZERO.
+ }
+ for (Listener l : mListeners) {
+ l.onParentConnectionChanged(this, mParentConnection);
+ }
+ }
+ }
+
+ public Connection getParentConnection() {
+ return mParentConnection;
+ }
+
+ public List<Connection> getChildConnections() {
+ return mChildConnections;
+ }
+
+ /**
* Sets the value of the {@link #getHandle()} property and notifies listeners.
*
* @param handle The new handle.
@@ -359,6 +426,32 @@
}
/**
+ * TODO(santoscordon): Needs documentation.
+ */
+ protected void setIsConferenceCapable(boolean isConferenceCapable) {
+ if (mIsConferenceCapable != isConferenceCapable) {
+ mIsConferenceCapable = isConferenceCapable;
+ for (Listener l : mListeners) {
+ l.onConferenceCapableChanged(this, mIsConferenceCapable);
+ }
+ }
+ }
+
+ /**
+ * TODO(santoscordon): Needs documentation.
+ */
+ protected void setDestroyed() {
+ // It is possible that onDestroy() will trigger the listener to remove itself which will
+ // result in a concurrent modification exception. To counteract this we make a copy of the
+ // listeners and iterate on that.
+ for (Listener l : new ArrayList<>(mListeners)) {
+ if (mListeners.contains(l)) {
+ l.onDestroyed(this);
+ }
+ }
+ }
+
+ /**
* Notifies this Connection and listeners that the {@link #getCallAudioState()} property
* has a new value.
*
@@ -418,6 +511,11 @@
protected void onDisconnect() {}
/**
+ * Notifies this Connection of a request to disconnect.
+ */
+ protected void onSeparate() {}
+
+ /**
* Notifies this Connection of a request to abort.
*/
protected void onAbort() {}
@@ -449,6 +547,28 @@
*/
protected void onPostDialContinue(boolean proceed) {}
+ /**
+ * TODO(santoscordon): Needs documentation.
+ */
+ protected void onConference() {}
+
+ /**
+ * TODO(santoscordon): Needs documentation.
+ */
+ protected void onChildrenChanged(List<Connection> children) {}
+
+ private void addChild(Connection connection) {
+ Log.d(this, "adding child %s", connection);
+ mChildConnections.add(connection);
+ onChildrenChanged(mChildConnections);
+ }
+
+ private void removeChild(Connection connection) {
+ Log.d(this, "removing child %s", connection);
+ mChildConnections.remove(connection);
+ onChildrenChanged(mChildConnections);
+ }
+
private void setState(int state) {
Log.d(this, "setState: %s", stateToString(state));
onSetState(state);
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index 59e977d..9dfad2d 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -20,10 +20,15 @@
import android.os.Bundle;
import android.telephony.DisconnectCause;
+import android.os.SystemClock;
+
+import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* A {@link android.app.Service} that provides telephone connections to
@@ -32,7 +37,6 @@
public abstract class ConnectionService extends CallService {
// Flag controlling whether PII is emitted into the logs
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
-
private static final Connection NULL_CONNECTION = new Connection() {};
// Mappings from Connections to IDs as understood by the current CallService implementation
@@ -99,6 +103,20 @@
Log.d(this, "Adapter onRingback %b", ringback);
getAdapter().setRequestingRingback(id, ringback);
}
+
+ @Override
+ public void onConferenceCapableChanged(Connection c, boolean isConferenceCapable) {
+ String id = mIdByConnection.get(c);
+ getAdapter().setCanConference(id, isConferenceCapable);
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onParentConnectionChanged(Connection c, Connection parent) {
+ String id = mIdByConnection.get(c);
+ String parentId = parent == null ? null : mIdByConnection.get(parent);
+ getAdapter().setIsConferenced(id, parentId);
+ }
};
@Override
@@ -110,8 +128,7 @@
@Override
public void onResult(Uri handle, Subscription... result) {
boolean isCompatible = result.length > 0;
- Log.d(this, "adapter setIsCompatibleWith "
- + callInfo.getId() + " " + isCompatible);
+ Log.d(this, "adapter setIsCompatibleWith ");
getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
}
@@ -135,7 +152,7 @@
new Response<ConnectionRequest, Connection>() {
@Override
public void onResult(ConnectionRequest request, Connection... result) {
- if (result.length != 1) {
+ if (result != null && result.length != 1) {
Log.d(this, "adapter handleFailedOutgoingCall %s", callInfo);
getAdapter().handleFailedOutgoingCall(
request,
@@ -145,10 +162,10 @@
c.abort();
}
} else {
- addConnection(callInfo.getId(), result[0]);
Log.d(this, "adapter handleSuccessfulOutgoingCall %s",
callInfo.getId());
getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
+ addConnection(callInfo.getId(), result[0]);
}
}
@@ -177,7 +194,7 @@
new Response<ConnectionRequest, Connection>() {
@Override
public void onResult(ConnectionRequest request, Connection... result) {
- if (result.length != 1) {
+ if (result != null && result.length != 1) {
Log.d(this, "adapter handleFailedOutgoingCall %s", callId);
getAdapter().handleFailedOutgoingCall(
request,
@@ -258,27 +275,43 @@
/** @hide */
@Override
- public final void addToConference(String conferenceCallId, List<String> callIds) {
- Log.d(this, "addToConference %s, %s", conferenceCallId, callIds);
+ public final void conference(final String conferenceCallId, String callId) {
+ Log.d(this, "conference %s, %s", conferenceCallId, callId);
- List<Connection> connections = new LinkedList<>();
- for (String id : callIds) {
- Connection connection = findConnectionForAction(id, "addToConference");
- if (connection == NULL_CONNECTION) {
- Log.w(this, "Connection missing in conference request %s.", id);
- return;
- }
- connections.add(connection);
+ Connection connection = findConnectionForAction(callId, "conference");
+ if (connection == NULL_CONNECTION) {
+ Log.w(this, "Connection missing in conference request %s.", callId);
+ return;
}
- // TODO(santoscordon): Find an existing conference call or create a new one. Then call
- // conferenceWith on it.
+ onCreateConferenceConnection(conferenceCallId, connection,
+ new Response<String, Connection>() {
+ /** ${inheritDoc} */
+ @Override
+ public void onResult(String ignored, Connection... result) {
+ Log.d(this, "onCreateConference.Response %s", (Object[]) result);
+ if (result != null && result.length == 1) {
+ Connection conferenceConnection = result[0];
+ if (!mIdByConnection.containsKey(conferenceConnection)) {
+ Log.v(this, "sending new conference call %s", conferenceCallId);
+ getAdapter().addConferenceCall(conferenceCallId);
+ addConnection(conferenceCallId, conferenceConnection);
+ }
+ }
+ }
+
+ /** ${inheritDoc} */
+ @Override
+ public void onError(String request, int code, String reason) {
+ // no-op
+ }
+ });
}
/** @hide */
@Override
- public final void splitFromConference(String conferenceCallId, String callId) {
- Log.d(this, "splitFromConference(%s, %s)", conferenceCallId, callId);
+ public final void splitFromConference(String callId) {
+ Log.d(this, "splitFromConference(%s)", callId);
Connection connection = findConnectionForAction(callId, "splitFromConference");
if (connection == NULL_CONNECTION) {
@@ -309,6 +342,13 @@
}
/**
+ * Returns all connections currently associated with this connection service.
+ */
+ public Collection<Connection> getAllConnections() {
+ return mConnectionById.values();
+ }
+
+ /**
* Find a set of Subscriptions matching a given handle (e.g. phone number).
*
* @param handle A handle (e.g. phone number) with which to connect.
@@ -329,6 +369,21 @@
Response<ConnectionRequest, Connection> callback) {}
/**
+ * Returns a new or existing conference connection when the the user elects to convert the
+ * specified connection into a conference call. The specified connection can be any connection
+ * which had previously specified itself as conference-capable including both simple connections
+ * and connections previously returned from this method.
+ *
+ * @param connection The connection from which the user opted to start a conference call.
+ * @param token The token to be passed into the response callback.
+ * @param callback The callback for providing the potentially-new conference connection.
+ */
+ public void onCreateConferenceConnection(
+ String token,
+ Connection connection,
+ Response<String, Connection> callback) {}
+
+ /**
* Create a Connection to match an incoming connection notification.
*
* @param request Data encapsulating details of the desired Connection.
@@ -338,6 +393,20 @@
ConnectionRequest request,
Response<ConnectionRequest, Connection> callback) {}
+ /**
+ * Notifies that a connection has been added to this connection service and sent to Telecomm.
+ *
+ * @param connection The connection which was added.
+ */
+ public void onConnectionAdded(Connection connection) {}
+
+ /**
+ * Notified that a connection has been removed from this connection service.
+ *
+ * @param connection The connection which was removed.
+ */
+ public void onConnectionRemoved(Connection connection) {}
+
static String toLogSafePhoneNumber(String number) {
// For unknown number, log empty string.
if (number == null) {
@@ -387,12 +456,14 @@
mConnectionById.put(callId, connection);
mIdByConnection.put(connection, callId);
connection.addConnectionListener(mConnectionListener);
+ onConnectionAdded(connection);
}
private void removeConnection(Connection connection) {
connection.removeConnectionListener(mConnectionListener);
mConnectionById.remove(mIdByConnection.get(connection));
mIdByConnection.remove(connection);
+ onConnectionRemoved(connection);
}
private Connection findConnectionForAction(String callId, String action) {
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
index 0bef419..86b7a50 100644
--- a/telecomm/java/android/telecomm/InCallAdapter.java
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -199,15 +199,14 @@
}
/**
- * Instructs Telecomm to conference the specified calls together.
+ * Instructs Telecomm to conference the specified call.
*
* @param callId The unique ID of the call.
- * @param callIdToConference The unique ID of the call to conference with.
* @hide
*/
- void conferenceWith(String callId, String callIdToConference) {
+ public void conference(String callId) {
try {
- mAdapter.conferenceWith(callId, callIdToConference);
+ mAdapter.conference(callId);
} catch (RemoteException ignored) {
}
}
@@ -219,7 +218,7 @@
* @param callId The unique ID of the call.
* @hide
*/
- void splitFromConference(String callId) {
+ public void splitFromConference(String callId) {
try {
mAdapter.splitFromConference(callId);
} catch (RemoteException ignored) {
diff --git a/telecomm/java/android/telecomm/InCallCall.java b/telecomm/java/android/telecomm/InCallCall.java
index b531ccd..432e378 100644
--- a/telecomm/java/android/telecomm/InCallCall.java
+++ b/telecomm/java/android/telecomm/InCallCall.java
@@ -39,7 +39,6 @@
private final GatewayInfo mGatewayInfo;
private final CallServiceDescriptor mCurrentCallServiceDescriptor;
private final CallServiceDescriptor mHandoffCallServiceDescriptor;
- private final List<String> mConferenceCapableCallIds;
private final String mParentCallId;
private final List<String> mChildCallIds;
@@ -57,8 +56,7 @@
CallServiceDescriptor descriptor,
CallServiceDescriptor handoffDescriptor) {
this(id, state, disconnectCauseCode, disconnectCauseMsg, capabilities, connectTimeMillis,
- handle, gatewayInfo, descriptor, handoffDescriptor, Collections.EMPTY_LIST, null,
- Collections.EMPTY_LIST);
+ handle, gatewayInfo, descriptor, handoffDescriptor, null, Collections.EMPTY_LIST);
}
/** @hide */
@@ -73,7 +71,6 @@
GatewayInfo gatewayInfo,
CallServiceDescriptor descriptor,
CallServiceDescriptor handoffDescriptor,
- List<String> conferenceCapableCallIds,
String parentCallId,
List<String> childCallIds) {
mId = id;
@@ -86,7 +83,6 @@
mGatewayInfo = gatewayInfo;
mCurrentCallServiceDescriptor = descriptor;
mHandoffCallServiceDescriptor = handoffDescriptor;
- mConferenceCapableCallIds = conferenceCapableCallIds;
mParentCallId = parentCallId;
mChildCallIds = childCallIds;
}
@@ -151,14 +147,6 @@
}
/**
- * The calls with which this call can conference.
- * @hide
- */
- public List<String> getConferenceCapableCallIds() {
- return mConferenceCapableCallIds;
- }
-
- /**
* The conference call to which this call is conferenced. Null if not conferenced.
* @hide
*/
@@ -191,14 +179,12 @@
GatewayInfo gatewayInfo = source.readParcelable(classLoader);
CallServiceDescriptor descriptor = source.readParcelable(classLoader);
CallServiceDescriptor handoffDescriptor = source.readParcelable(classLoader);
- List<String> conferenceCapableCallIds = new ArrayList<>();
- source.readList(conferenceCapableCallIds, classLoader);
String parentCallId = source.readString();
List<String> childCallIds = new ArrayList<>();
source.readList(childCallIds, classLoader);
return new InCallCall(id, state, disconnectCauseCode, disconnectCauseMsg, capabilities,
connectTimeMillis, handle, gatewayInfo, descriptor, handoffDescriptor,
- conferenceCapableCallIds, parentCallId, childCallIds);
+ parentCallId, childCallIds);
}
@Override
@@ -226,8 +212,12 @@
destination.writeParcelable(mGatewayInfo, 0);
destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
destination.writeParcelable(mHandoffCallServiceDescriptor, 0);
- destination.writeList(mConferenceCapableCallIds);
destination.writeString(mParentCallId);
destination.writeList(mChildCallIds);
}
+
+ @Override
+ public String toString() {
+ return String.format("[%s, parent:%s, children:%s]", mId, mParentCallId, mChildCallIds);
+ }
}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallService.aidl b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
index 9139aa6..827f331 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallService.aidl
@@ -56,9 +56,9 @@
void stopDtmfTone(String callId);
- void addToConference(String conferenceCallId, in List<String> callIds);
+ void conference(String conferenceCallId, String callId);
- void splitFromConference(String conferenceCallId, String callId);
+ void splitFromConference(String callId);
void onPostDialContinue(String callId, boolean proceed);
}
diff --git a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
index b380293..6e176eb 100644
--- a/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ICallServiceAdapter.aidl
@@ -47,9 +47,11 @@
void setRequestingRingback(String callId, boolean ringing);
- void setCanConferenceWith(String callId, in List<String> conferenceCapableCallIds);
+ void setCanConference(String callId, boolean canConference);
- void setIsConferenced(String conferenceCallId, String callId, boolean isConferenced);
+ void setIsConferenced(String callId, String conferenceCallId);
+
+ void addConferenceCall(String callId, in CallInfo callInfo);
void removeCall(String callId);
diff --git a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
index f144043..5717456 100644
--- a/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecomm/IInCallAdapter.aidl
@@ -48,7 +48,7 @@
void handoffCall(String callId);
- void conferenceWith(String callId, String callIdToConference);
+ void conference(String callId);
void splitFromConference(String callId);
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index ed7f6b8..b935d2a 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -36,6 +36,7 @@
import android.telephony.Rlog;
import android.util.SparseIntArray;
+import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
@@ -166,7 +167,9 @@
// TODO: We don't check for SecurityException here (requires
// CALL_PRIVILEGED permission).
if (scheme.equals("voicemail")) {
- return TelephonyManager.getDefault().getCompleteVoiceMailNumber();
+ long subId = intent.getLongExtra(SUBSCRIPTION_KEY,
+ SubscriptionManager.getDefaultVoiceSubId());
+ return TelephonyManager.getDefault().getCompleteVoiceMailNumber(subId);
}
if (context == null) {
@@ -1144,7 +1147,7 @@
* @return A locally acceptable formatting of the input, or the raw input if
* formatting rules aren't known for the number
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static String formatNumber(String source) {
SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1162,7 +1165,7 @@
* @return The phone number formatted with the given formatting type.
*
* @hide
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static String formatNumber(String source, int defaultFormattingType) {
SpannableStringBuilder text = new SpannableStringBuilder(source);
@@ -1177,7 +1180,7 @@
* @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
* rules are not known for the given locale
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static int getFormatTypeForLocale(Locale locale) {
String country = locale.getCountry();
@@ -1193,7 +1196,7 @@
* @param defaultFormattingType The default formatting rules to apply if the number does
* not begin with +[country_code]
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static void formatNumber(Editable text, int defaultFormattingType) {
int formatType = defaultFormattingType;
@@ -1241,7 +1244,7 @@
*
* @param text the number to be formatted, will be modified with the formatting
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static void formatNanpNumber(Editable text) {
int length = text.length();
@@ -1356,7 +1359,7 @@
* @param text the number to be formatted, will be modified with
* the formatting
*
- * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead
+ * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead
*/
public static void formatJapaneseNumber(Editable text) {
JapanesePhoneNumberFormatter.format(text);
@@ -1560,9 +1563,23 @@
* listed in the RIL / SIM, otherwise return false.
*/
public static boolean isEmergencyNumber(String number) {
+ return isEmergencyNumber(getDefaultVoiceSubId(), number);
+ }
+
+ /**
+ * Checks a given number against the list of
+ * emergency numbers provided by the RIL and SIM card.
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / SIM, otherwise return false.
+ * @hide
+ */
+ public static boolean isEmergencyNumber(long subId, String number) {
// Return true only if the specified number *exactly* matches
// one of the emergency numbers listed by the RIL / SIM.
- return isEmergencyNumberInternal(number, true /* useExactMatch */);
+ return isEmergencyNumberInternal(subId, number, true /* useExactMatch */);
}
/**
@@ -1586,9 +1603,33 @@
* @hide
*/
public static boolean isPotentialEmergencyNumber(String number) {
+ return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number);
+ }
+
+ /**
+ * Checks if given number might *potentially* result in
+ * a call to an emergency service on the current network.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number according to the list managed by the RIL or
+ * SIM, *or* if the specified number simply starts with the same
+ * digits as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / SIM, *or* if the number starts with the
+ * same digits as any of those emergency numbers.
+ * @hide
+ */
+ public static boolean isPotentialEmergencyNumber(long subId, String number) {
// Check against the emergency numbers listed by the RIL / SIM,
// and *don't* require an exact match.
- return isEmergencyNumberInternal(number, false /* useExactMatch */);
+ return isEmergencyNumberInternal(subId, number, false /* useExactMatch */);
}
/**
@@ -1611,7 +1652,32 @@
* listed in the RIL / sim, otherwise return false.
*/
private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) {
- return isEmergencyNumberInternal(number, null, useExactMatch);
+ return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, useExactMatch);
+ }
+
+ /**
+ * Helper function for isEmergencyNumber(String) and
+ * isPotentialEmergencyNumber(String).
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ *
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ * (Setting useExactMatch to false allows you to identify
+ * number that could *potentially* result in emergency calls
+ * since many networks will actually ignore trailing digits
+ * after a valid emergency number.)
+ *
+ * @return true if the number is in the list of emergency numbers
+ * listed in the RIL / sim, otherwise return false.
+ */
+ private static boolean isEmergencyNumberInternal(long subId, String number,
+ boolean useExactMatch) {
+ return isEmergencyNumberInternal(subId, number, null, useExactMatch);
}
/**
@@ -1625,7 +1691,21 @@
* @hide
*/
public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
- return isEmergencyNumberInternal(number,
+ return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
+ }
+
+ /**
+ * Checks if a given number is an emergency number for a specific country.
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @return if the number is an emergency number for the specific country, then return true,
+ * otherwise false
+ * @hide
+ */
+ public static boolean isEmergencyNumber(long subId, String number, String defaultCountryIso) {
+ return isEmergencyNumberInternal(subId, number,
defaultCountryIso,
true /* useExactMatch */);
}
@@ -1652,7 +1732,33 @@
* @hide
*/
public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) {
- return isEmergencyNumberInternal(number,
+ return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
+ }
+
+ /**
+ * Checks if a given number might *potentially* result in a call to an
+ * emergency service, for a specific country.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number in the specified country, *or* if the number
+ * simply starts with the same digits as any emergency number for that
+ * country.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @return true if the number is an emergency number for the specific
+ * country, *or* if the number starts with the same digits as
+ * any of those emergency numbers.
+ * @hide
+ */
+ public static boolean isPotentialEmergencyNumber(long subId, String number,
+ String defaultCountryIso) {
+ return isEmergencyNumberInternal(subId, number,
defaultCountryIso,
false /* useExactMatch */);
}
@@ -1674,6 +1780,29 @@
private static boolean isEmergencyNumberInternal(String number,
String defaultCountryIso,
boolean useExactMatch) {
+ return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, defaultCountryIso,
+ useExactMatch);
+ }
+
+ /**
+ * Helper function for isEmergencyNumber(String, String) and
+ * isPotentialEmergencyNumber(String, String).
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param defaultCountryIso the specific country which the number should be checked against
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * @return true if the number is an emergency number for the specified country.
+ * @hide
+ */
+ private static boolean isEmergencyNumberInternal(long subId, String number,
+ String defaultCountryIso,
+ boolean useExactMatch) {
// If the number passed in is null, just return false:
if (number == null) return false;
@@ -1692,9 +1821,14 @@
// to the list.
number = extractNetworkPortionAlt(number);
+ String numbers = "";
+ int slotId = SubscriptionManager.getSlotId(subId);
// retrieve the list of emergency numbers
// check read-write ecclist property first
- String numbers = SystemProperties.get("ril.ecclist");
+ String ecclist = (slotId == 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
+
+ numbers = SystemProperties.get(ecclist);
+
if (TextUtils.isEmpty(numbers)) {
// then read-only ecclist property since old RIL only uses this
numbers = SystemProperties.get("ro.ril.ecclist");
@@ -1742,15 +1876,29 @@
/**
* Checks if a given number is an emergency number for the country that the user is in.
- * @param context the specific context which the number should be checked against
- * @param number the number to look up.
*
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
* @return true if the specified number is an emergency number for the country the user
* is currently in.
*/
public static boolean isLocalEmergencyNumber(Context context, String number) {
- return isLocalEmergencyNumberInternal(context,
- number,
+ return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
+ }
+
+ /**
+ * Checks if a given number is an emergency number for the country that the user is in.
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
+ * @return true if the specified number is an emergency number for the country the user
+ * is currently in.
+ * @hide
+ */
+ public static boolean isLocalEmergencyNumber(Context context, long subId, String number) {
+ return isLocalEmergencyNumberInternal(subId, number,
+ context,
true /* useExactMatch */);
}
@@ -1767,9 +1915,9 @@
* This method is intended for internal use by the phone app when
* deciding whether to allow ACTION_CALL intents from 3rd party apps
* (where we're required to *not* allow emergency calls to be placed.)
- * @param context the specific context which the number should be checked against
- * @param number the number to look up.
*
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
* @return true if the specified number is an emergency number for a local country, based on the
* CountryDetector.
*
@@ -1777,16 +1925,44 @@
* @hide
*/
public static boolean isPotentialLocalEmergencyNumber(Context context, String number) {
- return isLocalEmergencyNumberInternal(context,
- number,
+ return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
+ }
+
+ /**
+ * Checks if a given number might *potentially* result in a call to an
+ * emergency service, for the country that the user is in. The current
+ * country is determined using the CountryDetector.
+ *
+ * Specifically, this method will return true if the specified number
+ * is an emergency number in the current country, *or* if the number
+ * simply starts with the same digits as any emergency number for the
+ * current country.
+ *
+ * This method is intended for internal use by the phone app when
+ * deciding whether to allow ACTION_CALL intents from 3rd party apps
+ * (where we're required to *not* allow emergency calls to be placed.)
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
+ * @return true if the specified number is an emergency number for a local country, based on the
+ * CountryDetector.
+ *
+ * @hide
+ */
+ public static boolean isPotentialLocalEmergencyNumber(Context context, long subId,
+ String number) {
+ return isLocalEmergencyNumberInternal(subId, number,
+ context,
false /* useExactMatch */);
}
/**
* Helper function for isLocalEmergencyNumber() and
* isPotentialLocalEmergencyNumber().
- * @param context the specific context which the number should be checked against
+ *
* @param number the number to look up.
+ * @param context the specific context which the number should be checked against
* @param useExactMatch if true, consider a number to be an emergency
* number only if it *exactly* matches a number listed in
* the RIL / SIM. If false, a number is considered to be an
@@ -1797,9 +1973,34 @@
* local country, based on the CountryDetector.
*
* @see android.location.CountryDetector
+ * @hide
*/
- private static boolean isLocalEmergencyNumberInternal(Context context,
- String number,
+ private static boolean isLocalEmergencyNumberInternal(String number,
+ Context context,
+ boolean useExactMatch) {
+ return isLocalEmergencyNumberInternal(getDefaultVoiceSubId(), number, context,
+ useExactMatch);
+ }
+
+ /**
+ * Helper function for isLocalEmergencyNumber() and
+ * isPotentialLocalEmergencyNumber().
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @param context the specific context which the number should be checked against
+ * @param useExactMatch if true, consider a number to be an emergency
+ * number only if it *exactly* matches a number listed in
+ * the RIL / SIM. If false, a number is considered to be an
+ * emergency number if it simply starts with the same digits
+ * as any of the emergency numbers listed in the RIL / SIM.
+ *
+ * @return true if the specified number is an emergency number for a
+ * local country, based on the CountryDetector.
+ * @hide
+ */
+ private static boolean isLocalEmergencyNumberInternal(long subId, String number,
+ Context context,
boolean useExactMatch) {
String countryIso;
CountryDetector detector = (CountryDetector) context.getSystemService(
@@ -1812,7 +2013,7 @@
Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
+ countryIso);
}
- return isEmergencyNumberInternal(number, countryIso, useExactMatch);
+ return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch);
}
/**
@@ -1826,10 +2027,26 @@
* to read the VM number.
*/
public static boolean isVoiceMailNumber(String number) {
+ return isVoiceMailNumber(SubscriptionManager.getDefaultSubId(), number);
+ }
+
+ /**
+ * isVoiceMailNumber: checks a given number against the voicemail
+ * number provided by the RIL and SIM card. The caller must have
+ * the READ_PHONE_STATE credential.
+ *
+ * @param subId the subscription id of the SIM.
+ * @param number the number to look up.
+ * @return true if the number is in the list of voicemail. False
+ * otherwise, including if the caller does not have the permission
+ * to read the VM number.
+ * @hide
+ */
+ public static boolean isVoiceMailNumber(long subId, String number) {
String vmNumber;
try {
- vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+ vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(subId);
} catch (SecurityException ex) {
return false;
}
@@ -2561,5 +2778,11 @@
return true;
}
+ /**
+ * Returns Default voice subscription Id.
+ */
+ private static long getDefaultVoiceSubId() {
+ return SubscriptionManager.getDefaultVoiceSubId();
+ }
//==== End of utility methods used only in compareStrictly() =====
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 59ec6f5..c8c3063 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -20,11 +20,13 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
import android.telephony.CellLocation;
import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.SubscriptionManager;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
@@ -48,6 +50,7 @@
* appropriate LISTEN_ flags.
*/
public class PhoneStateListener {
+ private static final String TAG = "PhoneStateListener";
/**
* Stop listening for updates.
@@ -200,18 +203,42 @@
*/
public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO = 0x00002000;
+ /**
+ * Listen for changes to LTE network state
+ *
+ * @see #onLteNetworkStateChanged
+ * @hide
+ */
+ public static final int LISTEN_VOLTE_STATE = 0x00004000;
+
+ /*
+ * Subscription used to listen to the phone state changes
+ * @hide
+ */
+ /** @hide */
+ protected long mSubId = 0;
+
private final Handler mHandler;
public PhoneStateListener() {
- this(Looper.myLooper());
+ this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper());
+ }
+
+ /**
+ * @hide
+ */
+ public PhoneStateListener(long subId) {
+ this(subId, Looper.myLooper());
}
/** @hide */
- public PhoneStateListener(Looper looper) {
+ public PhoneStateListener(long subId, Looper looper) {
+ Rlog.d(TAG, "ctor: subId=" + subId + " looper=" + looper);
+ mSubId = subId;
mHandler = new Handler(looper) {
public void handleMessage(Message msg) {
- //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what)
- // + " msg=" + msg);
+ Rlog.d(TAG, "mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what)
+ + " msg=" + msg);
switch (msg.what) {
case LISTEN_SERVICE_STATE:
PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
@@ -258,6 +285,9 @@
PhoneStateListener.this.onDataConnectionRealTimeInfoChanged(
(DataConnectionRealTimeInfo)msg.obj);
break;
+ case LISTEN_VOLTE_STATE:
+ PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
+ break;
}
}
};
@@ -417,6 +447,15 @@
}
/**
+ * Callback invoked when the service state of LTE network
+ * related to the VoLTE service has changed.
+ * @param stateInfo is the current LTE network information
+ * @hide
+ */
+ public void onVoLteServiceStateChanged(VoLteServiceState stateInfo) {
+ }
+
+ /**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
*/
@@ -484,5 +523,9 @@
Message.obtain(mHandler, LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0,
dcRtInfo).sendToTarget();
}
+
+ public void onVoLteServiceStateChanged(VoLteServiceState lteState) {
+ Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget();
+ }
};
}
diff --git a/telephony/java/android/telephony/SubInfoRecord.aidl b/telephony/java/android/telephony/SubInfoRecord.aidl
new file mode 100755
index 0000000..a2de676
--- /dev/null
+++ b/telephony/java/android/telephony/SubInfoRecord.aidl
@@ -0,0 +1,19 @@
+/*
+* Copyright (C) 2011-2014 MediaTek 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.
+*/
+
+package android.telephony;
+
+parcelable SubInfoRecord;
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java
new file mode 100644
index 0000000..670def7
--- /dev/null
+++ b/telephony/java/android/telephony/SubInfoRecord.java
@@ -0,0 +1,108 @@
+/*
+* Copyright (C) 2011-2014 MediaTek 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.
+*/
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A parcelable holder class of byte[] for ISms aidl implementation
+ * @hide
+ */
+
+public class SubInfoRecord implements Parcelable {
+
+ public long mSubId;
+ public String mIccId;
+ public int mSlotId;
+ public String mDisplayName;
+ public int mNameSource;
+ public int mColor;
+ public String mNumber;
+ public int mDispalyNumberFormat;
+ public int mDataRoaming;
+ public int[] mSimIconRes;
+
+ public SubInfoRecord() {
+ this.mSubId = -1;
+ this.mIccId = "";
+ this.mSlotId = -1;
+ this.mDisplayName = "";
+ this.mNameSource = 0;
+ this.mColor = 0;
+ this.mNumber = "";
+ this.mDispalyNumberFormat = 0;
+ this.mDataRoaming = 0;
+ this.mSimIconRes = new int[2];
+ }
+
+
+ public SubInfoRecord(long subId, String iccId, int slotId, String displayname, int nameSource,
+ int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) {
+ this.mSubId = subId;
+ this.mIccId = iccId;
+ this.mSlotId = slotId;
+ this.mDisplayName = displayname;
+ this.mNameSource = nameSource;
+ this.mColor = mColor;
+ this.mNumber = mNumber;
+ this.mDispalyNumberFormat = displayFormat;
+ this.mDataRoaming = roaming;
+ this.mSimIconRes = iconRes;
+ }
+
+ public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() {
+ public SubInfoRecord createFromParcel(Parcel source) {
+ long mSubId = source.readLong();
+ String mIccId = source.readString();
+ int mSlotId = source.readInt();
+ String mDisplayName = source.readString();
+ int mNameSource = source.readInt();
+ int mColor = source.readInt();
+ String mNumber = source.readString();
+ int mDispalyNumberFormat = source.readInt();
+ int mDataRoaming = source.readInt();
+ int[] iconRes = new int[2];
+ source.readIntArray(iconRes);
+
+ return new SubInfoRecord(mSubId, mIccId, mSlotId, mDisplayName, mNameSource, mColor, mNumber,
+ mDispalyNumberFormat, mDataRoaming, iconRes);
+ }
+
+ public SubInfoRecord[] newArray(int size) {
+ return new SubInfoRecord[size];
+ }
+ };
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mSubId);
+ dest.writeString(mIccId);
+ dest.writeInt(mSlotId);
+ dest.writeString(mDisplayName);
+ dest.writeInt(mNameSource);
+ dest.writeInt(mColor);
+ dest.writeString(mNumber);
+ dest.writeInt(mDispalyNumberFormat);
+ dest.writeInt(mDataRoaming);
+ dest.writeIntArray(mSimIconRes);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
new file mode 100644
index 0000000..859a890
--- /dev/null
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -0,0 +1,708 @@
+/*
+* Copyright (C) 2011-2014 MediaTek 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.
+*/
+
+package android.telephony;
+
+import static android.Manifest.permission.READ_PHONE_STATE;
+
+import android.app.ActivityManagerNative;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.UserHandle;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.telephony.Rlog;
+import android.os.ServiceManager;
+import android.os.RemoteException;
+
+import com.android.internal.telephony.ISub;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+/**
+ *@hide
+ */
+public class SubscriptionManager implements BaseColumns {
+ private static final String LOG_TAG = "SUB";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ // An invalid subscription identifier
+ public static final long INVALID_SUB_ID = Long.MAX_VALUE;
+
+ // The default subscription identifier
+ public static final long DEFAULT_SUB_ID = Long.MAX_VALUE - 1;
+
+ public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ public static final int DEFAULT_INT_VALUE = -100;
+
+ public static final String DEFAULT_STRING_VALUE = "N/A";
+
+ public static final int EXTRA_VALUE_NEW_SIM = 1;
+ public static final int EXTRA_VALUE_REMOVE_SIM = 2;
+ public static final int EXTRA_VALUE_REPOSITION_SIM = 3;
+ public static final int EXTRA_VALUE_NOCHANGE = 4;
+
+ public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus";
+ public static final String INTENT_KEY_SIM_COUNT = "simCount";
+ public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot";
+ public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus";
+
+ /**
+ * The ICC ID of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ICC_ID = "icc_id";
+
+ /**
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String SIM_ID = "sim_id";
+
+ public static final int SIM_NOT_INSERTED = -1;
+
+ /**
+ * The display name of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName;
+
+ /**
+ * The display name source of a SIM.
+ * <P>Type: INT (int)</P>
+ */
+ public static final String NAME_SOURCE = "name_source";
+
+ public static final int DEFAULT_SOURCE = 0;
+
+ public static final int SIM_SOURCE = 1;
+
+ public static final int USER_INPUT = 2;
+
+ /**
+ * The color of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String COLOR = "color";
+
+ public static final int COLOR_1 = 0;
+
+ public static final int COLOR_2 = 1;
+
+ public static final int COLOR_3 = 2;
+
+ public static final int COLOR_4 = 3;
+
+ public static final int COLOR_DEFAULT = COLOR_1;
+
+ /**
+ * The phone number of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String NUMBER = "number";
+
+ /**
+ * The number display format of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+ public static final int DISPALY_NUMBER_NONE = 0;
+
+ public static final int DISPLAY_NUMBER_FIRST = 1;
+
+ public static final int DISPLAY_NUMBER_LAST = 2;
+
+ public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
+
+ /**
+ * Permission for data roaming of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String DATA_ROAMING = "data_roaming";
+
+ public static final int DATA_ROAMING_ENABLE = 1;
+
+ public static final int DATA_ROAMING_DISABLE = 0;
+
+ public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+ private static final int RES_TYPE_BACKGROUND_DARK = 0;
+
+ private static final int RES_TYPE_BACKGROUND_LIGHT = 1;
+
+ private static final int[] sSimBackgroundDarkRes = setSimResource(RES_TYPE_BACKGROUND_DARK);
+
+ private static final int[] sSimBackgroundLightRes = setSimResource(RES_TYPE_BACKGROUND_LIGHT);
+
+ private static HashMap<Integer, Long> mSimInfo = new HashMap<Integer, Long>();
+
+ public SubscriptionManager() {
+ if (DBG) logd("SubscriptionManager created");
+ }
+
+ /**
+ * Get the SubInfoRecord according to an index
+ * @param context Context provided by caller
+ * @param subId The unique SubInfoRecord index in database
+ * @return SubInfoRecord, maybe null
+ */
+ public static SubInfoRecord getSubInfoUsingSubId(Context context, long subId) {
+ if (VDBG) logd("[getSubInfoUsingSubIdx]+ subId:" + subId);
+ if (subId <= 0) {
+ if (VDBG) logd("[getSubInfoUsingSubIdx]- subId <= 0");
+ return null;
+ }
+
+ SubInfoRecord subInfo = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ subInfo = iSub.getSubInfoUsingSubId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return subInfo;
+
+ }
+
+ /**
+ * Get the SubInfoRecord according to an IccId
+ * @param context Context provided by caller
+ * @param iccId the IccId of SIM card
+ * @return SubInfoRecord, maybe null
+ */
+ public static List<SubInfoRecord> getSubInfoUsingIccId(Context context, String iccId) {
+ if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId);
+ if (iccId == null) {
+ logd("[getSubInfoUsingIccId]- null iccid");
+ return null;
+ }
+
+ List<SubInfoRecord> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getSubInfoUsingIccId(iccId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the SubInfoRecord according to slotId
+ * @param context Context provided by caller
+ * @param slotId the slot which the SIM is inserted
+ * @return SubInfoRecord, maybe null
+ */
+ public static List<SubInfoRecord> getSubInfoUsingSlotId(Context context, int slotId) {
+ if (VDBG) logd("[getSubInfoUsingSlotId]- slotId=" + slotId);
+ if (slotId < 0) {
+ logd("[getSubInfoUsingSlotId]- return null, slotId < 0");
+ return null;
+ }
+
+ List<SubInfoRecord> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getSubInfoUsingSlotId(slotId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Get all the SubInfoRecord(s) in subinfo database
+ * @param context Context provided by caller
+ * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+ */
+ public static List<SubInfoRecord> getAllSubInfoList(Context context) {
+ if (VDBG) logd("[getAllSubInfoList]+");
+
+ List<SubInfoRecord> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getAllSubInfoList();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+ * @param context Context provided by caller
+ * @return Array list of currently inserted SubInfoRecord(s)
+ */
+ public static List<SubInfoRecord> getActivatedSubInfoList(Context context) {
+ if (VDBG) logd("[getActivatedSubInfoList]+");
+
+ List<SubInfoRecord> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getActivatedSubInfoList();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the SUB count of all SUB(s) in subinfo database
+ * @param context Context provided by caller
+ * @return all SIM count in database, include what was inserted before
+ */
+ public static int getAllSubInfoCount(Context context) {
+ if (VDBG) logd("[getAllSubInfoCount]+");
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getAllSubInfoCount();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ /**
+ * Add a new SubInfoRecord to subinfo database if needed
+ * @param context Context provided by caller
+ * @param iccId the IccId of the SIM card
+ * @param slotId the slot which the SIM is inserted
+ * @return the URL of the newly created row or the updated row
+ */
+ public static Uri addSubInfoRecord(Context context, String iccId, int slotId) {
+ if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId);
+ if (iccId == null) {
+ logd("[addSubInfoRecord]- null iccId");
+ }
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ // FIXME: This returns 1 on success, 0 on error should should we return it?
+ iSub.addSubInfoRecord(iccId, slotId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ // FIXME: Always returns null?
+ return null;
+
+ }
+
+ /**
+ * Set SIM color by simInfo index
+ * @param context Context provided by caller
+ * @param color the color of the SIM
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setColor(Context context, int color, long subId) {
+ if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId);
+ int size = sSimBackgroundDarkRes.length;
+ if (subId <= 0 || color < 0 || color >= size) {
+ logd("[setColor]- fail");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setColor(color, subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Set display name by simInfo index
+ * @param context Context provided by caller
+ * @param displayName the display name of SIM card
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setDisplayName(Context context, String displayName, long subId) {
+ return setDisplayName(context, displayName, subId, -1);
+ }
+
+ /**
+ * Set display name by simInfo index with name source
+ * @param context Context provided by caller
+ * @param displayName the display name of SIM card
+ * @param subId the unique SubInfoRecord index in database
+ * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
+ * @return the number of records updated
+ */
+ public static int setDisplayName(Context context, String displayName, long subId, long nameSource) {
+ if (VDBG) logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource);
+ if (subId <= 0) {
+ logd("[setDisplayName]- fail");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Set phone number by subId
+ * @param context Context provided by caller
+ * @param number the phone number of the SIM
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setDispalyNumber(Context context, String number, long subId) {
+ if (VDBG) logd("[setDispalyNumber]+ number:" + number + " subId:" + subId);
+ if (number == null || subId <= 0) {
+ logd("[setDispalyNumber]- fail");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setDispalyNumber(number, subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
+ * @param context Context provided by caller
+ * @param format the display format of phone number
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setDisplayNumberFormat(Context context, int format, long subId) {
+ if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId);
+ if (format < 0 || subId <= 0) {
+ logd("[setDisplayNumberFormat]- fail, return -1");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setDisplayNumberFormat(format, subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ /**
+ * Set data roaming by simInfo index
+ * @param context Context provided by caller
+ * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ public static int setDataRoaming(Context context, int roaming, long subId) {
+ if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId);
+ if (roaming < 0 || subId <= 0) {
+ logd("[setDataRoaming]- fail");
+ return -1;
+ }
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.setDataRoaming(roaming, subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+ }
+
+ public static int getSlotId(long subId) {
+ if (VDBG) logd("[getSlotId]+ subId:" + subId);
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getSlotId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return result;
+
+ }
+
+ public static long[] getSubId(int slotId) {
+ if (VDBG) logd("[getSubId]+ slotId:" + slotId);
+
+ long[] subId = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ subId = iSub.getSubId(slotId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return subId;
+ }
+
+ public static int getPhoneId(long subId) {
+ if (VDBG) logd("[getPhoneId]+ subId=" + subId);
+
+ int result = 0;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getPhoneId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ if (VDBG) logd("[getPhoneId]- phonId=" + result);
+ return result;
+
+ }
+
+ private static int[] setSimResource(int type) {
+ int[] simResource = null;
+
+ switch (type) {
+ case RES_TYPE_BACKGROUND_DARK:
+ simResource = new int[] {
+ com.android.internal.R.drawable.sim_dark_blue,
+ com.android.internal.R.drawable.sim_dark_orange,
+ com.android.internal.R.drawable.sim_dark_green,
+ com.android.internal.R.drawable.sim_dark_purple
+ };
+ break;
+ case RES_TYPE_BACKGROUND_LIGHT:
+ simResource = new int[] {
+ com.android.internal.R.drawable.sim_light_blue,
+ com.android.internal.R.drawable.sim_light_orange,
+ com.android.internal.R.drawable.sim_light_green,
+ com.android.internal.R.drawable.sim_light_purple
+ };
+ break;
+ }
+
+ return simResource;
+ }
+
+ private static void logd(String msg) {
+ Rlog.d(LOG_TAG, "[SubManager] " + msg);
+ }
+
+ public static long normalizeSubId(long subId) {
+ long retVal = (subId == DEFAULT_SUB_ID) ? getDefaultSubId() : subId;
+ Rlog.d(LOG_TAG, "[SubManager] normalizeSubId subId=" + retVal);
+ return retVal;
+ }
+
+ public static boolean validSubId(long subId) {
+ return (subId != DEFAULT_SUB_ID) && (subId != -1);
+ }
+
+ /**
+ * @return the "system" defaultSubId on a voice capable device this
+ * will be getDefaultVoiceSubId() and on a data only device it will be
+ * getDefaultDataSubId().
+ */
+ public static long getDefaultSubId() {
+ long subId = 1;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ subId = iSub.getDefaultSubId();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ if (VDBG) logd("getDefaultSubId=" + subId);
+ return subId;
+ }
+
+ public static long getDefaultVoiceSubId() {
+ long subId = 1;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ subId = iSub.getDefaultVoiceSubId();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ if (VDBG) logd("getDefaultSubId, sub id = " + subId);
+ return subId;
+ }
+
+ public static void setDefaultVoiceSubId(long subId) {
+ if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId);
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.setDefaultVoiceSubId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ public static long getPreferredSmsSubId() {
+ // FIXME add framework support to get the preferred sub
+ return getDefaultSubId();
+ }
+
+ public static long getPreferredDataSubId() {
+ // FIXME add framework support to get the preferred sub
+ return getDefaultSubId();
+ }
+
+ public static long getDefaultDataSubId() {
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ return iSub.getDefaultDataSubId();
+ } else {
+ return -1;
+ }
+ } catch (RemoteException ex) {
+ return -1;
+ }
+ }
+
+ public static void setDefaultDataSubId(long subId) {
+ if (VDBG) logd("setDataSubscription sub id = " + subId);
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.setDefaultDataSubId(subId);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ public static void clearSubInfo()
+ {
+ if (VDBG) logd("[clearSubInfo]+");
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.clearSubInfo();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return;
+ }
+
+ public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) {
+ long [] subId = SubscriptionManager.getSubId(phoneId);
+ if ((subId != null) && (subId.length >= 1)) {
+ if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId);
+ intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); //FIXME: RENAME TO PHONE_ID_KEY ??
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId[0]);
+ } else {
+ logd("putPhoneIdAndSubIdExtra: no valid subs");
+ }
+ }
+}
+
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3f65bca..aaee99f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -86,6 +86,22 @@
private final Context mContext;
+ private static String multiSimConfig =
+ SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+
+ /** Enum indicating multisim variants
+ * DSDS - Dual SIM Dual Standby
+ * DSDA - Dual SIM Dual Active
+ * TSTS - Triple SIM Triple Standby
+ **/
+ /** @hide */
+ public enum MultiSimVariants {
+ DSDS,
+ DSDA,
+ TSTS,
+ UNKNOWN
+ };
+
/** @hide */
public TelephonyManager(Context context) {
Context appContext = context.getApplicationContext();
@@ -114,11 +130,61 @@
return sInstance;
}
+
+ /**
+ * Returns the multi SIM variant
+ * Returns DSDS for Dual SIM Dual Standby
+ * Returns DSDA for Dual SIM Dual Active
+ * Returns TSTS for Triple SIM Triple Standby
+ * Returns UNKNOWN for others
+ */
+ /** {@hide} */
+ public MultiSimVariants getMultiSimConfiguration() {
+ String mSimConfig =
+ SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+ if (mSimConfig.equals("dsds")) {
+ return MultiSimVariants.DSDS;
+ } else if (mSimConfig.equals("dsda")) {
+ return MultiSimVariants.DSDA;
+ } else if (mSimConfig.equals("tsts")) {
+ return MultiSimVariants.TSTS;
+ } else {
+ return MultiSimVariants.UNKNOWN;
+ }
+ }
+
+
+ /**
+ * Returns the number of phones available.
+ * Returns 1 for Single standby mode (Single SIM functionality)
+ * Returns 2 for Dual standby mode.(Dual SIM functionality)
+ */
+ /** {@hide} */
+ public int getPhoneCount() {
+ int phoneCount = 1;
+ switch (getMultiSimConfiguration()) {
+ case DSDS:
+ case DSDA:
+ phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
+ break;
+ case TSTS:
+ phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM;
+ break;
+ }
+ return phoneCount;
+ }
+
/** {@hide} */
public static TelephonyManager from(Context context) {
return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
}
+ /** {@hide} */
+ public boolean isMultiSimEnabled() {
+ return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") ||
+ multiSimConfig.equals("tsts"));
+ }
+
//
// Broadcast Intent actions
//
@@ -529,8 +595,23 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getDeviceId() {
+ return getDeviceId(getDefaultSim());
+ }
+
+ /**
+ * Returns the unique device ID of a subscription, for example, the IMEI for
+ * GSM and the MEID for CDMA phones. Return null if device ID is not available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param slotId of which deviceID is returned
+ */
+ /** {@hide} */
+ public String getDeviceId(int slotId) {
+ long[] subId = SubscriptionManager.getSubId(slotId);
try {
- return getSubscriberInfo().getDeviceId();
+ return getSubscriberInfo().getDeviceIdUsingSubId(subId[0]);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -578,8 +659,23 @@
* @hide
*/
public void enableLocationUpdates() {
+ enableLocationUpdates(getDefaultSubscription());
+ }
+
+ /**
+ * Enables location update notifications for a subscription.
+ * {@link PhoneStateListener#onCellLocationChanged
+ * PhoneStateListener.onCellLocationChanged} will be called on location updates.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
+ * CONTROL_LOCATION_UPDATES}
+ *
+ * @param subId for which the location updates are enabled
+ */
+ /** @hide */
+ public void enableLocationUpdates(long subId) {
try {
- getITelephony().enableLocationUpdates();
+ getITelephony().enableLocationUpdatesUsingSubId(subId);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -595,8 +691,13 @@
* @hide
*/
public void disableLocationUpdates() {
+ disableLocationUpdates(getDefaultSubscription());
+ }
+
+ /** @hide */
+ public void disableLocationUpdates(long subId) {
try {
- getITelephony().disableLocationUpdates();
+ getITelephony().disableLocationUpdatesUsingSubId(subId);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -644,22 +745,37 @@
* {@hide}
*/
public int getCurrentPhoneType() {
+ return getCurrentPhoneType(getDefaultSubscription());
+ }
+
+ /**
+ * Returns a constant indicating the device phone type for a subscription.
+ *
+ * @see #PHONE_TYPE_NONE
+ * @see #PHONE_TYPE_GSM
+ * @see #PHONE_TYPE_CDMA
+ *
+ * @param subId for which phone type is returned
+ */
+ /** {@hide} */
+ public int getCurrentPhoneType(long subId) {
+
try{
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getActivePhoneType();
+ return telephony.getActivePhoneTypeUsingSubId(subId);
} else {
// This can happen when the ITelephony interface is not up yet.
- return getPhoneTypeFromProperty();
+ return getPhoneTypeFromProperty(subId);
}
} catch (RemoteException ex) {
// This shouldn't happen in the normal case, as a backup we
// read from the system property.
- return getPhoneTypeFromProperty();
+ return getPhoneTypeFromProperty(subId);
} catch (NullPointerException ex) {
// This shouldn't happen in the normal case, as a backup we
// read from the system property.
- return getPhoneTypeFromProperty();
+ return getPhoneTypeFromProperty(subId);
}
}
@@ -680,20 +796,35 @@
}
private int getPhoneTypeFromProperty() {
- int type =
- SystemProperties.getInt(TelephonyProperties.CURRENT_ACTIVE_PHONE,
- getPhoneTypeFromNetworkType());
- return type;
+ return getPhoneTypeFromProperty(getDefaultSubscription());
+ }
+
+ /** {@hide} */
+ private int getPhoneTypeFromProperty(long subId) {
+ String type =
+ getTelephonyProperty
+ (TelephonyProperties.CURRENT_ACTIVE_PHONE, subId, null);
+ if (type != null) {
+ return (Integer.parseInt(type));
+ } else {
+ return getPhoneTypeFromNetworkType(subId);
+ }
}
private int getPhoneTypeFromNetworkType() {
+ return getPhoneTypeFromNetworkType(getDefaultSubscription());
+ }
+
+ /** {@hide} */
+ private int getPhoneTypeFromNetworkType(long subId) {
// When the system property CURRENT_ACTIVE_PHONE, has not been set,
// use the system property for default network type.
// This is a fail safe, and can only happen at first boot.
- int mode = SystemProperties.getInt("ro.telephony.default_network", -1);
- if (mode == -1)
- return PHONE_TYPE_NONE;
- return getPhoneType(mode);
+ String mode = getTelephonyProperty("ro.telephony.default_network", subId, null);
+ if (mode != null) {
+ return TelephonyManager.getPhoneType(Integer.parseInt(mode));
+ }
+ return TelephonyManager.PHONE_TYPE_NONE;
}
/**
@@ -828,7 +959,23 @@
* on a CDMA network).
*/
public String getNetworkOperatorName() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA);
+ return getNetworkOperatorName(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the alphabetic name of current registered operator
+ * for a particular subscription.
+ * <p>
+ * Availability: Only when user is registered to a network. Result may be
+ * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+ * on a CDMA network).
+ * @param subId
+ */
+ /** {@hide} */
+ public String getNetworkOperatorName(long subId) {
+
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
+ subId, "");
}
/**
@@ -839,17 +986,48 @@
* on a CDMA network).
*/
public String getNetworkOperator() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC);
+ return getNetworkOperator(getDefaultSubscription());
}
/**
+ * Returns the numeric name (MCC+MNC) of current registered operator
+ * for a particular subscription.
+ * <p>
+ * Availability: Only when user is registered to a network. Result may be
+ * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+ * on a CDMA network).
+ *
+ * @param subId
+ */
+ /** {@hide} */
+ public String getNetworkOperator(long subId) {
+
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC,
+ subId, "");
+ }
+
+ /**
* Returns true if the device is considered roaming on the current
* network, for GSM purposes.
* <p>
* Availability: Only when user registered to a network.
*/
public boolean isNetworkRoaming() {
- return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
+ return isNetworkRoaming(getDefaultSubscription());
+ }
+
+ /**
+ * Returns true if the device is considered roaming on the current
+ * network for a subscription.
+ * <p>
+ * Availability: Only when user registered to a network.
+ *
+ * @param subId
+ */
+ /** {@hide} */
+ public boolean isNetworkRoaming(long subId) {
+ return "true".equals(getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
+ subId, null));
}
/**
@@ -861,7 +1039,23 @@
* on a CDMA network).
*/
public String getNetworkCountryIso() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY);
+ return getNetworkCountryIso(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the ISO country code equivalent of the current registered
+ * operator's MCC (Mobile Country Code) of a subscription.
+ * <p>
+ * Availability: Only when user is registered to a network. Result may be
+ * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
+ * on a CDMA network).
+ *
+ * @param subId for which Network CountryIso is returned
+ */
+ /** {@hide} */
+ public String getNetworkCountryIso(long subId) {
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY,
+ subId, "");
}
/** Network type is unknown */
@@ -908,6 +1102,49 @@
/**
* Returns a constant indicating the radio technology (network type)
+ * currently in use on the device for a subscription.
+ * @return the network type
+ *
+ * @param subId for which network type is returned
+ *
+ * @see #NETWORK_TYPE_UNKNOWN
+ * @see #NETWORK_TYPE_GPRS
+ * @see #NETWORK_TYPE_EDGE
+ * @see #NETWORK_TYPE_UMTS
+ * @see #NETWORK_TYPE_HSDPA
+ * @see #NETWORK_TYPE_HSUPA
+ * @see #NETWORK_TYPE_HSPA
+ * @see #NETWORK_TYPE_CDMA
+ * @see #NETWORK_TYPE_EVDO_0
+ * @see #NETWORK_TYPE_EVDO_A
+ * @see #NETWORK_TYPE_EVDO_B
+ * @see #NETWORK_TYPE_1xRTT
+ * @see #NETWORK_TYPE_IDEN
+ * @see #NETWORK_TYPE_LTE
+ * @see #NETWORK_TYPE_EHRPD
+ * @see #NETWORK_TYPE_HSPAP
+ */
+ /** {@hide} */
+ public int getNetworkType(long subId) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getNetworkTypeUsingSubId(subId);
+ } else {
+ // This can happen when the ITelephony interface is not up yet.
+ return NETWORK_TYPE_UNKNOWN;
+ }
+ } catch(RemoteException ex) {
+ // This shouldn't happen in the normal case
+ return NETWORK_TYPE_UNKNOWN;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return NETWORK_TYPE_UNKNOWN;
+ }
+ }
+
+ /**
+ * Returns a constant indicating the radio technology (network type)
* currently in use on the device for data transmission.
* @return the network type
*
@@ -931,10 +1168,22 @@
* @hide
*/
public int getDataNetworkType() {
+ return getDataNetworkType(getDefaultSubscription());
+ }
+
+ /**
+ * Returns a constant indicating the radio technology (network type)
+ * currently in use on the device for data transmission for a subscription
+ * @return the network type
+ *
+ * @param subId for which network type is returned
+ */
+ /** {@hide} */
+ public int getDataNetworkType(long subId) {
try{
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getDataNetworkType();
+ return telephony.getDataNetworkTypeUsingSubId(subId);
} else {
// This can happen when the ITelephony interface is not up yet.
return NETWORK_TYPE_UNKNOWN;
@@ -954,10 +1203,19 @@
* @hide
*/
public int getVoiceNetworkType() {
+ return getVoiceNetworkType(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the NETWORK_TYPE_xxxx for voice for a subId
+ *
+ */
+ /** {@hide} */
+ public int getVoiceNetworkType(long subId) {
try{
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getVoiceNetworkType();
+ return telephony.getVoiceNetworkTypeUsingSubId(subId);
} else {
// This can happen when the ITelephony interface is not up yet.
return NETWORK_TYPE_UNKNOWN;
@@ -1023,6 +1281,13 @@
return getNetworkTypeName(getNetworkType());
}
+ /**
+ * Returns a string representation of the radio technology (network type)
+ * currently in use on the device.
+ * @param subId for which network type is returned
+ * @return the name of the radio technology
+ *
+ */
/** {@hide} */
public static String getNetworkTypeName(int type) {
switch (type) {
@@ -1093,8 +1358,20 @@
* @return true if a ICC card is present
*/
public boolean hasIccCard() {
+ return hasIccCard(getDefaultSim());
+ }
+
+ /**
+ * @return true if a ICC card is present for a subscription
+ *
+ * @param slotId for which icc card presence is checked
+ */
+ /** {@hide} */
+ // FIXME Input argument slotId should be of type int
+ public boolean hasIccCard(long slotId) {
+
try {
- return getITelephony().hasIccCard();
+ return getITelephony().hasIccCardUsingSlotId(slotId);
} catch (RemoteException ex) {
// Assume no ICC card if remote exception which shouldn't happen
return false;
@@ -1117,7 +1394,30 @@
* @see #SIM_STATE_CARD_IO_ERROR
*/
public int getSimState() {
- String prop = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE);
+ return getSimState(getDefaultSim());
+ }
+
+ /**
+ * Returns a constant indicating the state of the
+ * device SIM card in a slot.
+ *
+ * @param slotId
+ *
+ * @see #SIM_STATE_UNKNOWN
+ * @see #SIM_STATE_ABSENT
+ * @see #SIM_STATE_PIN_REQUIRED
+ * @see #SIM_STATE_PUK_REQUIRED
+ * @see #SIM_STATE_NETWORK_LOCKED
+ * @see #SIM_STATE_READY
+ */
+ /** {@hide} */
+ // FIXME the argument to pass is subId ??
+ public int getSimState(int slotId) {
+ long[] subId = SubscriptionManager.getSubId(slotId);
+ // FIXME Do not use a property to determine SIM_STATE, call
+ // appropriate method on some object.
+ String prop =
+ getTelephonyProperty(TelephonyProperties.PROPERTY_SIM_STATE, subId[0], "");
if ("ABSENT".equals(prop)) {
return SIM_STATE_ABSENT;
}
@@ -1150,7 +1450,27 @@
* @see #getSimState
*/
public String getSimOperator() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
+ long subId = getDefaultSubscription();
+ Rlog.d(TAG, "getSimOperator(): default subId=" + subId);
+ return getSimOperator(subId);
+ }
+
+ /**
+ * Returns the MCC+MNC (mobile country code + mobile network code) of the
+ * provider of the SIM for a particular subscription. 5 or 6 decimal digits.
+ * <p>
+ * Availability: SIM state must be {@link #SIM_STATE_READY}
+ *
+ * @see #getSimState
+ *
+ * @param subId for which SimOperator is returned
+ */
+ /** {@hide} */
+ public String getSimOperator(long subId) {
+ String operator = getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC,
+ subId, "");
+ Rlog.d(TAG, "getSimOperator: subId=" + subId + " operator=" + operator);
+ return operator;
}
/**
@@ -1161,14 +1481,40 @@
* @see #getSimState
*/
public String getSimOperatorName() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA);
+ return getSimOperatorName(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the Service Provider Name (SPN).
+ * <p>
+ * Availability: SIM state must be {@link #SIM_STATE_READY}
+ *
+ * @see #getSimState
+ *
+ * @param subId for which SimOperatorName is returned
+ */
+ /** {@hide} */
+ public String getSimOperatorName(long subId) {
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA,
+ subId, "");
}
/**
* Returns the ISO country code equivalent for the SIM provider's country code.
*/
public String getSimCountryIso() {
- return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY);
+ return getSimCountryIso(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the ISO country code equivalent for the SIM provider's country code.
+ *
+ * @param subId for which SimCountryIso is returned
+ */
+ /** {@hide} */
+ public String getSimCountryIso(long subId) {
+ return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
+ subId, "");
}
/**
@@ -1179,8 +1525,21 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getSimSerialNumber() {
+ return getSimSerialNumber(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the serial number for the given subscription, if applicable. Return null if it is
+ * unavailable.
+ * <p>
+ * @param subId for which Sim Serial number is returned
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ */
+ /** {@hide} */
+ public String getSimSerialNumber(long subId) {
try {
- return getSubscriberInfo().getIccSerialNumber();
+ return getSubscriberInfo().getIccSerialNumberUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1200,8 +1559,23 @@
* @hide
*/
public int getLteOnCdmaMode() {
+ return getLteOnCdmaMode(getDefaultSubscription());
+ }
+
+ /**
+ * Return if the current radio is LTE on CDMA for Subscription. This
+ * is a tri-state return value as for a period of time
+ * the mode may be unknown.
+ *
+ * @param subId for which radio is LTE on CDMA is returned
+ * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
+ * or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
+ *
+ */
+ /** {@hide} */
+ public int getLteOnCdmaMode(long subId) {
try {
- return getITelephony().getLteOnCdmaMode();
+ return getITelephony().getLteOnCdmaModeUsingSubId(subId);
} catch (RemoteException ex) {
// Assume no ICC card if remote exception which shouldn't happen
return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
@@ -1225,8 +1599,23 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getSubscriberId() {
+ return getSubscriberId(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the unique subscriber ID, for example, the IMSI for a GSM phone
+ * for a subscription.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subId whose subscriber id is returned
+ */
+ /** {@hide} */
+ public String getSubscriberId(long subId) {
try {
- return getSubscriberInfo().getSubscriberId();
+ return getSubscriberInfo().getSubscriberIdUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1254,6 +1643,27 @@
}
/**
+ * Returns the Group Identifier Level1 for a GSM phone for a particular subscription.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subscription whose subscriber id is returned
+ */
+ /** {@hide} */
+ public String getGroupIdLevel1(long subId) {
+ try {
+ return getSubscriberInfo().getGroupIdLevel1UsingSubId(subId);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
* Returns the phone number string for line 1, for example, the MSISDN
* for a GSM phone. Return null if it is unavailable.
* <p>
@@ -1261,8 +1671,22 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getLine1Number() {
+ return getLine1Number(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the phone number string for line 1, for example, the MSISDN
+ * for a GSM phone for a particular subscription. Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subId whose phone number for line 1 is returned
+ */
+ /** {@hide} */
+ public String getLine1Number(long subId) {
try {
- return getSubscriberInfo().getLine1Number();
+ return getSubscriberInfo().getLine1NumberUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1281,8 +1705,23 @@
* nobody seems to call this.
*/
public String getLine1AlphaTag() {
+ return getLine1AlphaTag(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the alphabetic identifier associated with the line 1 number
+ * for a subscription.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param subId whose alphabetic identifier associated with line 1 is returned
+ * nobody seems to call this.
+ */
+ /** {@hide} */
+ public String getLine1AlphaTag(long subId) {
try {
- return getSubscriberInfo().getLine1AlphaTag();
+ return getSubscriberInfo().getLine1AlphaTagUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1301,8 +1740,22 @@
* @hide
*/
public String getMsisdn() {
+ return getMsisdn(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the MSISDN string.
+ * for a GSM phone. Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param subId for which msisdn is returned
+ */
+ /** {@hide} */
+ public String getMsisdn(long subId) {
try {
- return getSubscriberInfo().getMsisdn();
+ return getSubscriberInfo().getMsisdnUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1318,8 +1771,21 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getVoiceMailNumber() {
+ return getVoiceMailNumber(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the voice mail number for a subscription.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param subId whose voice mail number is returned
+ */
+ /** {@hide} */
+ public String getVoiceMailNumber(long subId) {
try {
- return getSubscriberInfo().getVoiceMailNumber();
+ return getSubscriberInfo().getVoiceMailNumberUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1337,8 +1803,21 @@
* @hide
*/
public String getCompleteVoiceMailNumber() {
+ return getCompleteVoiceMailNumber(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the complete voice mail number. Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED}
+ *
+ * @param subId
+ */
+ /** {@hide} */
+ public String getCompleteVoiceMailNumber(long subId) {
try {
- return getSubscriberInfo().getCompleteVoiceMailNumber();
+ return getSubscriberInfo().getCompleteVoiceMailNumberUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1355,8 +1834,20 @@
* @hide
*/
public int getVoiceMessageCount() {
+ return getVoiceMessageCount(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the voice mail count for a subscription. Return 0 if unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param subId whose voice message count is returned
+ */
+ /** {@hide} */
+ public int getVoiceMessageCount(long subId) {
try {
- return getITelephony().getVoiceMessageCount();
+ return getITelephony().getVoiceMessageCountUsingSubId(subId);
} catch (RemoteException ex) {
return 0;
} catch (NullPointerException ex) {
@@ -1373,8 +1864,22 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getVoiceMailAlphaTag() {
+ return getVoiceMailAlphaTag(getDefaultSubscription());
+ }
+
+ /**
+ * Retrieves the alphabetic identifier associated with the voice
+ * mail number for a subscription.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param subId whose alphabetic identifier associated with the
+ * voice mail number is returned
+ */
+ /** {@hide} */
+ public String getVoiceMailAlphaTag(long subId) {
try {
- return getSubscriberInfo().getVoiceMailAlphaTag();
+ return getSubscriberInfo().getVoiceMailAlphaTagUsingSubId(subId);
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1437,7 +1942,6 @@
return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
}
-
/** Device call state: No activity. */
public static final int CALL_STATE_IDLE = 0;
/** Device call state: Ringing. A new call arrived and is
@@ -1453,8 +1957,19 @@
* Returns a constant indicating the call state (cellular) on the device.
*/
public int getCallState() {
+ return getCallState(getDefaultSubscription());
+ }
+
+ /**
+ * Returns a constant indicating the call state (cellular) on the device
+ * for a subscription.
+ *
+ * @param subId whose call state is returned
+ */
+ /** {@hide} */
+ public int getCallState(long subId) {
try {
- return getITelephony().getCallState();
+ return getITelephony().getCallStateUsingSubId(subId);
} catch (RemoteException ex) {
// the phone process is restarting.
return CALL_STATE_IDLE;
@@ -1575,8 +2090,8 @@
public void listen(PhoneStateListener listener, int events) {
String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
try {
- Boolean notifyNow = true;
- sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
+ Boolean notifyNow = (getITelephony() != null);
+ sRegistry.listenUsingSubId(listener.mSubId, pkgForDebug, listener.callback, events, notifyNow);
} catch (RemoteException ex) {
// system process dead
} catch (NullPointerException ex) {
@@ -1590,8 +2105,16 @@
* @hide
*/
public int getCdmaEriIconIndex() {
+ return getCdmaEriIconIndex(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the CDMA ERI icon index to display for a subscription
+ */
+ /** {@hide} */
+ public int getCdmaEriIconIndex(long subId) {
try {
- return getITelephony().getCdmaEriIconIndex();
+ return getITelephony().getCdmaEriIconIndexUsingSubId(subId);
} catch (RemoteException ex) {
// the phone process is restarting.
return -1;
@@ -1608,8 +2131,18 @@
* @hide
*/
public int getCdmaEriIconMode() {
+ return getCdmaEriIconMode(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the CDMA ERI icon mode for a subscription.
+ * 0 - ON
+ * 1 - FLASHING
+ */
+ /** {@hide} */
+ public int getCdmaEriIconMode(long subId) {
try {
- return getITelephony().getCdmaEriIconMode();
+ return getITelephony().getCdmaEriIconModeUsingSubId(subId);
} catch (RemoteException ex) {
// the phone process is restarting.
return -1;
@@ -1624,8 +2157,17 @@
* @hide
*/
public String getCdmaEriText() {
+ return getCdmaEriText(getDefaultSubscription());
+ }
+
+ /**
+ * Returns the CDMA ERI text, of a subscription
+ *
+ */
+ /** {@hide} */
+ public String getCdmaEriText(long subId) {
try {
- return getITelephony().getCdmaEriText();
+ return getITelephony().getCdmaEriTextUsingSubId(subId);
} catch (RemoteException ex) {
// the phone process is restarting.
return null;
@@ -1924,6 +2466,286 @@
}
/**
+ * Returns Default subscription.
+ */
+ private static long getDefaultSubscription() {
+ return SubscriptionManager.getDefaultSubId();
+ }
+
+ /** {@hide} */
+ public int getDefaultSim() {
+ //TODO Need to get it from Telephony Devcontroller
+ return 0;
+ }
+
+ /**
+ * Sets the telephony property with the value specified.
+ *
+ * @hide
+ */
+ public static void setTelephonyProperty(String property, long subId, String value) {
+ String propVal = "";
+ String p[] = null;
+ String prop = SystemProperties.get(property);
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+
+ if (value == null) {
+ value = "";
+ }
+
+ if (prop != null) {
+ p = prop.split(",");
+ }
+
+ if (phoneId < 0) return;
+
+ for (int i = 0; i < phoneId; i++) {
+ String str = "";
+ if ((p != null) && (i < p.length)) {
+ str = p[i];
+ }
+ propVal = propVal + str + ",";
+ }
+
+ propVal = propVal + value;
+ if (p != null) {
+ for (int i = phoneId + 1; i < p.length; i++) {
+ propVal = propVal + "," + p[i];
+ }
+ }
+
+ // TODO: workaround for QC
+ if (property.length() > SystemProperties.PROP_NAME_MAX || propVal.length() > SystemProperties.PROP_VALUE_MAX) {
+ Rlog.d(TAG, "setTelephonyProperty length too long:" + property + ", " + propVal);
+ return;
+ }
+
+ Rlog.d(TAG, "setTelephonyProperty property=" + property + " propVal=" + propVal);
+ SystemProperties.set(property, propVal);
+ }
+
+ /**
+ * Convenience function for retrieving a value from the secure settings
+ * value list as an integer. Note that internally setting values are
+ * always stored as strings; this function converts the string to an
+ * integer for you.
+ * <p>
+ * This version does not take a default value. If the setting has not
+ * been set, or the string value is not a number,
+ * it throws {@link SettingNotFoundException}.
+ *
+ * @param cr The ContentResolver to access.
+ * @param name The name of the setting to retrieve.
+ * @param index The index of the list
+ *
+ * @throws SettingNotFoundException Thrown if a setting by the given
+ * name can't be found or the setting value is not an integer.
+ *
+ * @return The value at the given index of settings.
+ * @hide
+ */
+ public static int getIntAtIndex(android.content.ContentResolver cr,
+ String name, int index)
+ throws android.provider.Settings.SettingNotFoundException {
+ String v = android.provider.Settings.Global.getString(cr, name);
+ if (v != null) {
+ String valArray[] = v.split(",");
+ if ((index >= 0) && (index < valArray.length) && (valArray[index] != null)) {
+ try {
+ return Integer.parseInt(valArray[index]);
+ } catch (NumberFormatException e) {
+ //Log.e(TAG, "Exception while parsing Integer: ", e);
+ }
+ }
+ }
+ throw new android.provider.Settings.SettingNotFoundException(name);
+ }
+
+ /**
+ * Convenience function for updating settings value as coma separated
+ * integer values. This will either create a new entry in the table if the
+ * given name does not exist, or modify the value of the existing row
+ * with that name. Note that internally setting values are always
+ * stored as strings, so this function converts the given value to a
+ * string before storing it.
+ *
+ * @param cr The ContentResolver to access.
+ * @param name The name of the setting to modify.
+ * @param index The index of the list
+ * @param value The new value for the setting to be added to the list.
+ * @return true if the value was set, false on database errors
+ * @hide
+ */
+ public static boolean putIntAtIndex(android.content.ContentResolver cr,
+ String name, int index, int value) {
+ String data = "";
+ String valArray[] = null;
+ String v = android.provider.Settings.Global.getString(cr, name);
+
+ if (v != null) {
+ valArray = v.split(",");
+ }
+
+ // Copy the elements from valArray till index
+ for (int i = 0; i < index; i++) {
+ String str = "";
+ if ((valArray != null) && (i < valArray.length)) {
+ str = valArray[i];
+ }
+ data = data + str + ",";
+ }
+
+ data = data + value;
+
+ // Copy the remaining elements from valArray if any.
+ if (valArray != null) {
+ for (int i = index+1; i < valArray.length; i++) {
+ data = data + "," + valArray[i];
+ }
+ }
+ return android.provider.Settings.Global.putString(cr, name, data);
+ }
+
+ /**
+ * Gets the telephony property.
+ *
+ * @hide
+ */
+ public static String getTelephonyProperty(String property, long subId, String defaultVal) {
+ String propVal = null;
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ String prop = SystemProperties.get(property);
+ if ((prop != null) && (prop.length() > 0)) {
+ String values[] = prop.split(",");
+ if ((phoneId >= 0) && (phoneId < values.length) && (values[phoneId] != null)) {
+ propVal = values[phoneId];
+ }
+ }
+ return propVal == null ? defaultVal : propVal;
+ }
+
+ /** @hide */
+ public int getSimCount() {
+ if(isMultiSimEnabled()) {
+ //TODO Need to get it from Telephony Devcontroller
+ return 2;
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+ * @return IMS Service Table or null if not present or not loaded
+ * @hide
+ */
+ public String getIsimIst() {
+ try {
+ return getSubscriberInfo().getIsimIst();
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
+ * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
+ * @return an array of PCSCF strings with one PCSCF per string, or null if
+ * not present or not loaded
+ * @hide
+ */
+ public String[] getIsimPcscf() {
+ try {
+ return getSubscriberInfo().getIsimPcscf();
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
+ * Returns the response of ISIM Authetification through RIL.
+ * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo.
+ * @return the response of ISIM Authetification, or null if not available
+ * @hide
+ * @deprecated
+ * @see getIccSimChallengeResponse with appType=PhoneConstants.APPTYPE_ISIM
+ */
+ public String getIsimChallengeResponse(String nonce){
+ try {
+ return getSubscriberInfo().getIsimChallengeResponse(nonce);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return null;
+ }
+ }
+
+ /**
+ * Returns the response of SIM Authentication through RIL.
+ * Returns null if the Authentication hasn't been successful
+ * @param subId subscription ID to be queried
+ * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+ * @param data authentication challenge data
+ * @return the response of SIM Authentication, or null if not available
+ * @hide
+ */
+ public String getIccSimChallengeResponse(long subId, int appType, String data) {
+ try {
+ return getSubscriberInfo().getIccSimChallengeResponse(subId, appType, data);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone starts
+ return null;
+ }
+ }
+
+ /**
+ * Returns the response of SIM Authentication through RIL for the default subscription.
+ * Returns null if the Authentication hasn't been successful
+ * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+ * @param data authentication challenge data
+ * @return the response of SIM Authentication, or null if not available
+ * @hide
+ */
+ public String getIccSimChallengeResponse(int appType, String data) {
+ return getIccSimChallengeResponse(getDefaultSubscription(), appType, data);
+ }
+
+ /**
+ * Get P-CSCF address from PCO after data connection is established or modified.
+ *
+ * @return array of P-CSCF address
+ * @hide
+ */
+ public String[] getPcscfAddress() {
+ try {
+ return getITelephony().getPcscfAddress();
+ } catch (RemoteException e) {
+ return new String[0];
+ }
+ }
+
+ /**
+ * Set IMS registration state
+ *
+ * @param Registration state
+ * @hide
+ */
+ public void setImsRegistrationState(boolean registered) {
+ try {
+ getITelephony().setImsRegistrationState(registered);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Get the preferred network type.
* Used for device configuration by some CDMA operators.
*
diff --git a/telephony/java/android/telephony/VoLteServiceState.aidl b/telephony/java/android/telephony/VoLteServiceState.aidl
new file mode 100644
index 0000000..59dd04f
--- /dev/null
+++ b/telephony/java/android/telephony/VoLteServiceState.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2014 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable VoLteServiceState;
+
diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java
new file mode 100644
index 0000000..afef601b
--- /dev/null
+++ b/telephony/java/android/telephony/VoLteServiceState.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+
+/**
+ * Contains LTE network state related information.
+ *
+ * @hide
+ */
+public final class VoLteServiceState implements Parcelable {
+
+ private static final String LOG_TAG = "VoLteServiceState";
+ private static final boolean DBG = false;
+
+ //Use int max, as -1 is a valid value in signal strength
+ public static final int INVALID = 0x7FFFFFFF;
+
+ public static final int NOT_SUPPORTED = 0;
+ public static final int SUPPORTED = 1;
+
+ // Single Radio Voice Call Continuity(SRVCC) progress state
+ public static final int HANDOVER_STARTED = 0;
+ public static final int HANDOVER_COMPLETED = 1;
+ public static final int HANDOVER_FAILED = 2;
+ public static final int HANDOVER_CANCELED = 3;
+
+ private int mSrvccState;
+
+ /**
+ * Create a new VoLteServiceState from a intent notifier Bundle
+ *
+ * This method is used by PhoneStateIntentReceiver and maybe by
+ * external applications.
+ *
+ * @param m Bundle from intent notifier
+ * @return newly created VoLteServiceState
+ *
+ * @hide
+ */
+ public static VoLteServiceState newFromBundle(Bundle m) {
+ VoLteServiceState ret;
+ ret = new VoLteServiceState();
+ ret.setFromNotifierBundle(m);
+ return ret;
+ }
+
+ /**
+ * Empty constructor
+ *
+ * @hide
+ */
+ public VoLteServiceState() {
+ initialize();
+ }
+
+ /**
+ * Constructor
+ *
+ * @hide
+ */
+ public VoLteServiceState(int srvccState) {
+ initialize();
+
+ mSrvccState = srvccState;
+ }
+
+ /**
+ * Copy constructors
+ *
+ * @param s Source VoLteServiceState
+ *
+ * @hide
+ */
+ public VoLteServiceState(VoLteServiceState s) {
+ copyFrom(s);
+ }
+
+ /**
+ * Initialize values to defaults.
+ *
+ * @hide
+ */
+ private void initialize() {
+ mSrvccState = INVALID;
+ }
+
+ /**
+ * @hide
+ */
+ protected void copyFrom(VoLteServiceState s) {
+ mSrvccState = s.mSrvccState;
+ }
+
+ /**
+ * Construct a VoLteServiceState object from the given parcel.
+ *
+ * @hide
+ */
+ public VoLteServiceState(Parcel in) {
+ if (DBG) log("Size of VoLteServiceState parcel:" + in.dataSize());
+
+ mSrvccState = in.readInt();
+ }
+
+ /**
+ * {@link Parcelable#writeToParcel}
+ */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mSrvccState);
+ }
+
+ /**
+ * {@link Parcelable#describeContents}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@link Parcelable.Creator}
+ *
+ * @hide
+ */
+ public static final Parcelable.Creator<VoLteServiceState> CREATOR = new Parcelable.Creator() {
+ public VoLteServiceState createFromParcel(Parcel in) {
+ return new VoLteServiceState(in);
+ }
+
+ public VoLteServiceState[] newArray(int size) {
+ return new VoLteServiceState[size];
+ }
+ };
+
+ /**
+ * Validate the individual fields as per the range
+ * specified in ril.h
+ * Set to invalid any field that is not in the valid range
+ *
+ * @return
+ * Valid values for all fields
+ * @hide
+ */
+ public void validateInput() {
+ }
+
+ public int hashCode() {
+ int primeNum = 31;
+ return ((mSrvccState * primeNum));
+ }
+
+ /**
+ * @return true if the LTE network states are the same
+ */
+ @Override
+ public boolean equals (Object o) {
+ VoLteServiceState s;
+
+ try {
+ s = (VoLteServiceState) o;
+ } catch (ClassCastException ex) {
+ return false;
+ }
+
+ if (o == null) {
+ return false;
+ }
+
+ return (mSrvccState == s.mSrvccState);
+ }
+
+ /**
+ * @return string representation.
+ */
+ @Override
+ public String toString() {
+ return ("VoLteServiceState:"
+ + " " + mSrvccState);
+ }
+
+ /**
+ * Set VoLteServiceState based on intent notifier map
+ *
+ * @param m intent notifier map
+ * @hide
+ */
+ private void setFromNotifierBundle(Bundle m) {
+ mSrvccState = m.getInt("mSrvccState");
+ }
+
+ /**
+ * Set intent notifier Bundle based on VoLteServiceState
+ *
+ * @param m intent notifier Bundle
+ * @hide
+ */
+ public void fillInNotifierBundle(Bundle m) {
+ m.putInt("mSrvccState", mSrvccState);
+ }
+
+ public int getSrvccState() {
+ return mSrvccState;
+ }
+
+ /**
+ * log
+ */
+ private static void log(String s) {
+ Rlog.w(LOG_TAG, s);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index f8dd7cf..745c9d0 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -37,6 +37,9 @@
import com.android.i18n.phonenumbers.NumberParseException;
import com.android.i18n.phonenumbers.PhoneNumberUtil;
import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
+import android.telephony.SubscriptionManager;
+
+import android.telephony.TelephonyManager;
import java.util.Locale;
@@ -233,6 +236,7 @@
info.contactExists = true;
}
cursor.close();
+ cursor = null;
}
info.needUpdate = false;
@@ -269,6 +273,23 @@
public static CallerInfo getCallerInfo(Context context, String number) {
if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number...");
+ long subId = SubscriptionManager.getDefaultSubId();
+ return getCallerInfo(context, number, subId);
+ }
+
+ /**
+ * getCallerInfo given a phone number and subscription, look up in the call-log database
+ * for the matching caller id info.
+ * @param context the context used to get the ContentResolver
+ * @param number the phone number used to lookup caller id
+ * @param subId the subscription for checking for if voice mail number or not
+ * @return the CallerInfo which contains the caller id for the given
+ * number. The returned CallerInfo is null if no number is supplied. If
+ * a matching number is not found, then a generic caller info is returned,
+ * with all relevant fields empty or null.
+ */
+ public static CallerInfo getCallerInfo(Context context, String number, long subId) {
+
if (TextUtils.isEmpty(number)) {
return null;
}
@@ -278,7 +299,7 @@
// shortcut and skip the query.
if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
return new CallerInfo().markAsEmergency(context);
- } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+ } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
return new CallerInfo().markAsVoiceMail();
}
@@ -400,10 +421,17 @@
// TODO: As in the emergency number handling, we end up writing a
// string in the phone number field.
/* package */ CallerInfo markAsVoiceMail() {
+
+ long subId = SubscriptionManager.getDefaultSubId();
+ return markAsVoiceMail(subId);
+
+ }
+
+ /* package */ CallerInfo markAsVoiceMail(long subId) {
mIsVoiceMail = true;
try {
- String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
+ String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag(subId);
phoneNumber = voiceMailLabel;
} catch (SecurityException se) {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 34fed5e..fe403d9 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -24,12 +24,15 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.telephony.Rlog;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
/**
* Helper class to make it easier to run asynchronous caller-id lookup queries.
@@ -75,6 +78,8 @@
public Object cookie;
public int event;
public String number;
+
+ public long subId;
}
@@ -207,11 +212,17 @@
// However, if there is any code that calls this method, we should
// check the parameters to make sure they're viable.
if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
+ if (cursor != null) {
+ cursor.close();
+ }
return;
}
if (cw.event == EVENT_END_OF_QUEUE) {
release();
+ if (cursor != null) {
+ cursor.close();
+ }
return;
}
@@ -232,7 +243,7 @@
// comments at the top of CallerInfo class).
mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
} else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
- mCallerInfo = new CallerInfo().markAsVoiceMail();
+ mCallerInfo = new CallerInfo().markAsVoiceMail(cw.subId);
} else {
mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
if (DBG) Rlog.d(LOG_TAG, "==> Got mCallerInfo: " + mCallerInfo);
@@ -289,6 +300,10 @@
" for token: " + token + mCallerInfo);
cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
}
+
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
@@ -334,6 +349,25 @@
*/
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
OnQueryCompleteListener listener, Object cookie) {
+
+ long subId = SubscriptionManager.getDefaultSubId();
+ return startQuery(token, context, number, listener, cookie, subId);
+ }
+
+ /**
+ * Factory method to start the query based on a number with specific subscription.
+ *
+ * Note: if the number contains an "@" character we treat it
+ * as a SIP address, and look it up directly in the Data table
+ * rather than using the PhoneLookup table.
+ * TODO: But eventually we should expose two separate methods, one for
+ * numbers and one for SIP addresses, and then have
+ * PhoneUtils.startGetCallerInfo() decide which one to call based on
+ * the phone type of the incoming connection.
+ */
+ public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
+ OnQueryCompleteListener listener, Object cookie, long subId) {
+
if (DBG) {
Rlog.d(LOG_TAG, "##### CallerInfoAsyncQuery startQuery()... #####");
Rlog.d(LOG_TAG, "- number: " + /*number*/ "xxxxxxx");
@@ -397,11 +431,12 @@
cw.listener = listener;
cw.cookie = cookie;
cw.number = number;
+ cw.subId = subId;
// check to see if these are recognized numbers, and use shortcuts if we can.
if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) {
cw.event = EVENT_EMERGENCY_NUMBER;
- } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+ } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) {
cw.event = EVENT_VOICEMAIL_NUMBER;
} else {
cw.event = EVENT_NEW_QUERY;
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3f36645..a95336e 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -23,6 +23,7 @@
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
+import android.telephony.VoLteServiceState;
oneway interface IPhoneStateListener {
void onServiceStateChanged(in ServiceState serviceState);
@@ -41,5 +42,6 @@
void onPreciseCallStateChanged(in PreciseCallState callState);
void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
+ void onVoLteServiceStateChanged(in VoLteServiceState lteState);
}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 03940dc..4734965 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -28,6 +28,13 @@
String getDeviceId();
/**
+ * Retrieves the unique device ID of a subId for the device, e.g., IMEI
+ * for GSM phones.
+ */
+ String getDeviceIdUsingSubId(long subId);
+
+
+ /**
* Retrieves the software version number for the device, e.g., IMEI/SV
* for GSM phones.
*/
@@ -39,46 +46,94 @@
String getSubscriberId();
/**
+ * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones.
+ */
+ String getSubscriberIdUsingSubId(long subId);
+
+ /**
* Retrieves the Group Identifier Level1 for GSM phones.
*/
String getGroupIdLevel1();
/**
+ * Retrieves the Group Identifier Level1 for GSM phones of a subId.
+ */
+ String getGroupIdLevel1UsingSubId(long subId);
+
+ /**
* Retrieves the serial number of the ICC, if applicable.
*/
String getIccSerialNumber();
/**
+ * Retrieves the serial number of a given subId.
+ */
+ String getIccSerialNumberUsingSubId(long subId);
+
+ /**
* Retrieves the phone number string for line 1.
*/
String getLine1Number();
/**
+ * Retrieves the phone number string for line 1 of a subcription.
+ */
+ String getLine1NumberUsingSubId(long subId);
+
+
+ /**
* Retrieves the alpha identifier for line 1.
*/
String getLine1AlphaTag();
/**
+ * Retrieves the alpha identifier for line 1 of a subId.
+ */
+ String getLine1AlphaTagUsingSubId(long subId);
+
+
+ /**
* Retrieves MSISDN Number.
*/
String getMsisdn();
/**
+ * Retrieves the Msisdn of a subId.
+ */
+ String getMsisdnUsingSubId(long subId);
+
+ /**
* Retrieves the voice mail number.
*/
String getVoiceMailNumber();
/**
+ * Retrieves the voice mail number of a given subId.
+ */
+ String getVoiceMailNumberUsingSubId(long subId);
+
+ /**
* Retrieves the complete voice mail number.
*/
String getCompleteVoiceMailNumber();
/**
+ * Retrieves the complete voice mail number for particular subId
+ */
+ String getCompleteVoiceMailNumberUsingSubId(long subId);
+
+ /**
* Retrieves the alpha identifier associated with the voice mail number.
*/
String getVoiceMailAlphaTag();
/**
+ * Retrieves the alpha identifier associated with the voice mail number
+ * of a subId.
+ */
+ String getVoiceMailAlphaTagUsingSubId(long subId);
+
+ /**
* Returns the IMS private user identity (IMPI) that was loaded from the ISIM.
* @return the IMPI, or null if not present or not loaded
*/
@@ -96,4 +151,38 @@
* not present or not loaded
*/
String[] getIsimImpu();
+
+ /**
+ * Returns the IMS Service Table (IST) that was loaded from the ISIM.
+ * @return IMS Service Table or null if not present or not loaded
+ */
+ String getIsimIst();
+
+ /**
+ * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM.
+ * @return an array of PCSCF strings with one PCSCF per string, or null if
+ * not present or not loaded
+ */
+ String[] getIsimPcscf();
+
+ /**
+ * TODO: Deprecate and remove this interface. Superceded by getIccsimChallengeResponse.
+ * Returns the response of ISIM Authetification through RIL.
+ * @return the response of ISIM Authetification, or null if
+ * the Authentification hasn't been successed or isn't present iphonesubinfo.
+ */
+ String getIsimChallengeResponse(String nonce);
+
+ /**
+ * Returns the response of the SIM application on the UICC to authentication
+ * challenge/response algorithm. The data string and challenge response are
+ * Base64 encoded Strings.
+ * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
+ *
+ * @param subId subscription ID to be queried
+ * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
+ * @param data authentication challenge data
+ * @return challenge response
+ */
+ String getIccSimChallengeResponse(long subId, int appType, String data);
}
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 3e8db06..9e975e9 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -42,6 +42,13 @@
List<SmsRawData> getAllMessagesFromIccEf(String callingPkg);
/**
+ * Retrieves all messages currently stored on ICC.
+ * @param subId the subId id.
+ * @return list of SmsRawData of all sms on ICC
+ */
+ List<SmsRawData> getAllMessagesFromIccEfUsingSubId(in long subId, String callingPkg);
+
+ /**
* Update the specified message on the ICC.
*
* @param messageIndex record index of message to update
@@ -56,6 +63,21 @@
in byte[] pdu);
/**
+ * Update the specified message on the ICC.
+ *
+ * @param messageIndex record index of message to update
+ * @param newStatus new message status (STATUS_ON_ICC_READ,
+ * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
+ * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
+ * @param pdu the raw PDU to store
+ * @param subId the subId id.
+ * @return success or not
+ *
+ */
+ boolean updateMessageOnIccEfUsingSubId(in long subId, String callingPkg,
+ int messageIndex, int newStatus, in byte[] pdu);
+
+ /**
* Copy a raw SMS PDU to the ICC.
*
* @param pdu the raw PDU to store
@@ -67,6 +89,19 @@
boolean copyMessageToIccEf(String callingPkg, int status, in byte[] pdu, in byte[] smsc);
/**
+ * Copy a raw SMS PDU to the ICC.
+ *
+ * @param pdu the raw PDU to store
+ * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
+ * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
+ * @param subId the subId id.
+ * @return success or not
+ *
+ */
+ boolean copyMessageToIccEfUsingSubId(in long subId, String callingPkg, int status,
+ in byte[] pdu, in byte[] smsc);
+
+ /**
* Send a data SMS.
*
* @param smsc the SMSC to send the message through, or NULL for the
@@ -93,6 +128,34 @@
in byte[] data, in PendingIntent sentIntent, in PendingIntent deliveryIntent);
/**
+ * Send a data SMS.
+ *
+ * @param smsc the SMSC to send the message through, or NULL for the
+ * default SMSC
+ * @param data the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applicaitons,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param subId the subId id.
+ */
+ void sendDataUsingSubId(long subId, String callingPkg, in String destAddr,
+ in String scAddr, in int destPort, in byte[] data, in PendingIntent sentIntent,
+ in PendingIntent deliveryIntent);
+
+ /**
* Send an SMS.
*
* @param smsc the SMSC to send the message through, or NULL for the
@@ -119,6 +182,47 @@
in PendingIntent sentIntent, in PendingIntent deliveryIntent);
/**
+ * Send an SMS.
+ *
+ * @param smsc the SMSC to send the message through, or NULL for the
+ * default SMSC
+ * @param text the body of the message to send
+ * @param sentIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:<br>
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+ * <code>RESULT_ERROR_RADIO_OFF</code><br>
+ * <code>RESULT_ERROR_NULL_PDU</code><br>
+ * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+ * the extra "errorCode" containing a radio technology specific value,
+ * generally only useful for troubleshooting.<br>
+ * The per-application based SMS control checks sentIntent. If sentIntent
+ * is NULL the caller will be checked against all unknown applications,
+ * which cause smaller number of SMS to be sent in checking period.
+ * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ * @param subId the subId on which the SMS has to be sent.
+ */
+ void sendTextUsingSubId(in long subId, String callingPkg, in String destAddr,
+ in String scAddr, in String text, in PendingIntent sentIntent,
+ in PendingIntent deliveryIntent);
+
+ /**
+ * Inject an SMS PDU into the android platform.
+ *
+ * @param pdu is the byte array of pdu to be injected into android application framework
+ * @param format is the format of SMS pdu (android.telephony.SmsMessage.FORMAT_3GPP or
+ * android.telephony.SmsMessage.FORMAT_3GPP2)
+ * @param receivedIntent if not NULL this <code>PendingIntent</code> is
+ * broadcast when the message is successfully received by the
+ * android application framework. This intent is broadcasted at
+ * the same time an SMS received from radio is acknowledged back.
+ */
+ void injectSmsPdu(in byte[] pdu, String format, in PendingIntent receivedIntent);
+
+ /**
* Send a multi-part text based SMS.
*
* @param destinationAddress the address to send the message to
@@ -145,6 +249,34 @@
in List<PendingIntent> deliveryIntents);
/**
+ * Send a multi-part text based SMS.
+ *
+ * @param destinationAddress the address to send the message to
+ * @param scAddress is the service center address or null to use
+ * the current default SMSC
+ * @param parts an <code>ArrayList</code> of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be <code>Activity.RESULT_OK<code> for success,
+ * or one of these errors:
+ * <code>RESULT_ERROR_GENERIC_FAILURE</code>
+ * <code>RESULT_ERROR_RADIO_OFF</code>
+ * <code>RESULT_ERROR_NULL_PDU</code>.
+ * @param deliveryIntents if not null, an <code>ArrayList</code> of
+ * <code>PendingIntent</code>s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
+ * @param subId the subId on which the SMS has to be sent.
+ */
+ void sendMultipartTextUsingSubId(in long subId, String callingPkg,
+ in String destinationAddress, in String scAddress,
+ in List<String> parts, in List<PendingIntent> sentIntents,
+ in List<PendingIntent> deliveryIntents);
+
+ /**
* Enable reception of cell broadcast (SMS-CB) messages with the given
* message identifier. Note that if two different clients enable the same
* message identifier, they must both disable it for the device to stop
@@ -159,6 +291,21 @@
boolean enableCellBroadcast(int messageIdentifier);
/**
+ * Enable reception of cell broadcast (SMS-CB) messages with the given
+ * message identifier. Note that if two different clients enable the same
+ * message identifier, they must both disable it for the device to stop
+ * receiving those messages.
+ *
+ * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param subId for which the broadcast has to be enabled
+ * @return true if successful, false otherwise
+ *
+ * @see #disableCellBroadcast(int)
+ */
+ boolean enableCellBroadcastUsingSubId(in long subId, int messageIdentifier);
+
+ /**
* Disable reception of cell broadcast (SMS-CB) messages with the given
* message identifier. Note that if two different clients enable the same
* message identifier, they must both disable it for the device to stop
@@ -172,6 +319,21 @@
*/
boolean disableCellBroadcast(int messageIdentifier);
+ /**
+ * Disable reception of cell broadcast (SMS-CB) messages with the given
+ * message identifier. Note that if two different clients enable the same
+ * message identifier, they must both disable it for the device to stop
+ * receiving those messages.
+ *
+ * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param subId for which the broadcast has to be disabled
+ * @return true if successful, false otherwise
+ *
+ * @see #enableCellBroadcast(int)
+ */
+ boolean disableCellBroadcastUsingSubId(in long subId, int messageIdentifier);
+
/*
* Enable reception of cell broadcast (SMS-CB) messages with the given
* message identifier range. Note that if two different clients enable
@@ -188,6 +350,23 @@
*/
boolean enableCellBroadcastRange(int startMessageId, int endMessageId);
+ /*
+ * Enable reception of cell broadcast (SMS-CB) messages with the given
+ * message identifier range. Note that if two different clients enable
+ * a message identifier range, they must both disable it for the device
+ * to stop receiving those messages.
+ *
+ * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param subId for which the broadcast has to be enabled
+ * @return true if successful, false otherwise
+ *
+ * @see #disableCellBroadcastRange(int, int)
+ */
+ boolean enableCellBroadcastRangeUsingSubId(long subId, int startMessageId, int endMessageId);
+
/**
* Disable reception of cell broadcast (SMS-CB) messages with the given
* message identifier range. Note that if two different clients enable
@@ -205,18 +384,52 @@
boolean disableCellBroadcastRange(int startMessageId, int endMessageId);
/**
+ * Disable reception of cell broadcast (SMS-CB) messages with the given
+ * message identifier range. Note that if two different clients enable
+ * a message identifier range, they must both disable it for the device
+ * to stop receiving those messages.
+ *
+ * @param startMessageId first message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param endMessageId last message identifier as specified in TS 23.041 (3GPP) or
+ * C.R1001-G (3GPP2)
+ * @param subId for which the broadcast has to be disabled
+ * @return true if successful, false otherwise
+ *
+ * @see #enableCellBroadcastRange(int, int, int)
+ */
+ boolean disableCellBroadcastRangeUsingSubId(long subId, int startMessageId,
+ int endMessageId);
+
+ /**
* Returns the premium SMS send permission for the specified package.
* Requires system permission.
*/
int getPremiumSmsPermission(String packageName);
/**
+ * Returns the premium SMS send permission for the specified package.
+ * Requires system permission.
+ */
+ int getPremiumSmsPermissionUsingSubId(long subId, String packageName);
+
+ /**
* Set the SMS send permission for the specified package.
* Requires system permission.
*/
void setPremiumSmsPermission(String packageName, int permission);
/**
+ * Set the SMS send permission for the specified package.
+ * Requires system permission.
+ */
+ /**
+ * Set the SMS send permission for the specified package.
+ * Requires system permission.
+ */
+ void setPremiumSmsPermissionUsingSubId(long subId, String packageName, int permission);
+
+ /**
* SMS over IMS is supported if IMS is registered and SMS is supported
* on IMS.
*
@@ -227,6 +440,23 @@
boolean isImsSmsSupported();
/**
+ * SMS over IMS is supported if IMS is registered and SMS is supported
+ * on IMS.
+ * @param subId for subId which isImsSmsSupported is queried
+ * @return true if SMS over IMS is supported, false otherwise
+ *
+ * @see #getImsSmsFormat()
+ */
+ boolean isImsSmsSupportedUsingSubId(long subId);
+
+ /*
+ * get user prefered SMS subId
+ * @return subId id
+ */
+ long getPreferredSmsSubscription();
+
+
+ /**
* Gets SMS format supported on IMS. SMS over IMS format is
* either 3GPP or 3GPP2.
*
@@ -237,4 +467,25 @@
* @see #isImsSmsSupported()
*/
String getImsSmsFormat();
+
+ /**
+ * Gets SMS format supported on IMS. SMS over IMS format is
+ * either 3GPP or 3GPP2.
+ * @param subId for subId which getImsSmsFormat is queried
+ * @return android.telephony.SmsMessage.FORMAT_3GPP,
+ * android.telephony.SmsMessage.FORMAT_3GPP2
+ * or android.telephony.SmsMessage.FORMAT_UNKNOWN
+ *
+ * @see #isImsSmsSupported()
+ */
+ String getImsSmsFormatUsingSubId(long subId);
+
+
+
+
+ /*
+ * Get SMS prompt property, enabled or not
+ * @return true if enabled, false otherwise
+ */
+ boolean isSMSPromptEnabled();
}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
new file mode 100755
index 0000000..6021ccf
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -0,0 +1,153 @@
+/*
+* Copyright (C) 2011-2014 MediaTek 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.
+*/
+
+package com.android.internal.telephony;
+
+import android.app.PendingIntent;
+import android.telephony.SubInfoRecord;
+
+interface ISub {
+ /**
+ * Get the SubInfoRecord according to an index
+ * @param context Context provided by caller
+ * @param subId The unique SubInfoRecord index in database
+ * @return SubInfoRecord, maybe null
+ */
+ SubInfoRecord getSubInfoUsingSubId(long subId);
+
+ /**
+ * Get the SubInfoRecord according to an IccId
+ * @param context Context provided by caller
+ * @param iccId the IccId of SIM card
+ * @return SubInfoRecord, maybe null
+ */
+ List<SubInfoRecord> getSubInfoUsingIccId(String iccId);
+
+ /**
+ * Get the SubInfoRecord according to slotId
+ * @param context Context provided by caller
+ * @param slotId the slot which the SIM is inserted
+ * @return SubInfoRecord, maybe null
+ */
+ List<SubInfoRecord> getSubInfoUsingSlotId(int slotId);
+
+ /**
+ * Get all the SubInfoRecord(s) in subinfo database
+ * @param context Context provided by caller
+ * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before
+ */
+ List<SubInfoRecord> getAllSubInfoList();
+
+ /**
+ * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+ * @param context Context provided by caller
+ * @return Array list of currently inserted SubInfoRecord(s)
+ */
+ List<SubInfoRecord> getActivatedSubInfoList();
+
+ /**
+ * Get the SUB count of all SUB(s) in subinfo database
+ * @param context Context provided by caller
+ * @return all SIM count in database, include what was inserted before
+ */
+ int getAllSubInfoCount();
+
+ /**
+ * Add a new SubInfoRecord to subinfo database if needed
+ * @param context Context provided by caller
+ * @param iccId the IccId of the SIM card
+ * @param slotId the slot which the SIM is inserted
+ * @return the URL of the newly created row or the updated row
+ */
+ int addSubInfoRecord(String iccId, int slotId);
+
+ /**
+ * Set SIM color by simInfo index
+ * @param context Context provided by caller
+ * @param color the color of the SIM
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setColor(int color, long subId);
+
+ /**
+ * Set display name by simInfo index
+ * @param context Context provided by caller
+ * @param displayName the display name of SIM card
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setDisplayName(String displayName, long subId);
+
+ /**
+ * Set display name by simInfo index with name source
+ * @param context Context provided by caller
+ * @param displayName the display name of SIM card
+ * @param subId the unique SubInfoRecord index in database
+ * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
+ * @return the number of records updated
+ */
+ int setDisplayNameUsingSrc(String displayName, long subId, long nameSource);
+
+ /**
+ * Set phone number by subId
+ * @param context Context provided by caller
+ * @param number the phone number of the SIM
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setDispalyNumber(String number, long subId);
+
+ /**
+ * Set number display format. 0: none, 1: the first four digits, 2: the last four digits
+ * @param context Context provided by caller
+ * @param format the display format of phone number
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setDisplayNumberFormat(int format, long subId);
+
+ /**
+ * Set data roaming by simInfo index
+ * @param context Context provided by caller
+ * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming
+ * @param subId the unique SubInfoRecord index in database
+ * @return the number of records updated
+ */
+ int setDataRoaming(int roaming, long subId);
+
+ int getSlotId(long subId);
+
+ long[] getSubId(int slotId);
+
+ long getDefaultSubId();
+
+ int clearSubInfo();
+
+ int getPhoneId(long subId);
+
+ /**
+ * Get the default data subscription
+ * @return Id of the data subscription
+ */
+ long getDefaultDataSubId();
+
+ void setDefaultDataSubId(long subId);
+
+ long getDefaultVoiceSubId();
+
+ void setDefaultVoiceSubId(long subId);
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index acaa8de..407da87 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,14 +16,11 @@
package com.android.internal.telephony;
-import android.content.ComponentName;
import android.os.Bundle;
-import android.telephony.CellInfo;
+import java.util.List;
import android.telephony.NeighboringCellInfo;
+import android.telephony.CellInfo;
-import java.util.List;
-
-import java.util.List;
/**
* Interface used to interact with the phone. Mostly this is used by the
@@ -56,6 +53,13 @@
boolean endCall();
/**
+ * End call on particular subId or go to the Home screen
+ * @param subId user preferred subId.
+ * @return whether it hung up
+ */
+ boolean endCallUsingSubId(long subId);
+
+ /**
* Answer the currently-ringing call.
*
* If there's already a current active call, that call will be
@@ -92,6 +96,23 @@
boolean isOffhook();
/**
+ * Check if a particular subId has an active or holding call
+ *
+ * @param subId user preferred subId.
+ * @return true if the phone state is OFFHOOK.
+ */
+ boolean isOffhookUsingSubId(long subId);
+
+ /**
+ * Check if an incoming phone call is ringing or call waiting
+ * on a particular subId.
+ *
+ * @param subId user preferred subId.
+ * @return true if the phone state is RINGING.
+ */
+ boolean isRingingUsingSubId(long subId);
+
+ /**
* Check if an incoming phone call is ringing or call waiting.
* @return true if the phone state is RINGING.
*/
@@ -104,12 +125,27 @@
boolean isIdle();
/**
+ * Check if the phone is idle on a particular subId.
+ *
+ * @param subId user preferred subId.
+ * @return true if the phone state is IDLE.
+ */
+ boolean isIdleUsingSubId(long subId);
+
+ /**
* Check to see if the radio is on or not.
* @return returns true if the radio is on.
*/
boolean isRadioOn();
/**
+ * Check to see if the radio is on or not on particular subId.
+ * @param subId user preferred subId.
+ * @return returns true if the radio is on.
+ */
+ boolean isRadioOnUsingSubId(long subId);
+
+ /**
* Check if the SIM pin lock is enabled.
* @return true if the SIM pin lock is enabled.
*/
@@ -128,6 +164,15 @@
boolean supplyPin(String pin);
/**
+ * Supply a pin to unlock the SIM for particular subId.
+ * Blocks until a result is determined.
+ * @param pin The pin to check.
+ * @param subId user preferred subId.
+ * @return whether the operation was a success.
+ */
+ boolean supplyPinUsingSubId(long subId, String pin);
+
+ /**
* Supply puk to unlock the SIM and set SIM pin to new pin.
* Blocks until a result is determined.
* @param puk The puk to check.
@@ -137,6 +182,16 @@
boolean supplyPuk(String puk, String pin);
/**
+ * Supply puk to unlock the SIM and set SIM pin to new pin.
+ * Blocks until a result is determined.
+ * @param puk The puk to check.
+ * pin The new pin to be set in SIM
+ * @param subId user preferred subId.
+ * @return whether the operation was a success.
+ */
+ boolean supplyPukUsingSubId(long subId, String puk, String pin);
+
+ /**
* Supply a pin to unlock the SIM. Blocks until a result is determined.
* Returns a specific success/error code.
* @param pin The pin to check.
@@ -146,6 +201,15 @@
int[] supplyPinReportResult(String pin);
/**
+ * Supply a pin to unlock the SIM. Blocks until a result is determined.
+ * Returns a specific success/error code.
+ * @param pin The pin to check.
+ * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+ * retValue[1] = number of attempts remaining if known otherwise -1
+ */
+ int[] supplyPinReportResultUsingSubId(long subId, String pin);
+
+ /**
* Supply puk to unlock the SIM and set SIM pin to new pin.
* Blocks until a result is determined.
* Returns a specific success/error code
@@ -157,6 +221,17 @@
int[] supplyPukReportResult(String puk, String pin);
/**
+ * Supply puk to unlock the SIM and set SIM pin to new pin.
+ * Blocks until a result is determined.
+ * Returns a specific success/error code
+ * @param puk The puk to check
+ * pin The pin to check.
+ * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code
+ * retValue[1] = number of attempts remaining if known otherwise -1
+ */
+ int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin);
+
+ /**
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
* without SEND (so <code>dial</code> is not appropriate).
*
@@ -166,16 +241,38 @@
boolean handlePinMmi(String dialString);
/**
+ * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
+ * without SEND (so <code>dial</code> is not appropriate) for
+ * a particular subId.
+ * @param dialString the MMI command to be executed.
+ * @param subId user preferred subId.
+ * @return true if MMI command is executed.
+ */
+ boolean handlePinMmiUsingSubId(long subId, String dialString);
+
+ /**
* Toggles the radio on or off.
*/
void toggleRadioOnOff();
/**
+ * Toggles the radio on or off on particular subId.
+ * @param subId user preferred subId.
+ */
+ void toggleRadioOnOffUsingSubId(long subId);
+
+ /**
* Set the radio to on or off
*/
boolean setRadio(boolean turnOn);
/**
+ * Set the radio to on or off on particular subId.
+ * @param subId user preferred subId.
+ */
+ boolean setRadioUsingSubId(long subId, boolean turnOn);
+
+ /**
* Set the radio to on or off unconditionally
*/
boolean setRadioPower(boolean turnOn);
@@ -186,16 +283,35 @@
void updateServiceLocation();
/**
+ * Request to update location information for a subscrition in service state
+ * @param subId user preferred subId.
+ */
+ void updateServiceLocationUsingSubId(long subId);
+
+ /**
* Enable location update notifications.
*/
void enableLocationUpdates();
/**
+ * Enable location update notifications.
+ * @param subId user preferred subId.
+ */
+ void enableLocationUpdatesUsingSubId(long subId);
+
+ /**
* Disable location update notifications.
*/
void disableLocationUpdates();
/**
+ * Disable location update notifications.
+ * @param subId user preferred subId.
+ */
+ void disableLocationUpdatesUsingSubId(long subId);
+
+
+ /**
* Enable a specific APN type.
*/
int enableApnType(String type);
@@ -206,6 +322,16 @@
int disableApnType(String type);
/**
+ * Enable a specific APN type with subscription.
+ */
+ int enableApnTypeUsingSub(long subId, String type);
+
+ /**
+ * Disable a specific APN type with subscription.
+ */
+ int disableApnTypeUsingSub(long subId, String type);
+
+ /**
* Allow mobile data connections.
*/
boolean enableDataConnectivity();
@@ -228,6 +354,12 @@
List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg);
int getCallState();
+
+ /**
+ * Returns the call state for a subId.
+ */
+ int getCallStateUsingSubId(long subId);
+
int getDataActivity();
int getDataState();
@@ -239,11 +371,25 @@
int getActivePhoneType();
/**
+ * Returns the current active phone type as integer for particular subId.
+ * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
+ * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
+ * @param subId user preferred subId.
+ */
+ int getActivePhoneTypeUsingSubId(long subId);
+
+ /**
* Returns the CDMA ERI icon index to display
*/
int getCdmaEriIconIndex();
/**
+ * Returns the CDMA ERI icon index to display on particular subId.
+ * @param subId user preferred subId.
+ */
+ int getCdmaEriIconIndexUsingSubId(long subId);
+
+ /**
* Returns the CDMA ERI icon mode,
* 0 - ON
* 1 - FLASHING
@@ -251,11 +397,25 @@
int getCdmaEriIconMode();
/**
+ * Returns the CDMA ERI icon mode on particular subId,
+ * 0 - ON
+ * 1 - FLASHING
+ * @param subId user preferred subId.
+ */
+ int getCdmaEriIconModeUsingSubId(long subId);
+
+ /**
* Returns the CDMA ERI text,
*/
String getCdmaEriText();
/**
+ * Returns the CDMA ERI text for particular subId,
+ * @param subId user preferred subId.
+ */
+ String getCdmaEriTextUsingSubId(long subId);
+
+ /**
* Returns true if OTA service provisioning needs to run.
* Only relevant on some technologies, others will always
* return false.
@@ -268,26 +428,61 @@
int getVoiceMessageCount();
/**
+ * Returns the unread count of voicemails for a subId.
+ * @param subId user preferred subId.
+ * Returns the unread count of voicemails
+ */
+ int getVoiceMessageCountUsingSubId(long subId);
+
+ /**
* Returns the network type for data transmission
*/
int getNetworkType();
/**
+ * Returns the network type of a subId.
+ * @param subId user preferred subId.
+ * Returns the network type
+ */
+ int getNetworkTypeUsingSubId(long subId);
+
+ /**
* Returns the network type for data transmission
*/
int getDataNetworkType();
/**
+ * Returns the data network type of a subId
+ * @param subId user preferred subId.
+ * Returns the network type
+ */
+ int getDataNetworkTypeUsingSubId(long subId);
+
+ /**
* Returns the network type for voice
*/
int getVoiceNetworkType();
/**
+ * Returns the voice network type of a subId
+ * @param subId user preferred subId.
+ * Returns the network type
+ */
+ int getVoiceNetworkTypeUsingSubId(long subId);
+
+ /**
* Return true if an ICC card is present
*/
boolean hasIccCard();
/**
+ * Return true if an ICC card is present for a subId.
+ * @param slotId user preferred slotId.
+ * Return true if an ICC card is present
+ */
+ boolean hasIccCardUsingSlotId(long slotId);
+
+ /**
* Return if the current radio is LTE on CDMA. This
* is a tri-state return value as for a period of time
* the mode may be unknown.
@@ -298,6 +493,16 @@
int getLteOnCdmaMode();
/**
+ * Return if the current radio is LTE on CDMA. This
+ * is a tri-state return value as for a period of time
+ * the mode may be unknown.
+ *
+ * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE}
+ * or {@link PHone#LTE_ON_CDMA_TRUE}
+ */
+ int getLteOnCdmaModeUsingSubId(long subId);
+
+ /**
* Returns the all observed cell information of the device.
*/
List<CellInfo> getAllCellInfo();
@@ -308,6 +513,12 @@
void setCellInfoListRate(int rateInMillis);
/**
+ * get default sim
+ * @return sim id
+ */
+ int getDefaultSim();
+
+ /**
* Opens a logical channel to the ICC card.
*
* Input parameters equivalent to TS 27.007 AT+CCHO command.
@@ -428,4 +639,16 @@
* @return true on enabled
*/
boolean getDataEnabled();
+
+ /**
+ * Get P-CSCF address from PCO after data connection is established or modified.
+ */
+ String[] getPcscfAddress();
+
+ /**
+ * Set IMS registration state
+ */
+ void setImsRegistrationState(boolean registered);
+
}
+
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index b104c11..fd2d1c7 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -24,22 +24,36 @@
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
+import android.telephony.CellInfo;
+import android.telephony.VoLteServiceState;
import com.android.internal.telephony.IPhoneStateListener;
interface ITelephonyRegistry {
void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
-
+ void listenUsingSubId(in long subId, String pkg, IPhoneStateListener callback, int events,
+ boolean notifyNow);
void notifyCallState(int state, String incomingNumber);
+ void notifyCallStateUsingSubId(in long subId, int state, String incomingNumber);
void notifyServiceState(in ServiceState state);
+ void notifyServiceStateUsingSubId(in long subId, in ServiceState state);
void notifySignalStrength(in SignalStrength signalStrength);
+ void notifySignalStrengthUsingSubId(in long subId, in SignalStrength signalStrength);
void notifyMessageWaitingChanged(boolean mwi);
+ void notifyMessageWaitingChangedUsingSubId(in long subId, boolean mwi);
void notifyCallForwardingChanged(boolean cfi);
+ void notifyCallForwardingChangedUsingSubId(in long subId, boolean cfi);
void notifyDataActivity(int state);
+ void notifyDataActivityUsingSubId(in long subId, int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String apnType, in LinkProperties linkProperties,
in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
+ void notifyDataConnectionUsingSubId(long subId, int state, boolean isDataConnectivityPossible,
+ String reason, String apn, String apnType, in LinkProperties linkProperties,
+ in NetworkCapabilities networkCapabilities, int networkType, boolean roaming);
void notifyDataConnectionFailed(String reason, String apnType);
+ void notifyDataConnectionFailedUsingSubId(long subId, String reason, String apnType);
void notifyCellLocation(in Bundle cellLocation);
+ void notifyCellLocationUsingSubId(in long subId, in Bundle cellLocation);
void notifyOtaspChanged(in int otaspMode);
void notifyCellInfo(in List<CellInfo> cellInfo);
void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
@@ -47,5 +61,7 @@
void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
String failCause);
+ void notifyCellInfoUsingSubId(in long subId, in List<CellInfo> cellInfo);
void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
+ void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index 08f4379..aecf955 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -58,6 +58,7 @@
public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE;
public static final int PHONE_TYPE_SIP = RILConstants.SIP_PHONE;
public static final int PHONE_TYPE_THIRD_PARTY = RILConstants.THIRD_PARTY_PHONE;
+ public static final int PHONE_TYPE_IMS = RILConstants.IMS_PHONE;
// Modes for LTE_ON_CDMA
public static final int LTE_ON_CDMA_UNKNOWN = RILConstants.LTE_ON_CDMA_UNKNOWN;
@@ -133,4 +134,55 @@
/** APN type for IA Initial Attach APN */
public static final String APN_TYPE_IA = "ia";
+ // FIXME: This looks to be used as default phoneId, rename
+ // or use SubscriptionManager.DEFAULT_SUB_ID
+ public static final int DEFAULT_SUBSCRIPTION = 0;
+
+ // FIXME: This looks to be used as invalid phoneId, rename
+ // or use SubscriptionManager.INVALID_SUB_ID
+ public static final int INVALID_SUBSCRIPTION = -1;
+
+ public static final int RIL_CARD_MAX_APPS = 8;
+
+ public static final int DEFAULT_CARD_INDEX = 0;
+
+ public static final int MAX_PHONE_COUNT_SINGLE_SIM = 1;
+
+ public static final int MAX_PHONE_COUNT_DUAL_SIM = 2;
+
+ public static final int MAX_PHONE_COUNT_TRI_SIM = 3;
+
+ public static final String SUBSCRIPTION_KEY = "subscription";
+
+ public static final String SLOT_KEY = "slot";
+
+ public static final String SUB_SETTING = "subSettings";
+
+ public static final int SUB1 = 0;
+ public static final int SUB2 = 1;
+ public static final int SUB3 = 2;
+
+ public static final int EVENT_SUBSCRIPTION_ACTIVATED = 500;
+ public static final int EVENT_SUBSCRIPTION_DEACTIVATED = 501;
+
+ // TODO: Remove these constants and use an int instead.
+ public static final int SIM_ID_1 = 0;
+ public static final int SIM_ID_2 = 1;
+ public static final int SIM_ID_3 = 2;
+ public static final int SIM_ID_4 = 3;
+
+ // ICC SIM Application Types
+ // TODO: Replace the IccCardApplicationStatus.AppType enums with these constants
+ public static final int APPTYPE_UNKNOWN = 0;
+ public static final int APPTYPE_SIM = 1;
+ public static final int APPTYPE_USIM = 2;
+ public static final int APPTYPE_RUIM = 3;
+ public static final int APPTYPE_CSIM = 4;
+ public static final int APPTYPE_ISIM = 5;
+
+ public enum CardUnavailableReason {
+ REASON_CARD_REMOVED,
+ REASON_RADIO_UNAVAILABLE,
+ REASON_SIM_REFRESH_RESET
+ };
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 815211c..0271d0a 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -57,6 +57,7 @@
retries needed */
int MISSING_RESOURCE = 16; /* no logical channel available */
int NO_SUCH_ELEMENT = 17; /* application not found on SIM */
+ int SUBSCRIPTION_NOT_SUPPORTED = 26; /* Subscription not supported */
/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
@@ -85,6 +86,7 @@
int CDMA_PHONE = 2;
int SIP_PHONE = 3;
int THIRD_PARTY_PHONE = 4;
+ int IMS_PHONE = 5;
int LTE_ON_CDMA_UNKNOWN = -1;
int LTE_ON_CDMA_FALSE = 0;
@@ -282,6 +284,11 @@
int RIL_REQUEST_NV_WRITE_CDMA_PRL = 120;
int RIL_REQUEST_NV_RESET_CONFIG = 121;
int RIL_REQUEST_SET_RADIO_MODE = 122;
+ int RIL_REQUEST_DATA_IDLE = 123;
+ int RIL_REQUEST_SET_UICC_SUBSCRIPTION = 124;
+ int RIL_REQUEST_ALLOW_DATA = 125;
+ int RIL_REQUEST_GET_HARDWARE_CONFIG = 126;
+ int RIL_REQUEST_ICC_SIM_AUTHENTICATION = 127;
int RIL_UNSOL_RESPONSE_BASE = 1000;
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
@@ -322,4 +329,7 @@
int RIL_UNSOL_VOICE_RADIO_TECH_CHANGED = 1035;
int RIL_UNSOL_CELL_INFO_LIST = 1036;
int RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1037;
+ int RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED = 1038;
+ int RIL_UNSOL_SRVCC_STATE_NOTIFY = 1039;
+ int RIL_UNSOL_HARDWARE_CONFIG_CHANGED = 1040;
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 9ad2d42..5954947 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import android.content.Intent;
+
/**
* The intents that the telephony services broadcast.
*
@@ -48,7 +50,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -69,7 +71,7 @@
*
* <p class="note">
* Requires no permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -88,7 +90,7 @@
*
* <p class="note">
* Requires no permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -114,7 +116,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -136,7 +138,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -176,7 +178,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -207,7 +209,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -225,7 +227,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -243,7 +245,7 @@
*
* <p class="note">
* Requires the READ_PHONE_STATE permission.
- *
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
@@ -315,4 +317,85 @@
public static final String EXTRA_PLMN = "plmn";
public static final String EXTRA_SHOW_SPN = "showSpn";
public static final String EXTRA_SPN = "spn";
+
+ /**
+ * <p>Broadcast Action: It indicates one column of a siminfo record has been changed
+ * The intent will have the following extra values:</p>
+ * <ul>
+ * <li><em>columnName</em> - The siminfo column that is updated.</li>
+ * <li><em>stringContent</em> - The string value of the updated column.</li>
+ * <li><em>intContent</em> - The int value of the updated column.</li>
+ * </ul>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_SIMINFO_CONTENT_CHANGE
+ = "android.intent.action.ACTION_SIMINFO_CONTENT_CHANGE";
+
+ /**
+ * <p>Broadcast Action: It indicates one column of a subinfo record has been changed
+ * The intent will have the following extra values:</p>
+ * <ul>
+ * <li><em>columnName</em> - The siminfo column that is updated.</li>
+ * <li><em>stringContent</em> - The string value of the updated column.</li>
+ * <li><em>intContent</em> - The int value of the updated column.</li>
+ * </ul>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_SUBINFO_CONTENT_CHANGE
+ = "android.intent.action.ACTION_SUBINFO_CONTENT_CHANGE";
+
+ /**
+ * <p>Broadcast Action: It indicates siminfo update is completed when SIM inserted state change
+ * The intent will have the following extra values:</p>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_SIMINFO_UPDATED
+ = "android.intent.action.ACTION_SIMINFO_UPDATED";
+
+ /**
+ * <p>Broadcast Action: It indicates subinfo record update is completed
+ * when SIM inserted state change
+ * The intent will have the following extra values:</p>
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ public static final String ACTION_SUBINFO_RECORD_UPDATED
+ = "android.intent.action.ACTION_SUBINFO_RECORD_UPDATED";
+
+ public static final String EXTRA_COLUMN_NAME = "columnName";
+ public static final String EXTRA_INT_CONTENT = "intContent";
+ public static final String EXTRA_STRING_CONTENT = "stringContent";
+
+ /**
+ * Broadcast Action: The default subscription has changed. This has the following
+ * extra values:</p>
+ * <ul>
+ * <li><em>subscription</em> - A int, the current default subscription.</li>
+ * </ul>
+ */
+ public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED
+ = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED";
+
+ /**
+ * Broadcast Action: The default data subscription has changed. This has the following
+ * extra values:</p>
+ * <ul>
+ * <li><em>subscription</em> - A int, the current data default subscription.</li>
+ * </ul>
+ */
+ public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED
+ = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED";
+
+ /**
+ * Broadcast Action: The default voice subscription has changed. This has the following
+ * extra values:</p>
+ * <ul>
+ * <li><em>subscription</em> - A int, the current voice default subscription.</li>
+ * </ul>
+ */
+ public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED
+ = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED";
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index f95e081..5ec4247 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -187,4 +187,26 @@
* Ignore RIL_UNSOL_NITZ_TIME_RECEIVED completely, used for debugging/testing.
*/
static final String PROPERTY_IGNORE_NITZ = "telephony.test.ignore.nitz";
+
+ /**
+ * Property to set multi sim feature.
+ * Type: String(dsds, dsda)
+ */
+ static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config";
+
+ /**
+ * Property to store default subscription.
+ */
+ static final String PROPERTY_DEFAULT_SUBSCRIPTION = "persist.radio.default.sub";
+
+ /**
+ * Property to enable MMS Mode.
+ * Type: string ( default = silent, enable to = prompt )
+ */
+ static final String PROPERTY_MMS_TRANSACTION = "mms.transaction";
+
+ /**
+ * Set to the sim count.
+ */
+ static final String PROPERTY_SIM_COUNT = "ro.telephony.sim.count";
}
diff --git a/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java b/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java
new file mode 100644
index 0000000..45e5216
--- /dev/null
+++ b/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java
@@ -0,0 +1,64 @@
+package com.android.speech.tts;
+
+import android.speech.tts.TtsEngines;
+import android.test.InstrumentationTestCase;
+
+import java.util.Locale;
+
+public class TtsEnginesTests extends InstrumentationTestCase {
+ private TtsEngines mTtsHelper;
+
+ @Override
+ public void setUp() {
+ mTtsHelper = new TtsEngines(getInstrumentation().getContext());
+ }
+
+ public void testParseLocaleString() {
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng-usa"));
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng-USA"));
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("en-US"));
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("en_us"));
+ assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng_US"));
+ assertEquals(new Locale("en", "US", "foobar"),
+ mTtsHelper.parseLocaleString("eng_US-foobar"));
+ assertEquals(new Locale("en", "", "foobar"), mTtsHelper.parseLocaleString("eng__foobar"));
+ assertNull(mTtsHelper.parseLocaleString("cc_xx_barbar"));
+ assertNull(mTtsHelper.parseLocaleString("cc--barbar"));
+
+ assertEquals(new Locale("en"), mTtsHelper.parseLocaleString("eng"));
+ assertEquals(new Locale("en","US","var"), mTtsHelper.parseLocaleString("eng-USA-var"));
+ }
+
+ public void testToOldLocaleStringFormat() {
+ assertArraysEqual(new String[]{"deu", "DEU", ""},
+ TtsEngines.toOldLocaleStringFormat(new Locale("de", "DE")));
+ assertArraysEqual(new String[]{"deu", "", ""},
+ TtsEngines.toOldLocaleStringFormat(new Locale("de")));
+ assertArraysEqual(new String[]{"eng", "", ""},
+ TtsEngines.toOldLocaleStringFormat(new Locale("en")));
+ assertArraysEqual(new String[]{"eng", "USA", ""},
+ TtsEngines.toOldLocaleStringFormat(new Locale("foo")));
+ }
+
+ public void testGetLocalePrefForEngine() {
+ assertEquals(new Locale("en", "US"),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:en-US"));
+ assertEquals(new Locale("en", "US"),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:eng-usa"));
+ assertEquals(new Locale("en", "US"),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:eng_USA"));
+ assertEquals(new Locale("de", "DE"),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:deu-deu"));
+ assertEquals(Locale.getDefault(),
+ mTtsHelper.getLocalePrefForEngine("foo","foo:,bar:xx"));
+ assertEquals(Locale.getDefault(),
+ mTtsHelper.getLocalePrefForEngine("other","foo:,bar:xx"));
+ }
+
+ private void assertArraysEqual(String[] expected, String[] actual) {
+ assertEquals("array length", expected.length, actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("index " + i, expected[i], actual[i]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml
index 113dce3..db2efc3 100644
--- a/tests/VectorDrawableTest/AndroidManifest.xml
+++ b/tests/VectorDrawableTest/AndroidManifest.xml
@@ -17,13 +17,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.dynamic" >
+
<uses-sdk android:minSdkVersion="20" />
<application
android:hardwareAccelerated="true"
android:label="vector" >
-
- <activity
+ <activity
android:name="VectorDrawablePerformance"
android:label="Vector Performance" >
<intent-filter>
@@ -31,13 +31,13 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
<activity
android:name="VectorDrawableAnimation"
android:label="VectorTestAnimation" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
</activity>
@@ -52,6 +52,15 @@
</intent-filter>
</activity>
<activity
+ android:name="AnimatedVectorDrawableTest"
+ android:label="AnimatedVectorDrawableTest" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="com.android.test.dynamic.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
android:name="VectorDrawable01"
android:label="VectorTest1" >
<intent-filter>
@@ -68,7 +77,6 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
<activity
android:name="VectorDrawableStaticPerf"
@@ -78,9 +86,7 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
-
<activity
android:name="VectorCheckbox"
android:label="On a Checkbox" >
@@ -89,7 +95,6 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
<activity
android:name="VectorPathChecking"
@@ -99,7 +104,6 @@
<category android:name="com.android.test.dynamic.TEST" />
</intent-filter>
-
</activity>
</application>
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml
new file mode 100644
index 0000000..d47e019
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <set android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="5000"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ <objectAnimator
+ android:duration="5000"
+ android:propertyName="trimPathEnd"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </set>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml
new file mode 100644
index 0000000..3bf2865
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation02.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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <objectAnimator
+ android:duration="5000"
+ android:propertyName="fill"
+ android:valueFrom="#FF000000"
+ android:valueTo="#FFFF0000"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml
new file mode 100644
index 0000000..72beba2
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation03.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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <objectAnimator
+ android:duration="6000"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="360"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml
new file mode 100644
index 0000000..ff86668
--- /dev/null
+++ b/tests/VectorDrawableTest/res/anim/trim_path_animation04.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.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <objectAnimator
+ android:duration="9000"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="360"/>
+
+</set>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
new file mode 100644
index 0000000..b8681b6
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/vector_drawable12" >
+
+ <target
+ android:name="pie1"
+ android:animation="@anim/trim_path_animation01" />
+ <target
+ android:name="v"
+ android:animation="@anim/trim_path_animation02" />
+
+ <target
+ android:name="rotationGroup"
+ android:animation="@anim/trim_path_animation03" />
+ <target
+ android:name="rotationGroup3"
+ android:animation="@anim/trim_path_animation03" />
+ <target
+ android:name="rotationGroupBlue"
+ android:animation="@anim/trim_path_animation03" />
+
+</animated-vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 3042f6a..e28ec41 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -23,11 +23,15 @@
android:viewportHeight="600"
android:viewportWidth="600" />
- <group>
+ <group
+ android:name="rotationGroup"
+ android:pivotX="300.0"
+ android:pivotY="300.0"
+ android:rotation="45.0" >
<path
android:name="pie1"
- android:pathData="M300,70 a230,230 0 1,0 1,0 z"
android:fill="#00000000"
+ android:pathData="M300,70 a230,230 0 1,0 1,0 z"
android:stroke="#FF00FF00"
android:strokeWidth="70"
android:trimPathEnd=".75"
@@ -36,7 +40,66 @@
<path
android:name="v"
android:fill="#FF00FF00"
- android:pathData="M300,70 l 0,-70 70,70 -70,70z"/>
+ android:pathData="M300,70 l 0,-70 70,70 -70,70z" />
+
+ <group
+ android:name="translateToCenterGroup"
+ android:rotation="0.0"
+ android:translateX="200.0"
+ android:translateY="200.0" >
+ <path
+ android:name="twoLines"
+ android:pathData="@string/twoLinePathData"
+ android:stroke="#FFFF0000"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="rotationGroup2"
+ android:pivotX="0.0"
+ android:pivotY="0.0"
+ android:rotation="-45.0" >
+ <path
+ android:name="twoLines1"
+ android:pathData="@string/twoLinePathData"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroupHalf"
+ android:translateX="65.0"
+ android:translateY="80.0" >
+ <group
+ android:name="rotationGroup3"
+ android:pivotX="-65.0"
+ android:pivotY="-80.0"
+ android:rotation="-45.0" >
+ <path
+ android:name="twoLines2"
+ android:fill="#FF00FF00"
+ android:pathData="@string/twoLinePathData"
+ android:stroke="#FF00FF00"
+ android:strokeWidth="20" />
+
+ <group
+ android:name="translateGroup"
+ android:translateX="65.0"
+ android:translateY="80.0" >
+ <group
+ android:name="rotationGroupBlue"
+ android:pivotX="-65.0"
+ android:pivotY="-80.0"
+ android:rotation="-45.0" >
+ <path
+ android:name="twoLines3"
+ android:pathData="@string/twoLinePathData"
+ android:stroke="#FF0000FF"
+ android:strokeWidth="20" />
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
+ </group>
</group>
</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
new file mode 100644
index 0000000..6e864fa
--- /dev/null
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.test.dynamic;
+
+import android.app.Activity;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+public class AnimatedVectorDrawableTest extends Activity {
+ private static final String LOGCAT = "VectorDrawableAnimationTest";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Button button = new Button(this);
+ button.setBackgroundResource(R.drawable.animation_vector_drawable01);
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ AnimatedVectorDrawable frameAnimation = (AnimatedVectorDrawable) v.getBackground();
+ frameAnimation.start();
+ }
+ });
+
+ setContentView(button);
+ }
+}
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
index 99de037..93b06b6 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java
@@ -14,6 +14,7 @@
package com.android.test.dynamic;
+import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
@@ -27,7 +28,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Button button = new Button(this);
+ final Button button = new Button(this);
button.setBackgroundResource(R.drawable.animation_drawable_vector);
button.setOnClickListener(new View.OnClickListener() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 09e6878..e1064b1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -197,7 +197,7 @@
}
@Override
- public void onRectangleOnScreenRequested(IBinder window, Rect rectangle, boolean immediate) {
+ public void onRectangleOnScreenRequested(IBinder window, Rect rectangle) {
// pass for now.
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 48396d5..b64ad60 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -342,6 +342,12 @@
/**
* @hide
+ * Uid of app owning the BSSID
+ */
+ public int bssidOwnerUid;
+
+ /**
+ * @hide
* BSSID list on which this configuration was seen.
* TODO: prevent this list to grow infinitely, age-out the results
*/
@@ -1105,6 +1111,7 @@
didSelfAdd = source.didSelfAdd;
lastConnectUid = source.lastConnectUid;
lastUpdateUid = source.lastUpdateUid;
+ bssidOwnerUid = source.bssidOwnerUid;
creatorUid = source.creatorUid;
peerWifiConfiguration = source.peerWifiConfiguration;
blackListTimestamp = source.blackListTimestamp;
@@ -1153,6 +1160,7 @@
dest.writeInt(creatorUid);
dest.writeInt(lastConnectUid);
dest.writeInt(lastUpdateUid);
+ dest.writeInt(bssidOwnerUid);
dest.writeLong(blackListTimestamp);
}
@@ -1192,6 +1200,7 @@
config.creatorUid = in.readInt();
config.lastConnectUid = in.readInt();
config.lastUpdateUid = in.readInt();
+ config.bssidOwnerUid = in.readInt();
config.blackListTimestamp = in.readLong();
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 6760c56..54a7df2 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -137,7 +137,7 @@
public int lowRssiCount;
/**
- * @hide *
+ * @hide
*/
public int score;
@@ -215,7 +215,6 @@
mRssi = INVALID_RSSI;
mLinkSpeed = -1;
mFrequency = -1;
- txBad = 0;
}
/** @hide */
@@ -228,6 +227,7 @@
setLinkSpeed(-1);
setFrequency(-1);
setMeteredHint(false);
+ txBad = 0;
txSuccess = 0;
rxSuccess = 0;
txRetries = 0;
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
index 8375d09..61c2b8a 100644
--- a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
@@ -16,6 +16,8 @@
package android.net.wifi.passpoint;
+import android.net.wifi.ScanResult;
+import android.net.wifi.passpoint.WifiPasspointPolicy;
import android.os.Messenger;
/**
@@ -27,5 +29,6 @@
{
Messenger getMessenger();
int getPasspointState();
+ List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
index 8ab5c1e..aec8797 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
@@ -286,10 +286,11 @@
public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append("BSSID: ").append(bssid);
+ sb.append("BSSID: ").append("(").append(bssid).append(")");
if (venueName != null)
- sb.append(" venueName: ").append(venueName.replace("\n", "\\n"));
+ sb.append(" venueName: ").append("(")
+ .append(venueName.replace("\n", "\\n")).append(")");
if (networkAuthType != null) {
sb.append(" networkAuthType: ");
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index 55acbad..2f158c2 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -22,6 +22,8 @@
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
@@ -45,58 +47,53 @@
/* Passpoint states values */
- /** Passpoint is in an known state. This should only occur in boot time @hide */
+ /** Passpoint is in an unknown state. This should only occur in boot time */
public static final int PASSPOINT_STATE_UNKNOWN = 0;
- /** Passpoint is disabled. This occurs when wifi is disabled. @hide */
+ /** Passpoint is disabled. This occurs when wifi is disabled */
public static final int PASSPOINT_STATE_DISABLED = 1;
- /** Passpoint is enabled and in discovery state. @hide */
+ /** Passpoint is enabled and in discovery state */
public static final int PASSPOINT_STATE_DISCOVERY = 2;
- /** Passpoint is enabled and in access state. @hide */
+ /** Passpoint is enabled and in access state */
public static final int PASSPOINT_STATE_ACCESS = 3;
- /** Passpoint is enabled and in provisioning state. @hide */
+ /** Passpoint is enabled and in provisioning state */
public static final int PASSPOINT_STATE_PROVISION = 4;
/* Passpoint callback error codes */
- /** Indicates that the operation failed due to an internal error @hide */
- public static final int ERROR = 0;
+ /** Indicates that the operation failed due to an internal error */
+ public static final int REASON_ERROR = 0;
- /** Indicates that the operation failed because wifi is disabled @hide */
- public static final int WIFI_DISABLED = 1;
+ /** Indicates that the operation failed because wifi is disabled */
+ public static final int REASON_WIFI_DISABLED = 1;
- /** Indicates that the operation failed because the framework is busy @hide */
- public static final int BUSY = 2;
+ /** Indicates that the operation failed because the framework is busy */
+ public static final int REASON_BUSY = 2;
+
+ /** Indicates that the operation failed because parameter is invalid */
+ public static final int REASON_INVALID_PARAMETER = 3;
+
+ /** Indicates that the operation failed because the server is not trusted */
+ public static final int REASON_NOT_TRUSTED = 4;
/**
* protocol supported for Passpoint
- * @hide
*/
public static final String PROTOCOL_DM = "OMA-DM-ClientInitiated";
/**
* protocol supported for Passpoint
- * @hide
*/
public static final String PROTOCOL_SOAP = "SPP-ClientInitiated";
/* Passpoint broadcasts */
/**
- * Broadcast intent action indicating that Passpoint online sign up is
- * avaiable.
- * @hide
- */
- public static final String PASSPOINT_OSU_AVAILABLE =
- "android.net.wifi.passpoint.OSU_AVAILABLE";
-
- /**
* Broadcast intent action indicating that the state of Passpoint
* connectivity has changed
- * @hide
*/
public static final String PASSPOINT_STATE_CHANGED_ACTION =
"android.net.wifi.passpoint.STATE_CHANGE";
@@ -104,7 +101,6 @@
/**
* Broadcast intent action indicating that the saved Passpoint credential
* list has changed
- * @hide
*/
public static final String PASSPOINT_CRED_CHANGED_ACTION =
"android.net.wifi.passpoint.CRED_CHANGE";
@@ -112,21 +108,18 @@
/**
* Broadcast intent action indicating that Passpoint online sign up is
* avaiable.
- * @hide
*/
public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
"android.net.wifi.passpoint.OSU_AVAILABLE";
/**
* Broadcast intent action indicating that user remediation is required
- * @hide
*/
public static final String PASSPOINT_USER_REM_REQ_ACTION =
"android.net.wifi.passpoint.USER_REM_REQ";
/**
* Interface for callback invocation when framework channel is lost
- * @hide
*/
public interface ChannelListener {
/**
@@ -138,14 +131,13 @@
/**
* Interface for callback invocation on an application action
- * @hide
*/
public interface ActionListener {
/** The operation succeeded */
public void onSuccess();
/**
- * * The operation failed
+ * The operation failed
*
* @param reason The reason for failure could be one of
* {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
@@ -155,7 +147,6 @@
/**
* Interface for callback invocation when doing OSU or user remediation
- * @hide
*/
public interface OsuRemListener {
/** The operation succeeded */
@@ -171,11 +162,11 @@
/**
* Browser launch is requried for user interaction. When this callback
- * is called, app should launch browser / webview to the given URL.
+ * is called, app should launch browser / webview to the given URI.
*
- * @param url URL for browser launch
+ * @param uri URI for browser launch
*/
- public void onBrowserLaunch(String url);
+ public void onBrowserLaunch(String uri);
/**
* When this is called, app should dismiss the previously lanched browser.
@@ -187,7 +178,6 @@
* A channel that connects the application to the wifi passpoint framework.
* Most passpoint operations require a Channel as an argument.
* An instance of Channel is obtained by doing a call on {@link #initialize}
- * @hide
*/
public static class Channel {
private final static int INVALID_LISTENER_KEY = 0;
@@ -288,7 +278,8 @@
@Override
public void handleMessage(Message message) {
- Object listener = getListener(message.arg2, false);
+ Object listener = null;
+
switch (message.what) {
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
if (mChannelListener != null) {
@@ -300,6 +291,7 @@
case REQUEST_ANQP_INFO_SUCCEEDED:
WifiPasspointInfo result = (WifiPasspointInfo) message.obj;
anqpRequestFinish(result);
+ listener = getListener(message.arg2, false);
if (listener != null) {
((ActionListener) listener).onSuccess();
}
@@ -307,6 +299,7 @@
case REQUEST_ANQP_INFO_FAILED:
anqpRequestFinish((ScanResult) message.obj);
+ listener = getListener(message.arg2, false);
if (listener == null)
getListener(message.arg2, true);
if (listener != null) {
@@ -314,6 +307,31 @@
}
break;
+ case START_OSU_SUCCEEDED:
+ listener = getListener(message.arg2, true);
+ if (listener != null) {
+ ((OsuRemListener) listener).onSuccess();
+ }
+ break;
+
+ case START_OSU_FAILED:
+ listener = getListener(message.arg2, true);
+ if (listener != null) {
+ ((OsuRemListener) listener).onFailure(message.arg1);
+ }
+ break;
+
+ case START_OSU_BROWSER:
+ listener = getListener(message.arg2, true);
+ if (listener != null) {
+ ParcelableString str = (ParcelableString) message.obj;
+ if (str.string == null)
+ ((OsuRemListener) listener).onBrowserDismiss();
+ else
+ ((OsuRemListener) listener).onBrowserLaunch(str.string);
+ }
+ break;
+
default:
Log.d(TAG, "Ignored " + message);
break;
@@ -323,25 +341,46 @@
}
+ public static class ParcelableString implements Parcelable {
+ public String string;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(string);
+ }
+
+ public static final Parcelable.Creator<ParcelableString> CREATOR =
+ new Parcelable.Creator<ParcelableString>() {
+ @Override
+ public ParcelableString createFromParcel(Parcel in) {
+ ParcelableString ret = new ParcelableString();
+ ret.string = in.readString();
+ return ret;
+ }
+ @Override
+ public ParcelableString[] newArray(int size) {
+ return new ParcelableString[size];
+ }
+ };
+ }
+
private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
- /** @hide */
- public static final int REQUEST_ANQP_INFO = BASE + 1;
-
- /** @hide */
- public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2;
-
- /** @hide */
- public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3;
-
- /** @hide */
- public static final int REQUEST_OSU_INFO = BASE + 4;
-
- /** @hide */
- public static final int REQUEST_OSU_INFO_FAILED = BASE + 5;
-
- /** @hide */
- public static final int REQUEST_OSU_INFO_SUCCEEDED = BASE + 6;
+ public static final int REQUEST_ANQP_INFO = BASE + 1;
+ public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2;
+ public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3;
+ public static final int REQUEST_OSU_ICON = BASE + 4;
+ public static final int REQUEST_OSU_ICON_FAILED = BASE + 5;
+ public static final int REQUEST_OSU_ICON_SUCCEEDED = BASE + 6;
+ public static final int START_OSU = BASE + 7;
+ public static final int START_OSU_BROWSER = BASE + 8;
+ public static final int START_OSU_FAILED = BASE + 9;
+ public static final int START_OSU_SUCCEEDED = BASE + 10;
private Context mContext;
IWifiPasspointManager mService;
@@ -350,7 +389,6 @@
* TODO: doc
* @param context
* @param service
- * @hide
*/
public WifiPasspointManager(Context context, IWifiPasspointManager service) {
mContext = context;
@@ -368,7 +406,6 @@
* @return Channel instance that is necessary for performing any further
* passpoint operations
*
- * @hide
*/
public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
Messenger messenger = getMessenger();
@@ -387,8 +424,6 @@
/**
* STOPSHIP: temp solution, should use supplicant manager instead, check
* with b/13931972
- *
- * @hide
*/
public Messenger getMessenger() {
try {
@@ -398,7 +433,6 @@
}
}
- /** @hide */
public int getPasspointState() {
try {
return mService.getPasspointState();
@@ -407,7 +441,6 @@
}
}
- /** @hide */
public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
ActionListener listener) {
Log.d(TAG, "requestAnqpInfo start");
@@ -434,14 +467,16 @@
Log.d(TAG, "requestAnqpInfo end");
}
- /** @hide */
public void requestOsuIcons(Channel c, List<WifiPasspointOsuProvider> requested,
int resolution, ActionListener listener) {
}
- /** @hide */
public List<WifiPasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
- return null;
+ try {
+ return mService.requestCredentialMatch(requested);
+ } catch (RemoteException e) {
+ return null;
+ }
}
/**
@@ -486,21 +521,21 @@
return true;
}
- /** @hide */
- public void startOsu(Channel c, WifiPasspointOsuProvider selected, OsuRemListener listener) {
-
+ public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {
+ Log.d(TAG, "startOsu start");
+ checkChannel(c);
+ int key = c.putListener(listener);
+ c.mAsyncChannel.sendMessage(START_OSU, 0, key, osu);
+ Log.d(TAG, "startOsu end");
}
- /** @hide */
public void startUserRemediation(Channel c, OsuRemListener listener) {
}
- /** @hide */
- public void connect(WifiPasspointPolicy selected) {
+ public void connect(WifiPasspointPolicy policy) {
}
private static void checkChannel(Channel c) {
- if (c == null)
- throw new IllegalArgumentException("Channel needs to be initialized");
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
}
}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
index f40dc4f..b54b70c 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
@@ -87,12 +87,12 @@
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
- sb.append("SSID: ").append(ssid);
+ sb.append("SSID: ").append("<").append(ssid).append(">");
if (friendlyName != null)
- sb.append(" friendlyName: ").append(friendlyName);
+ sb.append(" friendlyName: ").append("<").append(friendlyName).append(">");
if (serverUri != null)
- sb.append(" serverUri: ").append(serverUri);
- sb.append(" osuMethod: ").append(osuMethod);
+ sb.append(" serverUri: ").append("<").append(serverUri).append(">");
+ sb.append(" osuMethod: ").append("<").append(osuMethod).append(">");
if (iconFileName != null) {
sb.append(" icon: <").append(iconWidth).append("x")
.append(iconHeight).append(" ")
@@ -100,9 +100,9 @@
.append(iconFileName).append(">");
}
if (osuNai != null)
- sb.append(" osuNai: ").append(osuNai);
+ sb.append(" osuNai: ").append("<").append(osuNai).append(">");
if (osuService != null)
- sb.append(" osuService: ").append(osuService);
+ sb.append(" osuService: ").append("<").append(osuService).append(">");
return sb.toString();
}