Merge "Add a timeout for disconnecting devices to recover from error situation"
diff --git a/Android.mk b/Android.mk
index ea8314c..752a5f8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -183,6 +183,7 @@
media/java/android/media/IAudioFocusDispatcher.aidl \
media/java/android/media/IMediaScannerListener.aidl \
media/java/android/media/IMediaScannerService.aidl \
+ media/java/android/media/IRemoteControlClient.aidl \
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
diff --git a/api/current.txt b/api/current.txt
index 6cef3a7..fcf8bcf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15,6 +15,7 @@
field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
+ field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -1031,6 +1032,7 @@
field public static final int translationY = 16843555; // 0x1010323
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
+ field public static final int uiOptions = 16843682; // 0x10103a2
field public static final int uncertainGestureColor = 16843382; // 0x1010276
field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
@@ -1497,6 +1499,12 @@
field public static final int Animation_InputMethod = 16973910; // 0x1030056
field public static final int Animation_Toast = 16973828; // 0x1030004
field public static final int Animation_Translucent = 16973827; // 0x1030003
+ field public static final int DeviceDefault_ButtonBar = 16974287; // 0x10301cf
+ field public static final int DeviceDefault_ButtonBar_AlertDialog = 16974288; // 0x10301d0
+ field public static final int DeviceDefault_Light_ButtonBar = 16974290; // 0x10301d2
+ field public static final int DeviceDefault_Light_ButtonBar_AlertDialog = 16974291; // 0x10301d3
+ field public static final int DeviceDefault_Light_SegmentedButton = 16974292; // 0x10301d4
+ field public static final int DeviceDefault_SegmentedButton = 16974289; // 0x10301d1
field public static final int Holo_ButtonBar = 16974053; // 0x10300e5
field public static final int Holo_ButtonBar_AlertDialog = 16974055; // 0x10300e7
field public static final int Holo_Light_ButtonBar = 16974054; // 0x10300e6
@@ -1511,6 +1519,40 @@
field public static final int MediaButton_Previous = 16973880; // 0x1030038
field public static final int MediaButton_Rew = 16973884; // 0x103003c
field public static final int TextAppearance = 16973886; // 0x103003e
+ field public static final int TextAppearance_DeviceDefault = 16974253; // 0x10301ad
+ field public static final int TextAppearance_DeviceDefault_DialogWindowTitle = 16974264; // 0x10301b8
+ field public static final int TextAppearance_DeviceDefault_Inverse = 16974254; // 0x10301ae
+ field public static final int TextAppearance_DeviceDefault_Large = 16974255; // 0x10301af
+ field public static final int TextAppearance_DeviceDefault_Large_Inverse = 16974256; // 0x10301b0
+ field public static final int TextAppearance_DeviceDefault_Medium = 16974257; // 0x10301b1
+ field public static final int TextAppearance_DeviceDefault_Medium_Inverse = 16974258; // 0x10301b2
+ field public static final int TextAppearance_DeviceDefault_SearchResult_Subtitle = 16974262; // 0x10301b6
+ field public static final int TextAppearance_DeviceDefault_SearchResult_Title = 16974261; // 0x10301b5
+ field public static final int TextAppearance_DeviceDefault_Small = 16974259; // 0x10301b3
+ field public static final int TextAppearance_DeviceDefault_Small_Inverse = 16974260; // 0x10301b4
+ field public static final int TextAppearance_DeviceDefault_Widget = 16974265; // 0x10301b9
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Menu = 16974286; // 0x10301ce
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Subtitle = 16974279; // 0x10301c7
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Subtitle_Inverse = 16974283; // 0x10301cb
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Title = 16974278; // 0x10301c6
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionBar_Title_Inverse = 16974282; // 0x10301ca
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Subtitle = 16974281; // 0x10301c9
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Subtitle_Inverse = 16974285; // 0x10301cd
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Title = 16974280; // 0x10301c8
+ field public static final int TextAppearance_DeviceDefault_Widget_ActionMode_Title_Inverse = 16974284; // 0x10301cc
+ field public static final int TextAppearance_DeviceDefault_Widget_Button = 16974266; // 0x10301ba
+ field public static final int TextAppearance_DeviceDefault_Widget_DropDownHint = 16974271; // 0x10301bf
+ field public static final int TextAppearance_DeviceDefault_Widget_DropDownItem = 16974272; // 0x10301c0
+ field public static final int TextAppearance_DeviceDefault_Widget_EditText = 16974274; // 0x10301c2
+ field public static final int TextAppearance_DeviceDefault_Widget_IconMenu_Item = 16974267; // 0x10301bb
+ field public static final int TextAppearance_DeviceDefault_Widget_PopupMenu = 16974275; // 0x10301c3
+ field public static final int TextAppearance_DeviceDefault_Widget_PopupMenu_Large = 16974276; // 0x10301c4
+ field public static final int TextAppearance_DeviceDefault_Widget_PopupMenu_Small = 16974277; // 0x10301c5
+ field public static final int TextAppearance_DeviceDefault_Widget_TabWidget = 16974268; // 0x10301bc
+ field public static final int TextAppearance_DeviceDefault_Widget_TextView = 16974269; // 0x10301bd
+ field public static final int TextAppearance_DeviceDefault_Widget_TextView_PopupMenu = 16974270; // 0x10301be
+ field public static final int TextAppearance_DeviceDefault_Widget_TextView_SpinnerItem = 16974273; // 0x10301c1
+ field public static final int TextAppearance_DeviceDefault_WindowTitle = 16974263; // 0x10301b7
field public static final int TextAppearance_DialogWindowTitle = 16973889; // 0x1030041
field public static final int TextAppearance_Holo = 16974075; // 0x10300fb
field public static final int TextAppearance_Holo_DialogWindowTitle = 16974103; // 0x1030117
@@ -1524,15 +1566,15 @@
field public static final int TextAppearance_Holo_Small = 16974081; // 0x1030101
field public static final int TextAppearance_Holo_Small_Inverse = 16974082; // 0x1030102
field public static final int TextAppearance_Holo_Widget = 16974085; // 0x1030105
- field public static final int TextAppearance_Holo_Widget_ActionBar_Menu = 16974113; // 0x1030121
+ field public static final int TextAppearance_Holo_Widget_ActionBar_Menu = 16974112; // 0x1030120
field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle = 16974099; // 0x1030113
- field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle_Inverse = 16974110; // 0x103011e
+ field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle_Inverse = 16974109; // 0x103011d
field public static final int TextAppearance_Holo_Widget_ActionBar_Title = 16974098; // 0x1030112
- field public static final int TextAppearance_Holo_Widget_ActionBar_Title_Inverse = 16974109; // 0x103011d
+ field public static final int TextAppearance_Holo_Widget_ActionBar_Title_Inverse = 16974108; // 0x103011c
field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle = 16974101; // 0x1030115
- field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle_Inverse = 16974112; // 0x1030120
+ field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle_Inverse = 16974111; // 0x103011f
field public static final int TextAppearance_Holo_Widget_ActionMode_Title = 16974100; // 0x1030114
- field public static final int TextAppearance_Holo_Widget_ActionMode_Title_Inverse = 16974111; // 0x103011f
+ field public static final int TextAppearance_Holo_Widget_ActionMode_Title_Inverse = 16974110; // 0x103011e
field public static final int TextAppearance_Holo_Widget_Button = 16974086; // 0x1030106
field public static final int TextAppearance_Holo_Widget_DropDownHint = 16974091; // 0x103010b
field public static final int TextAppearance_Holo_Widget_DropDownItem = 16974092; // 0x103010c
@@ -1576,6 +1618,30 @@
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
+ field public static final int Theme_DeviceDefault = 16974120; // 0x1030128
+ field public static final int Theme_DeviceDefault_Dialog = 16974126; // 0x103012e
+ field public static final int Theme_DeviceDefault_DialogWhenLarge = 16974134; // 0x1030136
+ field public static final int Theme_DeviceDefault_DialogWhenLarge_NoActionBar = 16974135; // 0x1030137
+ field public static final int Theme_DeviceDefault_Dialog_MinWidth = 16974127; // 0x103012f
+ field public static final int Theme_DeviceDefault_Dialog_NoActionBar = 16974128; // 0x1030130
+ field public static final int Theme_DeviceDefault_Dialog_NoActionBar_MinWidth = 16974129; // 0x1030131
+ field public static final int Theme_DeviceDefault_InputMethod = 16974142; // 0x103013e
+ field public static final int Theme_DeviceDefault_Light = 16974123; // 0x103012b
+ field public static final int Theme_DeviceDefault_Light_DarkActionBar = 16974143; // 0x103013f
+ field public static final int Theme_DeviceDefault_Light_Dialog = 16974130; // 0x1030132
+ field public static final int Theme_DeviceDefault_Light_DialogWhenLarge = 16974136; // 0x1030138
+ field public static final int Theme_DeviceDefault_Light_DialogWhenLarge_NoActionBar = 16974137; // 0x1030139
+ field public static final int Theme_DeviceDefault_Light_Dialog_MinWidth = 16974131; // 0x1030133
+ field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar = 16974132; // 0x1030134
+ field public static final int Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth = 16974133; // 0x1030135
+ field public static final int Theme_DeviceDefault_Light_NoActionBar = 16974124; // 0x103012c
+ field public static final int Theme_DeviceDefault_Light_NoActionBar_Fullscreen = 16974125; // 0x103012d
+ field public static final int Theme_DeviceDefault_Light_Panel = 16974139; // 0x103013b
+ field public static final int Theme_DeviceDefault_NoActionBar = 16974121; // 0x1030129
+ field public static final int Theme_DeviceDefault_NoActionBar_Fullscreen = 16974122; // 0x103012a
+ field public static final int Theme_DeviceDefault_Panel = 16974138; // 0x103013a
+ 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
field public static final int Theme_Holo = 16973931; // 0x103006b
field public static final int Theme_Holo_Dialog = 16973935; // 0x103006f
@@ -1586,6 +1652,7 @@
field public static final int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072
field public static final int Theme_Holo_InputMethod = 16973951; // 0x103007f
field public static final int Theme_Holo_Light = 16973934; // 0x103006e
+ field public static final int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119
field public static final int Theme_Holo_Light_Dialog = 16973939; // 0x1030073
field public static final int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079
field public static final int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a
@@ -1595,17 +1662,9 @@
field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
- field public static final int Theme_Holo_Light_SolidActionBar = 16974122; // 0x103012a
- field public static final int Theme_Holo_Light_SolidActionBar_Inverse = 16974123; // 0x103012b
- field public static final int Theme_Holo_Light_SolidActionBar_Inverse_SplitActionBarWhenNarrow = 16974126; // 0x103012e
- field public static final int Theme_Holo_Light_SolidActionBar_SplitActionBarWhenNarrow = 16974125; // 0x103012d
- field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974106; // 0x103011a
field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
- field public static final int Theme_Holo_SolidActionBar = 16974121; // 0x1030129
- field public static final int Theme_Holo_SolidActionBar_SplitActionBarWhenNarrow = 16974124; // 0x103012c
- field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974105; // 0x1030119
field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
field public static final int Theme_InputMethod = 16973908; // 0x1030054
@@ -1647,6 +1706,115 @@
field public static final int Widget_CompoundButton_RadioButton = 16973850; // 0x103001a
field public static final int Widget_CompoundButton_Star = 16973851; // 0x103001b
field public static final int Widget_DatePicker = 16974062; // 0x10300ee
+ field public static final int Widget_DeviceDefault = 16974144; // 0x1030140
+ field public static final int Widget_DeviceDefault_ActionBar = 16974187; // 0x103016b
+ field public static final int Widget_DeviceDefault_ActionBar_Solid = 16974195; // 0x1030173
+ field public static final int Widget_DeviceDefault_ActionBar_TabBar = 16974194; // 0x1030172
+ field public static final int Widget_DeviceDefault_ActionBar_TabText = 16974193; // 0x1030171
+ field public static final int Widget_DeviceDefault_ActionBar_TabView = 16974192; // 0x1030170
+ field public static final int Widget_DeviceDefault_ActionButton = 16974182; // 0x1030166
+ field public static final int Widget_DeviceDefault_ActionButton_CloseMode = 16974186; // 0x103016a
+ field public static final int Widget_DeviceDefault_ActionButton_Overflow = 16974183; // 0x1030167
+ field public static final int Widget_DeviceDefault_ActionButton_TextButton = 16974184; // 0x1030168
+ field public static final int Widget_DeviceDefault_ActionMode = 16974185; // 0x1030169
+ field public static final int Widget_DeviceDefault_AutoCompleteTextView = 16974151; // 0x1030147
+ field public static final int Widget_DeviceDefault_Button = 16974145; // 0x1030141
+ field public static final int Widget_DeviceDefault_Button_Borderless = 16974188; // 0x103016c
+ field public static final int Widget_DeviceDefault_Button_Borderless_Small = 16974149; // 0x1030145
+ field public static final int Widget_DeviceDefault_Button_Inset = 16974147; // 0x1030143
+ field public static final int Widget_DeviceDefault_Button_Small = 16974146; // 0x1030142
+ field public static final int Widget_DeviceDefault_Button_Toggle = 16974148; // 0x1030144
+ field public static final int Widget_DeviceDefault_CalendarView = 16974190; // 0x103016e
+ field public static final int Widget_DeviceDefault_CompoundButton_CheckBox = 16974152; // 0x1030148
+ field public static final int Widget_DeviceDefault_CompoundButton_RadioButton = 16974169; // 0x1030159
+ field public static final int Widget_DeviceDefault_CompoundButton_Star = 16974173; // 0x103015d
+ field public static final int Widget_DeviceDefault_DatePicker = 16974191; // 0x103016f
+ field public static final int Widget_DeviceDefault_DropDownItem = 16974177; // 0x1030161
+ field public static final int Widget_DeviceDefault_DropDownItem_Spinner = 16974178; // 0x1030162
+ field public static final int Widget_DeviceDefault_EditText = 16974154; // 0x103014a
+ field public static final int Widget_DeviceDefault_ExpandableListView = 16974155; // 0x103014b
+ field public static final int Widget_DeviceDefault_GridView = 16974156; // 0x103014c
+ field public static final int Widget_DeviceDefault_HorizontalScrollView = 16974171; // 0x103015b
+ field public static final int Widget_DeviceDefault_ImageButton = 16974157; // 0x103014d
+ field public static final int Widget_DeviceDefault_Light = 16974196; // 0x1030174
+ field public static final int Widget_DeviceDefault_Light_ActionBar = 16974243; // 0x10301a3
+ field public static final int Widget_DeviceDefault_Light_ActionBar_Solid = 16974247; // 0x10301a7
+ field public static final int Widget_DeviceDefault_Light_ActionBar_Solid_Inverse = 16974248; // 0x10301a8
+ field public static final int Widget_DeviceDefault_Light_ActionBar_TabBar = 16974246; // 0x10301a6
+ field public static final int Widget_DeviceDefault_Light_ActionBar_TabBar_Inverse = 16974249; // 0x10301a9
+ field public static final int Widget_DeviceDefault_Light_ActionBar_TabText = 16974245; // 0x10301a5
+ field public static final int Widget_DeviceDefault_Light_ActionBar_TabText_Inverse = 16974251; // 0x10301ab
+ field public static final int Widget_DeviceDefault_Light_ActionBar_TabView = 16974244; // 0x10301a4
+ field public static final int Widget_DeviceDefault_Light_ActionBar_TabView_Inverse = 16974250; // 0x10301aa
+ field public static final int Widget_DeviceDefault_Light_ActionButton = 16974239; // 0x103019f
+ field public static final int Widget_DeviceDefault_Light_ActionButton_CloseMode = 16974242; // 0x10301a2
+ field public static final int Widget_DeviceDefault_Light_ActionButton_Overflow = 16974240; // 0x10301a0
+ field public static final int Widget_DeviceDefault_Light_ActionMode = 16974241; // 0x10301a1
+ field public static final int Widget_DeviceDefault_Light_ActionMode_Inverse = 16974252; // 0x10301ac
+ field public static final int Widget_DeviceDefault_Light_AutoCompleteTextView = 16974203; // 0x103017b
+ field public static final int Widget_DeviceDefault_Light_Button = 16974197; // 0x1030175
+ field public static final int Widget_DeviceDefault_Light_Button_Borderless_Small = 16974201; // 0x1030179
+ field public static final int Widget_DeviceDefault_Light_Button_Inset = 16974199; // 0x1030177
+ field public static final int Widget_DeviceDefault_Light_Button_Small = 16974198; // 0x1030176
+ field public static final int Widget_DeviceDefault_Light_Button_Toggle = 16974200; // 0x1030178
+ field public static final int Widget_DeviceDefault_Light_CalendarView = 16974238; // 0x103019e
+ field public static final int Widget_DeviceDefault_Light_CompoundButton_CheckBox = 16974204; // 0x103017c
+ field public static final int Widget_DeviceDefault_Light_CompoundButton_RadioButton = 16974224; // 0x1030190
+ field public static final int Widget_DeviceDefault_Light_CompoundButton_Star = 16974228; // 0x1030194
+ field public static final int Widget_DeviceDefault_Light_DropDownItem = 16974232; // 0x1030198
+ field public static final int Widget_DeviceDefault_Light_DropDownItem_Spinner = 16974233; // 0x1030199
+ field public static final int Widget_DeviceDefault_Light_EditText = 16974206; // 0x103017e
+ field public static final int Widget_DeviceDefault_Light_ExpandableListView = 16974207; // 0x103017f
+ field public static final int Widget_DeviceDefault_Light_GridView = 16974208; // 0x1030180
+ field public static final int Widget_DeviceDefault_Light_HorizontalScrollView = 16974226; // 0x1030192
+ field public static final int Widget_DeviceDefault_Light_ImageButton = 16974209; // 0x1030181
+ field public static final int Widget_DeviceDefault_Light_ListPopupWindow = 16974235; // 0x103019b
+ field public static final int Widget_DeviceDefault_Light_ListView = 16974210; // 0x1030182
+ field public static final int Widget_DeviceDefault_Light_ListView_DropDown = 16974205; // 0x103017d
+ field public static final int Widget_DeviceDefault_Light_PopupMenu = 16974236; // 0x103019c
+ field public static final int Widget_DeviceDefault_Light_PopupWindow = 16974211; // 0x1030183
+ field public static final int Widget_DeviceDefault_Light_ProgressBar = 16974212; // 0x1030184
+ field public static final int Widget_DeviceDefault_Light_ProgressBar_Horizontal = 16974213; // 0x1030185
+ field public static final int Widget_DeviceDefault_Light_ProgressBar_Inverse = 16974217; // 0x1030189
+ field public static final int Widget_DeviceDefault_Light_ProgressBar_Large = 16974216; // 0x1030188
+ field public static final int Widget_DeviceDefault_Light_ProgressBar_Large_Inverse = 16974219; // 0x103018b
+ field public static final int Widget_DeviceDefault_Light_ProgressBar_Small = 16974214; // 0x1030186
+ field public static final int Widget_DeviceDefault_Light_ProgressBar_Small_Inverse = 16974218; // 0x103018a
+ field public static final int Widget_DeviceDefault_Light_ProgressBar_Small_Title = 16974215; // 0x1030187
+ field public static final int Widget_DeviceDefault_Light_RatingBar = 16974221; // 0x103018d
+ field public static final int Widget_DeviceDefault_Light_RatingBar_Indicator = 16974222; // 0x103018e
+ field public static final int Widget_DeviceDefault_Light_RatingBar_Small = 16974223; // 0x103018f
+ field public static final int Widget_DeviceDefault_Light_ScrollView = 16974225; // 0x1030191
+ field public static final int Widget_DeviceDefault_Light_SeekBar = 16974220; // 0x103018c
+ field public static final int Widget_DeviceDefault_Light_Spinner = 16974227; // 0x1030193
+ field public static final int Widget_DeviceDefault_Light_Tab = 16974237; // 0x103019d
+ field public static final int Widget_DeviceDefault_Light_TabWidget = 16974229; // 0x1030195
+ field public static final int Widget_DeviceDefault_Light_TextView = 16974202; // 0x103017a
+ field public static final int Widget_DeviceDefault_Light_TextView_SpinnerItem = 16974234; // 0x103019a
+ field public static final int Widget_DeviceDefault_Light_WebTextView = 16974230; // 0x1030196
+ field public static final int Widget_DeviceDefault_Light_WebView = 16974231; // 0x1030197
+ field public static final int Widget_DeviceDefault_ListPopupWindow = 16974180; // 0x1030164
+ field public static final int Widget_DeviceDefault_ListView = 16974158; // 0x103014e
+ field public static final int Widget_DeviceDefault_ListView_DropDown = 16974153; // 0x1030149
+ field public static final int Widget_DeviceDefault_PopupMenu = 16974181; // 0x1030165
+ field public static final int Widget_DeviceDefault_PopupWindow = 16974159; // 0x103014f
+ field public static final int Widget_DeviceDefault_ProgressBar = 16974160; // 0x1030150
+ field public static final int Widget_DeviceDefault_ProgressBar_Horizontal = 16974161; // 0x1030151
+ field public static final int Widget_DeviceDefault_ProgressBar_Large = 16974164; // 0x1030154
+ field public static final int Widget_DeviceDefault_ProgressBar_Small = 16974162; // 0x1030152
+ field public static final int Widget_DeviceDefault_ProgressBar_Small_Title = 16974163; // 0x1030153
+ field public static final int Widget_DeviceDefault_RatingBar = 16974166; // 0x1030156
+ field public static final int Widget_DeviceDefault_RatingBar_Indicator = 16974167; // 0x1030157
+ field public static final int Widget_DeviceDefault_RatingBar_Small = 16974168; // 0x1030158
+ field public static final int Widget_DeviceDefault_ScrollView = 16974170; // 0x103015a
+ field public static final int Widget_DeviceDefault_SeekBar = 16974165; // 0x1030155
+ field public static final int Widget_DeviceDefault_Spinner = 16974172; // 0x103015c
+ field public static final int Widget_DeviceDefault_Tab = 16974189; // 0x103016d
+ field public static final int Widget_DeviceDefault_TabWidget = 16974174; // 0x103015e
+ field public static final int Widget_DeviceDefault_TextView = 16974150; // 0x1030146
+ field public static final int Widget_DeviceDefault_TextView_SpinnerItem = 16974179; // 0x1030163
+ field public static final int Widget_DeviceDefault_WebTextView = 16974175; // 0x103015f
+ field public static final int Widget_DeviceDefault_WebView = 16974176; // 0x1030160
field public static final int Widget_DropDownItem = 16973867; // 0x103002b
field public static final int Widget_DropDownItem_Spinner = 16973868; // 0x103002c
field public static final int Widget_EditText = 16973859; // 0x1030023
@@ -1656,7 +1824,7 @@
field public static final int Widget_GridView = 16973874; // 0x1030032
field public static final int Widget_Holo = 16973962; // 0x103008a
field public static final int Widget_Holo_ActionBar = 16974004; // 0x10300b4
- field public static final int Widget_Holo_ActionBar_Solid = 16974114; // 0x1030122
+ field public static final int Widget_Holo_ActionBar_Solid = 16974113; // 0x1030121
field public static final int Widget_Holo_ActionBar_TabBar = 16974071; // 0x10300f7
field public static final int Widget_Holo_ActionBar_TabText = 16974070; // 0x10300f6
field public static final int Widget_Holo_ActionBar_TabView = 16974069; // 0x10300f5
@@ -1668,7 +1836,7 @@
field public static final int Widget_Holo_AutoCompleteTextView = 16973968; // 0x1030090
field public static final int Widget_Holo_Button = 16973963; // 0x103008b
field public static final int Widget_Holo_Button_Borderless = 16974050; // 0x10300e2
- field public static final int Widget_Holo_Button_Borderless_Small = 16974107; // 0x103011b
+ field public static final int Widget_Holo_Button_Borderless_Small = 16974106; // 0x103011a
field public static final int Widget_Holo_Button_Inset = 16973965; // 0x103008d
field public static final int Widget_Holo_Button_Small = 16973964; // 0x103008c
field public static final int Widget_Holo_Button_Toggle = 16973966; // 0x103008e
@@ -1686,22 +1854,22 @@
field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096
field public static final int Widget_Holo_Light = 16974005; // 0x10300b5
field public static final int Widget_Holo_Light_ActionBar = 16974049; // 0x10300e1
- field public static final int Widget_Holo_Light_ActionBar_Solid = 16974115; // 0x1030123
- field public static final int Widget_Holo_Light_ActionBar_Solid_Inverse = 16974116; // 0x1030124
+ field public static final int Widget_Holo_Light_ActionBar_Solid = 16974114; // 0x1030122
+ field public static final int Widget_Holo_Light_ActionBar_Solid_Inverse = 16974115; // 0x1030123
field public static final int Widget_Holo_Light_ActionBar_TabBar = 16974074; // 0x10300fa
- field public static final int Widget_Holo_Light_ActionBar_TabBar_Inverse = 16974117; // 0x1030125
+ field public static final int Widget_Holo_Light_ActionBar_TabBar_Inverse = 16974116; // 0x1030124
field public static final int Widget_Holo_Light_ActionBar_TabText = 16974073; // 0x10300f9
- field public static final int Widget_Holo_Light_ActionBar_TabText_Inverse = 16974119; // 0x1030127
+ field public static final int Widget_Holo_Light_ActionBar_TabText_Inverse = 16974118; // 0x1030126
field public static final int Widget_Holo_Light_ActionBar_TabView = 16974072; // 0x10300f8
- field public static final int Widget_Holo_Light_ActionBar_TabView_Inverse = 16974118; // 0x1030126
+ field public static final int Widget_Holo_Light_ActionBar_TabView_Inverse = 16974117; // 0x1030125
field public static final int Widget_Holo_Light_ActionButton = 16974045; // 0x10300dd
field public static final int Widget_Holo_Light_ActionButton_CloseMode = 16974048; // 0x10300e0
field public static final int Widget_Holo_Light_ActionButton_Overflow = 16974046; // 0x10300de
field public static final int Widget_Holo_Light_ActionMode = 16974047; // 0x10300df
- field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974120; // 0x1030128
+ field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
- field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974108; // 0x103011c
+ field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974107; // 0x103011b
field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
field public static final int Widget_Holo_Light_Button_Toggle = 16974009; // 0x10300b9
@@ -5637,6 +5805,7 @@
field public static final int SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7; // 0x7
field public static final int SCREEN_ORIENTATION_UNSPECIFIED = -1; // 0xffffffff
field public static final int SCREEN_ORIENTATION_USER = 2; // 0x2
+ field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
field public int configChanges;
field public int flags;
field public int launchMode;
@@ -5646,6 +5815,7 @@
field public java.lang.String targetActivity;
field public java.lang.String taskAffinity;
field public int theme;
+ field public int uiOptions;
}
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -5696,6 +5866,7 @@
field public int targetSdkVersion;
field public java.lang.String taskAffinity;
field public int theme;
+ field public int uiOptions;
field public int uid;
}
@@ -11118,6 +11289,7 @@
public class ConnectivityManager {
method public android.net.NetworkInfo getActiveNetworkInfo();
+ method public android.net.NetworkQuotaInfo getActiveNetworkQuotaInfo();
method public android.net.NetworkInfo[] getAllNetworkInfo();
method public boolean getBackgroundDataSetting();
method public android.net.NetworkInfo getNetworkInfo(int);
@@ -11132,7 +11304,7 @@
field public static final 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 java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
+ field public static final deprecated java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
field public static final java.lang.String EXTRA_NO_CONNECTIVITY = "noConnectivity";
field public static final java.lang.String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
field public static final java.lang.String EXTRA_REASON = "reason";
@@ -11277,6 +11449,16 @@
enum_constant public static final android.net.NetworkInfo.State UNKNOWN;
}
+ public class NetworkQuotaInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getEstimatedBytes();
+ method public long getHardLimitBytes();
+ method public long getSoftLimitBytes();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final long NO_LIMIT = -1L; // 0xffffffffffffffffL
+ }
+
public class ParseException extends java.lang.RuntimeException {
field public java.lang.String response;
}
@@ -23162,6 +23344,7 @@
method public abstract void setTitle(java.lang.CharSequence);
method public abstract void setTitleColor(int);
method public void setType(int);
+ method public void setUiOptions(int);
method public abstract void setVolumeControlStream(int);
method public void setWindowAnimations(int);
method public void setWindowManager(android.view.WindowManager, android.os.IBinder, java.lang.String);
@@ -24136,7 +24319,7 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
- field public static final int RESULT_ATTR_LOOKS_TYPO = 2; // 0x2
+ field public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 2; // 0x2
}
public final class TextInfo implements android.os.Parcelable {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d5b669e..98b867d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4399,6 +4399,9 @@
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
+ if (info.uiOptions != 0) {
+ mWindow.setUiOptions(info.uiOptions);
+ }
mUiThread = Thread.currentThread();
mMainThread = aThread;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ca6f085..28bc424 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1163,7 +1163,10 @@
* <p> If this API returns true, it means the callback will be called.
* The callback will be called with the current state of Bluetooth.
* If the state is not what was requested, an internal error would be the
- * reason.
+ * reason. If Bluetooth is already on and if this function is called to turn
+ * it on, the api will return true and a callback will be called.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param on True for on, false for off.
* @param callback The callback to notify changes to the state.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 4858f14..bba329d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -433,7 +433,19 @@
* the mode from the theme will be used.
*/
public int softInputMode;
-
+
+ /**
+ * The desired extra UI options for this activity and its main window.
+ * Set from the {@link android.R.attr#uiOptions} attribute in the
+ * activity's manifest.
+ */
+ public int uiOptions = 0;
+
+ /**
+ * Flag for use with uiOptions.
+ */
+ public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1;
+
public ActivityInfo() {
}
@@ -448,6 +460,7 @@
screenOrientation = orig.screenOrientation;
configChanges = orig.configChanges;
softInputMode = orig.softInputMode;
+ uiOptions = orig.uiOptions;
}
/**
@@ -479,6 +492,9 @@
+ " configChanges=0x" + Integer.toHexString(configChanges)
+ " softInputMode=0x" + Integer.toHexString(softInputMode));
}
+ if (uiOptions != 0) {
+ pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
+ }
super.dumpBack(pw, prefix);
}
@@ -503,6 +519,7 @@
dest.writeInt(screenOrientation);
dest.writeInt(configChanges);
dest.writeInt(softInputMode);
+ dest.writeInt(uiOptions);
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -526,5 +543,6 @@
screenOrientation = source.readInt();
configChanges = source.readInt();
softInputMode = source.readInt();
+ uiOptions = source.readInt();
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ddb6ef0..65a8750 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -91,6 +91,13 @@
public String backupAgentName;
/**
+ * The default extra UI options for activities in this application.
+ * Set from the {@link android.R.attr#uiOptions} attribute in the
+ * activity's manifest.
+ */
+ public int uiOptions = 0;
+
+ /**
* Value for {@link #flags}: if set, this application is installed in the
* device's system image.
*/
@@ -456,6 +463,9 @@
if (descriptionRes != 0) {
pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
}
+ if (uiOptions != 0) {
+ pw.println(prefix + "uiOptions=0x" + Integer.toHexString(uiOptions));
+ }
super.dumpBack(pw, prefix);
}
@@ -509,6 +519,7 @@
installLocation = orig.installLocation;
manageSpaceActivityName = orig.manageSpaceActivityName;
descriptionRes = orig.descriptionRes;
+ uiOptions = orig.uiOptions;
}
@@ -547,6 +558,7 @@
dest.writeString(manageSpaceActivityName);
dest.writeString(backupAgentName);
dest.writeInt(descriptionRes);
+ dest.writeInt(uiOptions);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -584,6 +596,7 @@
manageSpaceActivityName = source.readString();
backupAgentName = source.readString();
descriptionRes = source.readInt();
+ uiOptions = source.readInt();
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 53d6bb1..22fdc98 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -598,7 +598,12 @@
assmgr = new AssetManager();
assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Build.VERSION.RESOURCES_SDK_INT);
+
int cookie = assmgr.addAssetPath(packageFilePath);
+ if (cookie == 0) {
+ return null;
+ }
+
parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
} catch (Exception e) {
if (assmgr != null) assmgr.close();
@@ -1645,6 +1650,9 @@
}
}
+ ai.uiOptions = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
+
sa.recycle();
if (outError[0] != null) {
@@ -1850,6 +1858,10 @@
a.info.theme = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
+ a.info.uiOptions = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestActivity_uiOptions,
+ a.info.applicationInfo.uiOptions);
+
String str;
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
@@ -2091,6 +2103,7 @@
info.screenOrientation = target.info.screenOrientation;
info.taskAffinity = target.info.taskAffinity;
info.theme = target.info.theme;
+ info.uiOptions = target.info.uiOptions;
Activity a = new Activity(mParseActivityAliasArgs, info);
if (outError[0] != null) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a564d97..eb9cd21 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -16,10 +16,11 @@
package android.net;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.os.Binder;
-import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import java.net.InetAddress;
@@ -67,11 +68,19 @@
* is set to {@code true} if there are no connected networks at all.
*/
public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+
/**
* The lookup key for a {@link NetworkInfo} object. Retrieve with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ *
+ * @deprecated Since {@link NetworkInfo} can vary based on UID, applications
+ * should always obtain network information through
+ * {@link #getActiveNetworkInfo()} or
+ * {@link #getAllNetworkInfo()}.
*/
+ @Deprecated
public static final String EXTRA_NETWORK_INFO = "networkInfo";
+
/**
* The lookup key for a boolean that indicates whether a connect event
* is for a network to which the connectivity manager was failing over
@@ -515,6 +524,19 @@
}
/**
+ * Return quota status for the current active network, or {@code null} if no
+ * network is active. Quota status can change rapidly, so these values
+ * shouldn't be cached.
+ */
+ public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
+ try {
+ return mService.getActiveNetworkQuotaInfo();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Gets the value of the setting for enabling Mobile data.
*
* @return Whether mobile data is enabled.
@@ -546,10 +568,7 @@
* {@hide}
*/
public ConnectivityManager(IConnectivityManager service) {
- if (service == null) {
- throw new IllegalArgumentException("missing IConnectivityManager");
- }
- mService = service;
+ mService = checkNotNull(service, "missing IConnectivityManager");
}
/**
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b1d99a4..f391200 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,6 +18,7 @@
import android.net.LinkProperties;
import android.net.NetworkInfo;
+import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
import android.net.ProxyProperties;
import android.os.IBinder;
@@ -47,6 +48,8 @@
NetworkState[] getAllNetworkState();
+ NetworkQuotaInfo getActiveNetworkQuotaInfo();
+
boolean setRadios(boolean onOff);
boolean setRadio(int networkType, boolean turnOn);
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 3e07b0a..633c38e0 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -18,6 +18,8 @@
import android.net.INetworkPolicyListener;
import android.net.NetworkPolicy;
+import android.net.NetworkQuotaInfo;
+import android.net.NetworkState;
import android.net.NetworkTemplate;
/**
@@ -27,6 +29,7 @@
*/
interface INetworkPolicyManager {
+ /** Control UID policies. */
void setUidPolicy(int uid, int policy);
int getUidPolicy(int uid);
@@ -35,12 +38,17 @@
void registerListener(INetworkPolicyListener listener);
void unregisterListener(INetworkPolicyListener listener);
+ /** Control network policies atomically. */
void setNetworkPolicies(in NetworkPolicy[] policies);
NetworkPolicy[] getNetworkPolicies();
+ /** Snooze limit on policy matching given template. */
void snoozePolicy(in NetworkTemplate template);
+ /** Control if background data is restricted system-wide. */
void setRestrictBackground(boolean restrictBackground);
boolean getRestrictBackground();
+ NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
+
}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 7336550..5501f38 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -119,22 +119,22 @@
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- if (DBG) {
+ if (VDBG) {
mMdst.log("MdstHandler connected");
}
mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj;
} else {
- if (DBG) {
+ if (VDBG) {
mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1);
}
}
break;
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- mMdst.log("Disconnected from DataStateTracker");
+ if (VDBG) mMdst.log("Disconnected from DataStateTracker");
mMdst.mDataConnectionTrackerAc = null;
break;
default: {
- mMdst.log("Ignorning unknown message=" + msg);
+ if (VDBG) mMdst.log("Ignorning unknown message=" + msg);
break;
}
}
@@ -221,13 +221,13 @@
mLinkProperties = intent.getParcelableExtra(
Phone.DATA_LINK_PROPERTIES_KEY);
if (mLinkProperties == null) {
- log("CONNECTED event did not supply link properties.");
+ loge("CONNECTED event did not supply link properties.");
mLinkProperties = new LinkProperties();
}
mLinkCapabilities = intent.getParcelableExtra(
Phone.DATA_LINK_CAPABILITIES_KEY);
if (mLinkCapabilities == null) {
- log("CONNECTED event did not supply link capabilities.");
+ loge("CONNECTED event did not supply link capabilities.");
mLinkCapabilities = new LinkCapabilities();
}
setDetailedState(DetailedState.CONNECTED, reason, apnName);
@@ -238,7 +238,7 @@
if (TextUtils.equals(reason, Phone.REASON_LINK_PROPERTIES_CHANGED)) {
mLinkProperties = intent.getParcelableExtra(Phone.DATA_LINK_PROPERTIES_KEY);
if (mLinkProperties == null) {
- log("No link property in LINK_PROPERTIES change event.");
+ loge("No link property in LINK_PROPERTIES change event.");
mLinkProperties = new LinkProperties();
}
// Just update reason field in this NetworkInfo
@@ -269,7 +269,7 @@
setDetailedState(DetailedState.FAILED, reason, apnName);
} else if (intent.getAction().
equals(DataConnectionTracker.ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) {
- if (DBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
+ if (VDBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
mMessenger = intent.getParcelableExtra(DataConnectionTracker.EXTRA_MESSENGER);
AsyncChannel ac = new AsyncChannel();
ac.connect(mContext, MobileDataStateTracker.this.mHandler, mMessenger);
@@ -437,7 +437,7 @@
*/
for (int retry = 0; retry < 2; retry++) {
if (mPhoneService == null) {
- log("Ignoring mobile radio request because could not acquire PhoneService");
+ loge("Ignoring mobile radio request because could not acquire PhoneService");
break;
}
@@ -448,7 +448,7 @@
}
}
- log("Could not set radio power to " + (turnOn ? "on" : "off"));
+ loge("Could not set radio power to " + (turnOn ? "on" : "off"));
return false;
}
@@ -457,12 +457,12 @@
*/
public void setDataEnable(boolean enabled) {
try {
- log("setDataEnable: E enabled=" + enabled);
+ if (DBG) log("setDataEnable: E enabled=" + enabled);
mDataConnectionTrackerAc.sendMessage(DataConnectionTracker.CMD_SET_DATA_ENABLE,
enabled ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED);
- log("setDataEnable: X enabled=" + enabled);
+ if (VDBG) log("setDataEnable: X enabled=" + enabled);
} catch (Exception e) {
- log("setDataEnable: X mAc was null" + e);
+ loge("setDataEnable: X mAc was null" + e);
}
}
@@ -473,15 +473,15 @@
public void setDependencyMet(boolean met) {
Bundle bundle = Bundle.forPair(DataConnectionTracker.APN_TYPE_KEY, mApnType);
try {
- log("setDependencyMet: E met=" + met);
+ if (DBG) log("setDependencyMet: E met=" + met);
Message msg = Message.obtain();
msg.what = DataConnectionTracker.CMD_SET_DEPENDENCY_MET;
msg.arg1 = (met ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED);
msg.setData(bundle);
mDataConnectionTrackerAc.sendMessage(msg);
- log("setDependencyMet: X met=" + met);
+ if (VDBG) log("setDependencyMet: X met=" + met);
} catch (NullPointerException e) {
- log("setDependencyMet: X mAc was null" + e);
+ loge("setDependencyMet: X mAc was null" + e);
}
}
@@ -508,7 +508,7 @@
*/
for (int retry = 0; retry < 2; retry++) {
if (mPhoneService == null) {
- log("Ignoring feature request because could not acquire PhoneService");
+ loge("Ignoring feature request because could not acquire PhoneService");
break;
}
@@ -523,7 +523,7 @@
}
}
- log("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
+ loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
return Phone.APN_REQUEST_FAILED;
}
diff --git a/core/java/android/net/NetworkQuotaInfo.aidl b/core/java/android/net/NetworkQuotaInfo.aidl
new file mode 100644
index 0000000..98a02c4
--- /dev/null
+++ b/core/java/android/net/NetworkQuotaInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkQuotaInfo;
diff --git a/core/java/android/net/NetworkQuotaInfo.java b/core/java/android/net/NetworkQuotaInfo.java
new file mode 100644
index 0000000..b85f925
--- /dev/null
+++ b/core/java/android/net/NetworkQuotaInfo.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about quota status on a specific network.
+ */
+public class NetworkQuotaInfo implements Parcelable {
+ private final long mEstimatedBytes;
+ private final long mSoftLimitBytes;
+ private final long mHardLimitBytes;
+
+ public static final long NO_LIMIT = -1;
+
+ /** {@hide} */
+ public NetworkQuotaInfo(long estimatedBytes, long softLimitBytes, long hardLimitBytes) {
+ mEstimatedBytes = estimatedBytes;
+ mSoftLimitBytes = softLimitBytes;
+ mHardLimitBytes = hardLimitBytes;
+ }
+
+ /** {@hide} */
+ public NetworkQuotaInfo(Parcel in) {
+ mEstimatedBytes = in.readLong();
+ mSoftLimitBytes = in.readLong();
+ mHardLimitBytes = in.readLong();
+ }
+
+ public long getEstimatedBytes() {
+ return mEstimatedBytes;
+ }
+
+ public long getSoftLimitBytes() {
+ return mSoftLimitBytes;
+ }
+
+ public long getHardLimitBytes() {
+ return mHardLimitBytes;
+ }
+
+ /** {@inheritDoc} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(mEstimatedBytes);
+ out.writeLong(mSoftLimitBytes);
+ out.writeLong(mHardLimitBytes);
+ }
+
+ public static final Creator<NetworkQuotaInfo> CREATOR = new Creator<NetworkQuotaInfo>() {
+ public NetworkQuotaInfo createFromParcel(Parcel in) {
+ return new NetworkQuotaInfo(in);
+ }
+
+ public NetworkQuotaInfo[] newArray(int size) {
+ return new NetworkQuotaInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 4ffabb1..7a4b811 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -405,11 +405,10 @@
final long curEnd = randomLong(r, curStart, end);
entry.rxBytes = randomLong(r, 0, rx);
entry.txBytes = randomLong(r, 0, tx);
-
- recordData(curStart, curEnd, entry);
-
rx -= entry.rxBytes;
tx -= entry.txBytes;
+
+ recordData(curStart, curEnd, entry);
}
}
diff --git a/core/java/android/server/BluetoothPanProfileHandler.java b/core/java/android/server/BluetoothPanProfileHandler.java
index 0d63e19..ff22a45 100644
--- a/core/java/android/server/BluetoothPanProfileHandler.java
+++ b/core/java/android/server/BluetoothPanProfileHandler.java
@@ -173,7 +173,7 @@
if (!mBluetoothService.disconnectPanServerDeviceNative(objectPath,
device.getAddress(),
- panDevice.mIfaceAddr)) {
+ panDevice.mIface)) {
errorLog("could not disconnect Pan Server Device "+device.getAddress());
// Restore prev state
@@ -291,6 +291,7 @@
panDevice.mState = state;
panDevice.mIfaceAddr = ifaceAddr;
panDevice.mLocalRole = role;
+ panDevice.mIface = iface;
}
Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 28546dc..3029c9d 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -1565,6 +1565,8 @@
@Override
public boolean changeApplicationBluetoothState(boolean on,
IBluetoothStateChangeCallback callback, IBinder binder) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+
int pid = Binder.getCallingPid();
//mStateChangeTracker is a synchronized map
if (!mStateChangeTracker.containsKey(pid)) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 66d2641..f2b6b1f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -635,16 +635,8 @@
destroySurface();
// Create an EGL surface we can render into.
- mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
-
- if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
- int error = sEgl.eglGetError();
- if (error == EGL_BAD_NATIVE_WINDOW) {
- Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
- return null;
- }
- throw new RuntimeException("createWindowSurface failed "
- + getEGLErrorString(error));
+ if (!createSurface(holder)) {
+ return null;
}
/*
@@ -713,18 +705,34 @@
// Cancels any existing buffer to ensure we'll get a buffer
// of the right size before we call eglSwapBuffers
sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+
+ if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+ sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+ mEglSurface = null;
+ setEnabled(false);
+ }
+
+ if (holder.getSurface().isValid()) {
+ if (!createSurface(holder)) {
+ return;
+ }
+ setEnabled(true);
+ }
+ }
+
+ private boolean createSurface(SurfaceHolder holder) {
mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) {
int error = sEgl.eglGetError();
if (error == EGL_BAD_NATIVE_WINDOW) {
Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
- return;
+ return false;
}
throw new RuntimeException("createWindowSurface failed "
+ getEGLErrorString(error));
}
+ return true;
}
@Override
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 911bf2f..ec4c5a29 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1253,6 +1253,11 @@
mScroller.abortAnimation();
}
disposeResizeBuffer();
+ // Our surface is gone
+ if (mAttachInfo.mHardwareRenderer != null &&
+ mAttachInfo.mHardwareRenderer.isEnabled()) {
+ mAttachInfo.mHardwareRenderer.destroy(true);
+ }
} else if (surfaceGenerationId != mSurface.getGenerationId() &&
mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
fullRedrawNeeded = true;
@@ -1273,7 +1278,7 @@
}
} catch (RemoteException e) {
}
-
+
if (DEBUG_ORIENTATION) Log.v(
TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e07085c..6ac679c 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1213,5 +1213,10 @@
* @see android.app.Activity#getVolumeControlStream()
*/
public abstract int getVolumeControlStream();
-
+
+ /**
+ * Set extra options that will influence the UI for this window.
+ * @param uiOptions Flags specifying extra options for this window.
+ */
+ public void setUiOptions(int uiOptions) { }
}
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index 3332f1e..ed0f89d 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -34,9 +34,9 @@
/**
* Flag of the attributes of the suggestions that can be obtained by
* {@link #getSuggestionsAttributes}: this tells that the text service thinks the requested
- * word looks a typo.
+ * word looks like a typo.
*/
- public static final int RESULT_ATTR_LOOKS_TYPO = 0x0002;
+ public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 0x0002;
private final int mSuggestionsAttributes;
private final String[] mSuggestions;
private final boolean mSuggestionsAvailable;
diff --git a/core/java/android/webkit/DeviceMotionService.java b/core/java/android/webkit/DeviceMotionService.java
index 7d7a0f0..b4d5759 100755
--- a/core/java/android/webkit/DeviceMotionService.java
+++ b/core/java/android/webkit/DeviceMotionService.java
@@ -99,6 +99,7 @@
mUpdateRunnable = new Runnable() {
@Override
public void run() {
+ assert mIsRunning;
mManager.onMotionChange(new Double(mLastAcceleration[0]),
new Double(mLastAcceleration[1]), new Double(mLastAcceleration[2]),
INTERVAL_MILLIS);
@@ -157,6 +158,11 @@
assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
assert(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER);
+ // We may get callbacks after the call to getSensorManager().unregisterListener() returns.
+ if (!mIsRunning) {
+ return;
+ }
+
boolean firstData = mLastAcceleration == null;
mLastAcceleration = event.values;
if (firstData) {
diff --git a/core/java/android/webkit/DeviceOrientationService.java b/core/java/android/webkit/DeviceOrientationService.java
index f3c0576..47c8ab7 100755
--- a/core/java/android/webkit/DeviceOrientationService.java
+++ b/core/java/android/webkit/DeviceOrientationService.java
@@ -188,6 +188,7 @@
assert(event.values.length == 3);
assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
+ // We may get callbacks after the call to getSensorManager().unregisterListener() returns.
if (!mIsRunning) {
return;
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f4fd551..7620a63 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -8405,9 +8405,9 @@
}
}
- // Called by JNI to invalidate the View, given rectangle coordinates in
- // content space
- private void pageSwapCallback() {
+ /** @hide Called by JNI when pages are swapped (only occurs with hardware
+ * acceleration) */
+ protected void pageSwapCallback() {
if (inEditingMode()) {
didUpdateWebTextViewDimensions(ANYWHERE);
}
@@ -8426,11 +8426,11 @@
WebViewCore.ViewState viewState = draw.mViewState;
boolean isPictureAfterFirstLayout = viewState != null;
- // Request a callback on pageSwap (to reposition the webtextview)
- boolean registerPageSwapCallback =
- !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
-
if (updateBaseLayer) {
+ // Request a callback on pageSwap (to reposition the webtextview)
+ boolean registerPageSwapCallback =
+ !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
+
setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
getSettings().getShowVisualIndicator(),
isPictureAfterFirstLayout, registerPageSwapCallback);
@@ -9084,6 +9084,16 @@
}
}
+ /** @hide send content invalidate */
+ protected void contentInvalidateAll() {
+ mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL);
+ }
+
+ /** @hide call pageSwapCallback upon next page swap */
+ protected void registerPageSwapCallback() {
+ nativeRegisterPageSwapCallback();
+ }
+
/**
* Begin collecting per-tile profiling data
*
@@ -9245,6 +9255,7 @@
private native void nativeStopGL();
private native Rect nativeSubtractLayers(Rect content);
private native int nativeTextGeneration();
+ private native void nativeRegisterPageSwapCallback();
private native void nativeTileProfilingStart();
private native float nativeTileProfilingStop();
private native void nativeTileProfilingClear();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8d8023b..400cdbd 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -999,6 +999,7 @@
static final int DUMP_V8COUNTERS = 173;
static final int SET_JS_FLAGS = 174;
+ static final int CONTENT_INVALIDATE_ALL = 175;
// Geolocation
static final int GEOLOCATION_PERMISSIONS_PROVIDE = 180;
@@ -1503,6 +1504,10 @@
nativeSetJsFlags((String)msg.obj);
break;
+ case CONTENT_INVALIDATE_ALL:
+ nativeContentInvalidateAll();
+ break;
+
case SAVE_WEBARCHIVE:
WebView.SaveWebArchiveMessage saveMessage =
(WebView.SaveWebArchiveMessage)msg.obj;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index f354c6e..d977029 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -250,6 +250,7 @@
* {@inheritDoc}
*/
public GridLayout(Context context) {
+ //noinspection NullableProblems
this(context, null);
}
@@ -519,14 +520,6 @@
return result;
}
- private static int sum(int[] a) {
- int result = 0;
- for (int i = 0, N = a.length; i < N; i++) {
- result += a[i];
- }
- return result;
- }
-
@SuppressWarnings("unchecked")
private static <T> T[] append(T[] a, T[] b) {
T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
@@ -553,6 +546,7 @@
}
}
+ /** @noinspection UnusedParameters*/
private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
if (c.getClass() == Space.class) {
return 0;
@@ -576,7 +570,7 @@
return getDefaultMargin(c, isAtEdge, horizontal, leading);
}
- private int getMargin(View view, boolean horizontal, boolean leading) {
+ private int getMargin1(View view, boolean horizontal, boolean leading) {
LayoutParams lp = getLayoutParams(view);
int margin = horizontal ?
(leading ? lp.leftMargin : lp.rightMargin) :
@@ -584,6 +578,19 @@
return margin == UNDEFINED ? getDefaultMarginValue(view, lp, horizontal, leading) : margin;
}
+ private int getMargin(View view, boolean horizontal, boolean leading) {
+ if (mAlignmentMode == ALIGN_MARGINS) {
+ return getMargin1(view, horizontal, leading);
+ } else {
+ Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
+ int[] margins = leading ? axis.getLeadingMargins() : axis.getTrailingMargins();
+ LayoutParams lp = getLayoutParams(view);
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ int index = leading ? spec.span.min : spec.span.max;
+ return margins[index];
+ }
+ }
+
private int getTotalMargin(View child, boolean horizontal) {
return getMargin(child, horizontal, true) + getMargin(child, horizontal, false);
}
@@ -733,15 +740,6 @@
graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
}
- private void drawRectangle(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
- x2 = x2 - 1;
- y2 = y2 - 1;
- graphics.drawLine(x1, y1, x1, y2, paint);
- graphics.drawLine(x1, y1, x2, y1, paint);
- graphics.drawLine(x1, y2, x2, y2, paint);
- graphics.drawLine(x2, y1, x2, y2, paint);
- }
-
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -751,6 +749,7 @@
int width = getWidth() - getPaddingLeft() - getPaddingRight();
Paint paint = new Paint();
+ paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.argb(50, 255, 255, 255));
int[] xs = mHorizontalAxis.locations;
@@ -773,22 +772,18 @@
paint.setColor(Color.BLUE);
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
- drawRectangle(canvas,
- c.getLeft(),
- c.getTop(),
- c.getRight(),
- c.getBottom(), paint);
+ canvas.drawRect(c.getLeft(), c.getTop(), c.getRight(), c.getBottom(), paint);
}
// Draw margins
paint.setColor(Color.MAGENTA);
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
- drawRectangle(canvas,
- c.getLeft() - getMargin(c, true, true),
- c.getTop() - getMargin(c, false, true),
- c.getRight() + getMargin(c, true, false),
- c.getBottom() + getMargin(c, false, false), paint);
+ canvas.drawRect(
+ c.getLeft() - getMargin1(c, true, true),
+ c.getTop() - getMargin1(c, false, true),
+ c.getRight() + getMargin1(c, true, false),
+ c.getBottom() + getMargin1(c, false, false), paint);
}
}
}
@@ -875,11 +870,7 @@
if (isGone(c)) {
return 0;
}
- int result = getMeasurement(c, horizontal);
- if (mAlignmentMode == ALIGN_MARGINS) {
- return result + getTotalMargin(c, horizontal);
- }
- return result;
+ return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
}
@Override
@@ -920,6 +911,9 @@
mHorizontalAxis.layout(targetWidth - paddingLeft - paddingRight);
mVerticalAxis.layout(targetHeight - paddingTop - paddingBottom);
+ int[] hLocations = mHorizontalAxis.getLocations();
+ int[] vLocations = mVerticalAxis.getLocations();
+
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
if (isGone(c)) continue;
@@ -930,11 +924,11 @@
Interval colSpan = columnSpec.span;
Interval rowSpan = rowSpec.span;
- int x1 = mHorizontalAxis.getLocationIncludingMargin(true, colSpan.min);
- int y1 = mVerticalAxis.getLocationIncludingMargin(true, rowSpan.min);
+ int x1 = hLocations[colSpan.min];
+ int y1 = vLocations[rowSpan.min];
- int x2 = mHorizontalAxis.getLocationIncludingMargin(false, colSpan.max);
- int y2 = mVerticalAxis.getLocationIncludingMargin(false, rowSpan.max);
+ int x2 = hLocations[colSpan.max];
+ int y2 = vLocations[rowSpan.max];
int cellWidth = x2 - x1;
int cellHeight = y2 - y1;
@@ -951,36 +945,29 @@
Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i);
// Gravity offsets: the location of the alignment group relative to its cell group.
+ //noinspection NullableProblems
int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true)));
+ //noinspection NullableProblems
int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true)));
- if (mAlignmentMode == ALIGN_MARGINS) {
- int leftMargin = getMargin(c, true, true);
- int topMargin = getMargin(c, false, true);
- int rightMargin = getMargin(c, true, false);
- int bottomMargin = getMargin(c, false, false);
+ int leftMargin = getMargin(c, true, true);
+ int topMargin = getMargin(c, false, true);
+ int rightMargin = getMargin(c, true, false);
+ int bottomMargin = getMargin(c, false, false);
- // Same calculation as getMeasurementIncludingMargin()
- int mWidth = leftMargin + pWidth + rightMargin;
- int mHeight = topMargin + pHeight + bottomMargin;
+ // Same calculation as getMeasurementIncludingMargin()
+ int mWidth = leftMargin + pWidth + rightMargin;
+ int mHeight = topMargin + pHeight + bottomMargin;
- // Alignment offsets: the location of the view relative to its alignment group.
- int a2vx = colBounds.getOffset(c, hAlign, mWidth);
- int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
+ // Alignment offsets: the location of the view relative to its alignment group.
+ int a2vx = colBounds.getOffset(c, hAlign, mWidth);
+ int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
- dx = c2ax + a2vx + leftMargin;
- dy = c2ay + a2vy + topMargin;
+ dx = c2ax + a2vx + leftMargin;
+ dy = c2ay + a2vy + topMargin;
- cellWidth -= leftMargin + rightMargin;
- cellHeight -= topMargin + bottomMargin;
- } else {
- // Alignment offsets: the location of the view relative to its alignment group.
- int a2vx = colBounds.getOffset(c, hAlign, pWidth);
- int a2vy = rowBounds.getOffset(c, vAlign, pHeight);
-
- dx = c2ax + a2vx;
- dy = c2ay + a2vy;
- }
+ cellWidth -= leftMargin + rightMargin;
+ cellHeight -= topMargin + bottomMargin;
int type = PRF;
int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type);
@@ -1366,10 +1353,9 @@
String axis = horizontal ? "horizontal" : "vertical";
int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
- boolean changed = false;
// We take one extra pass over traditional Bellman-Ford (and omit their final step)
for (int i = 0; i < N; i++) {
- changed = false;
+ boolean changed = false;
for (int j = 0, length = arcs.length; j < length; j++) {
changed |= relax(locations, arcs[j]);
}
@@ -1420,7 +1406,7 @@
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
Interval span = spec.span;
int index = leading ? span.min : span.max;
- margins[index] = max(margins[index], getMargin(c, horizontal, leading));
+ margins[index] = max(margins[index], getMargin1(c, horizontal, leading));
}
}
@@ -1446,34 +1432,8 @@
return trailingMargins;
}
- private void addMargins() {
- int[] leadingMargins = getLeadingMargins();
- int[] trailingMargins = getTrailingMargins();
-
- int delta = 0;
- for (int i = 0, N = getCount(); i < N; i++) {
- int margins = leadingMargins[i] + trailingMargins[i + 1];
- delta += margins;
- locations[i + 1] += delta;
- }
- }
-
- private int getLocationIncludingMargin(boolean leading, int index) {
- int location = locations[index];
- int margin;
- if (mAlignmentMode != ALIGN_MARGINS) {
- margin = (leading ? leadingMargins : trailingMargins)[index];
- } else {
- margin = 0;
- }
- return leading ? (location + margin) : (location - margin);
- }
-
private void computeLocations(int[] a) {
solve1(getArcs(), a);
- if (mAlignmentMode != ALIGN_MARGINS) {
- addMargins();
- }
}
private int[] getLocations() {
@@ -1495,12 +1455,6 @@
}
private void setParentConstraints(int min, int max) {
- if (mAlignmentMode != ALIGN_MARGINS) {
- int margins = sum(getLeadingMargins()) + sum(getTrailingMargins());
- min -= margins;
- max -= margins;
- }
-
parentMin.value = min;
parentMax.value = -max;
locationsValid = false;
@@ -1905,10 +1859,6 @@
this.values = compact(values, index);
}
- private K getKey(int i) {
- return keys[index[i]];
- }
-
private V getValue(int i) {
return values[index[i]];
}
@@ -1958,8 +1908,6 @@
of the values for each View.
*/
private static class Bounds {
- private static final Bounds GONE = new Bounds();
-
public int before;
public int after;
public int flexibility; // we're flexible iff all included specs are flexible
@@ -1995,8 +1943,8 @@
protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
this.flexibility &= spec.getFlexibility();
int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
- // todo test this works correctly when the returned value is UNDEFINED
Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal);
+ // todo test this works correctly when the returned value is UNDEFINED
int before = alignment.getAlignmentValue(c, size);
include(before, size - before);
}
@@ -2079,6 +2027,7 @@
if (max != interval.max) {
return false;
}
+ //noinspection RedundantIfStatement
if (min != interval.min) {
return false;
}
@@ -2113,57 +2062,33 @@
* For column groups, this specifies the horizontal alignment.
*/
public static class Spec {
- private static final int UNDEFINED_FLEXIBILITY = UNDEFINED;
-
final Interval span;
-
final Alignment alignment;
- /**
- * The <em>flexibility</em> property tells GridLayout how to derive minimum and maximum size
- * values for a component. Specifications are made with respect to a child's
- * 'measured size'. A child's measured size is, in turn, controlled by its
- * height and width layout parameters which either specify a size or, in
- * the case of {@link LayoutParams#WRAP_CONTENT WRAP_CONTENT}, defer to
- * the computed size of the component.
- * <p>
- * A cell group is flexible only if <em>all</em> of its components are flexible.
- * <p>
- * By default, flexibility is {@link #INFLEXIBLE} only when alignment/gravity is undefined.
- */
- final int flexibility;
-
- private Spec(Interval span, Alignment alignment, int flexibility) {
+ private Spec(Interval span, Alignment alignment) {
this.span = span;
this.alignment = alignment;
- this.flexibility = flexibility;
}
/* Copying constructor */
private Spec(Spec that) {
- this(that.span, that.alignment, that.flexibility);
+ this(that.span, that.alignment);
}
private Spec(int start, int size, Alignment alignment) {
- this(new Interval(start, start + size), alignment, UNDEFINED);
+ this(new Interval(start, start + size), alignment);
}
private Spec copyWriteSpan(Interval span) {
- return new Spec(span, alignment, flexibility);
+ return new Spec(span, alignment);
}
private Spec copyWriteAlignment(Alignment alignment) {
- return new Spec(span, alignment, flexibility);
- }
-
- private static int defaultFlexibility(Alignment alignment) {
- return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
+ return new Spec(span, alignment);
}
int getFlexibility() {
- return (flexibility != UNDEFINED_FLEXIBILITY) ?
- flexibility :
- defaultFlexibility(alignment);
+ return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
}
/**
@@ -2190,6 +2115,7 @@
if (!alignment.equals(spec.alignment)) {
return false;
}
+ //noinspection RedundantIfStatement
if (!span.equals(spec.span)) {
return false;
}
@@ -2447,15 +2373,5 @@
private static final int INFLEXIBLE = 0;
- /**
- * Indicates that a view's size should be greater than or equal to the size specified by
- * its layout parameters.
- *
- * @deprecated Please use {@link #spec(int, int, Alignment)} instead,
- * all spec's that define alignment (gravity) are assumed to able to stretch.
- *
- * @hide
- */
- @Deprecated
- public static final int CAN_STRETCH = 2;
+ private static final int CAN_STRETCH = 2;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 65ee745..968d612 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -343,6 +343,9 @@
private Drawable mSelectHandleRight;
private Drawable mSelectHandleCenter;
+ // Global listener that detects changes in the global position of the TextView
+ private PositionListener mPositionListener;
+
private float mLastDownPositionX, mLastDownPositionY;
private Callback mCustomSelectionActionModeCallback;
@@ -394,7 +397,7 @@
*/
boolean onEditorAction(TextView v, int actionId, KeyEvent event);
}
-
+
public TextView(Context context) {
this(context, null);
}
@@ -2081,7 +2084,7 @@
TextAppearance_textStyle, -1);
setTypefaceByIndex(typefaceIndex, styleIndex);
-
+
if (appearance.getBoolean(com.android.internal.R.styleable.TextAppearance_textAllCaps,
false)) {
setTransformationMethod(new AllCapsTransformationMethod(getContext()));
@@ -3019,7 +3022,7 @@
* To style your strings, attach android.text.style.* objects to a
* {@link android.text.SpannableString SpannableString}, or see the
* <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">
- * Available Resource Types</a> documentation for an example of setting
+ * Available Resource Types</a> documentation for an example of setting
* formatted text in the XML resource file.
*
* @attr ref android.R.styleable#TextView_text
@@ -8757,32 +8760,247 @@
return ((minOffset >= selectionStart) && (maxOffset < selectionEnd));
}
+ private PositionListener getPositionListener() {
+ if (mPositionListener == null) {
+ mPositionListener = new PositionListener();
+ }
+ return mPositionListener;
+ }
+
+ private interface TextViewPositionListener {
+ public void updatePosition(int parentPositionX, int parentPositionY, boolean modified);
+ }
+
+ private class PositionListener implements ViewTreeObserver.OnPreDrawListener {
+ // 3 handles, 2 ActionPopup (suggestionsPopup first hides the others)
+ private final int MAXIMUM_NUMBER_OF_LISTENERS = 5;
+ private TextViewPositionListener[] mPositionListeners =
+ new TextViewPositionListener[MAXIMUM_NUMBER_OF_LISTENERS];
+ private boolean mCanMove[] = new boolean[MAXIMUM_NUMBER_OF_LISTENERS];
+ private boolean mPositionHasChanged = true;
+ // Absolute position of the TextView with respect to its parent window
+ private int mPositionX, mPositionY;
+ private int mNumberOfListeners;
+
+ public void addSubscriber(TextViewPositionListener positionListener, boolean canMove) {
+ if (mNumberOfListeners == 0) {
+ updatePosition();
+ ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+ vto.addOnPreDrawListener(this);
+ }
+
+ int emptySlotIndex = -1;
+ for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
+ TextViewPositionListener listener = mPositionListeners[i];
+ if (listener == positionListener) {
+ return;
+ } else if (emptySlotIndex < 0 && listener == null) {
+ emptySlotIndex = i;
+ }
+ }
+
+ mPositionListeners[emptySlotIndex] = positionListener;
+ mCanMove[emptySlotIndex] = canMove;
+ mNumberOfListeners++;
+ }
+
+ public void removeSubscriber(TextViewPositionListener positionListener) {
+ for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
+ if (mPositionListeners[i] == positionListener) {
+ mPositionListeners[i] = null;
+ mNumberOfListeners--;
+ break;
+ }
+ }
+
+ if (mNumberOfListeners == 0) {
+ ViewTreeObserver vto = TextView.this.getViewTreeObserver();
+ vto.removeOnPreDrawListener(this);
+ }
+ }
+
+ public int getPositionX() {
+ return mPositionX;
+ }
+
+ public int getPositionY() {
+ return mPositionY;
+ }
+
+ @Override
+ public boolean onPreDraw() {
+ updatePosition();
+
+ for (int i = 0; i < MAXIMUM_NUMBER_OF_LISTENERS; i++) {
+ if (mPositionHasChanged || mCanMove[i]) {
+ TextViewPositionListener positionListener = mPositionListeners[i];
+ if (positionListener != null) {
+ positionListener.updatePosition(mPositionX, mPositionY,
+ mPositionHasChanged);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private void updatePosition() {
+ TextView.this.getLocationInWindow(mTempCoords);
+
+ mPositionHasChanged = mTempCoords[0] != mPositionX || mTempCoords[1] != mPositionY;
+
+ mPositionX = mTempCoords[0];
+ mPositionY = mTempCoords[1];
+ }
+
+ public boolean isVisible(int positionX, int positionY) {
+ final TextView textView = TextView.this;
+
+ if (mTempRect == null) mTempRect = new Rect();
+ final Rect clip = mTempRect;
+ clip.left = getCompoundPaddingLeft();
+ clip.top = getExtendedPaddingTop();
+ clip.right = textView.getWidth() - getCompoundPaddingRight();
+ clip.bottom = textView.getHeight() - getExtendedPaddingBottom();
+
+ final ViewParent parent = textView.getParent();
+ if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) {
+ return false;
+ }
+
+ int posX = mPositionX + positionX;
+ int posY = mPositionY + positionY;
+
+ // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal.
+ return posX >= clip.left - 1 && posX <= clip.right + 1 &&
+ posY >= clip.top && posY <= clip.bottom;
+ }
+
+ public boolean isOffsetVisible(int offset) {
+ final int line = mLayout.getLineForOffset(offset);
+ final int lineBottom = mLayout.getLineBottom(line);
+ final int primaryHorizontal = (int) mLayout.getPrimaryHorizontal(offset);
+ return isVisible(primaryHorizontal, lineBottom);
+ }
+ }
+
+ private abstract class PinnedPopupWindow implements TextViewPositionListener {
+ protected PopupWindow mPopupWindow;
+ protected LinearLayout mContentView;
+ int mPositionX, mPositionY;
+
+ protected abstract void createPopupWindow();
+ protected abstract void initContentView();
+ protected abstract int getTextOffset();
+ protected abstract int getVerticalLocalPosition(int line);
+ protected abstract int clipVertically(int positionY);
+
+ public PinnedPopupWindow() {
+ createPopupWindow();
+
+ mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+ mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+ mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ mContentView = new LinearLayout(TextView.this.getContext());
+ LayoutParams wrapContent = new LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ mContentView.setLayoutParams(wrapContent);
+
+ initContentView();
+ mPopupWindow.setContentView(mContentView);
+ }
+
+ public void show() {
+ final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ mContentView.measure(
+ View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
+ View.MeasureSpec.AT_MOST),
+ View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
+ View.MeasureSpec.AT_MOST));
+
+ TextView.this.getPositionListener().addSubscriber(this, false);
+
+ computeLocalPosition();
+
+ final PositionListener positionListener = TextView.this.getPositionListener();
+ updatePosition(positionListener.getPositionX(), positionListener.getPositionY());
+ }
+
+ private void computeLocalPosition() {
+ final int offset = getTextOffset();
+
+ final int width = mContentView.getMeasuredWidth();
+ mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f);
+ mPositionX += viewportToContentHorizontalOffset();
+
+ final int line = mLayout.getLineForOffset(offset);
+ mPositionY = getVerticalLocalPosition(line);
+ mPositionY += viewportToContentVerticalOffset();
+ }
+
+ private void updatePosition(int parentPositionX, int parentPositionY) {
+ int positionX = parentPositionX + mPositionX;
+ int positionY = parentPositionY + mPositionY;
+
+ positionY = clipVertically(positionY);
+
+ // Horizontal clipping
+ final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ final int width = mContentView.getMeasuredWidth();
+ positionX = Math.min(displayMetrics.widthPixels - width, positionX);
+ positionX = Math.max(0, positionX);
+
+ if (isShowing()) {
+ mPopupWindow.update(positionX, positionY, -1, -1);
+ } else {
+ mPopupWindow.showAtLocation(TextView.this, Gravity.NO_GRAVITY,
+ positionX, positionY);
+ }
+ }
+
+ public void hide() {
+ mPopupWindow.dismiss();
+ TextView.this.getPositionListener().removeSubscriber(this);
+ }
+
+ @Override
+ public void updatePosition(int parentPositionX, int parentPositionY, boolean modified) {
+ if (isShowing() && getPositionListener().isOffsetVisible(getTextOffset())) {
+ updatePosition(parentPositionX, parentPositionY);
+ } else {
+ hide();
+ }
+ }
+
+ public boolean isShowing() {
+ return mPopupWindow.isShowing();
+ }
+ }
+
private static class SuggestionRangeSpan extends UnderlineSpan {
// TODO themable, would be nice to make it a child class of TextAppearanceSpan, but
// there is no way to have underline and TextAppearanceSpan.
}
- private class SuggestionsPopupWindow implements OnClickListener {
+ private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnClickListener {
private static final int MAX_NUMBER_SUGGESTIONS = 5;
private static final int NO_SUGGESTIONS = -1;
- private final PopupWindow mPopupWindow;
- private LinearLayout mSuggestionsContainer;
private WordIterator mSuggestionWordIterator;
private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan[0];
- public SuggestionsPopupWindow() {
+ @Override
+ protected void createPopupWindow() {
mPopupWindow = new PopupWindow(TextView.this.mContext, null,
- com.android.internal.R.attr.textSuggestionsWindowStyle);
- mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+ com.android.internal.R.attr.textSuggestionsWindowStyle);
mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
mPopupWindow.setOutsideTouchable(true);
- mPopupWindow.setClippingEnabled(true);
+ mPopupWindow.setClippingEnabled(false);
+ }
- mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
- mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
-
- mSuggestionsContainer = new LinearLayout(TextView.this.mContext);
- mSuggestionsContainer.setOrientation(LinearLayout.VERTICAL);
+ @Override
+ protected void initContentView() {
+ mContentView.setOrientation(LinearLayout.VERTICAL);
LayoutInflater inflater = (LayoutInflater) TextView.this.mContext.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -8795,7 +9013,7 @@
// Inflate the suggestion items once and for all.
for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
View childView = inflater.inflate(mTextEditSuggestionItemLayout,
- mSuggestionsContainer, false);
+ mContentView, false);
if (! (childView instanceof TextView)) {
throw new IllegalArgumentException(
@@ -8803,11 +9021,9 @@
}
childView.setTag(new SuggestionInfo());
- mSuggestionsContainer.addView(childView);
+ mContentView.addView(childView);
childView.setOnClickListener(this);
}
-
- mPopupWindow.setContentView(mSuggestionsContainer);
}
private class SuggestionInfo {
@@ -8827,30 +9043,61 @@
SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
// Cache the span length for performance reason.
- final HashMap<SuggestionSpan, Integer> spanLengthMap =
- new HashMap<SuggestionSpan, Integer>();
+ final HashMap<SuggestionSpan, Integer> spansLengths =
+ new HashMap<SuggestionSpan, Integer>();
for (SuggestionSpan suggestionSpan : suggestionSpans) {
int start = spannable.getSpanStart(suggestionSpan);
int end = spannable.getSpanEnd(suggestionSpan);
- spanLengthMap.put(suggestionSpan, end - start);
+ spansLengths.put(suggestionSpan, Integer.valueOf(end - start));
}
// The suggestions are sorted according to the lenght of the text that they cover
// (shorter first)
Arrays.sort(suggestionSpans, new Comparator<SuggestionSpan>() {
public int compare(SuggestionSpan span1, SuggestionSpan span2) {
- return spanLengthMap.get(span1) - spanLengthMap.get(span2);
+ return spansLengths.get(span1).intValue() - spansLengths.get(span2).intValue();
}
});
return suggestionSpans;
}
+ @Override
public void show() {
if (!(mText instanceof Editable)) return;
+ updateSuggestions();
- Spannable spannable = (Spannable) TextView.this.mText;
+ super.show();
+ }
+
+ @Override
+ protected int getTextOffset() {
+ return getSelectionStart();
+ }
+
+ @Override
+ protected int getVerticalLocalPosition(int line) {
+ return mLayout.getLineBottom(line);
+ }
+
+ @Override
+ protected int clipVertically(int positionY) {
+ final int height = mContentView.getMeasuredHeight();
+ final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+ return Math.min(positionY, displayMetrics.heightPixels - height);
+ }
+
+ @Override
+ public void hide() {
+ super.hide();
+ if ((mText instanceof Editable) && mSuggestionRangeSpan != null) {
+ ((Editable) mText).removeSpan(mSuggestionRangeSpan);
+ }
+ }
+
+ private void updateSuggestions() {
+ Spannable spannable = (Spannable)TextView.this.mText;
SuggestionSpan[] suggestionSpans = getSuggestionSpans();
final int nbSpans = suggestionSpans.length;
@@ -8869,7 +9116,7 @@
String[] suggestions = suggestionSpan.getSuggestions();
int nbSuggestions = suggestions.length;
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
- TextView textView = (TextView) mSuggestionsContainer.getChildAt(
+ TextView textView = (TextView) mContentView.getChildAt(
totalNbSuggestions);
textView.setText(suggestions[suggestionIndex]);
SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
@@ -8889,7 +9136,7 @@
if (totalNbSuggestions == 0) {
// TODO Replace by final text, use a dedicated layout, add a fade out timer...
- TextView textView = (TextView) mSuggestionsContainer.getChildAt(0);
+ TextView textView = (TextView) mContentView.getChildAt(0);
textView.setText("No suggestions available");
SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
suggestionInfo.spanStart = NO_SUGGESTIONS;
@@ -8900,26 +9147,17 @@
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
for (int i = 0; i < totalNbSuggestions; i++) {
- final TextView textView = (TextView) mSuggestionsContainer.getChildAt(i);
+ final TextView textView = (TextView) mContentView.getChildAt(i);
highlightTextDifferences(textView, spanUnionStart, spanUnionEnd);
}
}
for (int i = 0; i < totalNbSuggestions; i++) {
- mSuggestionsContainer.getChildAt(i).setVisibility(VISIBLE);
+ mContentView.getChildAt(i).setVisibility(VISIBLE);
}
for (int i = totalNbSuggestions; i < MAX_NUMBER_SUGGESTIONS; i++) {
- mSuggestionsContainer.getChildAt(i).setVisibility(GONE);
+ mContentView.getChildAt(i).setVisibility(GONE);
}
-
- final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
- final int screenWidth = displayMetrics.widthPixels;
- final int screenHeight = displayMetrics.heightPixels;
- mSuggestionsContainer.measure(
- View.MeasureSpec.makeMeasureSpec(screenWidth, View.MeasureSpec.AT_MOST),
- View.MeasureSpec.makeMeasureSpec(screenHeight, View.MeasureSpec.AT_MOST));
-
- positionAtCursor();
}
private long[] getWordLimits(CharSequence text) {
@@ -9071,17 +9309,6 @@
textView.setText(ssb);
}
- public void hide() {
- if ((mText instanceof Editable) && mSuggestionRangeSpan != null) {
- ((Editable) mText).removeSpan(mSuggestionRangeSpan);
- }
- mPopupWindow.dismiss();
- }
-
- public boolean isShowing() {
- return mPopupWindow.isShowing();
- }
-
@Override
public void onClick(View view) {
if (view instanceof TextView) {
@@ -9141,44 +9368,6 @@
}
hide();
}
-
- void positionAtCursor() {
- View contentView = mPopupWindow.getContentView();
- int width = contentView.getMeasuredWidth();
- int height = contentView.getMeasuredHeight();
- final int offset = TextView.this.getSelectionStart();
- final int line = mLayout.getLineForOffset(offset);
- final int lineBottom = mLayout.getLineBottom(line);
- float primaryHorizontal = mLayout.getPrimaryHorizontal(offset);
-
- final Rect bounds = sCursorControllerTempRect;
- bounds.left = (int) (primaryHorizontal - width / 2.0f);
- bounds.top = lineBottom;
-
- bounds.right = bounds.left + width;
- bounds.bottom = bounds.top + height;
-
- convertFromViewportToContentCoordinates(bounds);
-
- final int[] coords = mTempCoords;
- TextView.this.getLocationInWindow(coords);
- coords[0] += bounds.left;
- coords[1] += bounds.top;
-
- final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
- final int screenHeight = displayMetrics.heightPixels;
-
- // Vertical clipping
- if (coords[1] + height > screenHeight) {
- coords[1] = screenHeight - height;
- }
-
- // Horizontal clipping
- coords[0] = Math.min(displayMetrics.widthPixels - width, coords[0]);
- coords[0] = Math.max(0, coords[0]);
-
- mPopupWindow.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
- }
}
void showSuggestions() {
@@ -9359,7 +9548,7 @@
boolean allowText = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_allowActionMenuItemTextWithIcon);
- mode.setTitle(allowText ?
+ mode.setTitle(allowText ?
mContext.getString(com.android.internal.R.string.textSelectionCABTitle) : null);
mode.setSubtitle(null);
@@ -9452,29 +9641,23 @@
}
}
- private class ActionPopupWindow implements OnClickListener {
- private static final int TEXT_EDIT_ACTION_POPUP_TEXT =
+ private class ActionPopupWindow extends PinnedPopupWindow implements OnClickListener {
+ private static final int POPUP_TEXT_LAYOUT =
com.android.internal.R.layout.text_edit_action_popup_text;
- private final PopupWindow mPopupWindow;
private TextView mPasteTextView;
private TextView mReplaceTextView;
- private LinearLayout mContentView;
// Whether or not the Paste action should be available when the action popup is displayed
private boolean mWithPaste;
- public ActionPopupWindow() {
+ @Override
+ protected void createPopupWindow() {
mPopupWindow = new PopupWindow(TextView.this.mContext, null,
com.android.internal.R.attr.textSelectHandleWindowStyle);
mPopupWindow.setClippingEnabled(true);
- mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
+ }
- mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
- mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
-
- mContentView = new LinearLayout(TextView.this.getContext());
- LayoutParams wrapContent = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- mContentView.setLayoutParams(wrapContent);
+ @Override
+ protected void initContentView() {
mContentView.setOrientation(LinearLayout.HORIZONTAL);
mContentView.setBackgroundResource(
com.android.internal.R.drawable.text_edit_side_paste_window);
@@ -9482,36 +9665,26 @@
LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mPasteTextView = (TextView) inflater.inflate(TEXT_EDIT_ACTION_POPUP_TEXT, null);
+ LayoutParams wrapContent = new LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ mPasteTextView = (TextView) inflater.inflate(POPUP_TEXT_LAYOUT, null);
mPasteTextView.setLayoutParams(wrapContent);
mContentView.addView(mPasteTextView);
mPasteTextView.setText(com.android.internal.R.string.paste);
mPasteTextView.setOnClickListener(this);
- mReplaceTextView = (TextView) inflater.inflate(TEXT_EDIT_ACTION_POPUP_TEXT, null);
+ mReplaceTextView = (TextView) inflater.inflate(POPUP_TEXT_LAYOUT, null);
mReplaceTextView.setLayoutParams(wrapContent);
mContentView.addView(mReplaceTextView);
mReplaceTextView.setText(com.android.internal.R.string.replace);
mReplaceTextView.setOnClickListener(this);
-
- mPopupWindow.setContentView(mContentView);
}
+ @Override
public void show() {
mPasteTextView.setVisibility(mWithPaste && canPaste() ? View.VISIBLE : View.GONE);
-
- final int size = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- mContentView.measure(size, size);
-
- positionAtCursor();
- }
-
- public void hide() {
- mPopupWindow.dismiss();
- }
-
- public boolean isShowing() {
- return mPopupWindow.isShowing();
+ super.show();
}
@Override
@@ -9524,48 +9697,30 @@
}
}
- void positionAtCursor() {
- int width = mContentView.getMeasuredWidth();
- int height = mContentView.getMeasuredHeight();
- final int selectionStart = TextView.this.getSelectionStart();
- final int selectionEnd = TextView.this.getSelectionEnd();
- final int offset = (selectionStart + selectionEnd) / 2;
- final int line = mLayout.getLineForOffset(offset);
- final int lineTop = mLayout.getLineTop(line);
- float primaryHorizontal = mLayout.getPrimaryHorizontal(offset);
+ @Override
+ protected int getTextOffset() {
+ return (getSelectionStart() + getSelectionEnd()) / 2;
+ }
- final Rect bounds = sCursorControllerTempRect;
- bounds.left = (int) (primaryHorizontal - width / 2.0f);
- bounds.top = lineTop - height;
+ @Override
+ protected int getVerticalLocalPosition(int line) {
+ return mLayout.getLineTop(line) - mContentView.getMeasuredHeight();
+ }
- bounds.right = bounds.left + width;
- bounds.bottom = bounds.top + height;
-
- convertFromViewportToContentCoordinates(bounds);
-
- final int[] coords = mTempCoords;
- TextView.this.getLocationInWindow(coords);
- coords[0] += bounds.left;
- coords[1] += bounds.top;
-
- // Vertical clipping, move under edited line and to the side of insertion cursor
- if (coords[1] < 0) {
- coords[1] += height;
- final int lineBottom = mLayout.getLineBottom(line);
- final int lineHeight = lineBottom - lineTop;
- coords[1] += lineHeight;
+ @Override
+ protected int clipVertically(int positionY) {
+ if (positionY < 0) {
+ final int offset = getTextOffset();
+ final int line = mLayout.getLineForOffset(offset);
+ positionY += mLayout.getLineBottom(line) - mLayout.getLineTop(line);
+ positionY += mContentView.getMeasuredHeight();
// Assumes insertion and selection handles share the same height
final Drawable handle = mContext.getResources().getDrawable(mTextSelectHandleRes);
- coords[1] += handle.getIntrinsicHeight();
+ positionY += handle.getIntrinsicHeight();
}
- // Horizontal clipping
- coords[0] = Math.max(0, coords[0]);
- final int screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
- coords[0] = Math.min(screenWidth - width, coords[0]);
-
- mPopupWindow.showAtLocation(TextView.this, Gravity.NO_GRAVITY, coords[0], coords[1]);
+ return positionY;
}
public void setShowWithPaste(boolean withPaste) {
@@ -9573,7 +9728,7 @@
}
}
- private abstract class HandleView extends View implements ViewTreeObserver.OnPreDrawListener {
+ private abstract class HandleView extends View implements TextViewPositionListener {
protected Drawable mDrawable;
private final PopupWindow mContainer;
// Position with respect to the parent TextView
@@ -9581,21 +9736,19 @@
private boolean mIsDragging;
// Offset from touch position to mPosition
private float mTouchToWindowOffsetX, mTouchToWindowOffsetY;
- protected float mHotspotX;
+ protected int mHotspotX;
// Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
private float mTouchOffsetY;
// Where the touch position should be on the handle to ensure a maximum cursor visibility
private float mIdealVerticalOffset;
// Parent's (TextView) previous position in window
private int mLastParentX, mLastParentY;
- // PopupWindow container absolute position with respect to the enclosing window
- private int mContainerPositionX, mContainerPositionY;
- // Visible or not (scrolled off screen), whether or not this handle should be visible
- private boolean mIsActive = false;
- // Used to detect that setFrame was called
- private boolean mNeedsUpdate = true;
// Transient action popup window for Paste and Replace actions
protected ActionPopupWindow mActionPopupWindow;
+ // Previous text character offset
+ private int mPreviousOffset = -1;
+ // Previous text character offset
+ private boolean mPositionHasChanged = true;
// Used to delay the appearance of the action popup window
private Runnable mActionPopupShower;
@@ -9615,15 +9768,6 @@
mIdealVerticalOffset = 0.7f * handleHeight;
}
- @Override
- protected boolean setFrame(int left, int top, int right, int bottom) {
- boolean changed = super.setFrame(left, top, right, bottom);
- // onPreDraw is called for PhoneWindow before the layout of this view is
- // performed. Make sure to update position, even if container didn't move.
- if (changed) mNeedsUpdate = true;
- return changed;
- }
-
protected abstract void initDrawable();
// Touch-up filter: number of previous positions remembered
@@ -9641,12 +9785,6 @@
}
private void addPositionToTouchUpFilter(int offset) {
- if (mNumberPreviousOffsets > 0 &&
- mPreviousOffsets[mPreviousOffsetIndex] == offset) {
- // Make sure only actual changes of position are recorded.
- return;
- }
-
mPreviousOffsetIndex = (mPreviousOffsetIndex + 1) % HISTORY_SIZE;
mPreviousOffsets[mPreviousOffsetIndex] = offset;
mPreviousOffsetsTimes[mPreviousOffsetIndex] = SystemClock.uptimeMillis();
@@ -9665,28 +9803,28 @@
if (i > 0 && i < iMax &&
(now - mPreviousOffsetsTimes[index]) > TOUCH_UP_FILTER_DELAY_BEFORE) {
- updateOffset(mPreviousOffsets[index]);
+ positionAtCursorOffset(mPreviousOffsets[index]);
}
}
+ public boolean offsetHasBeenChanged() {
+ return mNumberPreviousOffsets > 1;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
}
public void show() {
- if (isShowing()) {
- mContainer.update(mContainerPositionX, mContainerPositionY, -1, -1);
- } else {
- mContainer.showAtLocation(TextView.this, 0,
- mContainerPositionX, mContainerPositionY);
+ if (isShowing()) return;
- if (!mIsActive) {
- ViewTreeObserver vto = TextView.this.getViewTreeObserver();
- vto.addOnPreDrawListener(this);
- mIsActive = true;
- }
- }
+ getPositionListener().addSubscriber(this, true);
+
+ // Make sure the offset is always considered new, even when focusing at same position
+ mPreviousOffset = -1;
+ positionAtCursorOffset(getCurrentCursorOffset());
+
hideActionPopupWindow();
}
@@ -9699,9 +9837,7 @@
public void hide() {
dismiss();
- ViewTreeObserver vto = TextView.this.getViewTreeObserver();
- vto.removeOnPreDrawListener(this);
- mIsActive = false;
+ TextView.this.getPositionListener().removeSubscriber(this);
}
void showActionPopupWindow(int delay, boolean withPaste) {
@@ -9734,7 +9870,7 @@
return mContainer.isShowing();
}
- private boolean isPositionVisible() {
+ private boolean isVisible() {
// Always show a dragging handle.
if (mIsDragging) {
return true;
@@ -9744,103 +9880,71 @@
return false;
}
- final int extendedPaddingTop = getExtendedPaddingTop();
- final int extendedPaddingBottom = getExtendedPaddingBottom();
- final int compoundPaddingLeft = getCompoundPaddingLeft();
- final int compoundPaddingRight = getCompoundPaddingRight();
-
- final TextView textView = TextView.this;
-
- if (mTempRect == null) mTempRect = new Rect();
- final Rect clip = mTempRect;
- clip.left = compoundPaddingLeft;
- clip.top = extendedPaddingTop;
- clip.right = textView.getWidth() - compoundPaddingRight;
- clip.bottom = textView.getHeight() - extendedPaddingBottom;
-
- final ViewParent parent = textView.getParent();
- if (parent == null || !parent.getChildVisibleRect(textView, clip, null)) {
- return false;
- }
-
- final int[] coords = mTempCoords;
- textView.getLocationInWindow(coords);
- final int posX = coords[0] + mPositionX + (int) mHotspotX;
- final int posY = coords[1] + mPositionY;
-
- // Offset by 1 to take into account 0.5 and int rounding around getPrimaryHorizontal.
- return posX >= clip.left - 1 && posX <= clip.right + 1 &&
- posY >= clip.top && posY <= clip.bottom;
+ return getPositionListener().isVisible(mPositionX + mHotspotX, mPositionY);
}
public abstract int getCurrentCursorOffset();
- public abstract void updateOffset(int offset);
+ public abstract void updateSelection(int offset);
public abstract void updatePosition(float x, float y);
protected void positionAtCursorOffset(int offset) {
- // A HandleView relies on the layout, which may be nulled by external methods.
+ // A HandleView relies on the layout, which may be nulled by external methods
if (mLayout == null) {
// Will update controllers' state, hiding them and stopping selection mode if needed
prepareCursorControllers();
return;
}
- addPositionToTouchUpFilter(offset);
- final int line = mLayout.getLineForOffset(offset);
- final int lineBottom = mLayout.getLineBottom(line);
+ if (offset != mPreviousOffset) {
+ updateSelection(offset);
+ addPositionToTouchUpFilter(offset);
+ final int line = mLayout.getLineForOffset(offset);
- mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX);
- mPositionY = lineBottom;
+ mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX);
+ mPositionY = mLayout.getLineBottom(line);
- // Take TextView's padding into account.
- mPositionX += viewportToContentHorizontalOffset();
- mPositionY += viewportToContentVerticalOffset();
+ // Take TextView's padding into account.
+ mPositionX += viewportToContentHorizontalOffset();
+ mPositionY += viewportToContentVerticalOffset();
+
+ mPreviousOffset = offset;
+ mPositionHasChanged = true;
+ }
}
- private void checkForContainerPositionChange() {
- positionAtCursorOffset(getCurrentCursorOffset());
-
- final int previousContainerPositionX = mContainerPositionX;
- final int previousContainerPositionY = mContainerPositionY;
-
- TextView.this.getLocationInWindow(mTempCoords);
- mContainerPositionX = mTempCoords[0] + mPositionX;
- mContainerPositionY = mTempCoords[1] + mPositionY;
-
- mNeedsUpdate |= previousContainerPositionX != mContainerPositionX;
- mNeedsUpdate |= previousContainerPositionY != mContainerPositionY;
- }
-
- public boolean onPreDraw() {
- checkForContainerPositionChange();
- if (mNeedsUpdate) {
+ public void updatePosition(int parentPositionX, int parentPositionY, boolean modified) {
+ if (modified || mPositionHasChanged) {
if (mIsDragging) {
- if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) {
- mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX;
- mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY;
- mLastParentX = mTempCoords[0];
- mLastParentY = mTempCoords[1];
+ // Update touchToWindow offset in case of parent scrolling while dragging
+ if (parentPositionX != mLastParentX || parentPositionY != mLastParentY) {
+ mTouchToWindowOffsetX += parentPositionX - mLastParentX;
+ mTouchToWindowOffsetY += parentPositionY - mLastParentY;
+ mLastParentX = parentPositionX;
+ mLastParentY = parentPositionY;
}
onHandleMoved();
}
- if (isPositionVisible()) {
- mContainer.update(mContainerPositionX, mContainerPositionY, -1, -1);
-
- if (mIsActive && !isShowing()) {
- show();
+ if (isVisible()) {
+ final int positionX = parentPositionX + mPositionX;
+ final int positionY = parentPositionY + mPositionY;
+ if (isShowing()) {
+ mContainer.update(positionX, positionY, -1, -1);
+ } else {
+ mContainer.showAtLocation(TextView.this, Gravity.NO_GRAVITY,
+ positionX, positionY);
}
} else {
if (isShowing()) {
dismiss();
}
}
- mNeedsUpdate = false;
+
+ mPositionHasChanged = false;
}
- return true;
}
@Override
@@ -9857,10 +9961,9 @@
mTouchToWindowOffsetX = ev.getRawX() - mPositionX;
mTouchToWindowOffsetY = ev.getRawY() - mPositionY;
- final int[] coords = mTempCoords;
- TextView.this.getLocationInWindow(coords);
- mLastParentX = coords[0];
- mLastParentY = coords[1];
+ final PositionListener positionListener = getPositionListener();
+ mLastParentX = positionListener.getPositionX();
+ mLastParentY = positionListener.getPositionY();
mIsDragging = true;
break;
}
@@ -9963,7 +10066,7 @@
mTextSelectHandleRes);
}
mDrawable = mSelectHandleCenter;
- mHotspotX = mDrawable.getIntrinsicWidth() / 2.0f;
+ mHotspotX = mDrawable.getIntrinsicWidth() / 2;
}
@Override
@@ -9977,15 +10080,17 @@
break;
case MotionEvent.ACTION_UP:
- final float deltaX = mDownPositionX - ev.getRawX();
- final float deltaY = mDownPositionY - ev.getRawY();
- final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
- if (distanceSquared < mSquaredTouchSlopDistance) {
- if (mActionPopupWindow != null && mActionPopupWindow.isShowing()) {
- // Tapping on the handle dismisses the displayed action popup
- mActionPopupWindow.hide();
- } else {
- show(0);
+ if (!offsetHasBeenChanged()) {
+ final float deltaX = mDownPositionX - ev.getRawX();
+ final float deltaY = mDownPositionY - ev.getRawY();
+ final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+ if (distanceSquared < mSquaredTouchSlopDistance) {
+ if (mActionPopupWindow != null && mActionPopupWindow.isShowing()) {
+ // Tapping on the handle dismisses the displayed action popup
+ mActionPopupWindow.hide();
+ } else {
+ show(0);
+ }
}
}
hideAfterDelay();
@@ -10008,13 +10113,13 @@
}
@Override
- public void updateOffset(int offset) {
+ public void updateSelection(int offset) {
Selection.setSelection((Spannable) mText, offset);
}
@Override
public void updatePosition(float x, float y) {
- updateOffset(getOffsetForPosition(x, y));
+ positionAtCursorOffset(getOffsetForPosition(x, y));
}
@Override
@@ -10038,7 +10143,7 @@
mTextSelectHandleLeftRes);
}
mDrawable = mSelectHandleLeft;
- mHotspotX = mDrawable.getIntrinsicWidth() * 3.0f / 4.0f;
+ mHotspotX = (mDrawable.getIntrinsicWidth() * 3) / 4;
}
@Override
@@ -10047,7 +10152,7 @@
}
@Override
- public void updateOffset(int offset) {
+ public void updateSelection(int offset) {
Selection.setSelection((Spannable) mText, offset, getSelectionEnd());
}
@@ -10063,7 +10168,7 @@
// Handles can not cross and selection is at least one character
if (offset >= selectionEnd) offset = selectionEnd - 1;
- Selection.setSelection((Spannable) mText, offset, selectionEnd);
+ positionAtCursorOffset(offset);
}
public ActionPopupWindow getActionPopupWindow() {
@@ -10079,7 +10184,7 @@
mTextSelectHandleRightRes);
}
mDrawable = mSelectHandleRight;
- mHotspotX = mDrawable.getIntrinsicWidth() / 4.0f;
+ mHotspotX = mDrawable.getIntrinsicWidth() / 4;
}
@Override
@@ -10088,7 +10193,7 @@
}
@Override
- public void updateOffset(int offset) {
+ public void updateSelection(int offset) {
Selection.setSelection((Spannable) mText, getSelectionStart(), offset);
}
@@ -10104,7 +10209,7 @@
// Handles can not cross and selection is at least one character
if (offset <= selectionStart) offset = selectionStart + 1;
- Selection.setSelection((Spannable) mText, selectionStart, offset);
+ positionAtCursorOffset(offset);
}
public void setActionPopupWindow(ActionPopupWindow actionPopupWindow) {
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 1531946..6d65782 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.internal.content;
import android.os.Build;
@@ -17,6 +33,12 @@
private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2);
+ /**
+ * Sums the size of native binaries in an APK.
+ *
+ * @param apkFile APK file to scan for native libraries
+ * @return size of all native binary files in bytes
+ */
public static long sumNativeBinariesLI(File apkFile) {
final String cpuAbi = Build.CPU_ABI;
final String cpuAbi2 = Build.CPU_ABI2;
@@ -26,6 +48,14 @@
private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath,
String cpuAbi, String cpuAbi2);
+ /**
+ * Copies native binaries to a shared library directory.
+ *
+ * @param apkFile APK file to scan for native libraries
+ * @param sharedLibraryDir directory for libraries to be copied to
+ * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
+ * error code from that class if not
+ */
public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) {
final String cpuAbi = Build.CPU_ABI;
final String cpuAbi2 = Build.CPU_ABI2;
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index ec64552..266728b 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -39,6 +39,8 @@
public static final int RECOMMEND_FAILED_INVALID_LOCATION = -3;
public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4;
public static final int RECOMMEND_MEDIA_UNAVAILABLE = -5;
+ public static final int RECOMMEND_FAILED_INVALID_URI = -6;
+
private static final boolean localLOGV = true;
private static final String TAG = "PackageHelper";
// App installation location settings values
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 7839a08..5e70e4c 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -150,6 +150,11 @@
private CopyOnWriteArrayList<WeakReference<MenuPresenter>> mPresenters =
new CopyOnWriteArrayList<WeakReference<MenuPresenter>>();
+
+ /**
+ * Currently expanded menu item; must be collapsed when we clear.
+ */
+ private MenuItemImpl mExpandedItem;
/**
* Called by menu to notify of close and selection changes.
@@ -512,6 +517,9 @@
}
public void clear() {
+ if (mExpandedItem != null) {
+ collapseItemActionView(mExpandedItem);
+ }
mItems.clear();
onItemsChanged(true);
@@ -1223,11 +1231,14 @@
}
startDispatchingItemsChanged();
+ if (expanded) {
+ mExpandedItem = item;
+ }
return expanded;
}
public boolean collapseItemActionView(MenuItemImpl item) {
- if (mPresenters.isEmpty()) return false;
+ if (mPresenters.isEmpty() || mExpandedItem != item) return false;
boolean collapsed = false;
@@ -1242,6 +1253,9 @@
}
startDispatchingItemsChanged();
+ if (collapsed) {
+ mExpandedItem = null;
+ }
return collapsed;
}
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 446c842..4878b0f 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1265,9 +1265,8 @@
@Override
public void initForMenu(Context context, MenuBuilder menu) {
// Clear the expanded action view when menus change.
- mExpandedActionView = null;
- if (mCurrentExpandedItem != null) {
- mCurrentExpandedItem.collapseActionView();
+ if (mMenu != null && mCurrentExpandedItem != null) {
+ mMenu.collapseItemActionView(mCurrentExpandedItem);
}
mMenu = menu;
}
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 830f70e..5118351 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -51,15 +51,17 @@
namespace android {
-typedef void (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
-
// These match PackageManager.java install codes
typedef enum {
- INSTALL_SUCCEEDED = 0,
+ INSTALL_SUCCEEDED = 1,
INSTALL_FAILED_INVALID_APK = -2,
INSTALL_FAILED_INSUFFICIENT_STORAGE = -4,
+ INSTALL_FAILED_CONTAINER_ERROR = -18,
+ INSTALL_FAILED_INTERNAL_ERROR = -110,
} install_status_t;
+typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
+
// Equivalent to isFilenameSafe
static bool
isFilenameSafe(const char* filename)
@@ -140,17 +142,19 @@
return false;
}
-static void
+static install_status_t
sumFiles(JNIEnv* env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
{
size_t* total = (size_t*) arg;
size_t uncompLen;
if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, NULL, NULL)) {
- return;
+ return INSTALL_FAILED_INVALID_APK;
}
*total += uncompLen;
+
+ return INSTALL_SUCCEEDED;
}
/*
@@ -158,7 +162,7 @@
*
* This function assumes the library and path names passed in are considered safe.
*/
-static void
+static install_status_t
copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
{
jstring* javaNativeLibPath = (jstring*) arg;
@@ -170,7 +174,8 @@
time_t modTime;
if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, &when, &crc)) {
- return;
+ LOGD("Couldn't read zip entry info\n");
+ return INSTALL_FAILED_INVALID_APK;
} else {
struct tm t;
ZipFileRO::zipTimeToTimespec(when, &t);
@@ -182,50 +187,50 @@
char localFileName[nativeLibPath.size() + fileNameLen + 2];
if (strlcpy(localFileName, nativeLibPath.c_str(), sizeof(localFileName)) != nativeLibPath.size()) {
- LOGD("Couldn't allocate local file name for library: %s", strerror(errno));
- return;
+ LOGD("Couldn't allocate local file name for library");
+ return INSTALL_FAILED_INTERNAL_ERROR;
}
*(localFileName + nativeLibPath.size()) = '/';
if (strlcpy(localFileName + nativeLibPath.size() + 1, fileName, sizeof(localFileName)
- nativeLibPath.size() - 1) != fileNameLen) {
- LOGD("Couldn't allocate local file name for library: %s", strerror(errno));
- return;
+ LOGD("Couldn't allocate local file name for library");
+ return INSTALL_FAILED_INTERNAL_ERROR;
}
// Only copy out the native file if it's different.
struct stat st;
if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) {
- return;
+ return INSTALL_SUCCEEDED;
}
char localTmpFileName[nativeLibPath.size() + TMP_FILE_PATTERN_LEN + 2];
if (strlcpy(localTmpFileName, nativeLibPath.c_str(), sizeof(localTmpFileName))
!= nativeLibPath.size()) {
- LOGD("Couldn't allocate local file name for library: %s", strerror(errno));
- return;
+ LOGD("Couldn't allocate local file name for library");
+ return INSTALL_FAILED_INTERNAL_ERROR;
}
*(localFileName + nativeLibPath.size()) = '/';
if (strlcpy(localTmpFileName + nativeLibPath.size(), TMP_FILE_PATTERN,
TMP_FILE_PATTERN_LEN - nativeLibPath.size()) != TMP_FILE_PATTERN_LEN) {
- LOGI("Couldn't allocate temporary file name for library: %s", strerror(errno));
- return;
+ LOGI("Couldn't allocate temporary file name for library");
+ return INSTALL_FAILED_INTERNAL_ERROR;
}
int fd = mkstemp(localTmpFileName);
if (fd < 0) {
LOGI("Couldn't open temporary file name: %s: %s\n", localTmpFileName, strerror(errno));
- return;
+ return INSTALL_FAILED_CONTAINER_ERROR;
}
if (!zipFile->uncompressEntry(zipEntry, fd)) {
- LOGI("Failed uncompressing %s to %s: %s", fileName, localTmpFileName, strerror(errno));
+ LOGI("Failed uncompressing %s to %s\n", fileName, localTmpFileName);
close(fd);
unlink(localTmpFileName);
- return;
+ return INSTALL_FAILED_CONTAINER_ERROR;
}
close(fd);
@@ -238,7 +243,7 @@
if (utimes(localTmpFileName, times) < 0) {
LOGI("Couldn't change modification time on %s: %s\n", localTmpFileName, strerror(errno));
unlink(localTmpFileName);
- return;
+ return INSTALL_FAILED_CONTAINER_ERROR;
}
// Set the mode to 755
@@ -246,17 +251,19 @@
if (chmod(localTmpFileName, mode) < 0) {
LOGI("Couldn't change permissions on %s: %s\n", localTmpFileName, strerror(errno));
unlink(localTmpFileName);
- return;
+ return INSTALL_FAILED_CONTAINER_ERROR;
}
// Finally, rename it to the final name.
if (rename(localTmpFileName, localFileName) < 0) {
LOGI("Couldn't rename %s to %s: %s\n", localTmpFileName, localFileName, strerror(errno));
unlink(localTmpFileName);
- return;
+ return INSTALL_FAILED_CONTAINER_ERROR;
}
LOGV("Successfully moved %s to %s\n", localTmpFileName, localFileName);
+
+ return INSTALL_SUCCEEDED;
}
static install_status_t
@@ -301,10 +308,7 @@
}
const char* lastSlash = strrchr(fileName, '/');
- if (lastSlash == NULL) {
- LOG_ASSERT("last slash was null somehow for %s\n", fileName);
- continue;
- }
+ LOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName);
// Check to make sure the CPU ABI of this file is one we support.
const char* cpuAbiOffset = fileName + APK_LIB_LEN;
@@ -325,12 +329,17 @@
}
// If this is a .so file, check to see if we need to copy it.
- if (!strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
- && !strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)
- && isFilenameSafe(lastSlash + 1)) {
- callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
- } else if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
- callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
+ if ((!strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
+ && !strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)
+ && isFilenameSafe(lastSlash + 1))
+ || !strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
+
+ install_status_t ret = callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
+
+ if (ret != INSTALL_SUCCEEDED) {
+ LOGV("Failure for entry %s", lastSlash + 1);
+ return ret;
+ }
}
}
@@ -341,7 +350,7 @@
com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
jstring javaFilePath, jstring javaNativeLibPath, jstring javaCpuAbi, jstring javaCpuAbi2)
{
- return iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2,
+ return (jint) iterateOverNativeFiles(env, javaFilePath, javaCpuAbi, javaCpuAbi2,
copyFileIfChanged, &javaNativeLibPath);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f99a94c..21c3f1e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -294,12 +294,21 @@
<!-- Allows an application to read/write the voicemails owned by its own
package. -->
+ <!-- TODO: delete this permission when dependent content provider &
+ application code has been migrated to use ADD_VOICEMAIL instead -->
<permission android:name="com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="dangerous"
android:label="@string/permlab_readWriteOwnVoicemail"
android:description="@string/permdesc_readWriteOwnVoicemail" />
+ <!-- Allows an application to add voicemails into the system. -->
+ <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
+ android:permissionGroup="android.permission-group.PERSONAL_INFO"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_addVoicemail"
+ android:description="@string/permdesc_addVoicemail" />
+
<!-- ======================================= -->
<!-- Permissions for accessing location info -->
<!-- ======================================= -->
diff --git a/core/res/res/values-large/themes.xml b/core/res/res/values-large/themes.xml
index 9e3e0bb..871a131 100644
--- a/core/res/res/values-large/themes.xml
+++ b/core/res/res/values-large/themes.xml
@@ -16,6 +16,21 @@
** 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.MinWidth">
diff --git a/core/res/res/values-large/themes_device_defaults.xml b/core/res/res/values-large/themes_device_defaults.xml
new file mode 100644
index 0000000..52fff5c
--- /dev/null
+++ b/core/res/res/values-large/themes_device_defaults.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+This file contains the themes that are the Device Defaults.
+If you want to edit themes to skin your device, do it here.
+We recommend that you do not edit themes.xml and instead edit
+this file.
+
+Editing this file instead of themes.xml will greatly simplify
+merges for future platform versions and CTS compliance will be
+easier.
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+ <style name="Theme.DeviceDefault.DialogWhenLarge"
+ parent="@android:style/Theme.DeviceDefault.Dialog.MinWidth">
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+ <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar"
+ parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar.MinWidth">
+ <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+ </style>
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge"
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog.MinWidth">
+ </style>
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar"
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth">
+ </style>
+</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dd16bd0..847afa0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -710,6 +710,22 @@
<enum name="preferExternal" value="2" />
</attr>
+ <!-- Extra options for an activity's UI. If specified on the application
+ tag these will be considered defaults for all activities in the
+ application. -->
+ <attr name="uiOptions">
+ <!-- No extra UI options. -->
+ <flag name="none" value="0" />
+ <!-- Split the options menu into a separate bar at the bottom of
+ the screen when severely constrained for horizontal space.
+ (e.g. portrait mode on a phone.) Instead of a small number
+ of action buttons appearing in the action bar at the top
+ of the screen, the action bar will split into the top navigation
+ section and the bottom menu section. Menu items will not be
+ split across the two bars; they will always appear together. -->
+ <flag name="splitActionBarWhenNarrow" value="1" />
+ </attr>
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -812,6 +828,7 @@
application is running, the user will be informed of this.
@hide -->
<attr name="cantSaveState" format="boolean" />
+ <attr name="uiOptions" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
@@ -1302,6 +1319,7 @@
<attr name="windowSoftInputMode" />
<attr name="immersive" />
<attr name="hardwareAccelerated" />
+ <attr name="uiOptions" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 87e9249..f85dd85 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1783,11 +1783,11 @@
<public type="attr" name="minResizeHeight" />
<public type="attr" name="actionBarWidgetTheme" />
+ <public type="attr" name="uiOptions" />
<public type="style" name="TextAppearance.SuggestionHighlight" />
- <public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
- <public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
+ <public type="style" name="Theme.Holo.Light.DarkActionBar" />
<public type="style" name="Widget.Holo.Button.Borderless.Small" />
<public type="style" name="Widget.Holo.Light.Button.Borderless.Small" />
<public type="style" name="TextAppearance.Holo.Widget.ActionBar.Title.Inverse" />
@@ -1802,12 +1802,183 @@
<public type="style" name="Widget.Holo.Light.ActionBar.TabView.Inverse" />
<public type="style" name="Widget.Holo.Light.ActionBar.TabText.Inverse" />
<public type="style" name="Widget.Holo.Light.ActionMode.Inverse" />
- <public type="style" name="Theme.Holo.SolidActionBar" />
- <public type="style" name="Theme.Holo.Light.SolidActionBar" />
- <public type="style" name="Theme.Holo.Light.SolidActionBar.Inverse" />
- <public type="style" name="Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow" />
- <public type="style" name="Theme.Holo.Light.SolidActionBar.SplitActionBarWhenNarrow" />
- <public type="style" name="Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow" />
+
+ <public type="style" name="Theme.DeviceDefault" />
+ <public type="style" name="Theme.DeviceDefault.NoActionBar" />
+ <public type="style" name="Theme.DeviceDefault.NoActionBar.Fullscreen" />
+ <public type="style" name="Theme.DeviceDefault.Light" />
+ <public type="style" name="Theme.DeviceDefault.Light.NoActionBar" />
+ <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" />
+ <public type="style" name="Theme.DeviceDefault.Dialog" />
+ <public type="style" name="Theme.DeviceDefault.Dialog.MinWidth" />
+ <public type="style" name="Theme.DeviceDefault.Dialog.NoActionBar" />
+ <public type="style" name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" />
+ <public type="style" name="Theme.DeviceDefault.Light.Dialog" />
+ <public type="style" name="Theme.DeviceDefault.Light.Dialog.MinWidth" />
+ <public type="style" name="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
+ <public type="style" name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" />
+ <public type="style" name="Theme.DeviceDefault.DialogWhenLarge" />
+ <public type="style" name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" />
+ <public type="style" name="Theme.DeviceDefault.Light.DialogWhenLarge" />
+ <public type="style" name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" />
+ <public type="style" name="Theme.DeviceDefault.Panel" />
+ <public type="style" name="Theme.DeviceDefault.Light.Panel" />
+ <public type="style" name="Theme.DeviceDefault.Wallpaper" />
+ <public type="style" name="Theme.DeviceDefault.Wallpaper.NoTitleBar" />
+ <public type="style" name="Theme.DeviceDefault.InputMethod" />
+ <public type="style" name="Theme.DeviceDefault.Light.DarkActionBar" />
+
+ <public type="style" name="Widget.DeviceDefault" />
+ <public type="style" name="Widget.DeviceDefault.Button" />
+ <public type="style" name="Widget.DeviceDefault.Button.Small" />
+ <public type="style" name="Widget.DeviceDefault.Button.Inset" />
+ <public type="style" name="Widget.DeviceDefault.Button.Toggle" />
+ <public type="style" name="Widget.DeviceDefault.Button.Borderless.Small" />
+ <public type="style" name="Widget.DeviceDefault.TextView" />
+ <public type="style" name="Widget.DeviceDefault.AutoCompleteTextView" />
+ <public type="style" name="Widget.DeviceDefault.CompoundButton.CheckBox" />
+ <public type="style" name="Widget.DeviceDefault.ListView.DropDown" />
+ <public type="style" name="Widget.DeviceDefault.EditText" />
+ <public type="style" name="Widget.DeviceDefault.ExpandableListView" />
+ <public type="style" name="Widget.DeviceDefault.GridView" />
+ <public type="style" name="Widget.DeviceDefault.ImageButton" />
+ <public type="style" name="Widget.DeviceDefault.ListView" />
+ <public type="style" name="Widget.DeviceDefault.PopupWindow" />
+ <public type="style" name="Widget.DeviceDefault.ProgressBar" />
+ <public type="style" name="Widget.DeviceDefault.ProgressBar.Horizontal" />
+ <public type="style" name="Widget.DeviceDefault.ProgressBar.Small" />
+ <public type="style" name="Widget.DeviceDefault.ProgressBar.Small.Title" />
+ <public type="style" name="Widget.DeviceDefault.ProgressBar.Large" />
+ <public type="style" name="Widget.DeviceDefault.SeekBar" />
+ <public type="style" name="Widget.DeviceDefault.RatingBar" />
+ <public type="style" name="Widget.DeviceDefault.RatingBar.Indicator" />
+ <public type="style" name="Widget.DeviceDefault.RatingBar.Small" />
+ <public type="style" name="Widget.DeviceDefault.CompoundButton.RadioButton" />
+ <public type="style" name="Widget.DeviceDefault.ScrollView" />
+ <public type="style" name="Widget.DeviceDefault.HorizontalScrollView" />
+ <public type="style" name="Widget.DeviceDefault.Spinner" />
+ <public type="style" name="Widget.DeviceDefault.CompoundButton.Star" />
+ <public type="style" name="Widget.DeviceDefault.TabWidget" />
+ <public type="style" name="Widget.DeviceDefault.WebTextView" />
+ <public type="style" name="Widget.DeviceDefault.WebView" />
+ <public type="style" name="Widget.DeviceDefault.DropDownItem" />
+ <public type="style" name="Widget.DeviceDefault.DropDownItem.Spinner" />
+ <public type="style" name="Widget.DeviceDefault.TextView.SpinnerItem" />
+ <public type="style" name="Widget.DeviceDefault.ListPopupWindow" />
+ <public type="style" name="Widget.DeviceDefault.PopupMenu" />
+ <public type="style" name="Widget.DeviceDefault.ActionButton" />
+ <public type="style" name="Widget.DeviceDefault.ActionButton.Overflow" />
+ <public type="style" name="Widget.DeviceDefault.ActionButton.TextButton" />
+ <public type="style" name="Widget.DeviceDefault.ActionMode" />
+ <public type="style" name="Widget.DeviceDefault.ActionButton.CloseMode" />
+ <public type="style" name="Widget.DeviceDefault.ActionBar" />
+ <public type="style" name="Widget.DeviceDefault.Button.Borderless" />
+ <public type="style" name="Widget.DeviceDefault.Tab" />
+ <public type="style" name="Widget.DeviceDefault.CalendarView" />
+ <public type="style" name="Widget.DeviceDefault.DatePicker" />
+ <public type="style" name="Widget.DeviceDefault.ActionBar.TabView" />
+ <public type="style" name="Widget.DeviceDefault.ActionBar.TabText" />
+ <public type="style" name="Widget.DeviceDefault.ActionBar.TabBar" />
+ <public type="style" name="Widget.DeviceDefault.ActionBar.Solid" />
+ <public type="style" name="Widget.DeviceDefault.Light" />
+ <public type="style" name="Widget.DeviceDefault.Light.Button" />
+ <public type="style" name="Widget.DeviceDefault.Light.Button.Small" />
+ <public type="style" name="Widget.DeviceDefault.Light.Button.Inset" />
+ <public type="style" name="Widget.DeviceDefault.Light.Button.Toggle" />
+ <public type="style" name="Widget.DeviceDefault.Light.Button.Borderless.Small" />
+ <public type="style" name="Widget.DeviceDefault.Light.TextView" />
+ <public type="style" name="Widget.DeviceDefault.Light.AutoCompleteTextView" />
+ <public type="style" name="Widget.DeviceDefault.Light.CompoundButton.CheckBox" />
+ <public type="style" name="Widget.DeviceDefault.Light.ListView.DropDown" />
+ <public type="style" name="Widget.DeviceDefault.Light.EditText" />
+ <public type="style" name="Widget.DeviceDefault.Light.ExpandableListView" />
+ <public type="style" name="Widget.DeviceDefault.Light.GridView" />
+ <public type="style" name="Widget.DeviceDefault.Light.ImageButton" />
+ <public type="style" name="Widget.DeviceDefault.Light.ListView" />
+ <public type="style" name="Widget.DeviceDefault.Light.PopupWindow" />
+ <public type="style" name="Widget.DeviceDefault.Light.ProgressBar" />
+ <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" />
+ <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Small" />
+ <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Small.Title" />
+ <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Large" />
+ <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Inverse" />
+ <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Small.Inverse" />
+ <public type="style" name="Widget.DeviceDefault.Light.ProgressBar.Large.Inverse" />
+ <public type="style" name="Widget.DeviceDefault.Light.SeekBar" />
+ <public type="style" name="Widget.DeviceDefault.Light.RatingBar" />
+ <public type="style" name="Widget.DeviceDefault.Light.RatingBar.Indicator" />
+ <public type="style" name="Widget.DeviceDefault.Light.RatingBar.Small" />
+ <public type="style" name="Widget.DeviceDefault.Light.CompoundButton.RadioButton" />
+ <public type="style" name="Widget.DeviceDefault.Light.ScrollView" />
+ <public type="style" name="Widget.DeviceDefault.Light.HorizontalScrollView" />
+ <public type="style" name="Widget.DeviceDefault.Light.Spinner" />
+ <public type="style" name="Widget.DeviceDefault.Light.CompoundButton.Star" />
+ <public type="style" name="Widget.DeviceDefault.Light.TabWidget" />
+ <public type="style" name="Widget.DeviceDefault.Light.WebTextView" />
+ <public type="style" name="Widget.DeviceDefault.Light.WebView" />
+ <public type="style" name="Widget.DeviceDefault.Light.DropDownItem" />
+ <public type="style" name="Widget.DeviceDefault.Light.DropDownItem.Spinner" />
+ <public type="style" name="Widget.DeviceDefault.Light.TextView.SpinnerItem" />
+ <public type="style" name="Widget.DeviceDefault.Light.ListPopupWindow" />
+ <public type="style" name="Widget.DeviceDefault.Light.PopupMenu" />
+ <public type="style" name="Widget.DeviceDefault.Light.Tab" />
+ <public type="style" name="Widget.DeviceDefault.Light.CalendarView" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionButton" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionButton.Overflow" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionMode" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionButton.CloseMode" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabView" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabText" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabBar" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar.Solid" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar.Solid.Inverse" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabView.Inverse" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionBar.TabText.Inverse" />
+ <public type="style" name="Widget.DeviceDefault.Light.ActionMode.Inverse" />
+
+ <public type="style" name="TextAppearance.DeviceDefault" />
+ <public type="style" name="TextAppearance.DeviceDefault.Inverse" />
+ <public type="style" name="TextAppearance.DeviceDefault.Large" />
+ <public type="style" name="TextAppearance.DeviceDefault.Large.Inverse" />
+ <public type="style" name="TextAppearance.DeviceDefault.Medium" />
+ <public type="style" name="TextAppearance.DeviceDefault.Medium.Inverse" />
+ <public type="style" name="TextAppearance.DeviceDefault.Small" />
+ <public type="style" name="TextAppearance.DeviceDefault.Small.Inverse" />
+ <public type="style" name="TextAppearance.DeviceDefault.SearchResult.Title" />
+ <public type="style" name="TextAppearance.DeviceDefault.SearchResult.Subtitle" />
+ <public type="style" name="TextAppearance.DeviceDefault.WindowTitle" />
+ <public type="style" name="TextAppearance.DeviceDefault.DialogWindowTitle" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.Button" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.TabWidget" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.TextView" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.TextView.PopupMenu" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.DropDownHint" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.DropDownItem" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.TextView.SpinnerItem" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.EditText" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.PopupMenu" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle.Inverse" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionMode.Title.Inverse" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" />
+ <public type="style" name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" />
+
+ <public type="style" name="DeviceDefault.ButtonBar" />
+ <public type="style" name="DeviceDefault.ButtonBar.AlertDialog" />
+ <public type="style" name="DeviceDefault.SegmentedButton" />
+ <public type="style" name="DeviceDefault.Light.ButtonBar" />
+ <public type="style" name="DeviceDefault.Light.ButtonBar.AlertDialog" />
+ <public type="style" name="DeviceDefault.Light.SegmentedButton" />
<public type="integer" name="status_bar_notification_info_maxnum" />
<public type="string" name="status_bar_notification_info_overflow" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c5aa4b2..a6c92f2 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2166,6 +2166,14 @@
voicemails that its associated service can access.</string>
<!-- Title of an application permission, listed so the user can choose whether
+ they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permlab_addVoicemail">add voicemail</string>
+ <!-- Description of an application permission, listed so the user can choose whether
+ they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_addVoicemail">Allows the application to add messages
+ to your voicemail inbox.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_writeGeolocationPermissions">Modify Browser geolocation permissions</string>
<!-- Description of an application permission, listed so the user can choose whether
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 5aa47b7..21f1cef 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -14,6 +14,20 @@
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 styles_device_defaults.xml.
+
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
<resources>
<!-- Global Theme Styles -->
<eat-comment />
@@ -95,19 +109,6 @@
<item name="windowExitAnimation">@anim/dialog_exit</item>
</style>
- <!-- Standard animations for hiding and showing the status bar. -->
- <style name="Animation.StatusBar">
- <item name="windowEnterAnimation">@anim/status_bar_enter</item>
- <item name="windowExitAnimation">@anim/status_bar_exit</item>
- </style>
-
- <!-- {@hide} -->
- <style name="Animation.StatusBar.IntruderAlert"
- parent="@android:style/Animation.StatusBar">
- <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item>
- <item name="android:windowExitAnimation">@anim/priority_alert_exit</item>
- </style>
-
<!-- Standard animations for a translucent window or activity. This
style is <em>not<em> used by default for the translucent theme
(since translucent activities are a special case that have no
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
new file mode 100644
index 0000000..7f1891e
--- /dev/null
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -0,0 +1,741 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+This file contains the themes that are the Device Defaults.
+If you want to edit styles to skin your device, do it here.
+We recommend that you do not edit styles.xml and instead edit
+this file.
+
+Editing this file instead of styles.xml will greatly simplify
+merges for future platform versions and CTS compliance will be
+easier.
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+ <!-- Widget Styles -->
+ <style name="Widget.DeviceDefault" parent="Widget.Holo" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Button" parent="Widget.Holo.Button" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Button.Small" parent="Widget.Holo.Button.Small" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Button.Inset" parent="Widget.Holo.Button.Inset" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Button.Toggle" parent="Widget.Holo.Button.Toggle" >
+
+ </style>
+ <style name="Widget.DeviceDefault.TextView" parent="Widget.Holo.TextView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Holo.AutoCompleteTextView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="Widget.Holo.CompoundButton.CheckBox" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ListView.DropDown" parent="Widget.Holo.ListView.DropDown" >
+
+ </style>
+ <style name="Widget.DeviceDefault.EditText" parent="Widget.Holo.EditText" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ExpandableListView" parent="Widget.Holo.ExpandableListView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.GridView" parent="Widget.Holo.GridView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ImageButton" parent="Widget.Holo.ImageButton" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ListView" parent="Widget.Holo.ListView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.PopupWindow" parent="Widget.Holo.PopupWindow" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ProgressBar" parent="Widget.Holo.ProgressBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ProgressBar.Horizontal" parent="Widget.Holo.ProgressBar.Horizontal" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ProgressBar.Small" parent="Widget.Holo.ProgressBar.Small" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ProgressBar.Small.Title" parent="Widget.Holo.ProgressBar.Small.Title" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ProgressBar.Large" parent="Widget.Holo.ProgressBar.Large" >
+
+ </style>
+ <style name="Widget.DeviceDefault.SeekBar" parent="Widget.Holo.SeekBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.RatingBar" parent="Widget.Holo.RatingBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.RatingBar.Indicator" parent="Widget.Holo.RatingBar.Indicator" >
+
+ </style>
+ <style name="Widget.DeviceDefault.RatingBar.Small" parent="Widget.Holo.RatingBar.Small" >
+
+ </style>
+ <style name="Widget.DeviceDefault.CompoundButton.RadioButton" parent="Widget.Holo.CompoundButton.RadioButton" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ScrollView" parent="Widget.Holo.ScrollView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.HorizontalScrollView" parent="Widget.Holo.HorizontalScrollView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Spinner" parent="Widget.Holo.Spinner" >
+
+ </style>
+ <style name="Widget.DeviceDefault.CompoundButton.Star" parent="Widget.Holo.CompoundButton.Star" >
+
+ </style>
+ <style name="Widget.DeviceDefault.TabWidget" parent="Widget.Holo.TabWidget" >
+
+ </style>
+ <style name="Widget.DeviceDefault.WebTextView" parent="Widget.Holo.WebTextView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.WebView" parent="Widget.Holo.WebView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.DropDownItem" parent="Widget.Holo.DropDownItem" >
+
+ </style>
+ <style name="Widget.DeviceDefault.DropDownItem.Spinner" parent="Widget.Holo.DropDownItem.Spinner" >
+
+ </style>
+ <style name="Widget.DeviceDefault.TextView.SpinnerItem" parent="Widget.Holo.TextView.SpinnerItem" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ListPopupWindow" parent="Widget.Holo.ListPopupWindow" >
+
+ </style>
+ <style name="Widget.DeviceDefault.PopupMenu" parent="Widget.Holo.PopupMenu" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionButton" parent="Widget.Holo.ActionButton" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionButton.Overflow" parent="Widget.Holo.ActionButton.Overflow" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionButton.TextButton" parent="Widget.Holo.ActionButton.TextButton" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionMode" parent="Widget.Holo.ActionMode" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionButton.CloseMode" parent="Widget.Holo.ActionButton.CloseMode" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionBar" parent="Widget.Holo.ActionBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Button.Borderless" parent="Widget.Holo.Button.Borderless" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Tab" parent="Widget.Holo.Tab" >
+
+ </style>
+ <style name="Widget.DeviceDefault.CalendarView" parent="Widget.Holo.CalendarView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.DatePicker" parent="Widget.Holo.DatePicker" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionBar.TabView" parent="Widget.Holo.ActionBar.TabView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionBar.TabText" parent="Widget.Holo.ActionBar.TabText" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionBar.TabBar" parent="Widget.Holo.ActionBar.TabBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.ActionBar.Solid" parent="Widget.Holo.ActionBar.Solid" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Button.Borderless.Small" parent="Widget.Holo.Button.Borderless.Small" >
+
+ </style>
+ <style name="Widget.DeviceDefault.AbsListView" parent="Widget.Holo.AbsListView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Spinner.DropDown.ActionBar" parent="Widget.Holo.Spinner.DropDown.ActionBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.PopupWindow.ActionMode" parent="Widget.Holo.PopupWindow.ActionMode" >
+
+ </style>
+ <style name="Widget.DeviceDefault.CompoundButton.Switch" parent="Widget.Holo.CompoundButton.Switch">
+
+ </style>
+ <style name="Widget.DeviceDefault.EditText.NumberPickerInputText" parent="Widget.Holo.EditText.NumberPickerInputText">
+
+ </style>
+ <style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Holo.ExpandableListView.White">
+
+ </style>
+ <style name="Widget.DeviceDefault.Gallery" parent="Widget.Holo.Gallery">
+
+ </style>
+ <style name="Widget.DeviceDefault.GestureOverlayView" parent="Widget.Holo.GestureOverlayView">
+
+ </style>
+ <style name="Widget.DeviceDefault.ImageButton.NumberPickerDownButton" parent="Widget.Holo.ImageButton.NumberPickerDownButton">
+
+ </style>
+ <style name="Widget.DeviceDefault.ImageButton.NumberPickerUpButton" parent="Widget.Holo.ImageButton.NumberPickerUpButton">
+
+ </style>
+ <style name="Widget.DeviceDefault.ImageWell" parent="Widget.Holo.ImageWell">
+
+ </style>
+ <style name="Widget.DeviceDefault.KeyboardView" parent="Widget.Holo.KeyboardView">
+
+ </style>
+ <style name="Widget.DeviceDefault.ListView.White" parent="Widget.Holo.ListView.White">
+
+ </style>
+ <style name="Widget.DeviceDefault.NumberPicker" parent="Widget.Holo.NumberPicker">
+
+ </style>
+ <style name="Widget.DeviceDefault.PreferenceFrameLayout" parent="Widget.Holo.PreferenceFrameLayout">
+
+ </style>
+ <style name="Widget.DeviceDefault.ProgressBar.Inverse" parent="Widget.Holo.ProgressBar.Inverse">
+
+
+ </style>
+ <style name="Widget.DeviceDefault.ProgressBar.Large.Inverse" parent="Widget.Holo.ProgressBar.Large.Inverse">
+
+ </style>
+ <style name="Widget.DeviceDefault.ProgressBar.Small.Inverse" parent="Widget.Holo.ProgressBar.Small.Inverse">
+
+ </style>
+ <style name="Widget.DeviceDefault.QuickContactBadge.WindowLarge" parent="Widget.Holo.QuickContactBadge.WindowLarge">
+
+ </style>
+ <style name="Widget.DeviceDefault.QuickContactBadge.WindowMedium" parent="Widget.Holo.QuickContactBadge.WindowMedium">
+
+ </style>
+ <style name="Widget.DeviceDefault.QuickContactBadge.WindowSmall" parent="Widget.Holo.QuickContactBadge.WindowSmall">
+
+ </style>
+ <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge" parent="Widget.Holo.QuickContactBadgeSmall.WindowLarge">
+
+ </style>
+ <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium" parent="Widget.Holo.QuickContactBadgeSmall.WindowMedium">
+
+ </style>
+ <style name="Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall" parent="Widget.Holo.QuickContactBadgeSmall.WindowSmall">
+
+ </style>
+ <style name="Widget.DeviceDefault.Spinner.DropDown" parent="Widget.Holo.Spinner.DropDown">
+
+ </style>
+ <style name="Widget.DeviceDefault.StackView" parent="Widget.Holo.StackView">
+
+ </style>
+ <style name="Widget.DeviceDefault.TextSelectHandle" parent="Widget.Holo.TextSelectHandle">
+
+ </style>
+ <style name="Widget.DeviceDefault.TextSuggestionsPopupWindow" parent="Widget.Holo.TextSuggestionsPopupWindow">
+
+ </style>
+ <style name="Widget.DeviceDefault.TextView.ListSeparator" parent="Widget.Holo.TextView.ListSeparator">
+
+ </style>
+ <style name="Widget.DeviceDefault.TimePicker" parent="Widget.Holo.TimePicker">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light" parent="Widget.Holo.Light" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Button" parent="Widget.Holo.Light.Button" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Button.Small" parent="Widget.Holo.Light.Button.Small" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Button.Inset" parent="Widget.Holo.Light.Button.Inset" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Button.Toggle" parent="Widget.Holo.Light.Button.Toggle" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.TextView" parent="Widget.Holo.Light.TextView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.AutoCompleteTextView" parent="Widget.Holo.Light.AutoCompleteTextView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.CompoundButton.CheckBox" parent="Widget.Holo.Light.CompoundButton.CheckBox" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ListView.DropDown" parent="Widget.Holo.Light.ListView.DropDown" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.EditText" parent="Widget.Holo.Light.EditText" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ExpandableListView" parent="Widget.Holo.Light.ExpandableListView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Holo.Light.GridView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Holo.Light.ImageButton" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Holo.Light.ListView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.PopupWindow" parent="Widget.Holo.Light.PopupWindow" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ProgressBar" parent="Widget.Holo.Light.ProgressBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Horizontal" parent="Widget.Holo.Light.ProgressBar.Horizontal" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Small" parent="Widget.Holo.Light.ProgressBar.Small" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Title" parent="Widget.Holo.Light.ProgressBar.Small.Title" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Large" parent="Widget.Holo.Light.ProgressBar.Large" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Inverse" parent="Widget.Holo.Light.ProgressBar.Inverse" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Small.Inverse" parent="Widget.Holo.Light.ProgressBar.Small.Inverse" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ProgressBar.Large.Inverse" parent="Widget.Holo.Light.ProgressBar.Large.Inverse" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.SeekBar" parent="Widget.Holo.Light.SeekBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.RatingBar" parent="Widget.Holo.Light.RatingBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.RatingBar.Indicator" parent="Widget.Holo.Light.RatingBar.Indicator" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.RatingBar.Small" parent="Widget.Holo.Light.RatingBar.Small" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.CompoundButton.RadioButton" parent="Widget.Holo.Light.CompoundButton.RadioButton" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ScrollView" parent="Widget.Holo.Light.ScrollView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.HorizontalScrollView" parent="Widget.Holo.Light.HorizontalScrollView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Spinner" parent="Widget.Holo.Light.Spinner" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.CompoundButton.Star" parent="Widget.Holo.Light.CompoundButton.Star" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.TabWidget" parent="Widget.Holo.Light.TabWidget" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.WebTextView" parent="Widget.Holo.Light.WebTextView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.WebView" parent="Widget.Holo.Light.WebView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.DropDownItem" parent="Widget.Holo.Light.DropDownItem" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.DropDownItem.Spinner" parent="Widget.Holo.Light.DropDownItem.Spinner" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.TextView.SpinnerItem" parent="Widget.Holo.Light.TextView.SpinnerItem" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ListPopupWindow" parent="Widget.Holo.Light.ListPopupWindow" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.PopupMenu" parent="Widget.Holo.Light.PopupMenu" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Tab" parent="Widget.Holo.Light.Tab" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.CalendarView" parent="Widget.Holo.Light.CalendarView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Button.Borderless.Small" parent="Widget.Holo.Light.Button.Borderless.Small" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionButton" parent="Widget.Holo.Light.ActionButton" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionButton.Overflow" parent="Widget.Holo.Light.ActionButton.Overflow" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionMode" parent="Widget.Holo.Light.ActionMode" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionButton.CloseMode" parent="Widget.Holo.Light.ActionButton.CloseMode" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar" parent="Widget.Holo.Light.ActionBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabView" parent="Widget.Holo.Light.ActionBar.TabView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabText" parent="Widget.Holo.Light.ActionBar.TabText" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabBar" parent="Widget.Holo.Light.ActionBar.TabBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar.Solid" parent="Widget.Holo.Light.ActionBar.Solid" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar.Solid.Inverse" parent="Widget.Holo.Light.ActionBar.Solid.Inverse" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse" parent="Widget.Holo.Light.ActionBar.TabBar.Inverse" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabView.Inverse" parent="Widget.Holo.Light.ActionBar.TabView.Inverse" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionBar.TabText.Inverse" parent="Widget.Holo.Light.ActionBar.TabText.Inverse" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ActionMode.Inverse" parent="Widget.Holo.Light.ActionMode.Inverse" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.AbsListView" parent="Widget.Holo.Light.AbsListView" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar" parent="Widget.Holo.Light.Spinner.DropDown.ActionBar" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.PopupWindow.ActionMode" parent="Widget.Holo.Light.PopupWindow.ActionMode" >
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Button.Borderless" parent="Widget.Holo.Light.Button.Borderless">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.DatePicker" parent="Widget.Holo.Light.DatePicker">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.EditText.NumberPickerInputText" parent="Widget.Holo.Light.EditText.NumberPickerInputText">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ExpandableListView.White" parent="Widget.Holo.Light.ExpandableListView.White">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Gallery" parent="Widget.Holo.Light.Gallery">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.GestureOverlayView" parent="Widget.Holo.Light.GestureOverlayView">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ImageButton.NumberPickerDownButton" parent="Widget.Holo.Light.ImageButton.NumberPickerDownButton">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ImageButton.NumberPickerUpButton" parent="Widget.Holo.Light.ImageButton.NumberPickerUpButton">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ImageWell" parent="Widget.Holo.Light.ImageWell">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.ListView.White" parent="Widget.Holo.Light.ListView.White">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.NumberPicker" parent="Widget.Holo.Light.NumberPicker">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.Spinner.DropDown" parent="Widget.Holo.Light.Spinner.DropDown">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.TextView.ListSeparator" parent="Widget.Holo.Light.TextView.ListSeparator">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.TimePicker" parent="Widget.Holo.Light.TimePicker">
+
+ </style>
+ <style name="Widget.DeviceDefault.Light.TextSuggestionsPopupWindow" parent="Widget.Holo.Light.TextSuggestionsPopupWindow">
+
+ </style>
+
+
+ <!-- Text Appearance Styles -->
+ <style name="TextAppearance.DeviceDefault" parent="TextAppearance.Holo" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Inverse" parent="TextAppearance.Holo.Inverse" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Large" parent="TextAppearance.Holo.Large" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Large.Inverse" parent="TextAppearance.Holo.Large.Inverse" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Medium" parent="TextAppearance.Holo.Medium" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Medium.Inverse" parent="TextAppearance.Holo.Medium.Inverse" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Small" parent="TextAppearance.Holo.Small" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Small.Inverse" parent="TextAppearance.Holo.Small.Inverse" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.SearchResult.Title" parent="TextAppearance.Holo.SearchResult.Title" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.SearchResult.Subtitle" parent="TextAppearance.Holo.SearchResult.Subtitle" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Holo.Widget" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.Button" parent="TextAppearance.Holo.Widget.Button" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.IconMenu.Item" parent="TextAppearance.Holo.Widget.IconMenu.Item" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.TabWidget" parent="TextAppearance.Holo.Widget.TabWidget" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.TextView" parent="TextAppearance.Holo.Widget.TextView" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.TextView.PopupMenu" parent="TextAppearance.Holo.Widget.TextView.PopupMenu" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.DropDownHint" parent="TextAppearance.Holo.Widget.DropDownHint" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.DropDownItem" parent="TextAppearance.Holo.Widget.DropDownItem" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.TextView.SpinnerItem" parent="TextAppearance.Holo.Widget.TextView.SpinnerItem" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.EditText" parent="TextAppearance.Holo.Widget.EditText" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.PopupMenu" parent="TextAppearance.Holo.Widget.PopupMenu" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Large" parent="TextAppearance.Holo.Widget.PopupMenu.Large" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.PopupMenu.Small" parent="TextAppearance.Holo.Widget.PopupMenu.Small" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title" parent="TextAppearance.Holo.Widget.ActionBar.Title" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle" parent="TextAppearance.Holo.Widget.ActionBar.Subtitle" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title" parent="TextAppearance.Holo.Widget.ActionMode.Title" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle" parent="TextAppearance.Holo.Widget.ActionMode.Subtitle" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.WindowTitle" parent="TextAppearance.Holo.WindowTitle" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.DialogWindowTitle" parent="TextAppearance.Holo.DialogWindowTitle" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Holo.Widget.ActionBar.Title.Inverse" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Holo.Widget.ActionBar.Subtitle.Inverse" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Title.Inverse" parent="TextAppearance.Holo.Widget.ActionMode.Title.Inverse" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionMode.Subtitle.Inverse" parent="TextAppearance.Holo.Widget.ActionMode.Subtitle.Inverse" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Widget.ActionBar.Menu" parent="TextAppearance.Holo.Widget.ActionBar.Menu" >
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light" parent="TextAppearance.Holo.Light">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Inverse" parent="TextAppearance.Holo.Light.Inverse">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Large" parent="TextAppearance.Holo.Light.Large">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Large.Inverse" parent="TextAppearance.Holo.Light.Large.Inverse">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Medium" parent="TextAppearance.Holo.Light.Medium">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Medium.Inverse" parent="TextAppearance.Holo.Light.Medium.Inverse">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.SearchResult.Subtitle" parent="TextAppearance.Holo.Light.SearchResult.Subtitle">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.SearchResult.Title" parent="TextAppearance.Holo.Light.SearchResult.Title">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Small" parent="TextAppearance.Holo.Light.Small">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Small.Inverse" parent="TextAppearance.Holo.Light.Small.Inverse">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Widget.Button" parent="TextAppearance.Holo.Light.Widget.Button">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large" parent="TextAppearance.Holo.Light.Widget.PopupMenu.Large">
+
+ </style>
+ <style name="TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small" parent="TextAppearance.Holo.Light.Widget.PopupMenu.Small">
+
+ </style>
+
+
+ <!-- Preference Styles -->
+ <style name="Preference.DeviceDefault" parent="Preference.Holo">
+
+ </style>
+ <style name="Preference.DeviceDefault.Category" parent="Preference.Holo.Category">
+
+ </style>
+ <style name="Preference.DeviceDefault.CheckBoxPreference" parent="Preference.Holo.CheckBoxPreference">
+
+ </style>
+ <style name="Preference.DeviceDefault.DialogPreference" parent="Preference.Holo.DialogPreference">
+
+ </style>
+ <style name="Preference.DeviceDefault.DialogPreference.EditTextPreference" parent="Preference.Holo.DialogPreference.EditTextPreference">
+
+ </style>
+ <style name="Preference.DeviceDefault.DialogPreference.YesNoPreference" parent="Preference.Holo.DialogPreference.YesNoPreference">
+
+ </style>
+ <style name="Preference.DeviceDefault.Information" parent="Preference.Holo.Information">
+
+ </style>
+ <style name="Preference.DeviceDefault.PreferenceScreen" parent="Preference.Holo.PreferenceScreen">
+
+ </style>
+ <style name="Preference.DeviceDefault.RingtonePreference" parent="Preference.Holo.RingtonePreference">
+
+ </style>
+ <style name="Preference.DeviceDefault.SwitchPreference" parent="Preference.Holo.SwitchPreference">
+
+ </style>
+
+
+ <!-- AlertDialog Styles -->
+ <style name="AlertDialog.DeviceDefault" parent="AlertDialog.Holo">
+
+ </style>
+ <style name="AlertDialog.DeviceDefault.Light" parent="AlertDialog.DeviceDefault.Light" >
+
+ </style>
+
+
+ <!-- Animation Styles -->
+ <style name="Animation.DeviceDefault.Activity" parent="Animation.Holo.Activity">
+
+ </style>
+ <style name="Animation.DeviceDefault.Dialog" parent="Animation.Holo.Dialog">
+
+ </style>
+
+
+ <!-- DialogWindowTitle Styles -->
+ <style name="DialogWindowTitle.DeviceDefault" parent="DialogWindowTitle.Holo">
+
+ </style>
+ <style name="DialogWindowTitle.DeviceDefault.Light" parent="DialogWindowTitle.Holo.Light">
+
+ </style>
+
+
+ <!-- WindowTitle Styles -->
+ <style name="WindowTitle.DeviceDefault" parent="WindowTitle.Holo">
+
+ </style>
+ <style name="WindowTitleBackground.DeviceDefault" parent="WindowTitleBackground.Holo">
+
+ </style>
+
+
+ <!-- Other Styles -->
+ <style name="DeviceDefault.ButtonBar" parent="Holo.ButtonBar" >
+
+ </style>
+ <style name="DeviceDefault.ButtonBar.AlertDialog" parent="Holo.ButtonBar.AlertDialog" >
+
+ </style>
+ <style name="DeviceDefault.SegmentedButton" parent="Holo.SegmentedButton" >
+
+ </style>
+ <style name="DeviceDefault.Light.ButtonBar" parent="Holo.Light.ButtonBar" >
+
+ </style>
+ <style name="DeviceDefault.Light.ButtonBar.AlertDialog" parent="Holo.Light.ButtonBar.AlertDialog" >
+
+ </style>
+ <style name="DeviceDefault.Light.SegmentedButton" parent="Holo.Light.SegmentedButton" >
+
+ </style>
+</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 3e7c5ca..615a37d 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -14,6 +14,20 @@
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>
<!-- The default system theme. This is the theme used for activities
that have not explicitly set their own theme.
@@ -1207,7 +1221,7 @@
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
<item name="windowIsFloating">false</item>
- <item name="windowContentOverlay">@null</item>
+ <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
<item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@android:style/WindowTitle.Holo</item>
<item name="windowTitleSize">25dip</item>
@@ -1337,7 +1351,7 @@
<item name="actionBarTabTextStyle">@style/Widget.Holo.Light.ActionBar.TabText</item>
<item name="actionModeStyle">@style/Widget.Holo.Light.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Holo.Light.ActionButton.CloseMode</item>
- <item name="actionBarStyle">@android:style/Widget.Holo.Light.ActionBar</item>
+ <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid</item>
<item name="actionBarSize">@dimen/action_bar_default_height</item>
<item name="actionModePopupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow.ActionMode</item>
<item name="actionBarWidgetTheme">@null</item>
@@ -1384,22 +1398,10 @@
</style>
- <!-- Variant of the holographic (dark) theme that has a solid (opaque) action bar. -->
- <style name="Theme.Holo.SolidActionBar">
- <item name="android:actionBarStyle">@android:style/Widget.Holo.ActionBar.Solid</item>
- <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
- </style>
-
- <!-- Variant of the holographic (light) theme that has a solid (opaque) action bar. -->
- <style name="Theme.Holo.Light.SolidActionBar">
- <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid</item>
- <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
- </style>
-
<!-- Variant of the holographic (light) theme that has a solid (opaque) action bar
with an inverse color profile. The dark action bar sharply stands out against
the light content. -->
- <style name="Theme.Holo.Light.SolidActionBar.Inverse">
+ <style name="Theme.Holo.Light.DarkActionBar">
<item name="android:windowContentOverlay">@android:drawable/title_bar_shadow</item>
<item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse</item>
<item name="actionBarWidgetTheme">@android:style/Theme.Holo</item>
@@ -1427,30 +1429,6 @@
<item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_dark</item>
</style>
- <!-- Variant of the holographic (dark) theme that has a solid
- (opaque) action bar. The action bar will split across both
- the top and bottom of the screen when the screen is
- especially constrained for horizontal space. -->
- <style name="Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
-
- <!-- Variant of the holographic (light) theme that has a solid
- (opaque) action bar. The action bar will split across both
- the top and bottom of the screen when the screen is
- especially constrained for horizontal space. -->
- <style name="Theme.Holo.Light.SolidActionBar.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
-
- <!-- Variant of the holographic (light) theme that has a solid (opaque) action bar
- with an inverse color profile. The dark action bar sharply stands out against
- the light content. The action bar will split across both the top and bottom of
- the screen when the screen is especially constrained for horizontal space. -->
- <style name="Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
-
<!-- Variant of the holographic (dark) theme with no action bar. -->
<style name="Theme.Holo.NoActionBar">
<item name="android:windowActionBar">false</item>
@@ -1654,18 +1632,4 @@
<style name="Theme.Holo.Wallpaper.NoTitleBar">
<item name="android:windowNoTitle">true</item>
</style>
-
- <!-- Variant of the holographic (dark) theme with an action bar that
- splits across the top and bottom of the activity when constrained
- for horizontal space. -->
- <style name="Theme.Holo.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
-
- <!-- Variant of the holographic (light) theme with an action bar that
- splits across the top and bottom of the activity when constrained
- for horizontal space. -->
- <style name="Theme.Holo.Light.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
</resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
new file mode 100644
index 0000000..bf6329d
--- /dev/null
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -0,0 +1,423 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+===============================================================
+ PLEASE READ
+===============================================================
+This file contains the themes that are the Device Defaults.
+If you want to edit themes to skin your device, do it here.
+We recommend that you do not edit themes.xml and instead edit
+this file.
+
+Editing this file instead of themes.xml will greatly simplify
+merges for future platform versions and CTS compliance will be
+easier.
+===============================================================
+ PLEASE READ
+===============================================================
+ -->
+<resources>
+ <style name="Theme.DeviceDefault" parent="Theme.Holo" >
+ <!-- Text styles -->
+ <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
+ <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
+
+ <item name="textAppearanceLarge">@android:style/TextAppearance.DeviceDefault.Large</item>
+ <item name="textAppearanceMedium">@android:style/TextAppearance.DeviceDefault.Medium</item>
+ <item name="textAppearanceSmall">@android:style/TextAppearance.DeviceDefault.Small</item>
+ <item name="textAppearanceLargeInverse">@android:style/TextAppearance.DeviceDefault.Large.Inverse</item>
+ <item name="textAppearanceMediumInverse">@android:style/TextAppearance.DeviceDefault.Medium.Inverse</item>
+ <item name="textAppearanceSmallInverse">@android:style/TextAppearance.DeviceDefault.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.DeviceDefault.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle</item>
+
+ <item name="textAppearanceButton">@android:style/TextAppearance.DeviceDefault.Widget.Button</item>
+
+ <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.DeviceDefault.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.DeviceDefault.Widget.PopupMenu.Small</item>
+
+ <!-- Button styles -->
+ <item name="buttonStyle">@android:style/Widget.DeviceDefault.Button</item>
+
+ <item name="buttonStyleSmall">@android:style/Widget.DeviceDefault.Button.Small</item>
+ <item name="buttonStyleInset">@android:style/Widget.DeviceDefault.Button.Inset</item>
+
+ <item name="buttonStyleToggle">@android:style/Widget.DeviceDefault.Button.Toggle</item>
+ <item name="switchStyle">@android:style/Widget.DeviceDefault.CompoundButton.Switch</item>
+
+ <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Button.Borderless</item>
+
+ <item name="listSeparatorTextViewStyle">@android:style/Widget.DeviceDefault.TextView.ListSeparator</item>
+
+ <!-- Window attributes -->
+ <item name="windowTitleStyle">@android:style/WindowTitle.DeviceDefault</item>
+ <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.DeviceDefault</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item>
+
+ <!-- Dialog attributes -->
+ <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault</item>
+ <item name="dialogTheme">@android:style/Theme.DeviceDefault.Dialog</item>
+ <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Dialog.Alert</item>
+
+ <!-- Text selection handle attributes -->
+ <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@android:style/Widget.DeviceDefault.TextSuggestionsPopupWindow</item>
+
+ <!-- Widget styles -->
+ <item name="absListViewStyle">@android:style/Widget.DeviceDefault.AbsListView</item>
+ <item name="autoCompleteTextViewStyle">@android:style/Widget.DeviceDefault.AutoCompleteTextView</item>
+ <item name="checkboxStyle">@android:style/Widget.DeviceDefault.CompoundButton.CheckBox</item>
+ <item name="dropDownListViewStyle">@android:style/Widget.DeviceDefault.ListView.DropDown</item>
+ <item name="editTextStyle">@android:style/Widget.DeviceDefault.EditText</item>
+ <item name="expandableListViewStyle">@android:style/Widget.DeviceDefault.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@android:style/Widget.DeviceDefault.ExpandableListView.White</item>
+ <item name="galleryStyle">@android:style/Widget.DeviceDefault.Gallery</item>
+ <item name="gestureOverlayViewStyle">@android:style/Widget.DeviceDefault.GestureOverlayView</item>
+ <item name="gridViewStyle">@android:style/Widget.DeviceDefault.GridView</item>
+ <item name="imageButtonStyle">@android:style/Widget.DeviceDefault.ImageButton</item>
+ <item name="imageWellStyle">@android:style/Widget.DeviceDefault.ImageWell</item>
+ <item name="listViewStyle">@android:style/Widget.DeviceDefault.ListView</item>
+ <item name="listViewWhiteStyle">@android:style/Widget.DeviceDefault.ListView.White</item>
+ <item name="popupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow</item>
+ <item name="progressBarStyle">@android:style/Widget.DeviceDefault.ProgressBar</item>
+ <item name="progressBarStyleHorizontal">@android:style/Widget.DeviceDefault.ProgressBar.Horizontal</item>
+ <item name="progressBarStyleSmall">@android:style/Widget.DeviceDefault.ProgressBar.Small</item>
+ <item name="progressBarStyleSmallTitle">@android:style/Widget.DeviceDefault.ProgressBar.Small.Title</item>
+ <item name="progressBarStyleLarge">@android:style/Widget.DeviceDefault.ProgressBar.Large</item>
+ <item name="progressBarStyleInverse">@android:style/Widget.DeviceDefault.ProgressBar.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@android:style/Widget.DeviceDefault.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@android:style/Widget.DeviceDefault.ProgressBar.Large.Inverse</item>
+ <item name="seekBarStyle">@android:style/Widget.DeviceDefault.SeekBar</item>
+ <item name="ratingBarStyle">@android:style/Widget.DeviceDefault.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@android:style/Widget.DeviceDefault.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@android:style/Widget.DeviceDefault.RatingBar.Small</item>
+ <item name="radioButtonStyle">@android:style/Widget.DeviceDefault.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@android:style/Widget.DeviceDefault.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@android:style/Widget.DeviceDefault.HorizontalScrollView</item>
+ <item name="dropDownSpinnerStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown</item>
+ <item name="starStyle">@android:style/Widget.DeviceDefault.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@android:style/Widget.DeviceDefault.TabWidget</item>
+ <item name="textViewStyle">@android:style/Widget.DeviceDefault.TextView</item>
+ <item name="webTextViewStyle">@android:style/Widget.DeviceDefault.WebTextView</item>
+ <item name="webViewStyle">@android:style/Widget.DeviceDefault.WebView</item>
+ <item name="dropDownItemStyle">@android:style/Widget.DeviceDefault.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@android:style/Widget.DeviceDefault.DropDownItem.Spinner</item>
+ <item name="spinnerItemStyle">@android:style/Widget.DeviceDefault.TextView.SpinnerItem</item>
+ <item name="dropDownHintAppearance">@android:style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
+ <item name="keyboardViewStyle">@android:style/Widget.DeviceDefault.KeyboardView</item>
+ <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
+ <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
+ <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
+ <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
+ <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
+ <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
+ <item name="listPopupWindowStyle">@android:style/Widget.DeviceDefault.ListPopupWindow</item>
+ <item name="popupMenuStyle">@android:style/Widget.DeviceDefault.PopupMenu</item>
+ <item name="stackViewStyle">@android:style/Widget.DeviceDefault.StackView</item>
+
+ <!-- Preference styles -->
+ <item name="preferenceScreenStyle">@android:style/Preference.DeviceDefault.PreferenceScreen</item>
+ <item name="preferenceCategoryStyle">@android:style/Preference.DeviceDefault.Category</item>
+ <item name="preferenceStyle">@android:style/Preference.DeviceDefault</item>
+ <item name="preferenceInformationStyle">@android:style/Preference.DeviceDefault.Information</item>
+ <item name="checkBoxPreferenceStyle">@android:style/Preference.DeviceDefault.CheckBoxPreference</item>
+ <item name="switchPreferenceStyle">@android:style/Preference.DeviceDefault.SwitchPreference</item>
+ <item name="yesNoPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
+ <item name="dialogPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
+ <item name="ringtonePreferenceStyle">@android:style/Preference.DeviceDefault.RingtonePreference</item>
+
+ <!-- Action bar styles -->
+ <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</item>
+ <item name="actionBarTabStyle">@style/Widget.DeviceDefault.ActionBar.TabView</item>
+ <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.ActionBar.TabBar</item>
+ <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.ActionBar.TabText</item>
+ <item name="actionModeStyle">@style/Widget.DeviceDefault.ActionMode</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item>
+ <item name="actionBarStyle">@android:style/Widget.DeviceDefault.ActionBar</item>
+ <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
+
+ <item name="buttonBarStyle">@android:style/DeviceDefault.ButtonBar</item>
+ <item name="segmentedButtonStyle">@android:style/DeviceDefault.SegmentedButton</item>
+
+ <item name="searchDialogTheme">@style/Theme.DeviceDefault.SearchBar</item>
+
+ <!-- PreferenceFrameLayout attributes -->
+ <item name="preferenceFrameLayoutStyle">@android:style/Widget.DeviceDefault.PreferenceFrameLayout</item>
+
+ <!-- NumberPicker styles-->
+ <item name="numberPickerUpButtonStyle">@style/Widget.DeviceDefault.ImageButton.NumberPickerUpButton</item>
+ <item name="numberPickerDownButtonStyle">@style/Widget.DeviceDefault.ImageButton.NumberPickerDownButton</item>
+ <item name="numberPickerInputTextStyle">@style/Widget.DeviceDefault.EditText.NumberPickerInputText</item>
+ <item name="numberPickerStyle">@style/Widget.DeviceDefault.NumberPicker</item>
+
+ <!-- CalendarView style-->
+ <item name="calendarViewStyle">@style/Widget.DeviceDefault.CalendarView</item>
+
+ <!-- TimePicker style -->
+ <item name="timePickerStyle">@style/Widget.DeviceDefault.TimePicker</item>
+
+ <!-- DatePicker style -->
+ <item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
+ </style>
+ <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
+
+ </style>
+ <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
+ <!-- Text styles -->
+ <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
+ <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
+
+ <item name="textAppearanceLarge">@android:style/TextAppearance.DeviceDefault.Light.Large</item>
+ <item name="textAppearanceMedium">@android:style/TextAppearance.DeviceDefault.Light.Medium</item>
+ <item name="textAppearanceSmall">@android:style/TextAppearance.DeviceDefault.Light.Small</item>
+ <item name="textAppearanceLargeInverse">@android:style/TextAppearance.DeviceDefault.Light.Large.Inverse</item>
+ <item name="textAppearanceMediumInverse">@android:style/TextAppearance.DeviceDefault.Light.Medium.Inverse</item>
+ <item name="textAppearanceSmallInverse">@android:style/TextAppearance.DeviceDefault.Light.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.DeviceDefault.Light.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.DeviceDefault.Light.SearchResult.Subtitle</item>
+
+ <item name="textAppearanceButton">@android:style/TextAppearance.DeviceDefault.Light.Widget.Button</item>
+
+ <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.DeviceDefault.Light.Widget.PopupMenu.Small</item>
+
+ <!-- Button styles -->
+ <item name="buttonStyle">@android:style/Widget.DeviceDefault.Light.Button</item>
+
+ <item name="buttonStyleSmall">@android:style/Widget.DeviceDefault.Light.Button.Small</item>
+ <item name="buttonStyleInset">@android:style/Widget.DeviceDefault.Light.Button.Inset</item>
+
+ <item name="buttonStyleToggle">@android:style/Widget.DeviceDefault.Light.Button.Toggle</item>
+
+ <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Light.Button.Borderless</item>
+
+ <item name="listSeparatorTextViewStyle">@android:style/Widget.DeviceDefault.Light.TextView.ListSeparator</item>
+
+ <item name="windowTitleStyle">@android:style/WindowTitle.DeviceDefault</item>
+ <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.DeviceDefault</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Activity</item>
+
+ <!-- Dialog attributes -->
+ <item name="alertDialogStyle">@android:style/AlertDialog.DeviceDefault.Light</item>
+ <item name="dialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog</item>
+ <item name="alertDialogTheme">@android:style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
+ <!-- Text selection handle attributes -->
+ <item name="textSelectHandleWindowStyle">@android:style/Widget.DeviceDefault.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@android:style/Widget.DeviceDefault.Light.TextSuggestionsPopupWindow</item>
+
+ <!-- Widget styles -->
+ <item name="absListViewStyle">@android:style/Widget.DeviceDefault.Light.AbsListView</item>
+ <item name="autoCompleteTextViewStyle">@android:style/Widget.DeviceDefault.Light.AutoCompleteTextView</item>
+ <item name="checkboxStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.CheckBox</item>
+ <item name="dropDownListViewStyle">@android:style/Widget.DeviceDefault.ListView.DropDown</item>
+ <item name="editTextStyle">@android:style/Widget.DeviceDefault.Light.EditText</item>
+ <item name="expandableListViewStyle">@android:style/Widget.DeviceDefault.Light.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@android:style/Widget.DeviceDefault.Light.ExpandableListView.White</item>
+ <item name="galleryStyle">@android:style/Widget.DeviceDefault.Light.Gallery</item>
+ <item name="gestureOverlayViewStyle">@android:style/Widget.DeviceDefault.Light.GestureOverlayView</item>
+ <item name="gridViewStyle">@android:style/Widget.DeviceDefault.Light.GridView</item>
+ <item name="imageButtonStyle">@android:style/Widget.DeviceDefault.Light.ImageButton</item>
+ <item name="imageWellStyle">@android:style/Widget.DeviceDefault.Light.ImageWell</item>
+ <item name="listViewStyle">@android:style/Widget.DeviceDefault.Light.ListView</item>
+ <item name="listViewWhiteStyle">@android:style/Widget.DeviceDefault.Light.ListView.White</item>
+ <item name="popupWindowStyle">@android:style/Widget.DeviceDefault.Light.PopupWindow</item>
+ <item name="progressBarStyle">@android:style/Widget.DeviceDefault.Light.ProgressBar</item>
+ <item name="progressBarStyleHorizontal">@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal</item>
+ <item name="progressBarStyleSmall">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small</item>
+ <item name="progressBarStyleSmallTitle">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small.Title</item>
+ <item name="progressBarStyleLarge">@android:style/Widget.DeviceDefault.Light.ProgressBar.Large</item>
+ <item name="progressBarStyleInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@android:style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse</item>
+ <item name="seekBarStyle">@android:style/Widget.DeviceDefault.Light.SeekBar</item>
+ <item name="ratingBarStyle">@android:style/Widget.DeviceDefault.Light.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@android:style/Widget.DeviceDefault.Light.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@android:style/Widget.DeviceDefault.Light.RatingBar.Small</item>
+ <item name="radioButtonStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@android:style/Widget.DeviceDefault.Light.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@android:style/Widget.DeviceDefault.Light.HorizontalScrollView</item>
+ <item name="dropDownSpinnerStyle">@android:style/Widget.DeviceDefault.Light.Spinner.DropDown</item>
+ <item name="starStyle">@android:style/Widget.DeviceDefault.Light.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@android:style/Widget.DeviceDefault.Light.TabWidget</item>
+ <item name="textViewStyle">@android:style/Widget.DeviceDefault.Light.TextView</item>
+ <item name="webTextViewStyle">@android:style/Widget.DeviceDefault.Light.WebTextView</item>
+ <item name="webViewStyle">@android:style/Widget.DeviceDefault.Light.WebView</item>
+ <item name="dropDownItemStyle">@android:style/Widget.DeviceDefault.Light.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@android:style/Widget.DeviceDefault.Light.DropDownItem.Spinner</item>
+ <item name="spinnerItemStyle">@android:style/Widget.DeviceDefault.TextView.SpinnerItem</item>
+ <item name="dropDownHintAppearance">@android:style/TextAppearance.DeviceDefault.Widget.DropDownHint</item>
+ <item name="keyboardViewStyle">@android:style/Widget.DeviceDefault.KeyboardView</item>
+ <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowSmall</item>
+ <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowMedium</item>
+ <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadge.WindowLarge</item>
+ <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowSmall</item>
+ <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowMedium</item>
+ <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.DeviceDefault.QuickContactBadgeSmall.WindowLarge</item>
+ <item name="listPopupWindowStyle">@android:style/Widget.DeviceDefault.Light.ListPopupWindow</item>
+ <item name="popupMenuStyle">@android:style/Widget.DeviceDefault.Light.PopupMenu</item>
+ <item name="stackViewStyle">@android:style/Widget.DeviceDefault.StackView</item>
+
+ <!-- Preference styles -->
+ <item name="preferenceScreenStyle">@android:style/Preference.DeviceDefault.PreferenceScreen</item>
+ <item name="preferenceCategoryStyle">@android:style/Preference.DeviceDefault.Category</item>
+ <item name="preferenceStyle">@android:style/Preference.DeviceDefault</item>
+ <item name="preferenceInformationStyle">@android:style/Preference.DeviceDefault.Information</item>
+ <item name="checkBoxPreferenceStyle">@android:style/Preference.DeviceDefault.CheckBoxPreference</item>
+ <item name="switchPreferenceStyle">@android:style/Preference.DeviceDefault.SwitchPreference</item>
+ <item name="yesNoPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.YesNoPreference</item>
+ <item name="dialogPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@android:style/Preference.DeviceDefault.DialogPreference.EditTextPreference</item>
+ <item name="ringtonePreferenceStyle">@android:style/Preference.DeviceDefault.RingtonePreference</item>
+
+ <!-- Action bar styles -->
+ <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Light.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.Light.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.Light.ActionButton.Overflow</item>
+ <item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView</item>
+ <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar</item>
+ <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText</item>
+ <item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.Light.ActionButton.CloseMode</item>
+ <item name="actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar</item>
+ <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.Light.PopupWindow.ActionMode</item>
+
+ <item name="buttonBarStyle">@android:style/DeviceDefault.Light.ButtonBar</item>
+ <item name="segmentedButtonStyle">@android:style/DeviceDefault.Light.SegmentedButton</item>
+
+ <item name="searchDialogTheme">@style/Theme.DeviceDefault.Light.SearchBar</item>
+
+ <!-- NumberPicker attributes and styles-->
+ <item name="numberPickerUpButtonStyle">@style/Widget.DeviceDefault.Light.ImageButton.NumberPickerUpButton</item>
+ <item name="numberPickerDownButtonStyle">@style/Widget.DeviceDefault.Light.ImageButton.NumberPickerDownButton</item>
+ <item name="numberPickerInputTextStyle">@style/Widget.DeviceDefault.Light.EditText.NumberPickerInputText</item>
+ <item name="numberPickerStyle">@style/Widget.DeviceDefault.Light.NumberPicker</item>
+
+ <!-- CalendarView style-->
+ <item name="calendarViewStyle">@style/Widget.DeviceDefault.Light.CalendarView</item>
+
+ <!-- TimePicker style -->
+ <item name="timePickerStyle">@style/Widget.DeviceDefault.Light.TimePicker</item>
+
+ <!-- DatePicker style -->
+ <item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
+ </style>
+ <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Dialog" parent="Theme.Holo.Dialog" >
+ <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
+
+ <item name="android:buttonBarStyle">@android:style/DeviceDefault.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Button.Borderless.Small</item>
+
+ <item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
+ <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
+ </style>
+ <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Holo.Dialog.MinWidth" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Holo.Dialog.NoActionBar" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Dialog.NoActionBar.MinWidth" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Holo.Light.Dialog" >
+ <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
+
+ <item name="android:buttonBarStyle">@android:style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@android:style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
+
+ <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
+ <item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
+ </style>
+ <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Holo.Light.Dialog.MinWidth" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Holo.Light.Dialog.NoActionBar" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Light.Dialog.NoActionBar.MinWidth" >
+
+ </style>
+ <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Holo.DialogWhenLarge" >
+
+ </style>
+ <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Holo.DialogWhenLarge.NoActionBar" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Holo.Light.DialogWhenLarge" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.DialogWhenLarge.NoActionBar" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Panel" parent="Theme.Holo.Panel" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Holo.Light.Panel" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Holo.Wallpaper" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Holo.Wallpaper.NoTitleBar" >
+
+ </style>
+ <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Holo.InputMethod" >
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Holo.Light.DarkActionBar" >
+ <item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
+
+ <item name="actionDropDownStyle">@android:style/Widget.DeviceDefault.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@android:style/Widget.DeviceDefault.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@android:style/Widget.DeviceDefault.ActionButton.Overflow</item>
+ <item name="actionBarTabStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabView.Inverse</item>
+ <item name="actionBarTabBarStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabBar.Inverse</item>
+ <item name="actionBarTabTextStyle">@style/Widget.DeviceDefault.Light.ActionBar.TabText.Inverse</item>
+ <item name="actionModeStyle">@style/Widget.DeviceDefault.Light.ActionMode.Inverse</item>
+ <item name="actionModeCloseButtonStyle">@style/Widget.DeviceDefault.ActionButton.CloseMode</item>
+ <item name="actionModePopupWindowStyle">@android:style/Widget.DeviceDefault.PopupWindow.ActionMode</item>
+
+ </style>
+
+ <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Holo.Dialog.Alert">
+ <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
+ </style>
+ <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.DeviceDefault.Light.Dialog.Alert">
+ <item name="windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
+ </style>
+ <style name="Theme.DeviceDefault.SearchBar" parent="Theme.DeviceDefault.SearchBar">
+
+ </style>
+ <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.DeviceDefault.Light.SearchBar">
+
+ </style>
+</resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 5d28ef7..6c87c3b 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -3114,6 +3114,13 @@
PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
+ @LargeTest
+ public void testInstallNonexistentFile() {
+ int retCode = PackageManager.INSTALL_FAILED_INVALID_URI;
+ File invalidFile = new File("/nonexistent-file.apk");
+ invokeInstallPackageFail(Uri.fromFile(invalidFile), 0, retCode);
+ }
+
/*---------- Recommended install location tests ----*/
/*
* TODO's
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9bf3de8..9acf99b 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -44,9 +44,11 @@
///////////////////////////////////////////////////////////////////////////////
Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
- int flags, uint32_t italicStyle, uint32_t scaleX) :
+ int flags, uint32_t italicStyle, uint32_t scaleX,
+ SkPaint::Style style, uint32_t strokeWidth) :
mState(state), mFontId(fontId), mFontSize(fontSize),
- mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX) {
+ mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
+ mStyle(style), mStrokeWidth(mStrokeWidth) {
}
@@ -283,19 +285,22 @@
}
Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
- int flags, uint32_t italicStyle, uint32_t scaleX) {
+ int flags, uint32_t italicStyle, uint32_t scaleX,
+ SkPaint::Style style, uint32_t strokeWidth) {
Vector<Font*> &activeFonts = state->mActiveFonts;
for (uint32_t i = 0; i < activeFonts.size(); i++) {
Font* font = activeFonts[i];
if (font->mFontId == fontId && font->mFontSize == fontSize &&
font->mFlags == flags && font->mItalicStyle == italicStyle &&
- font->mScaleX == scaleX) {
+ font->mScaleX == scaleX && font->mStyle == style &&
+ (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
return font;
}
}
- Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle, scaleX);
+ Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
+ scaleX, style, strokeWidth);
activeFonts.push(newFont);
return newFont;
}
@@ -690,7 +695,11 @@
uint32_t italicStyle = *(uint32_t*) &skewX;
const float scaleXFloat = paint->getTextScaleX();
uint32_t scaleX = *(uint32_t*) &scaleXFloat;
- mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, scaleX);
+ SkPaint::Style style = paint->getStyle();
+ const float strokeWidthFloat = paint->getStrokeWidth();
+ uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
+ mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
+ scaleX, style, strokeWidth);
const float maxPrecacheFontSize = 40.0f;
bool isNewFont = currentNumFonts != mActiveFonts.size();
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 24ed6fa..1922812 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -82,7 +82,8 @@
* Creates a new font associated with the specified font state.
*/
static Font* create(FontRenderer* state, uint32_t fontId, float fontSize,
- int flags, uint32_t italicStyle, uint32_t scaleX);
+ int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style,
+ uint32_t strokeWidth);
protected:
friend class FontRenderer;
@@ -128,7 +129,7 @@
};
Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
- uint32_t scaleX);
+ uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);
// Cache of glyphs
DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
@@ -157,6 +158,8 @@
int mFlags;
uint32_t mItalicStyle;
uint32_t mScaleX;
+ SkPaint::Style mStyle;
+ uint32_t mStrokeWidth;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7258e11..731d1f3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1646,7 +1646,8 @@
IAudioService service = getService();
try {
status = service.requestAudioFocus(streamType, durationHint, mICallBack,
- mAudioFocusDispatcher, getIdForAudioFocusListener(l));
+ mAudioFocusDispatcher, getIdForAudioFocusListener(l),
+ mContext.getPackageName() /* package name */);
} catch (RemoteException e) {
Log.e(TAG, "Can't call requestAudioFocus() from AudioService due to "+e);
}
@@ -1682,7 +1683,9 @@
* in the application manifest.
*/
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
- //TODO enforce the rule about the receiver being declared in the manifest
+ if (eventReceiver == null) {
+ return;
+ }
IAudioService service = getService();
try {
service.registerMediaButtonEventReceiver(eventReceiver);
@@ -1697,6 +1700,9 @@
* that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
*/
public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
+ if (eventReceiver == null) {
+ return;
+ }
IAudioService service = getService();
try {
service.unregisterMediaButtonEventReceiver(eventReceiver);
@@ -1706,6 +1712,126 @@
}
/**
+ * @hide
+ * Registers the remote control client for providing information to display on the remotes.
+ * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
+ * that will receive the media button intent, and associated with the remote control
+ * client. This method has no effect if
+ * {@link #registerMediaButtonEventReceiver(ComponentName)} hasn't been called
+ * with the same eventReceiver, or if
+ * {@link #unregisterMediaButtonEventReceiver(ComponentName)} has been called.
+ * @param rcClient the client associated with the event receiver, responsible for providing
+ * the information to display on the remote control.
+ */
+ public void registerRemoteControlClient(ComponentName eventReceiver,
+ IRemoteControlClient rcClient) {
+ if (eventReceiver == null) {
+ return;
+ }
+ IAudioService service = getService();
+ try {
+ service.registerRemoteControlClient(eventReceiver, rcClient,
+ // used to match media button event receiver and audio focus
+ mContext.getPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
+ }
+ }
+
+ /**
+ * @hide
+ * @param eventReceiver
+ */
+ public void unregisterRemoteControlClient(ComponentName eventReceiver) {
+ if (eventReceiver == null) {
+ return;
+ }
+ IAudioService service = getService();
+ try {
+ // unregistering a IRemoteControlClient is equivalent to setting it to null
+ service.registerRemoteControlClient(eventReceiver, null, mContext.getPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
+ }
+ }
+
+ /**
+ * @hide
+ * Definitions of constants to be used in {@link android.media.IRemoteControlClient}.
+ */
+ public final class RemoteControlParameters {
+ public final static int PLAYSTATE_STOPPED = 1;
+ public final static int PLAYSTATE_PAUSED = 2;
+ public final static int PLAYSTATE_PLAYING = 3;
+ public final static int PLAYSTATE_FAST_FORWARDING = 4;
+ public final static int PLAYSTATE_REWINDING = 5;
+ public final static int PLAYSTATE_SKIPPING_FORWARDS = 6;
+ public final static int PLAYSTATE_SKIPPING_BACKWARDS = 7;
+ public final static int PLAYSTATE_BUFFERING = 8;
+
+ public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
+ public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1;
+ public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2;
+ public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3;
+ public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4;
+ public final static int FLAG_KEY_MEDIA_STOP = 1 << 5;
+ public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6;
+ public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
+ }
+
+ /**
+ * @hide
+ * Broadcast intent action indicating that the displays on the remote controls
+ * should be updated because a new remote control client is now active. If there is no
+ * {@link #EXTRA_REMOTE_CONTROL_CLIENT}, the remote control display should be cleared
+ * because there is no valid client to supply it with information.
+ *
+ * @see #EXTRA_REMOTE_CONTROL_CLIENT
+ */
+ public static final String REMOTE_CONTROL_CLIENT_CHANGED =
+ "android.media.REMOTE_CONTROL_CLIENT_CHANGED";
+
+ /**
+ * @hide
+ * The IRemoteControlClient monotonically increasing generation counter.
+ *
+ * @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
+ */
+ public static final String EXTRA_REMOTE_CONTROL_CLIENT =
+ "android.media.EXTRA_REMOTE_CONTROL_CLIENT";
+
+ /**
+ * @hide
+ * FIXME to be changed to address Neel's comments
+ * Force a refresh of the remote control client associated with the event receiver.
+ * @param eventReceiver
+ */
+ public void refreshRemoteControlDisplay(ComponentName eventReceiver) {
+ IAudioService service = getService();
+ try {
+ service.refreshRemoteControlDisplay(eventReceiver);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in refreshRemoteControlDisplay"+e);
+ }
+ }
+
+ /**
+ * @hide
+ * FIXME API to be used by implementors of remote controls, not a candidate for SDK
+ */
+ public void registerRemoteControlObserver() {
+
+ }
+
+ /**
+ * @hide
+ * FIXME API to be used by implementors of remote controls, not a candidate for SDK
+ */
+ public void unregisterRemoteControlObserver() {
+
+ }
+
+ /**
* @hide
* Reload audio settings. This method is called by Settings backup
* agent when audio settings are restored and causes the AudioService
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 682560a..cd55b0e 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -55,6 +55,7 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -113,6 +114,8 @@
private static final int MSG_SET_FORCE_USE = 10;
private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 11;
private static final int MSG_BT_HEADSET_CNCT_FAILED = 12;
+ private static final int MSG_RCDISPLAY_CLEAR = 13;
+ private static final int MSG_RCDISPLAY_UPDATE = 14;
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
// Timeout for connection to bluetooth headset service
@@ -184,7 +187,7 @@
AudioSystem.STREAM_RING, // STREAM_RING
AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
AudioSystem.STREAM_ALARM, // STREAM_ALARM
- AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION
+ AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED
AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF
@@ -239,9 +242,6 @@
*/
private int mVibrateSetting;
- /** @see System#NOTIFICATIONS_USE_RING_VOLUME */
- private int mNotificationsUseRingVolume;
-
// Broadcast receiver for device connections intent broadcasts
private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
@@ -371,7 +371,9 @@
// Register for media button intent broadcasts.
intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
- intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ // Workaround for bug on priority setting
+ //intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ intentFilter.setPriority(Integer.MAX_VALUE);
context.registerReceiver(mMediaButtonReceiver, intentFilter);
// Register for phone state monitoring
@@ -451,16 +453,6 @@
System.MUTE_STREAMS_AFFECTED,
((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
- if (mVoiceCapable) {
- mNotificationsUseRingVolume = System.getInt(cr,
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1);
- } else {
- mNotificationsUseRingVolume = 1;
- }
-
- if (mNotificationsUseRingVolume == 1) {
- STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
- }
// Each stream will read its own persisted settings
// Broadcast the sticky intent
@@ -885,7 +877,8 @@
requestAudioFocus(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
- IN_VOICE_COMM_FOCUS_ID /*clientId*/);
+ IN_VOICE_COMM_FOCUS_ID /*clientId*/,
+ "system");
}
}
@@ -897,7 +890,8 @@
requestAudioFocus(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
- IN_VOICE_COMM_FOCUS_ID /*clientId*/);
+ IN_VOICE_COMM_FOCUS_ID /*clientId*/,
+ "system");
}
// if exiting call
else if (newMode == AudioSystem.MODE_NORMAL) {
@@ -2155,6 +2149,33 @@
persistMediaButtonReceiver( (ComponentName) msg.obj );
break;
+ case MSG_RCDISPLAY_CLEAR:
+ Log.i(TAG, "Clear remote control display");
+ Intent clearIntent = new Intent(AudioManager.REMOTE_CONTROL_CLIENT_CHANGED);
+ // no extra means no IRemoteControlClient, which is a request to clear
+ clearIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcast(clearIntent);
+ break;
+
+ case MSG_RCDISPLAY_UPDATE:
+ synchronized(mCurrentRcLock) {
+ if (mCurrentRcClientRef.get() == null) {
+ // the remote control display owner has changed between the
+ // the message to update the display was sent, and the time it
+ // gets to be processed (now)
+ } else {
+ mCurrentRcClientGen++;
+ Log.i(TAG, "Display/update remote control ");
+ Intent rcClientIntent = new Intent(
+ AudioManager.REMOTE_CONTROL_CLIENT_CHANGED);
+ rcClientIntent.putExtra(AudioManager.EXTRA_REMOTE_CONTROL_CLIENT,
+ mCurrentRcClientGen);
+ rcClientIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcast(rcClientIntent);
+ }
+ }
+ break;
+
case MSG_BT_HEADSET_CNCT_FAILED:
resetBluetoothSco();
break;
@@ -2168,8 +2189,6 @@
super(new Handler());
mContentResolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
- mContentResolver.registerContentObserver(Settings.System.getUriFor(
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this);
}
@Override
@@ -2193,29 +2212,6 @@
mRingerModeAffectedStreams = ringerModeAffectedStreams;
setRingerModeInt(getRingerMode(), false);
}
-
- int notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
- Settings.System.NOTIFICATIONS_USE_RING_VOLUME,
- 1);
- if (mVoiceCapable) {
- if (notificationsUseRingVolume != mNotificationsUseRingVolume) {
- mNotificationsUseRingVolume = notificationsUseRingVolume;
- if (mNotificationsUseRingVolume == 1) {
- STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
- mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName(
- System.VOLUME_SETTINGS[AudioSystem.STREAM_RING]);
- } else {
- STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION;
- mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName(
- System.VOLUME_SETTINGS[AudioSystem.STREAM_NOTIFICATION]);
- // Persist notification volume volume as it was not persisted while aliased to ring volume
- // and persist with no delay as there might be registered observers of the persisted
- // notification volume.
- sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
- SENDMSG_REPLACE, 1, 1, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0);
- }
- }
- }
}
}
}
@@ -2567,23 +2563,25 @@
private static class FocusStackEntry {
public int mStreamType = -1;// no stream type
- public boolean mIsTransportControlReceiver = false;
public IAudioFocusDispatcher mFocusDispatcher = null;
public IBinder mSourceRef = null;
public String mClientId;
public int mFocusChangeType;
+ public String mPackageName;
+ public int mCallingUid;
public FocusStackEntry() {
}
- public FocusStackEntry(int streamType, int duration, boolean isTransportControlReceiver,
- IAudioFocusDispatcher afl, IBinder source, String id) {
+ public FocusStackEntry(int streamType, int duration,
+ IAudioFocusDispatcher afl, IBinder source, String id, String pn, int uid) {
mStreamType = streamType;
- mIsTransportControlReceiver = isTransportControlReceiver;
mFocusDispatcher = afl;
mSourceRef = source;
mClientId = id;
mFocusChangeType = duration;
+ mPackageName = pn;
+ mCallingUid = uid;
}
}
@@ -2600,13 +2598,15 @@
while(stackIterator.hasNext()) {
FocusStackEntry fse = stackIterator.next();
pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId
- + " -- duration: " +fse.mFocusChangeType);
+ + " -- duration: " + fse.mFocusChangeType
+ + " -- uid: " + fse.mCallingUid);
}
}
}
/**
* Helper function:
+ * Called synchronized on mAudioFocusLock
* Remove a focus listener from the focus stack.
* @param focusListenerToRemove the focus listener
* @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
@@ -2621,6 +2621,10 @@
if (signal) {
// notify the new top of the stack it gained focus
notifyTopOfAudioFocusStack();
+ // there's a new top of the stack, let the remote control know
+ synchronized(mRCStack) {
+ checkUpdateRemoteControlDisplay();
+ }
}
} else {
// focus is abandoned by a client that's not at the top of the stack,
@@ -2639,6 +2643,7 @@
/**
* Helper function:
+ * Called synchronized on mAudioFocusLock
* Remove focus listeners from the focus stack for a particular client.
*/
private void removeFocusStackEntryForClient(IBinder cb) {
@@ -2658,6 +2663,10 @@
// we removed an entry at the top of the stack:
// notify the new top of the stack it gained focus.
notifyTopOfAudioFocusStack();
+ // there's a new top of the stack, let the remote control know
+ synchronized(mRCStack) {
+ checkUpdateRemoteControlDisplay();
+ }
}
}
@@ -2700,7 +2709,7 @@
/** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
- IAudioFocusDispatcher fd, String clientId) {
+ IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId);
// the main stream type for the audio focus request is currently not used. It may
// potentially be used to handle multiple stream type-dependent audio focuses.
@@ -2743,8 +2752,13 @@
removeFocusStackEntry(clientId, false);
// push focus requester at the top of the audio focus stack
- mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, false, fd, cb,
- clientId));
+ mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
+ clientId, callingPackageName, Binder.getCallingUid()));
+
+ // there's a new top of the stack, let the remote control know
+ synchronized(mRCStack) {
+ checkUpdateRemoteControlDisplay();
+ }
}//synchronized(mAudioFocusLock)
// handle the potential premature death of the new holder of the focus
@@ -2831,19 +2845,100 @@
}
}
- private static class RemoteControlStackEntry {
- public ComponentName mReceiverComponent;// always non null
- // TODO implement registration expiration?
- //public int mRegistrationTime;
+ private final static Object mCurrentRcLock = new Object();
+ /**
+ * The one remote control client to be polled for display information.
+ * This object is never null, but its reference might.
+ * Access protected by mCurrentRcLock.
+ */
+ private static SoftReference<IRemoteControlClient> mCurrentRcClientRef =
+ new SoftReference<IRemoteControlClient>(null);
- public RemoteControlStackEntry() {
- }
+ /**
+ * A monotonically increasing generation counter for mCurrentRcClientRef.
+ * Only accessed with a lock on mCurrentRcLock.
+ */
+ private static int mCurrentRcClientGen = 0;
- public RemoteControlStackEntry(ComponentName r) {
- mReceiverComponent = r;
+ /**
+ * Returns the current remote control client.
+ * @param rcClientId the counter value that matches the extra
+ * {@link AudioManager#EXTRA_REMOTE_CONTROL_CLIENT} in the
+ * {@link AudioManager#REMOTE_CONTROL_CLIENT_CHANGED} event
+ * @return the current IRemoteControlClient from which information to display on the remote
+ * control can be retrieved, or null if rcClientId doesn't match the current generation
+ * counter.
+ */
+ public static IRemoteControlClient getRemoteControlClient(int rcClientId) {
+ synchronized(mCurrentRcLock) {
+ if (rcClientId == mCurrentRcClientGen) {
+ return mCurrentRcClientRef.get();
+ } else {
+ return null;
+ }
}
}
+ /**
+ * Inner class to monitor remote control client deaths, and remove the client for the
+ * remote control stack if necessary.
+ */
+ private class RcClientDeathHandler implements IBinder.DeathRecipient {
+ private IBinder mCb; // To be notified of client's death
+ private ComponentName mRcEventReceiver;
+
+ RcClientDeathHandler(IBinder cb, ComponentName eventReceiver) {
+ mCb = cb;
+ mRcEventReceiver = eventReceiver;
+ }
+
+ public void binderDied() {
+ Log.w(TAG, " RemoteControlClient died");
+ // remote control client died, make sure the displays don't use it anymore
+ // by setting its remote control client to null
+ registerRemoteControlClient(mRcEventReceiver, null, null/*ignored*/);
+ }
+
+ public IBinder getBinder() {
+ return mCb;
+ }
+ }
+
+ private static class RemoteControlStackEntry {
+ /** the target for the ACTION_MEDIA_BUTTON events */
+ public ComponentName mReceiverComponent;// always non null
+ public String mCallingPackageName;
+ public int mCallingUid;
+
+ /** provides access to the information to display on the remote control */
+ public SoftReference<IRemoteControlClient> mRcClientRef;
+ public RcClientDeathHandler mRcClientDeathHandler;
+
+ public RemoteControlStackEntry(ComponentName r) {
+ mReceiverComponent = r;
+ mCallingUid = -1;
+ mRcClientRef = new SoftReference<IRemoteControlClient>(null);
+ }
+
+ public void unlinkToRcClientDeath() {
+ if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
+ try {
+ mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
+ } catch (java.util.NoSuchElementException e) {
+ // not much we can do here
+ Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * The stack of remote control event receivers.
+ * Code sections and methods that modify the remote control event receiver stack are
+ * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
+ * stack, audio focus or RC, can lead to a change in the remote control display
+ */
private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
/**
@@ -2855,8 +2950,10 @@
synchronized(mRCStack) {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) {
- RemoteControlStackEntry fse = stackIterator.next();
- pw.println(" receiver:" + fse.mReceiverComponent);
+ RemoteControlStackEntry rcse = stackIterator.next();
+ pw.println(" receiver: " + rcse.mReceiverComponent +
+ " -- client: " + rcse.mRcClientRef.get() +
+ " -- uid: " + rcse.mCallingUid);
}
}
}
@@ -2909,6 +3006,7 @@
ComponentName receiverComponentName = ComponentName.unflattenFromString(receiverName);
registerMediaButtonEventReceiver(receiverComponentName);
}
+ // upon restoring (e.g. after boot), do we want to refresh all remotes?
}
/**
@@ -2921,14 +3019,20 @@
return;
}
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+ RemoteControlStackEntry rcse = null;
+ boolean wasInsideStack = false;
while(stackIterator.hasNext()) {
- RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
+ rcse = (RemoteControlStackEntry)stackIterator.next();
if(rcse.mReceiverComponent.equals(newReceiver)) {
+ wasInsideStack = true;
stackIterator.remove();
break;
}
}
- mRCStack.push(new RemoteControlStackEntry(newReceiver));
+ if (!wasInsideStack) {
+ rcse = new RemoteControlStackEntry(newReceiver);
+ }
+ mRCStack.push(rcse);
// post message to persist the default media button receiver
mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
@@ -2950,13 +3054,88 @@
}
}
+ /**
+ * Helper function:
+ * Called synchronized on mRCStack
+ */
+ private boolean isCurrentRcController(ComponentName eventReceiver) {
+ if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(eventReceiver)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Helper function:
+ * Called synchronized on mRCStack
+ */
+ private void clearRemoteControlDisplay() {
+ synchronized(mCurrentRcLock) {
+ mCurrentRcClientRef.clear();
+ }
+ mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
+ }
+
+ /**
+ * Helper function:
+ * Called synchronized on mRCStack
+ * mRCStack.empty() is false
+ */
+ private void updateRemoteControlDisplay() {
+ RemoteControlStackEntry rcse = mRCStack.peek();
+ // this is where we enforce opt-in for information display on the remote controls
+ // with the new AudioManager.registerRemoteControlClient() API
+ if (rcse.mRcClientRef.get() == null) {
+ // FIXME remove log before release: this warning will be displayed for every AF change
+ Log.w(TAG, "Can't update remote control display with null remote control client");
+ clearRemoteControlDisplay();
+ return;
+ }
+ synchronized(mCurrentRcLock) {
+ mCurrentRcClientRef = rcse.mRcClientRef;
+ }
+ mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, 0, 0, rcse) );
+ }
+
+ /**
+ * Helper function:
+ * Called synchronized on mFocusLock, then mRCStack
+ * Check whether the remote control display should be updated, triggers the update if required
+ */
+ private void checkUpdateRemoteControlDisplay() {
+ // determine whether the remote control display should be refreshed
+ // if either stack is empty, there is a mismatch, so clear the RC display
+ if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
+ clearRemoteControlDisplay();
+ return;
+ }
+ // if the top of the two stacks belong to different packages, there is a mismatch, clear
+ if ((mRCStack.peek().mCallingPackageName != null)
+ && (mFocusStack.peek().mPackageName != null)
+ && !(mRCStack.peek().mCallingPackageName.compareTo(
+ mFocusStack.peek().mPackageName) == 0)) {
+ clearRemoteControlDisplay();
+ return;
+ }
+ // if the audio focus didn't originate from the same Uid as the one in which the remote
+ // control information will be retrieved, clear
+ if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) {
+ clearRemoteControlDisplay();
+ return;
+ }
+ // refresh conditions were verified: update the remote controls
+ updateRemoteControlDisplay();
+ }
/** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Log.i(TAG, " Remote Control registerMediaButtonEventReceiver() for " + eventReceiver);
- synchronized(mRCStack) {
- pushMediaButtonReceiver(eventReceiver);
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ pushMediaButtonReceiver(eventReceiver);
+ checkUpdateRemoteControlDisplay();
+ }
}
}
@@ -2964,11 +3143,74 @@
public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Log.i(TAG, " Remote Control unregisterMediaButtonEventReceiver() for " + eventReceiver);
- synchronized(mRCStack) {
- removeMediaButtonReceiver(eventReceiver);
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ boolean topOfStackWillChange = isCurrentRcController(eventReceiver);
+ removeMediaButtonReceiver(eventReceiver);
+ if (topOfStackWillChange) {
+ checkUpdateRemoteControlDisplay();
+ }
+ }
}
}
+ /** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
+ public void registerRemoteControlClient(ComponentName eventReceiver,
+ IRemoteControlClient rcClient, String callingPackageName) {
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ // store the new display information
+ Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+ while(stackIterator.hasNext()) {
+ RemoteControlStackEntry rcse = stackIterator.next();
+ if(rcse.mReceiverComponent.equals(eventReceiver)) {
+ // already had a remote control client?
+ if (rcse.mRcClientDeathHandler != null) {
+ // stop monitoring the old client's death
+ rcse.unlinkToRcClientDeath();
+ }
+ // save the new remote control client
+ rcse.mRcClientRef = new SoftReference<IRemoteControlClient>(rcClient);
+ rcse.mCallingPackageName = callingPackageName;
+ rcse.mCallingUid = Binder.getCallingUid();
+ if (rcClient == null) {
+ break;
+ }
+ // monitor the new client's death
+ IBinder b = rcClient.asBinder();
+ RcClientDeathHandler rcdh =
+ new RcClientDeathHandler(b, rcse.mReceiverComponent);
+ try {
+ b.linkToDeath(rcdh, 0);
+ } catch (RemoteException e) {
+ // remote control client is DOA, disqualify it
+ Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
+ rcse.mRcClientRef.clear();
+ }
+ rcse.mRcClientDeathHandler = rcdh;
+ break;
+ }
+ }
+ // if the eventReceiver is at the top of the stack
+ // then check for potential refresh of the remote controls
+ if (isCurrentRcController(eventReceiver)) {
+ checkUpdateRemoteControlDisplay();
+ }
+ }
+ }
+ }
+
+ /** see AudioManager.refreshRemoteControlDisplay(ComponentName er) */
+ public void refreshRemoteControlDisplay(ComponentName eventReceiver) {
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ // only refresh if the eventReceiver is at the top of the stack
+ if (isCurrentRcController(eventReceiver)) {
+ checkUpdateRemoteControlDisplay();
+ }
+ }
+ }
+ }
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index e3bd7b4..1a05f152 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -18,6 +18,9 @@
import android.content.ComponentName;
import android.media.IAudioFocusDispatcher;
+import android.media.IRemoteControlClient;
+import android.net.Uri;
+import android.os.Bundle;
/**
* {@hide}
@@ -77,7 +80,7 @@
boolean isBluetoothScoOn();
int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l,
- String clientId);
+ String clientId, String callingPackageName);
int abandonAudioFocus(IAudioFocusDispatcher l, String clientId);
@@ -87,6 +90,11 @@
void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);
+ void registerRemoteControlClient(in ComponentName eventReceiver,
+ in IRemoteControlClient rcClient, in String callingPackageName);
+
+ void refreshRemoteControlDisplay(in ComponentName eventReceiver);
+
void startBluetoothSco(IBinder cb);
void stopBluetoothSco(IBinder cb);
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
new file mode 100644
index 0000000..a49371c
--- /dev/null
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.graphics.Bitmap;
+
+/**
+ * {@hide}
+ */
+interface IRemoteControlClient
+{
+ /**
+ * Called by a remote control to retrieve a String of information to display.
+ * @param field the identifier for a metadata field to retrieve. Valid values are
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+ * @return null if the given field is not supported, or the String matching the metadata field.
+ */
+ String getMetadataString(int field);
+
+ /**
+ * Returns the current playback state.
+ * @return one of the following values:
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_STOPPED},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_PAUSED},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_PLAYING},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_FAST_FORWARDING},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_REWINDING},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_SKIPPING_FORWARDS},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_SKIPPING_BACKWARDS},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_BUFFERING}.
+ */
+ int getPlaybackState();
+
+ /**
+ * Returns the flags for the media transport control buttons this client supports.
+ * @see {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PREVIOUS},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_REWIND},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PLAY},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PLAY_PAUSE},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PAUSE},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_STOP},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_FAST_FORWARD},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_NEXT}
+ */
+ int getTransportControlFlags();
+
+ Bitmap getAlbumArt(int width, int height);
+}
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 4203b6e..a5a6b64 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -92,7 +92,7 @@
size_t frameSize = 0;
uint8_t syncword[2];
- if (source->readAt(0, &syncword, 2) != 2) {
+ if (source->readAt(offset, &syncword, 2) != 2) {
return 0;
}
if ((syncword[0] != 0xff) || ((syncword[1] & 0xf6) != 0xf0)) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ac73351..a4f3922 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -976,11 +976,6 @@
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
video_def->xFramerate = 0; // No need for output port
- // FIXME:
- // Revmoe this workaround after work is done.
- if (!strncmp(mComponentName, "OMX.TI.DUCATI1", 14)) {
- video_def->xFramerate = (frameRate << 16);
- }
video_def->nBitrate = bitRate; // Q16 format
video_def->eCompressionFormat = compressionFormat;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 626cc86..eae6112 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -38,8 +38,7 @@
import android.os.StatFs;
import android.app.IntentService;
import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.Pair;
+import android.util.Slog;
import java.io.File;
import java.io.FileInputStream;
@@ -47,11 +46,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipFile;
import android.os.FileUtils;
import android.provider.Settings;
@@ -120,29 +114,39 @@
public PackageInfoLite getMinimalPackageInfo(final Uri fileUri, int flags, long threshold) {
PackageInfoLite ret = new PackageInfoLite();
if (fileUri == null) {
- Log.i(TAG, "Invalid package uri " + fileUri);
+ Slog.i(TAG, "Invalid package uri " + fileUri);
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
return ret;
}
String scheme = fileUri.getScheme();
if (scheme != null && !scheme.equals("file")) {
- Log.w(TAG, "Falling back to installing on internal storage only");
+ Slog.w(TAG, "Falling back to installing on internal storage only");
ret.recommendedInstallLocation = PackageHelper.RECOMMEND_INSTALL_INTERNAL;
return ret;
}
String archiveFilePath = fileUri.getPath();
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();
+
PackageParser.PackageLite pkg = PackageParser.parsePackageLite(archiveFilePath, 0);
if (pkg == null) {
- Log.w(TAG, "Failed to parse package");
- ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+ Slog.w(TAG, "Failed to parse package");
+
+ final File apkFile = new File(archiveFilePath);
+ if (!apkFile.exists()) {
+ ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
+ } else {
+ ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+ }
+
return ret;
}
ret.packageName = pkg.packageName;
ret.installLocation = pkg.installLocation;
+
ret.recommendedInstallLocation = recommendAppInstallLocation(pkg.installLocation,
archiveFilePath, flags, threshold);
+
return ret;
}
@@ -150,20 +154,28 @@
public boolean checkInternalFreeStorage(Uri packageUri, long threshold)
throws RemoteException {
final File apkFile = new File(packageUri.getPath());
- return isUnderInternalThreshold(apkFile, threshold);
+ try {
+ return isUnderInternalThreshold(apkFile, threshold);
+ } catch (FileNotFoundException e) {
+ return true;
+ }
}
@Override
public boolean checkExternalFreeStorage(Uri packageUri) throws RemoteException {
final File apkFile = new File(packageUri.getPath());
- return isUnderExternalThreshold(apkFile);
+ try {
+ return isUnderExternalThreshold(apkFile);
+ } catch (FileNotFoundException e) {
+ return true;
+ }
}
public ObbInfo getObbInfo(String filename) {
try {
return ObbScanner.getObbInfo(filename);
} catch (IOException e) {
- Log.d(TAG, "Couldn't get OBB info for " + filename);
+ Slog.d(TAG, "Couldn't get OBB info for " + filename);
return null;
}
}
@@ -221,7 +233,7 @@
// Make sure the sdcard is mounted.
String status = Environment.getExternalStorageState();
if (!status.equals(Environment.MEDIA_MOUNTED)) {
- Log.w(TAG, "Make sure sdcard is mounted.");
+ Slog.w(TAG, "Make sure sdcard is mounted.");
return null;
}
@@ -229,75 +241,81 @@
String codePath = packageURI.getPath();
File codeFile = new File(codePath);
- // Native files we need to copy to the container.
- List<Pair<ZipEntry, String>> nativeFiles = new ArrayList<Pair<ZipEntry, String>>();
-
// Calculate size of container needed to hold base APK.
- final int sizeMb = calculateContainerSize(codeFile, nativeFiles);
+ int sizeMb;
+ try {
+ sizeMb = calculateContainerSize(codeFile);
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "File does not exist when trying to copy " + codeFile.getPath());
+ return null;
+ }
// Create new container
- String newCachePath = null;
+ final String newCachePath;
if ((newCachePath = PackageHelper.createSdDir(sizeMb, newCid, key, Process.myUid())) == null) {
- Log.e(TAG, "Failed to create container " + newCid);
- return null;
- }
- if (localLOGV)
- Log.i(TAG, "Created container for " + newCid + " at path : " + newCachePath);
- File resFile = new File(newCachePath, resFileName);
- if (!FileUtils.copyFile(new File(codePath), resFile)) {
- Log.e(TAG, "Failed to copy " + codePath + " to " + resFile);
- // Clean up container
- PackageHelper.destroySdDir(newCid);
+ Slog.e(TAG, "Failed to create container " + newCid);
return null;
}
- try {
- ZipFile zipFile = new ZipFile(codeFile);
+ if (localLOGV) {
+ Slog.i(TAG, "Created container for " + newCid + " at path : " + newCachePath);
+ }
- File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
- sharedLibraryDir.mkdir();
-
- final int N = nativeFiles.size();
- for (int i = 0; i < N; i++) {
- final Pair<ZipEntry, String> entry = nativeFiles.get(i);
-
- InputStream is = zipFile.getInputStream(entry.first);
- try {
- File destFile = new File(sharedLibraryDir, entry.second);
- if (!FileUtils.copyToFile(is, destFile)) {
- throw new IOException("Couldn't copy native binary "
- + entry.first.getName() + " to " + entry.second);
- }
- } finally {
- is.close();
- }
+ final File resFile = new File(newCachePath, resFileName);
+ if (FileUtils.copyFile(new File(codePath), resFile)) {
+ if (localLOGV) {
+ Slog.i(TAG, "Copied " + codePath + " to " + resFile);
}
- } catch (IOException e) {
- Log.e(TAG, "Couldn't copy native file to container", e);
+ } else {
+ Slog.e(TAG, "Failed to copy " + codePath + " to " + resFile);
+ // Clean up container
PackageHelper.destroySdDir(newCid);
return null;
}
- if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile);
+ final File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
+ if (sharedLibraryDir.mkdir()) {
+ int ret = NativeLibraryHelper.copyNativeBinariesIfNeededLI(codeFile, sharedLibraryDir);
+ if (ret != PackageManager.INSTALL_SUCCEEDED) {
+ Slog.e(TAG, "Could not copy native libraries to " + sharedLibraryDir.getPath());
+ PackageHelper.destroySdDir(newCid);
+ return null;
+ }
+ } else {
+ Slog.e(TAG, "Could not create native lib directory: " + sharedLibraryDir.getPath());
+ PackageHelper.destroySdDir(newCid);
+ return null;
+ }
+
if (!PackageHelper.finalizeSdDir(newCid)) {
- Log.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath);
+ Slog.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath);
// Clean up container
PackageHelper.destroySdDir(newCid);
+ return null;
}
- if (localLOGV) Log.i(TAG, "Finalized container " + newCid);
+
+ if (localLOGV) {
+ Slog.i(TAG, "Finalized container " + newCid);
+ }
+
if (PackageHelper.isContainerMounted(newCid)) {
- if (localLOGV) Log.i(TAG, "Unmounting " + newCid +
- " at path " + newCachePath);
+ if (localLOGV) {
+ Slog.i(TAG, "Unmounting " + newCid + " at path " + newCachePath);
+ }
+
// Force a gc to avoid being killed.
Runtime.getRuntime().gc();
PackageHelper.unMountSdDir(newCid);
} else {
- if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted");
+ if (localLOGV) {
+ Slog.i(TAG, "Container " + newCid + " not mounted");
+ }
}
+
return newCachePath;
}
- public static boolean copyToFile(InputStream inputStream, FileOutputStream out) {
+ private static boolean copyToFile(InputStream inputStream, FileOutputStream out) {
try {
byte[] buffer = new byte[4096];
int bytesRead;
@@ -306,12 +324,12 @@
}
return true;
} catch (IOException e) {
- Log.i(TAG, "Exception : " + e + " when copying file");
+ Slog.i(TAG, "Exception : " + e + " when copying file");
return false;
}
}
- public static boolean copyToFile(File srcFile, FileOutputStream out) {
+ private static boolean copyToFile(File srcFile, FileOutputStream out) {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(srcFile);
@@ -323,7 +341,7 @@
}
}
- private boolean copyFile(Uri pPackageURI, FileOutputStream outStream) {
+ private boolean copyFile(Uri pPackageURI, FileOutputStream outStream) {
String scheme = pPackageURI.getScheme();
if (scheme == null || scheme.equals("file")) {
final File srcPackageFile = new File(pPackageURI.getPath());
@@ -331,7 +349,7 @@
// destination file in order to eliminate a window where the package directory
// scanner notices the new package file but it's not completely copied yet.
if (!copyToFile(srcPackageFile, outStream)) {
- Log.e(TAG, "Couldn't copy file: " + srcPackageFile);
+ Slog.e(TAG, "Couldn't copy file: " + srcPackageFile);
return false;
}
} else if (scheme.equals("content")) {
@@ -339,28 +357,31 @@
try {
fd = getContentResolver().openFileDescriptor(pPackageURI, "r");
} catch (FileNotFoundException e) {
- Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e);
+ Slog.e(TAG,
+ "Couldn't open file descriptor from download service. Failed with exception "
+ + e);
return false;
}
if (fd == null) {
- Log.e(TAG, "Couldn't open file descriptor from download service (null).");
+ Slog.e(TAG, "Couldn't open file descriptor from download service (null).");
return false;
} else {
if (localLOGV) {
- Log.v(TAG, "Opened file descriptor from download service.");
+ Slog.i(TAG, "Opened file descriptor from download service.");
}
ParcelFileDescriptor.AutoCloseInputStream
dlStream = new ParcelFileDescriptor.AutoCloseInputStream(fd);
// We copy the source package file to a temp file and then rename it to the
// destination file in order to eliminate a window where the package directory
- // scanner notices the new package file but it's not completely copied yet.
+ // scanner notices the new package file but it's not completely
+ // cop
if (!copyToFile(dlStream, outStream)) {
- Log.e(TAG, "Couldn't copy " + pPackageURI + " to temp file.");
+ Slog.e(TAG, "Couldn't copy " + pPackageURI + " to temp file.");
return false;
}
}
} else {
- Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
+ Slog.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
return false;
}
return true;
@@ -434,12 +455,20 @@
boolean fitsOnInternal = false;
if (checkBoth || prefer == PREFER_INTERNAL) {
- fitsOnInternal = isUnderInternalThreshold(apkFile, threshold);
+ try {
+ fitsOnInternal = isUnderInternalThreshold(apkFile, threshold);
+ } catch (FileNotFoundException e) {
+ return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
+ }
}
boolean fitsOnSd = false;
if (!emulated && (checkBoth || prefer == PREFER_EXTERNAL)) {
- fitsOnSd = isUnderExternalThreshold(apkFile);
+ try {
+ fitsOnSd = isUnderExternalThreshold(apkFile);
+ } catch (FileNotFoundException e) {
+ return PackageHelper.RECOMMEND_FAILED_INVALID_URI;
+ }
}
if (prefer == PREFER_INTERNAL) {
@@ -473,8 +502,20 @@
}
}
- private boolean isUnderInternalThreshold(File apkFile, long threshold) {
+ /**
+ * Measure a file to see if it fits within the free space threshold.
+ *
+ * @param apkFile file to check
+ * @param threshold byte threshold to compare against
+ * @return true if file fits under threshold
+ * @throws FileNotFoundException when APK does not exist
+ */
+ private boolean isUnderInternalThreshold(File apkFile, long threshold)
+ throws FileNotFoundException {
final long size = apkFile.length();
+ if (size == 0 && !apkFile.exists()) {
+ throw new FileNotFoundException();
+ }
final StatFs internalStats = new StatFs(Environment.getDataDirectory().getPath());
final long availInternalSize = (long) internalStats.getAvailableBlocks()
@@ -484,12 +525,19 @@
}
- private boolean isUnderExternalThreshold(File apkFile) {
+ /**
+ * Measure a file to see if it fits in the external free space.
+ *
+ * @param apkFile file to check
+ * @return true if file fits
+ * @throws IOException when file does not exist
+ */
+ private boolean isUnderExternalThreshold(File apkFile) throws FileNotFoundException {
if (Environment.isExternalStorageEmulated()) {
return false;
}
- final int sizeMb = calculateContainerSize(apkFile, null);
+ final int sizeMb = calculateContainerSize(apkFile);
final int availSdMb;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
@@ -508,10 +556,14 @@
*
* @param apkFile file from which to calculate size
* @return size in megabytes (2^20 bytes)
+ * @throws FileNotFoundException when file does not exist
*/
- private int calculateContainerSize(File apkFile, List<Pair<ZipEntry, String>> outFiles) {
+ private int calculateContainerSize(File apkFile) throws FileNotFoundException {
// Calculate size of container needed to hold base APK.
long sizeBytes = apkFile.length();
+ if (sizeBytes == 0 && !apkFile.exists()) {
+ throw new FileNotFoundException();
+ }
// Check all the native files that need to be copied and add that to the
// container size.
diff --git a/core/res/res/anim/priority_alert_enter.xml b/packages/SystemUI/res/anim/priority_alert_enter.xml
similarity index 100%
rename from core/res/res/anim/priority_alert_enter.xml
rename to packages/SystemUI/res/anim/priority_alert_enter.xml
diff --git a/core/res/res/anim/priority_alert_exit.xml b/packages/SystemUI/res/anim/priority_alert_exit.xml
similarity index 100%
rename from core/res/res/anim/priority_alert_exit.xml
rename to packages/SystemUI/res/anim/priority_alert_exit.xml
diff --git a/core/res/res/anim/status_bar_enter.xml b/packages/SystemUI/res/anim/status_bar_enter.xml
similarity index 87%
rename from core/res/res/anim/status_bar_enter.xml
rename to packages/SystemUI/res/anim/status_bar_enter.xml
index 1a1dc9b..f1c1301 100644
--- a/core/res/res/anim/status_bar_enter.xml
+++ b/packages/SystemUI/res/anim/status_bar_enter.xml
@@ -18,7 +18,8 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/decelerate_quad">
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/decelerate_quad">
<translate android:fromYDelta="-75%" android:toYDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
diff --git a/core/res/res/anim/status_bar_exit.xml b/packages/SystemUI/res/anim/status_bar_exit.xml
similarity index 88%
rename from core/res/res/anim/status_bar_exit.xml
rename to packages/SystemUI/res/anim/status_bar_exit.xml
index 1f71090..46462e2 100644
--- a/core/res/res/anim/status_bar_exit.xml
+++ b/packages/SystemUI/res/anim/status_bar_exit.xml
@@ -18,7 +18,8 @@
*/
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/accelerate_quad">
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/accelerate_quad">
<translate android:fromYDelta="0" android:toYDelta="-75%"
android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 91a8855..ad236b7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -52,4 +52,15 @@
<item name="android:windowExitAnimation">@*android:anim/shrink_fade_out_from_bottom</item>
</style>
+ <!-- Standard animations for hiding and showing the status bar. -->
+ <style name="Animation.StatusBar">
+ <item name="android:windowEnterAnimation">@anim/status_bar_enter</item>
+ <item name="android:windowExitAnimation">@anim/status_bar_exit</item>
+ </style>
+
+ <style name="Animation.StatusBar.IntruderAlert">
+ <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item>
+ <item name="android:windowExitAnimation">@anim/priority_alert_exit</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index 918d5a3..61da1f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -119,7 +119,8 @@
PixelFormat.RGBX_8888);
lp.gravity = getStatusBarGravity();
lp.setTitle("StatusBar");
- // TODO lp.windowAnimations = R.style.Animation_StatusBar;
+ lp.packageName = mContext.getPackageName();
+ lp.windowAnimations = R.style.Animation_StatusBar;
WindowManagerImpl.getDefault().addView(sb, lp);
if (SPEW) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
index 51fc7c2..3276e1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
@@ -16,16 +16,9 @@
package com.android.systemui.statusbar.phone;
-import android.animation.LayoutTransition;
import android.content.Context;
import android.util.AttributeSet;
-import android.view.Display;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.WindowManager;
import android.widget.LinearLayout;
-import android.util.Slog;
-
public class ExpandedView extends LinearLayout {
PhoneStatusBar mService;
@@ -38,8 +31,6 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
- setLayerType(LAYER_TYPE_HARDWARE, null);
}
/** We want to shrink down to 0, and ignore the background. */
@@ -49,7 +40,7 @@
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int height = bottom - top;
if (height != mPrevHeight) {
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 18026f1..7bb8277 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -16,12 +16,10 @@
package com.android.systemui.statusbar.phone;
-import android.app.Service;
import android.app.ActivityManagerNative;
import android.app.Dialog;
import android.app.Notification;
import android.app.PendingIntent;
-import android.app.Service;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -30,6 +28,7 @@
import android.content.res.Resources;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
@@ -65,16 +64,12 @@
import android.widget.RemoteViews;
import android.widget.ScrollView;
import android.widget.TextView;
-import android.widget.FrameLayout;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.systemui.R;
@@ -186,7 +181,6 @@
boolean mAnimating;
long mCurAnimationTime;
- float mDisplayHeight;
float mAnimY;
float mAnimVel;
float mAnimAccel;
@@ -201,6 +195,8 @@
// tracking calls to View.setSystemUiVisibility()
int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+ final Point mDisplaySize = new Point();
+
private class ExpandedDialog extends Dialog {
ExpandedDialog(Context context) {
super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
@@ -246,8 +242,11 @@
Resources res = context.getResources();
+ mDisplay.getSize(mDisplaySize);
loadDimens();
+ mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+
ExpandedView expanded = (ExpandedView)View.inflate(context,
R.layout.status_bar_expanded, null);
expanded.mService = this;
@@ -506,7 +505,8 @@
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
lp.y += height * 1.5; // FIXME
lp.setTitle("IntruderAlert");
- lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert;
+ lp.packageName = mContext.getPackageName();
+ lp.windowAnimations = R.style.Animation_StatusBar_IntruderAlert;
WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
}
@@ -1149,7 +1149,7 @@
if (mAnimating) {
y = (int)mAnimY;
} else {
- y = mDisplay.getHeight()-1;
+ y = mDisplaySize.y-1;
}
// Let the fling think that we're open so it goes in the right direction
// and doesn't try to re-open the windowshade.
@@ -1205,7 +1205,7 @@
if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
incrementAnim();
if (SPEW) Slog.d(TAG, "doAnimation after mAnimY=" + mAnimY);
- if (mAnimY >= mDisplay.getHeight()-1) {
+ if (mAnimY >= mDisplaySize.y-1) {
if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
mAnimating = false;
updateExpandedViewPos(EXPANDED_FULL_OPEN);
@@ -1291,7 +1291,6 @@
void performFling(int y, float vel, boolean always) {
mAnimatingReveal = false;
- mDisplayHeight = mDisplay.getHeight();
mAnimY = y;
mAnimVel = vel;
@@ -1301,7 +1300,7 @@
if (mExpanded) {
if (!always && (
vel > 200.0f
- || (y > (mDisplayHeight-25) && vel > -200.0f))) {
+ || (y > (mDisplaySize.y-25) && vel > -200.0f))) {
// We are expanded, but they didn't move sufficiently to cause
// us to retract. Animate back to the expanded position.
mAnimAccel = 2000.0f;
@@ -1319,7 +1318,7 @@
} else {
if (always || (
vel > 200.0f
- || (y > (mDisplayHeight/2) && vel > -200.0f))) {
+ || (y > (mDisplaySize.y/2) && vel > -200.0f))) {
// We are collapsed, and they moved enough to allow us to
// expand. Animate in the notifications.
mAnimAccel = 2000.0f;
@@ -1371,14 +1370,14 @@
mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
}
if ((!mExpanded && y < hitSize) ||
- (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
+ (mExpanded && y > (mDisplaySize.y-hitSize))) {
// We drop events at the edge of the screen to make the windowshade come
// down by accident less, especially when pushing open a device with a keyboard
// that rotates (like g1 and droid)
int x = (int)event.getRawX();
final int edgeBorder = mEdgeBorder;
- if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+ if (x >= edgeBorder && x < mDisplaySize.x - edgeBorder) {
prepareTracking(y, !mExpanded);// opening if we're not already fully visible
mVelocityTracker.addMovement(event);
}
@@ -1626,10 +1625,9 @@
+ ", mAnimAccel=" + mAnimAccel);
pw.println(" mCurAnimationTime=" + mCurAnimationTime
+ " mAnimLastTime=" + mAnimLastTime);
- pw.println(" mDisplayHeight=" + mDisplayHeight
- + " mAnimatingReveal=" + mAnimatingReveal
+ pw.println(" mAnimatingReveal=" + mAnimatingReveal
+ " mViewDelta=" + mViewDelta);
- pw.println(" mDisplayHeight=" + mDisplayHeight);
+ pw.println(" mDisplaySize=" + mDisplaySize);
pw.println(" mExpandedParams: " + mExpandedParams);
pw.println(" mExpandedView: " + viewInfo(mExpandedView));
pw.println(" mExpandedDialog: " + mExpandedDialog);
@@ -1721,17 +1719,13 @@
void onTrackingViewAttached() {
WindowManager.LayoutParams lp;
int pixelFormat;
- Drawable bg;
/// ---------- Expanded View --------------
pixelFormat = PixelFormat.TRANSLUCENT;
- final int disph = mDisplay.getHeight();
lp = mExpandedDialog.getWindow().getAttributes();
- lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
- lp.height = getExpandedHeight();
lp.x = 0;
- mTrackingPosition = lp.y = -disph; // sufficiently large negative
+ mTrackingPosition = lp.y = mDisplaySize.y; // sufficiently large negative
lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -1741,9 +1735,9 @@
lp.format = pixelFormat;
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
lp.setTitle("StatusBarExpanded");
- mExpandedDialog.getWindow().setAttributes(lp);
- mExpandedDialog.getWindow().setFormat(pixelFormat);
mExpandedParams = lp;
+ updateExpandedSize();
+ mExpandedDialog.getWindow().setFormat(pixelFormat);
mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
mExpandedDialog.setContentView(mExpandedView,
@@ -1751,7 +1745,6 @@
ViewGroup.LayoutParams.MATCH_PARENT));
mExpandedDialog.getWindow().setBackgroundDrawable(null);
mExpandedDialog.show();
- FrameLayout hack = (FrameLayout)mExpandedView.getParent();
}
void setDateViewVisibility(boolean visible, int anim) {
@@ -1768,6 +1761,20 @@
}
}
+ void updateExpandedInvisiblePosition() {
+ if (mTrackingView != null) {
+ mTrackingPosition = -mDisplaySize.y;
+ if (mTrackingParams != null) {
+ mTrackingParams.y = mTrackingPosition;
+ WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+ }
+ }
+ if (mExpandedParams != null) {
+ mExpandedParams.y = -mDisplaySize.y;
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ }
+ }
+
void updateExpandedViewPos(int expandedPosition) {
if (SPEW) {
Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
@@ -1776,22 +1783,12 @@
}
int h = mStatusBarView.getHeight();
- int disph = mDisplay.getHeight();
+ int disph = mDisplaySize.y;
// If the expanded view is not visible, make sure they're still off screen.
// Maybe the view was resized.
if (!mExpandedVisible) {
- if (mTrackingView != null) {
- mTrackingPosition = -disph;
- if (mTrackingParams != null) {
- mTrackingParams.y = mTrackingPosition;
- WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
- }
- }
- if (mExpandedParams != null) {
- mExpandedParams.y = -disph;
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
- }
+ updateExpandedInvisiblePosition();
return;
}
@@ -1816,14 +1813,21 @@
WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
if (mExpandedParams != null) {
- mCloseView.getLocationInWindow(mPositionTmp);
- final int closePos = mPositionTmp[1];
+ if (mCloseView.getWindowVisibility() == View.VISIBLE) {
+ mCloseView.getLocationInWindow(mPositionTmp);
+ final int closePos = mPositionTmp[1];
- mExpandedContents.getLocationInWindow(mPositionTmp);
- final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+ mExpandedContents.getLocationInWindow(mPositionTmp);
+ final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
- mExpandedParams.y = pos + mTrackingView.getHeight()
- - (mTrackingParams.height-closePos) - contentsBottom;
+ mExpandedParams.y = pos + mTrackingView.getHeight()
+ - (mTrackingParams.height-closePos) - contentsBottom;
+ } else {
+ // If the tracking view is not yet visible, then we can't have
+ // a good value of the close view location. We need to wait for
+ // it to be visible to do a layout.
+ mExpandedParams.y = -mDisplaySize.y;
+ }
int max = h;
if (mExpandedParams.y > max) {
mExpandedParams.y = max;
@@ -1859,14 +1863,24 @@
}
}
- int getExpandedHeight() {
- return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+ int getExpandedHeight(int disph) {
+ return disph - mStatusBarView.getHeight() - mCloseView.getHeight();
}
- void updateExpandedHeight() {
- if (mExpandedView != null) {
- mExpandedParams.height = getExpandedHeight();
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ void updateDisplaySize() {
+ mDisplay.getSize(mDisplaySize);
+ updateExpandedSize();
+ }
+
+ void updateExpandedSize() {
+ if (mExpandedDialog != null) {
+ mExpandedParams.width = mDisplaySize.x;
+ mExpandedParams.height = getExpandedHeight(mDisplaySize.y);
+ if (!mExpandedVisible) {
+ updateExpandedInvisiblePosition();
+ } else {
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c2390e8..db6907c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -77,6 +77,7 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ mService.updateDisplaySize();
boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
if (mNightMode != nightMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
index fd32a3d..fc0f332 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.os.Handler;
import android.util.AttributeSet;
import android.view.Display;
import android.view.KeyEvent;
@@ -29,6 +30,7 @@
PhoneStatusBar mService;
boolean mTracking;
int mStartX, mStartY;
+ Handler mHandler = new Handler();
public TrackingView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -39,7 +41,6 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- mService.updateExpandedHeight();
}
@Override
@@ -60,4 +61,16 @@
super.onAttachedToWindow();
mService.onTrackingViewAttached();
}
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility == VISIBLE) {
+ mHandler.post(new Runnable() {
+ @Override public void run() {
+ mService.updateExpandedViewPos(PhoneStatusBar.EXPANDED_LEAVE_ALONE);
+ }
+ });
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 174f733..14f7c11 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -35,13 +35,13 @@
import com.android.internal.view.menu.MenuDialogHelper;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.view.menu.MenuView;
-import com.android.internal.view.menu.SubMenuBuilder;
import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
import android.app.KeyguardManager;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -175,6 +175,8 @@
private AudioManager mAudioManager;
private KeyguardManager mKeyguardManager;
+ private int mUiOptions = 0;
+
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
@@ -213,6 +215,11 @@
}
@Override
+ public void setUiOptions(int uiOptions) {
+ mUiOptions = uiOptions;
+ }
+
+ @Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
@@ -545,6 +552,8 @@
if (!st.shownPanelView.hasFocus()) {
st.shownPanelView.requestFocus();
}
+ } else if (!st.isInExpandedMode) {
+ width = MATCH_PARENT;
}
st.isOpen = true;
@@ -2634,8 +2643,14 @@
mActionBar.initIndeterminateProgress();
}
- final boolean splitActionBar = getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowSplitActionBar, false);
+ boolean splitActionBar = false;
+ if ((mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0) {
+ splitActionBar = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.split_action_bar_is_narrow);
+ } else {
+ splitActionBar = getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowSplitActionBar, false);
+ }
if (splitActionBar) {
final ActionBarContainer splitView = (ActionBarContainer) findViewById(
com.android.internal.R.id.split_action_bar);
@@ -2648,7 +2663,7 @@
com.android.internal.R.id.action_context_bar);
cab.setSplitView(splitView);
} else {
- Log.e(TAG, "Window style requested split action bar with " +
+ Log.e(TAG, "Requested split action bar with " +
"incompatible window decor! Ignoring request.");
}
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ec45530..2355d5c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -51,6 +51,8 @@
#include <media/EffectsFactoryApi.h>
#include <audio_effects/effect_visualizer.h>
+#include <audio_effects/effect_ns.h>
+#include <audio_effects/effect_aec.h>
#include <cpustats/ThreadCpuUsage.h>
#include <powermanager/PowerManager.h>
@@ -148,7 +150,8 @@
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
- mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1)
+ mPrimaryHardwareDev(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
+ mBtNrec(false)
{
}
@@ -717,6 +720,31 @@
final_result = result ?: final_result;
}
mHardwareStatus = AUDIO_HW_IDLE;
+ // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 value;
+ if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) {
+ Mutex::Autolock _l(mLock);
+ bool btNrec = (value == AUDIO_PARAMETER_VALUE_ON);
+ if (mBtNrec != btNrec) {
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ sp<RecordThread> thread = mRecordThreads.valueAt(i);
+ RecordThread::RecordTrack *track = thread->track();
+ if (track != NULL) {
+ audio_devices_t device = (audio_devices_t)(
+ thread->device() & AUDIO_DEVICE_IN_ALL);
+ bool suspend = audio_is_bluetooth_sco_device(device) && btNrec;
+ thread->setEffectSuspended(FX_IID_AEC,
+ suspend,
+ track->sessionId());
+ thread->setEffectSuspended(FX_IID_NS,
+ suspend,
+ track->sessionId());
+ }
+ }
+ mBtNrec = btNrec;
+ }
+ }
return final_result;
}
@@ -1130,6 +1158,140 @@
LOGW("power manager service died !!!");
}
+void AudioFlinger::ThreadBase::setEffectSuspended(
+ const effect_uuid_t *type, bool suspend, int sessionId)
+{
+ Mutex::Autolock _l(mLock);
+ setEffectSuspended_l(type, suspend, sessionId);
+}
+
+void AudioFlinger::ThreadBase::setEffectSuspended_l(
+ const effect_uuid_t *type, bool suspend, int sessionId)
+{
+ sp<EffectChain> chain;
+ chain = getEffectChain_l(sessionId);
+ if (chain != 0) {
+ if (type != NULL) {
+ chain->setEffectSuspended_l(type, suspend);
+ } else {
+ chain->setEffectSuspendedAll_l(suspend);
+ }
+ }
+
+ updateSuspendedSessions_l(type, suspend, sessionId);
+}
+
+void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain)
+{
+ int index = mSuspendedSessions.indexOfKey(chain->sessionId());
+ if (index < 0) {
+ return;
+ }
+
+ KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects =
+ mSuspendedSessions.editValueAt(index);
+
+ for (size_t i = 0; i < sessionEffects.size(); i++) {
+ sp <SuspendedSessionDesc> desc = sessionEffects.valueAt(i);
+ for (int j = 0; j < desc->mRefCount; j++) {
+ if (sessionEffects.keyAt(i) == EffectChain::kKeyForSuspendAll) {
+ chain->setEffectSuspendedAll_l(true);
+ } else {
+ LOGV("checkSuspendOnAddEffectChain_l() suspending effects %08x",
+ desc->mType.timeLow);
+ chain->setEffectSuspended_l(&desc->mType, true);
+ }
+ }
+ }
+}
+
+void AudioFlinger::ThreadBase::updateSuspendedSessionsOnRemoveEffectChain_l(
+ const sp<EffectChain>& chain)
+{
+ int index = mSuspendedSessions.indexOfKey(chain->sessionId());
+ if (index < 0) {
+ return;
+ }
+ LOGV("updateSuspendedSessionsOnRemoveEffectChain_l() removed suspended session %d",
+ chain->sessionId());
+ mSuspendedSessions.removeItemsAt(index);
+}
+
+void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *type,
+ bool suspend,
+ int sessionId)
+{
+ int index = mSuspendedSessions.indexOfKey(sessionId);
+
+ KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects;
+
+ if (suspend) {
+ if (index >= 0) {
+ sessionEffects = mSuspendedSessions.editValueAt(index);
+ } else {
+ mSuspendedSessions.add(sessionId, sessionEffects);
+ }
+ } else {
+ if (index < 0) {
+ return;
+ }
+ sessionEffects = mSuspendedSessions.editValueAt(index);
+ }
+
+
+ int key = EffectChain::kKeyForSuspendAll;
+ if (type != NULL) {
+ key = type->timeLow;
+ }
+ index = sessionEffects.indexOfKey(key);
+
+ sp <SuspendedSessionDesc> desc;
+ if (suspend) {
+ if (index >= 0) {
+ desc = sessionEffects.valueAt(index);
+ } else {
+ desc = new SuspendedSessionDesc();
+ if (type != NULL) {
+ memcpy(&desc->mType, type, sizeof(effect_uuid_t));
+ }
+ sessionEffects.add(key, desc);
+ LOGV("updateSuspendedSessions_l() suspend adding effect %08x", key);
+ }
+ desc->mRefCount++;
+ } else {
+ if (index < 0) {
+ return;
+ }
+ desc = sessionEffects.valueAt(index);
+ if (--desc->mRefCount == 0) {
+ LOGV("updateSuspendedSessions_l() restore removing effect %08x", key);
+ sessionEffects.removeItemsAt(index);
+ if (sessionEffects.isEmpty()) {
+ LOGV("updateSuspendedSessions_l() restore removing session %d",
+ sessionId);
+ mSuspendedSessions.removeItem(sessionId);
+ }
+ }
+ }
+ if (!sessionEffects.isEmpty()) {
+ mSuspendedSessions.replaceValueFor(sessionId, sessionEffects);
+ }
+}
+
+void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
+ bool enabled,
+ int sessionId)
+{
+ Mutex::Autolock _l(mLock);
+
+ // TODO: implement PlaybackThread or RecordThread specific behavior here
+
+ sp<EffectChain> chain = getEffectChain_l(sessionId);
+ if (chain != 0) {
+ chain->checkSuspendOnEffectEnabled(effect, enabled);
+ }
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
@@ -4143,7 +4305,11 @@
}
mTrack = track.get();
-
+ // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
+ bool suspend = audio_is_bluetooth_sco_device(
+ (audio_devices_t)(mDevice & AUDIO_DEVICE_IN_ALL)) && mAudioFlinger->btNrec();
+ setEffectSuspended_l(FX_IID_AEC, suspend, sessionId);
+ setEffectSuspended_l(FX_IID_NS, suspend, sessionId);
}
lStatus = NO_ERROR;
@@ -4363,6 +4529,13 @@
status = BAD_VALUE;
} else {
mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL);
+ // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
+ if (mTrack != NULL) {
+ bool suspend = audio_is_bluetooth_sco_device(
+ (audio_devices_t)value) && mAudioFlinger->btNrec();
+ setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId());
+ setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId());
+ }
}
mDevice |= (uint32_t)value;
}
@@ -4490,6 +4663,12 @@
return result;
}
+AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track()
+{
+ Mutex::Autolock _l(mLock);
+ return mTrack;
+}
+
// ----------------------------------------------------------------------------
int AudioFlinger::openOutput(uint32_t *pDevices,
@@ -4874,10 +5053,6 @@
}
-// this UUID must match the one defined in media/libeffects/EffectVisualizer.cpp
-static const effect_uuid_t VISUALIZATION_UUID_ =
- {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-
sp<IEffect> AudioFlinger::createEffect(pid_t pid,
effect_descriptor_t *pDesc,
const sp<IEffectClient>& effectClient,
@@ -4915,14 +5090,6 @@
goto Exit;
}
- // check recording permission for visualizer
- if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
- memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) &&
- !recordingAllowed()) {
- lStatus = PERMISSION_DENIED;
- goto Exit;
- }
-
if (io == 0) {
if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
// output must be specified by AudioPolicyManager when using session
@@ -5003,6 +5170,13 @@
goto Exit;
}
+ // check recording permission for visualizer
+ if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
+ !recordingAllowed()) {
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+
// return effect descriptor
memcpy(pDesc, &desc, sizeof(effect_descriptor_t));
@@ -5069,10 +5243,10 @@
return handle;
}
-status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput)
+status_t AudioFlinger::moveEffects(int sessionId, int srcOutput, int dstOutput)
{
LOGV("moveEffects() session %d, srcOutput %d, dstOutput %d",
- session, srcOutput, dstOutput);
+ sessionId, srcOutput, dstOutput);
Mutex::Autolock _l(mLock);
if (srcOutput == dstOutput) {
LOGW("moveEffects() same dst and src outputs %d", dstOutput);
@@ -5091,24 +5265,24 @@
Mutex::Autolock _dl(dstThread->mLock);
Mutex::Autolock _sl(srcThread->mLock);
- moveEffectChain_l(session, srcThread, dstThread, false);
+ moveEffectChain_l(sessionId, srcThread, dstThread, false);
return NO_ERROR;
}
// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held
-status_t AudioFlinger::moveEffectChain_l(int session,
+status_t AudioFlinger::moveEffectChain_l(int sessionId,
AudioFlinger::PlaybackThread *srcThread,
AudioFlinger::PlaybackThread *dstThread,
bool reRegister)
{
LOGV("moveEffectChain_l() session %d from thread %p to thread %p",
- session, srcThread, dstThread);
+ sessionId, srcThread, dstThread);
- sp<EffectChain> chain = srcThread->getEffectChain_l(session);
+ sp<EffectChain> chain = srcThread->getEffectChain_l(sessionId);
if (chain == 0) {
LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p",
- session, srcThread);
+ sessionId, srcThread);
return INVALID_OPERATION;
}
@@ -5143,7 +5317,7 @@
AudioSystem::registerEffect(&effect->desc(),
dstOutput,
strategy,
- session,
+ sessionId,
effect->id());
}
effect = chain->getEffectFromId_l(0);
@@ -5385,6 +5559,7 @@
void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
const wp<EffectHandle>& handle) {
+
Mutex::Autolock _l(mLock);
LOGV("disconnectEffect() %p effect %p", this, effect.get());
// delete the effect module if removing last handle on it
@@ -5451,6 +5626,7 @@
if (mEffectChains[i]->sessionId() < session) break;
}
mEffectChains.insertAt(chain, i);
+ checkSuspendOnAddEffectChain_l(chain);
return NO_ERROR;
}
@@ -5463,6 +5639,7 @@
for (size_t i = 0; i < mEffectChains.size(); i++) {
if (chain == mEffectChains[i]) {
+ updateSuspendedSessionsOnRemoveEffectChain_l(chain);
mEffectChains.removeAt(i);
// detach all active tracks from the chain
for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
@@ -5540,6 +5717,8 @@
chain->setInBuffer(NULL);
chain->setOutBuffer(NULL);
+ checkSuspendOnAddEffectChain_l(chain);
+
mEffectChains.add(chain);
return NO_ERROR;
@@ -5552,6 +5731,7 @@
"removeEffectChain_l() %p invalid chain size %d on thread %p",
chain.get(), mEffectChains.size(), this);
if (mEffectChains.size() == 1) {
+ updateSuspendedSessionsOnRemoveEffectChain_l(chain);
mEffectChains.removeAt(0);
}
return 0;
@@ -5570,7 +5750,7 @@
int id,
int sessionId)
: mThread(wThread), mChain(chain), mId(id), mSessionId(sessionId), mEffectInterface(NULL),
- mStatus(NO_INIT), mState(IDLE)
+ mStatus(NO_INIT), mState(IDLE), mSuspended(false)
{
LOGV("Constructor %p", this);
int lStatus;
@@ -5634,14 +5814,17 @@
}
// if inserted in first place, move effect control from previous owner to this handle
if (i == 0) {
+ bool enabled = false;
if (h != 0) {
- h->setControl(false, true);
+ enabled = h->enabled();
+ h->setControl(false/*hasControl*/, true /*signal*/, enabled /*enabled*/);
}
- handle->setControl(true, false);
+ handle->setControl(true /*hasControl*/, false /*signal*/, enabled /*enabled*/);
status = NO_ERROR;
} else {
status = ALREADY_EXISTS;
}
+ LOGV("addHandle() %p added handle %p in position %d", this, handle.get(), i);
mHandles.insertAt(handle, i);
return status;
}
@@ -5657,13 +5840,21 @@
if (i == size) {
return size;
}
+ LOGV("removeHandle() %p removed handle %p in position %d", this, handle.unsafe_get(), i);
+
+ bool enabled = false;
+ EffectHandle *hdl = handle.unsafe_get();
+ if (hdl) {
+ LOGV("removeHandle() unsafe_get OK");
+ enabled = hdl->enabled();
+ }
mHandles.removeAt(i);
size = mHandles.size();
// if removed from first place, move effect control from this handle to next in line
if (i == 0 && size != 0) {
sp<EffectHandle> h = mHandles[0].promote();
if (h != 0) {
- h->setControl(true, true);
+ h->setControl(true /*hasControl*/, true /*signal*/ , enabled /*enabled*/);
}
}
@@ -5677,8 +5868,21 @@
return size;
}
+sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle()
+{
+ Mutex::Autolock _l(mLock);
+ sp<EffectHandle> handle;
+ if (mHandles.size() != 0) {
+ handle = mHandles[0].promote();
+ }
+ return handle;
+}
+
+
+
void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
{
+ LOGV("disconnect() %p handle %p ", this, handle.unsafe_get());
// keep a strong reference on this EffectModule to avoid calling the
// destructor before we exit
sp<EffectModule> keep(this);
@@ -6139,6 +6343,17 @@
return status;
}
+void AudioFlinger::EffectModule::setSuspended(bool suspended)
+{
+ Mutex::Autolock _l(mLock);
+ mSuspended = suspended;
+}
+bool AudioFlinger::EffectModule::suspended()
+{
+ Mutex::Autolock _l(mLock);
+ return mSuspended;
+}
+
status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -6235,7 +6450,8 @@
const sp<IEffectClient>& effectClient,
int32_t priority)
: BnEffect(),
- mEffect(effect), mEffectClient(effectClient), mClient(client), mPriority(priority), mHasControl(false)
+ mEffect(effect), mEffectClient(effectClient), mClient(client),
+ mPriority(priority), mHasControl(false), mEnabled(false)
{
LOGV("constructor %p", this);
@@ -6258,30 +6474,66 @@
{
LOGV("Destructor %p", this);
disconnect();
+ LOGV("Destructor DONE %p", this);
}
status_t AudioFlinger::EffectHandle::enable()
{
+ LOGV("enable %p", this);
if (!mHasControl) return INVALID_OPERATION;
if (mEffect == 0) return DEAD_OBJECT;
+ mEnabled = true;
+
+ sp<ThreadBase> thread = mEffect->thread().promote();
+ if (thread != 0) {
+ thread->checkSuspendOnEffectEnabled(mEffect, true, mEffect->sessionId());
+ }
+
+ // checkSuspendOnEffectEnabled() can suspend this same effect when enabled
+ if (mEffect->suspended()) {
+ return NO_ERROR;
+ }
+
return mEffect->setEnabled(true);
}
status_t AudioFlinger::EffectHandle::disable()
{
+ LOGV("disable %p", this);
if (!mHasControl) return INVALID_OPERATION;
- if (mEffect == NULL) return DEAD_OBJECT;
+ if (mEffect == 0) return DEAD_OBJECT;
- return mEffect->setEnabled(false);
+ mEnabled = false;
+
+ if (mEffect->suspended()) {
+ return NO_ERROR;
+ }
+
+ status_t status = mEffect->setEnabled(false);
+
+ sp<ThreadBase> thread = mEffect->thread().promote();
+ if (thread != 0) {
+ thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+ }
+
+ return status;
}
void AudioFlinger::EffectHandle::disconnect()
{
+ LOGV("disconnect %p", this);
if (mEffect == 0) {
return;
}
+
mEffect->disconnect(this);
+
+ sp<ThreadBase> thread = mEffect->thread().promote();
+ if (thread != 0) {
+ thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
+ }
+
// release sp on module => module destructor can be called now
mEffect.clear();
if (mCblk) {
@@ -6373,11 +6625,13 @@
return mCblkMemory;
}
-void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal)
+void AudioFlinger::EffectHandle::setControl(bool hasControl, bool signal, bool enabled)
{
LOGV("setControl %p control %d", this, hasControl);
mHasControl = hasControl;
+ mEnabled = enabled;
+
if (signal && mEffectClient != 0) {
mEffectClient->controlStatusChanged(hasControl);
}
@@ -6448,7 +6702,7 @@
}
-// getEffectFromDesc_l() must be called with PlaybackThread::mLock held
+// getEffectFromDesc_l() must be called with ThreadBase::mLock held
sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromDesc_l(effect_descriptor_t *descriptor)
{
sp<EffectModule> effect;
@@ -6463,7 +6717,7 @@
return effect;
}
-// getEffectFromId_l() must be called with PlaybackThread::mLock held
+// getEffectFromId_l() must be called with ThreadBase::mLock held
sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int id)
{
sp<EffectModule> effect;
@@ -6479,6 +6733,22 @@
return effect;
}
+// getEffectFromType_l() must be called with ThreadBase::mLock held
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromType_l(
+ const effect_uuid_t *type)
+{
+ sp<EffectModule> effect;
+ size_t size = mEffects.size();
+
+ for (size_t i = 0; i < size; i++) {
+ if (memcmp(&mEffects[i]->desc().type, type, sizeof(effect_uuid_t)) == 0) {
+ effect = mEffects[i];
+ break;
+ }
+ }
+ return effect;
+}
+
// Must be called with EffectChain::mLock locked
void AudioFlinger::EffectChain::process_l()
{
@@ -6773,6 +7043,166 @@
return NO_ERROR;
}
+// must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setEffectSuspended_l(
+ const effect_uuid_t *type, bool suspend)
+{
+ sp<SuspendedEffectDesc> desc;
+ // use effect type UUID timelow as key as there is no real risk of identical
+ // timeLow fields among effect type UUIDs.
+ int index = mSuspendedEffects.indexOfKey(type->timeLow);
+ if (suspend) {
+ if (index >= 0) {
+ desc = mSuspendedEffects.valueAt(index);
+ } else {
+ desc = new SuspendedEffectDesc();
+ memcpy(&desc->mType, type, sizeof(effect_uuid_t));
+ mSuspendedEffects.add(type->timeLow, desc);
+ LOGV("setEffectSuspended_l() add entry for %08x", type->timeLow);
+ }
+ if (desc->mRefCount++ == 0) {
+ sp<EffectModule> effect = getEffectIfEnabled(type);
+ if (effect != 0) {
+ desc->mEffect = effect;
+ effect->setSuspended(true);
+ effect->setEnabled(false);
+ }
+ }
+ } else {
+ if (index < 0) {
+ return;
+ }
+ desc = mSuspendedEffects.valueAt(index);
+ if (desc->mRefCount <= 0) {
+ LOGW("setEffectSuspended_l() restore refcount should not be 0 %d", desc->mRefCount);
+ desc->mRefCount = 1;
+ }
+ if (--desc->mRefCount == 0) {
+ LOGV("setEffectSuspended_l() remove entry for %08x", mSuspendedEffects.keyAt(index));
+ if (desc->mEffect != 0) {
+ sp<EffectModule> effect = desc->mEffect.promote();
+ if (effect != 0) {
+ effect->setSuspended(false);
+ sp<EffectHandle> handle = effect->controlHandle();
+ if (handle != 0) {
+ effect->setEnabled(handle->enabled());
+ }
+ }
+ desc->mEffect.clear();
+ }
+ mSuspendedEffects.removeItemsAt(index);
+ }
+ }
+}
+
+// must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setEffectSuspendedAll_l(bool suspend)
+{
+ sp<SuspendedEffectDesc> desc;
+
+ int index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
+ if (suspend) {
+ if (index >= 0) {
+ desc = mSuspendedEffects.valueAt(index);
+ } else {
+ desc = new SuspendedEffectDesc();
+ mSuspendedEffects.add((int)kKeyForSuspendAll, desc);
+ LOGV("setEffectSuspendedAll_l() add entry for 0");
+ }
+ if (desc->mRefCount++ == 0) {
+ Vector< sp<EffectModule> > effects = getSuspendEligibleEffects();
+ for (size_t i = 0; i < effects.size(); i++) {
+ setEffectSuspended_l(&effects[i]->desc().type, true);
+ }
+ }
+ } else {
+ if (index < 0) {
+ return;
+ }
+ desc = mSuspendedEffects.valueAt(index);
+ if (desc->mRefCount <= 0) {
+ LOGW("setEffectSuspendedAll_l() restore refcount should not be 0 %d", desc->mRefCount);
+ desc->mRefCount = 1;
+ }
+ if (--desc->mRefCount == 0) {
+ Vector<const effect_uuid_t *> types;
+ for (size_t i = 0; i < mSuspendedEffects.size(); i++) {
+ if (mSuspendedEffects.keyAt(i) == (int)kKeyForSuspendAll) {
+ continue;
+ }
+ types.add(&mSuspendedEffects.valueAt(i)->mType);
+ }
+ for (size_t i = 0; i < types.size(); i++) {
+ setEffectSuspended_l(types[i], false);
+ }
+ LOGV("setEffectSuspendedAll_l() remove entry for %08x", mSuspendedEffects.keyAt(index));
+ mSuspendedEffects.removeItem((int)kKeyForSuspendAll);
+ }
+ }
+}
+
+Vector< sp<AudioFlinger::EffectModule> > AudioFlinger::EffectChain::getSuspendEligibleEffects()
+{
+ Vector< sp<EffectModule> > effects;
+ for (size_t i = 0; i < mEffects.size(); i++) {
+ effect_descriptor_t desc = mEffects[i]->desc();
+ // auxiliary effects and vizualizer are never suspended on output mix
+ if ((mSessionId == AUDIO_SESSION_OUTPUT_MIX) && (
+ ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) ||
+ (memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0))) {
+ continue;
+ }
+ effects.add(mEffects[i]);
+ }
+ return effects;
+}
+
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectIfEnabled(
+ const effect_uuid_t *type)
+{
+ sp<EffectModule> effect;
+ effect = getEffectFromType_l(type);
+ if (effect != 0 && !effect->isEnabled()) {
+ effect.clear();
+ }
+ return effect;
+}
+
+void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
+ bool enabled)
+{
+ int index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
+ if (enabled) {
+ if (index < 0) {
+ // if the effect is not suspend check if all effects are suspended
+ index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
+ if (index < 0) {
+ return;
+ }
+ setEffectSuspended_l(&effect->desc().type, enabled);
+ index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
+ }
+ LOGV("checkSuspendOnEffectEnabled() enable suspending fx %08x",
+ effect->desc().type.timeLow);
+ sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
+ // if effect is requested to suspended but was not yet enabled, supend it now.
+ if (desc->mEffect == 0) {
+ desc->mEffect = effect;
+ effect->setEnabled(false);
+ effect->setSuspended(true);
+ }
+ } else {
+ if (index < 0) {
+ return;
+ }
+ LOGV("checkSuspendOnEffectEnabled() disable restoring fx %08x",
+ effect->desc().type.timeLow);
+ sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
+ desc->mEffect.clear();
+ effect->setSuspended(false);
+ }
+}
+
#undef LOG_TAG
#define LOG_TAG "AudioFlinger"
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 7b6215f..791341a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -165,7 +165,7 @@
int *id,
int *enabled);
- virtual status_t moveEffects(int session, int srcOutput, int dstOutput);
+ virtual status_t moveEffects(int sessionId, int srcOutput, int dstOutput);
enum hardware_call_state {
AUDIO_HW_IDLE = 0,
@@ -206,6 +206,8 @@
uint32_t getMode() { return mMode; }
+ bool btNrec() { return mBtNrec; }
+
private:
AudioFlinger();
virtual ~AudioFlinger();
@@ -477,14 +479,45 @@
// strategy is only meaningful for PlaybackThread which implements this method
virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; }
+ // suspend or restore effect according to the type of effect passed. a NULL
+ // type pointer means suspend all effects in the session
+ void setEffectSuspended(const effect_uuid_t *type,
+ bool suspend,
+ int sessionId = AUDIO_SESSION_OUTPUT_MIX);
+ // check if some effects must be suspended/restored when an effect is enabled
+ // or disabled
+ virtual void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
+ bool enabled,
+ int sessionId = AUDIO_SESSION_OUTPUT_MIX);
+
mutable Mutex mLock;
protected:
+ // entry describing an effect being suspended in mSuspendedSessions keyed vector
+ class SuspendedSessionDesc : public RefBase {
+ public:
+ SuspendedSessionDesc() : mRefCount(0) {}
+
+ int mRefCount; // number of active suspend requests
+ effect_uuid_t mType; // effect type UUID
+ };
+
void acquireWakeLock();
void acquireWakeLock_l();
void releaseWakeLock();
void releaseWakeLock_l();
+ void setEffectSuspended_l(const effect_uuid_t *type,
+ bool suspend,
+ int sessionId = AUDIO_SESSION_OUTPUT_MIX);
+ // updated mSuspendedSessions when an effect suspended or restored
+ void updateSuspendedSessions_l(const effect_uuid_t *type,
+ bool suspend,
+ int sessionId);
+ // check if some effects must be suspended when an effect chain is added
+ void checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain);
+ // updated mSuspendedSessions when an effect chain is removed
+ void updateSuspendedSessionsOnRemoveEffectChain_l(const sp<EffectChain>& chain);
friend class Track;
friend class TrackBase;
@@ -519,6 +552,9 @@
sp<IPowerManager> mPowerManager;
sp<IBinder> mWakeLockToken;
sp<PMDeathRecipient> mDeathRecipient;
+ // list of suspended effects per session and per type. The first vector is
+ // keyed by session ID, the second by type UUID timeLow field
+ KeyedVector< int, KeyedVector< int, sp<SuspendedSessionDesc> > > mSuspendedSessions;
};
// --- PlaybackThread ---
@@ -848,7 +884,7 @@
void audioConfigChanged_l(int event, int ioHandle, void *param2);
uint32_t nextUniqueId();
- status_t moveEffectChain_l(int session,
+ status_t moveEffectChain_l(int sessionId,
AudioFlinger::PlaybackThread *srcThread,
AudioFlinger::PlaybackThread *dstThread,
bool reRegister);
@@ -908,6 +944,7 @@
bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
void dump(char* buffer, size_t size);
+
private:
friend class AudioFlinger;
friend class RecordThread;
@@ -950,8 +987,6 @@
AudioStreamIn* getInput() { return mInput; }
virtual audio_stream_t* stream() { return &mInput->stream->common; }
-
- void setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; }
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
virtual bool checkForNewParameters_l();
@@ -963,6 +998,7 @@
virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
virtual uint32_t hasAudioSession(int sessionId);
+ RecordTrack* track();
private:
RecordThread();
@@ -1059,6 +1095,7 @@
int16_t *outBuffer() { return mConfig.outputCfg.buffer.s16; }
void setChain(const wp<EffectChain>& chain) { mChain = chain; }
void setThread(const wp<ThreadBase>& thread) { mThread = thread; }
+ wp<ThreadBase>& thread() { return mThread; }
status_t addHandle(sp<EffectHandle>& handle);
void disconnect(const wp<EffectHandle>& handle);
@@ -1071,6 +1108,10 @@
status_t setVolume(uint32_t *left, uint32_t *right, bool controller);
status_t setMode(uint32_t mode);
status_t stop();
+ void setSuspended(bool suspended);
+ bool suspended();
+
+ sp<EffectHandle> controlHandle();
status_t dump(int fd, const Vector<String16>& args);
@@ -1099,6 +1140,7 @@
uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after
// sending disable command.
uint32_t mDisableWaitCnt; // current process() calls count during disable period.
+ bool mSuspended; // effect is suspended: temporarily disabled by framework
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -1131,13 +1173,17 @@
// Give or take control of effect module
- void setControl(bool hasControl, bool signal);
+ // - hasControl: true if control is given, false if removed
+ // - signal: true client app should be signaled of change, false otherwise
+ // - enabled: state of the effect when control is passed
+ void setControl(bool hasControl, bool signal, bool enabled);
void commandExecuted(uint32_t cmdCode,
uint32_t cmdSize,
void *pCmdData,
uint32_t replySize,
void *pReplyData);
void setEnabled(bool enabled);
+ bool enabled() { return mEnabled; }
// Getters
int id() { return mEffect->id(); }
@@ -1160,6 +1206,8 @@
uint8_t* mBuffer; // pointer to parameter area in shared memory
int mPriority; // client application priority to control the effect
bool mHasControl; // true if this handle is controlling the effect
+ bool mEnabled; // cached enable state: needed when the effect is
+ // restored after being suspended
};
// the EffectChain class represents a group of effects associated to one audio session.
@@ -1174,6 +1222,10 @@
EffectChain(const wp<ThreadBase>& wThread, int sessionId);
~EffectChain();
+ // special key used for an entry in mSuspendedEffects keyed vector
+ // corresponding to a suspend all request.
+ static const int kKeyForSuspendAll = 0;
+
void process_l();
void lock() {
@@ -1191,6 +1243,7 @@
sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
sp<EffectModule> getEffectFromId_l(int id);
+ sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
bool setVolume_l(uint32_t *left, uint32_t *right);
void setDevice_l(uint32_t device);
void setMode_l(uint32_t mode);
@@ -1221,6 +1274,15 @@
void setStrategy(uint32_t strategy)
{ mStrategy = strategy; }
+ // suspend effect of the given type
+ void setEffectSuspended_l(const effect_uuid_t *type,
+ bool suspend);
+ // suspend all eligible effects
+ void setEffectSuspendedAll_l(bool suspend);
+ // check if effects should be suspend or restored when a given effect is enable or disabled
+ virtual void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
+ bool enabled);
+
status_t dump(int fd, const Vector<String16>& args);
protected:
@@ -1228,6 +1290,21 @@
EffectChain(const EffectChain&);
EffectChain& operator =(const EffectChain&);
+ class SuspendedEffectDesc : public RefBase {
+ public:
+ SuspendedEffectDesc() : mRefCount(0) {}
+
+ int mRefCount;
+ effect_uuid_t mType;
+ wp<EffectModule> mEffect;
+ };
+
+ // get a list of effect modules to suspend when an effect of the type
+ // passed is enabled.
+ Vector< sp<EffectModule> > getSuspendEligibleEffects();
+ // get an effect module if it is currently enable
+ sp<EffectModule> getEffectIfEnabled(const effect_uuid_t *type);
+
wp<ThreadBase> mThread; // parent mixer thread
Mutex mLock; // mutex protecting effect list
Vector<sp<EffectModule> > mEffects; // list of effect modules
@@ -1243,6 +1320,10 @@
uint32_t mNewLeftVolume; // new volume on left channel
uint32_t mNewRightVolume; // new volume on right channel
uint32_t mStrategy; // strategy for this effect chain
+ // mSuspendedEffects lists all effect currently suspended in the chain
+ // use effect type UUID timelow field as key. There is no real risk of identical
+ // timeLow fields among effect type UUIDs.
+ KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
};
struct AudioStreamOut {
@@ -1283,7 +1364,8 @@
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
volatile int32_t mNextUniqueId;
- uint32_t mMode;
+ uint32_t mMode;
+ bool mBtNrec;
};
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 541a8cf..bf9e014 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -40,6 +40,7 @@
import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
@@ -344,7 +345,7 @@
mPolicyManager.registerListener(mPolicyListener);
} catch (RemoteException e) {
// ouch, no rules updates means some processes may never get network
- Slog.e(TAG, "unable to register INetworkPolicyListener", e);
+ loge("unable to register INetworkPolicyListener" + e.toString());
}
final PowerManager powerManager = (PowerManager) context.getSystemService(
@@ -737,6 +738,30 @@
return result.toArray(new NetworkState[result.size()]);
}
+ private NetworkState getNetworkStateUnchecked(int networkType) {
+ if (isNetworkTypeValid(networkType)) {
+ final NetworkStateTracker tracker = mNetTrackers[networkType];
+ if (tracker != null) {
+ return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(),
+ tracker.getLinkCapabilities());
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
+ enforceAccessPermission();
+ final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
+ if (state != null) {
+ try {
+ return mPolicyManager.getNetworkQuotaInfo(state);
+ } catch (RemoteException e) {
+ }
+ }
+ return null;
+ }
+
public boolean setRadios(boolean turnOn) {
boolean result = true;
enforceChangePermission();
@@ -798,9 +823,11 @@
}
public void expire() {
- log("ConnectivityService FeatureUser expire(" +
- mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
- (System.currentTimeMillis() - mCreateTime) + " mSec ago");
+ if (VDBG) {
+ log("ConnectivityService FeatureUser expire(" +
+ mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
+ (System.currentTimeMillis() - mCreateTime) + " mSec ago");
+ }
stopUsingNetworkFeature(this, false);
}
@@ -843,7 +870,7 @@
if(networkType == ConnectivityManager.TYPE_MOBILE) {
usedNetworkType = convertFeatureToNetworkType(feature);
if (usedNetworkType < 0) {
- Slog.e(TAG, "Can't match any netTracker!");
+ loge("Can't match any netTracker!");
usedNetworkType = networkType;
}
}
@@ -953,7 +980,7 @@
return stopUsingNetworkFeature(u, true);
} else {
// none found!
- if (DBG) log("ignoring stopUsingNetworkFeature - not a live request");
+ if (VDBG) log("ignoring stopUsingNetworkFeature - not a live request");
return 1;
}
}
@@ -1081,7 +1108,7 @@
if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
tracker.isTeardownRequested()) {
- if (DBG) {
+ if (VDBG) {
log("requestRouteToHostAddress on down network " +
"(" + networkType + ") - dropped");
}
@@ -1152,13 +1179,13 @@
}
}
if (doAdd) {
- if (DBG) log("Adding " + r + " for interface " + ifaceName);
+ if (VDBG) log("Adding " + r + " for interface " + ifaceName);
mAddedRoutes.add(r);
try {
mNetd.addRoute(ifaceName, r);
} catch (Exception e) {
// never crash - catch them all
- loge("Exception trying to add a route: " + e);
+ if (VDBG) loge("Exception trying to add a route: " + e);
return false;
}
} else {
@@ -1166,16 +1193,16 @@
// we can remove it from the table
mAddedRoutes.remove(r);
if (mAddedRoutes.contains(r) == false) {
- if (DBG) log("Removing " + r + " for interface " + ifaceName);
+ if (VDBG) log("Removing " + r + " for interface " + ifaceName);
try {
mNetd.removeRoute(ifaceName, r);
} catch (Exception e) {
// never crash - catch them all
- loge("Exception trying to remove a route: " + e);
+ if (VDBG) loge("Exception trying to remove a route: " + e);
return false;
}
} else {
- if (DBG) log("not removing " + r + " as it's still in use");
+ if (VDBG) log("not removing " + r + " as it's still in use");
}
}
return true;
@@ -1220,7 +1247,7 @@
enforceAccessPermission();
boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.MOBILE_DATA, 1) == 1;
- if (DBG) log("getMobileDataEnabled returning " + retVal);
+ if (VDBG) log("getMobileDataEnabled returning " + retVal);
return retVal;
}
@@ -1247,7 +1274,7 @@
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (LOGD_RULES) {
- Slog.d(TAG, "onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
+ log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
}
synchronized (mRulesLock) {
@@ -1268,8 +1295,7 @@
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (LOGD_RULES) {
- Slog.d(TAG,
- "onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
+ log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
}
synchronized (mRulesLock) {
@@ -1294,8 +1320,8 @@
private void handleSetMobileData(boolean enabled) {
if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
- if (DBG) {
- Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
+ if (VDBG) {
+ log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
}
mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled);
}
@@ -1587,7 +1613,7 @@
mNetConfigs[type].priority) ||
mNetworkPreference == mActiveDefaultNetwork) {
// don't accept this one
- if (DBG) {
+ if (VDBG) {
log("Not broadcasting CONNECT_ACTION " +
"to torn down network " + info.getTypeName());
}
@@ -1688,9 +1714,11 @@
}
} else {
resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
- log("handleConnectivityChange: interface not not equivalent reset both" +
- " linkProperty[" + netType + "]:" +
- " resetMask=" + resetMask);
+ if (DBG) {
+ log("handleConnectivityChange: interface not not equivalent reset both" +
+ " linkProperty[" + netType + "]:" +
+ " resetMask=" + resetMask);
+ }
}
}
if (mNetConfigs[netType].isDefault()) {
@@ -1798,7 +1826,7 @@
String bufferSizes = SystemProperties.get(key);
if (bufferSizes.length() == 0) {
- loge(key + " not found in system properties. Using defaults");
+ if (VDBG) log(key + " not found in system properties. Using defaults");
// Setting to default values so we won't be stuck to previous values
key = "net.tcp.buffersize.default";
@@ -1807,7 +1835,7 @@
// Set values in kernel
if (bufferSizes.length() != 0) {
- if (DBG) {
+ if (VDBG) {
log("Setting TCP values: [" + bufferSizes
+ "] which comes from [" + key + "]");
}
@@ -1849,7 +1877,7 @@
*/
private void reassessPidDns(int myPid, boolean doBump)
{
- if (DBG) log("reassessPidDns for pid " + myPid);
+ if (VDBG) log("reassessPidDns for pid " + myPid);
for(int i : mPriorityList) {
if (mNetConfigs[i].isDefault()) {
continue;
@@ -1935,7 +1963,7 @@
String value = mDefaultDns.getHostAddress();
if (!value.equals(SystemProperties.get("net.dns1"))) {
if (DBG) {
- log("no dns provided for " + network + " - using " + value);
+ loge("no dns provided for " + network + " - using " + value);
}
changed = true;
SystemProperties.set("net.dns1", value);
@@ -1948,7 +1976,7 @@
if (!changed && value.equals(SystemProperties.get(key))) {
continue;
}
- if (DBG) {
+ if (VDBG) {
log("adding dns " + value + " for " + network);
}
changed = true;
@@ -1957,7 +1985,7 @@
}
for (int i = last + 1; i <= mNumDnsEntries; ++i) {
String key = "net.dns" + i;
- if (DBG) log("erasing " + key);
+ if (VDBG) log("erasing " + key);
changed = true;
SystemProperties.set(key, "");
}
@@ -1968,7 +1996,7 @@
mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses));
mNetd.setDefaultInterfaceForDns(iface);
} catch (Exception e) {
- Slog.e(TAG, "exception setting default dns interface: " + e);
+ loge("exception setting default dns interface: " + e);
}
}
if (!domains.equals(SystemProperties.get("net.dns.search"))) {
@@ -1998,7 +2026,7 @@
mNetd.setDnsServersForInterface(p.getInterfaceName(),
NetworkUtils.makeStrings(dnses));
} catch (Exception e) {
- Slog.e(TAG, "exception setting dns servers: " + e);
+ loge("exception setting dns servers: " + e);
}
// set per-pid dns for attached secondary nets
List pids = mNetRequestersPids[netType];
@@ -2335,7 +2363,7 @@
// 100 percent is full good, 0 is full bad.
public void reportInetCondition(int networkType, int percentage) {
- if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
+ if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR,
"ConnectivityService");
@@ -2372,7 +2400,7 @@
mDefaultInetCondition = condition;
int delay;
if (mInetConditionChangeInFlight == false) {
- if (DBG) log("starting a change hold");
+ if (VDBG) log("starting a change hold");
// setup a new hold to debounce this
if (mDefaultInetCondition > 50) {
delay = Settings.Secure.getInt(mContext.getContentResolver(),
@@ -2387,12 +2415,12 @@
} else {
// we've set the new condition, when this hold ends that will get
// picked up
- if (DBG) log("currently in hold - not setting new end evt");
+ if (VDBG) log("currently in hold - not setting new end evt");
}
}
private void handleInetConditionHoldEnd(int netType, int sequence) {
- if (DBG) {
+ if (VDBG) {
log("Inet hold end, net=" + netType +
", condition =" + mDefaultInetCondition +
", published condition =" + mDefaultInetConditionPublished);
@@ -2490,7 +2518,7 @@
mDefaultProxy = null;
}
}
- if (DBG) log("changing default proxy to " + proxy);
+ if (VDBG) log("changing default proxy to " + proxy);
if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return;
if (mGlobalProxy != null) return;
sendProxyBroadcast(proxy);
@@ -2517,7 +2545,7 @@
private void sendProxyBroadcast(ProxyProperties proxy) {
if (proxy == null) proxy = new ProxyProperties("", 0, "");
- log("sending Proxy Broadcast for " + proxy);
+ if (DBG) log("sending Proxy Broadcast for " + proxy);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index 88d94c2..fed554c 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -19,6 +19,9 @@
import android.net.LocalSocketAddress;
import android.net.LocalSocket;
import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.Slog;
@@ -39,7 +42,7 @@
* daemon which uses the libsysutils FrameworkListener
* protocol.
*/
-final class NativeDaemonConnector implements Runnable {
+final class NativeDaemonConnector implements Runnable, Handler.Callback {
private static final boolean LOCAL_LOGD = false;
private BlockingQueue<String> mResponseQueue;
@@ -47,6 +50,7 @@
private String TAG = "NativeDaemonConnector";
private String mSocket;
private INativeDaemonConnectorCallbacks mCallbacks;
+ private Handler mCallbackHandler;
private final int BUFFER_SIZE = 4096;
@@ -76,7 +80,11 @@
mResponseQueue = new LinkedBlockingQueue<String>(responseQueueSize);
}
+ @Override
public void run() {
+ HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
+ thread.start();
+ mCallbackHandler = new Handler(thread.getLooper(), this);
while (true) {
try {
@@ -88,6 +96,21 @@
}
}
+ @Override
+ public boolean handleMessage(Message msg) {
+ String event = (String) msg.obj;
+ try {
+ if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) {
+ Slog.w(TAG, String.format(
+ "Unhandled event '%s'", event));
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, String.format(
+ "Error handling '%s'", event), e);
+ }
+ return true;
+ }
+
private void listenToSocket() throws IOException {
LocalSocket socket = null;
@@ -119,20 +142,13 @@
String event = new String(buffer, start, i - start);
if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event));
- String[] tokens = event.split(" ");
+ String[] tokens = event.split(" ", 2);
try {
int code = Integer.parseInt(tokens[0]);
if (code >= ResponseCode.UnsolicitedInformational) {
- try {
- if (!mCallbacks.onEvent(code, event, tokens)) {
- Slog.w(TAG, String.format(
- "Unhandled event (%s)", event));
- }
- } catch (Exception ex) {
- Slog.e(TAG, String.format(
- "Error handling '%s'", event), ex);
- }
+ mCallbackHandler.sendMessage(
+ mCallbackHandler.obtainMessage(code, event));
} else {
try {
mResponseQueue.put(event);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 756cd00..a075255 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.net;
+import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.MANAGE_APP_TOKENS;
@@ -75,9 +76,11 @@
import android.net.INetworkStatsService;
import android.net.NetworkIdentity;
import android.net.NetworkPolicy;
+import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
+import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
@@ -1054,6 +1057,7 @@
synchronized (mRulesLock) {
mRestrictBackground = restrictBackground;
updateRulesForRestrictBackgroundLocked();
+ writePolicyLocked();
}
}
@@ -1066,6 +1070,68 @@
}
}
+ private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
+ for (NetworkPolicy policy : mNetworkPolicy.values()) {
+ if (policy.template.matches(ident)) {
+ return policy;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) {
+ mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
+
+ // only returns usage summary, so we don't require caller to have
+ // READ_NETWORK_USAGE_HISTORY.
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getNetworkQuotaInfoUnchecked(state);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private NetworkQuotaInfo getNetworkQuotaInfoUnchecked(NetworkState state) {
+ final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
+
+ final NetworkPolicy policy;
+ synchronized (mRulesLock) {
+ policy = findPolicyForNetworkLocked(ident);
+ }
+
+ if (policy == null) {
+ // missing policy means we can't derive useful quota info
+ return null;
+ }
+
+ final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+ : System.currentTimeMillis();
+
+ final long start = computeLastCycleBoundary(currentTime, policy);
+ final long end = currentTime;
+
+ // find total bytes used under policy
+ long totalBytes = 0;
+ try {
+ final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
+ policy.template, start, end);
+ final NetworkStats.Entry entry = stats.getValues(0, null);
+ totalBytes = entry.rxBytes + entry.txBytes;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "problem reading summary for template " + policy.template);
+ }
+
+ // report soft and hard limits under policy
+ final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes
+ : NetworkQuotaInfo.NO_LIMIT;
+ final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes
+ : NetworkQuotaInfo.NO_LIMIT;
+
+ return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 3d977d0..36371a57 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5025,16 +5025,18 @@
}
int loc = pkgLite.recommendedInstallLocation;
- if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION){
+ if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS){
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
- } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE){
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
ret = PackageManager.INSTALL_FAILED_INVALID_APK;
+ } else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
+ ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
- ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
+ ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
} else {
// Override with defaults if needed.
loc = installLocationPolicy(pkgLite, flags);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 32f300f..383c045 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -227,8 +227,13 @@
} else {
hwcl->sourceCrop.left = 0;
hwcl->sourceCrop.top = 0;
- hwcl->sourceCrop.right = buffer->width;
- hwcl->sourceCrop.bottom = buffer->height;
+ if (buffer != NULL) {
+ hwcl->sourceCrop.right = buffer->width;
+ hwcl->sourceCrop.bottom = buffer->height;
+ } else {
+ hwcl->sourceCrop.right = mTransformedBounds.width();
+ hwcl->sourceCrop.bottom = mTransformedBounds.height();
+ }
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
index 7bf25cf..4037a69 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
@@ -77,13 +77,23 @@
super.onDraw(canvas);
canvas.drawRGB(255, 255, 255);
+ mMediumPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ mMediumPaint.setStrokeWidth(2.0f);
canvas.drawText("Hello OpenGL renderer!", 100, 20, mMediumPaint);
+
+ mMediumPaint.setStyle(Paint.Style.FILL);
mMediumPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("Hello OpenGL renderer!", 100, 40, mMediumPaint);
+
+ mMediumPaint.setStyle(Paint.Style.STROKE);
+ mMediumPaint.setStrokeWidth(2.0f);
mMediumPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText("Hello OpenGL renderer!", 100, 60, mMediumPaint);
+
+ mMediumPaint.setStyle(Paint.Style.FILL);
mMediumPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("Hello OpenGL renderer!", 100, 100, mMediumPaint);
+
mMediumPaint.setShadowLayer(2.5f, 0.0f, 0.0f, 0xff000000);
canvas.drawText("Hello OpenGL renderer!", 100, 150, mMediumPaint);
mMediumPaint.clearShadowLayer();
diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml
index 66972ac..c4fd189 100644
--- a/tests/TileBenchmark/res/values/strings.xml
+++ b/tests/TileBenchmark/res/values/strings.xml
@@ -71,8 +71,16 @@
<string name="frames_per_second">Frames/sec</string>
<!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] -->
<string name="viewport_coverage">Coverage</string>
+ <!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] -->
+ <string name="render_millis">RenderMillis</string>
<!-- Format string for stat value overlay [CHAR LIMIT=15] -->
<string name="format_stat">%4.4f</string>
+
+ <!-- Format string for viewport position value overlay [CHAR LIMIT=25] -->
+ <string name="format_view_pos">View:(%1$d,%2$d)-(%3$d,%4$d)</string>
+ <!-- Format string for viewport position value overlay [CHAR LIMIT=25] -->
+ <string name="format_inval_pos">Inval:(%1$d,%2$d)-(%3$d,%4$d)</string>
+
<!-- Format string for displaying aggregate stats+values (nr of valid tiles,
etc.) [CHAR LIMIT=20] -->
<string name="format_stat_name">%1$-20s %2$3d</string>
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
index 36694a7..1eb1c00 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
@@ -83,14 +83,14 @@
}
};
- private class LoadFileTask extends AsyncTask<String, Void, TileData[][]> {
+ private class LoadFileTask extends AsyncTask<String, Void, RunData> {
@Override
- protected TileData[][] doInBackground(String... params) {
- TileData[][] data = null;
+ protected RunData doInBackground(String... params) {
+ RunData data = null;
try {
FileInputStream fis = openFileInput(params[0]);
ObjectInputStream in = new ObjectInputStream(fis);
- data = (TileData[][]) in.readObject();
+ data = (RunData) in.readObject();
in.close();
} catch (IOException ex) {
ex.printStackTrace();
@@ -101,7 +101,7 @@
}
@Override
- protected void onPostExecute(TileData data[][]) {
+ protected void onPostExecute(RunData data) {
if (data == null) {
Toast.makeText(getApplicationContext(),
getResources().getString(R.string.error_no_data),
@@ -110,7 +110,7 @@
}
mPlaybackView.setData(data);
- mFrameMax = data.length - 1;
+ mFrameMax = data.frames.length - 1;
mSeekBar.setMax(mFrameMax);
setFrame(null, 0);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
index 35b1563..9ea90f8 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
@@ -22,10 +22,12 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
-import android.os.Bundle;
+
+import com.test.tilebenchmark.RunData.TileData;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
public class PlaybackGraphs {
private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3;
@@ -44,7 +46,7 @@
return 0.0f;
}
- private interface MetricGen {
+ protected interface MetricGen {
public double getValue(TileData[] frame);
public double getMax();
@@ -52,7 +54,7 @@
public int getLabelId();
};
- private static MetricGen[] Metrics = new MetricGen[] {
+ protected static MetricGen[] Metrics = new MetricGen[] {
new MetricGen() {
// framerate graph
@Override
@@ -99,7 +101,7 @@
}
};
- private interface StatGen {
+ protected interface StatGen {
public double getValue(double sortedValues[]);
public int getLabelId();
@@ -116,7 +118,7 @@
+ sortedValues[intIndex + 1] * (alpha);
}
- private static StatGen[] Stats = new StatGen[] {
+ protected static StatGen[] Stats = new StatGen[] {
new StatGen() {
@Override
public double getValue(double[] sortedValues) {
@@ -157,21 +159,22 @@
}
private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
- private double[][] mStats = new double[Metrics.length][Stats.length];
+ protected double[][] mStats = new double[Metrics.length][Stats.length];
+ protected HashMap<String, Double> mSingleStats;
- public void setData(TileData[][] tileProfilingData) {
+ public void setData(RunData data) {
mShapes.clear();
- double metricValues[] = new double[tileProfilingData.length];
+ double metricValues[] = new double[data.frames.length];
- if (tileProfilingData.length == 0) {
+ if (data.frames.length == 0) {
return;
}
for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
// create graph out of rectangles, one per frame
int lastBar = 0;
- for (int frameIndex = 0; frameIndex < tileProfilingData.length; frameIndex++) {
- TileData frame[] = tileProfilingData[frameIndex];
+ for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
+ TileData frame[] = data.frames[frameIndex];
int newBar = (frame[0].top + frame[0].bottom) / 2;
MetricGen s = Metrics[metricIndex];
@@ -194,9 +197,11 @@
// store aggregate statistics per metric (median, and similar)
Arrays.sort(metricValues);
for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
- mStats[metricIndex][statIndex] = Stats[statIndex]
- .getValue(metricValues);
+ mStats[metricIndex][statIndex] =
+ Stats[statIndex].getValue(metricValues);
}
+
+ mSingleStats = data.singleStats;
}
}
@@ -215,7 +220,7 @@
}
public void draw(Canvas canvas, ArrayList<ShapeDrawable> shapes,
- String[] strings, Resources resources) {
+ ArrayList<String> strings, Resources resources) {
canvas.scale(CANVAS_SCALE, CANVAS_SCALE);
canvas.translate(BAR_WIDTH * Metrics.length, 0);
@@ -231,33 +236,18 @@
int yPos = LABELOFFSET;
canvas.drawText(label, xPos, yPos, whiteLabels);
for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
- label = resources.getString(R.string.format_stat,
- mStats[metricIndex][statIndex]);
+ String statLabel = resources.getString(
+ Stats[statIndex].getLabelId()).substring(0,3);
+ label = statLabel + " " + resources.getString(
+ R.string.format_stat, mStats[metricIndex][statIndex]);
yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE
/ 2;
canvas.drawText(label, xPos, yPos, whiteLabels);
}
}
- for (int stringIndex = 0; stringIndex < strings.length; stringIndex++) {
+ for (int stringIndex = 0; stringIndex < strings.size(); stringIndex++) {
int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2;
- canvas.drawText(strings[stringIndex], 0, yPos, whiteLabels);
+ canvas.drawText(strings.get(stringIndex), 0, yPos, whiteLabels);
}
}
-
- public Bundle getStatBundle(Resources resources) {
- Bundle b = new Bundle();
-
- for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
- for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
- String metricLabel = resources.getString(
- Metrics[metricIndex].getLabelId());
- String statLabel = resources.getString(
- Stats[statIndex].getLabelId());
- double value = mStats[metricIndex][statIndex];
- b.putDouble(metricLabel + " " + statLabel, value);
- }
- }
-
- return b;
- }
}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
index edc8643..5459c1f 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
@@ -30,10 +30,12 @@
import android.view.MotionEvent;
import android.view.View;
+import com.test.tilebenchmark.RunData.TileData;
+
import java.util.ArrayList;
public class PlaybackView extends View {
- public static final int TILE_SCALE = 300;
+ public static final int TILE_SCALE = 256;
private static final int INVAL_FLAG = -2;
private static final int INVAL_CYCLE = 250;
@@ -41,9 +43,9 @@
private PlaybackGraphs mGraphs;
private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>();
- private TileData mProfData[][] = null;
+ private RunData mProfData = null;
private GestureDetector mGestureDetector = null;
- private String mRenderStrings[] = new String[4];
+ private ArrayList<String> mRenderStrings = new ArrayList<String>();
private class TileDrawable extends ShapeDrawable {
TileData tile;
@@ -135,17 +137,30 @@
invalidate(); // may have animations, force redraw
}
+ private String statString(int labelId, int value) {
+ return getResources().getString(R.string.format_stat_name,
+ getResources().getString(labelId), value);
+ }
+ private String tileString(int formatStringId, TileData t) {
+ return getResources().getString(formatStringId,
+ t.left, t.top, t.right, t.bottom);
+ }
+
public int setFrame(int frame) {
- if (mProfData == null || mProfData.length == 0) {
+ if (mProfData == null || mProfData.frames.length == 0) {
return 0;
}
int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0, numInvals = 0;
mTempShapes.clear();
+ mRenderStrings.clear();
// create tile shapes (as they're drawn on bottom)
- for (TileData t : mProfData[frame]) {
- if (t.level != INVAL_FLAG && t != mProfData[frame][0]) {
+ for (TileData t : mProfData.frames[frame]) {
+ if (t == mProfData.frames[frame][0]){
+ // viewport 'tile', add coords to render strings
+ mRenderStrings.add(tileString(R.string.format_view_pos, t));
+ } else if (t.level != INVAL_FLAG) {
int colorId;
if (t.isReady) {
readyTiles++;
@@ -159,14 +174,16 @@
}
mTempShapes.add(new TileDrawable(t, colorId));
} else {
+ // inval 'tile', count and add coords to render strings
numInvals++;
+ mRenderStrings.add(tileString(R.string.format_inval_pos, t));
}
}
// create invalidate shapes (drawn above tiles)
int invalId = 0;
- for (TileData t : mProfData[frame]) {
- if (t.level == INVAL_FLAG && t != mProfData[frame][0]) {
+ for (TileData t : mProfData.frames[frame]) {
+ if (t.level == INVAL_FLAG && t != mProfData.frames[frame][0]) {
TileDrawable invalShape = new TileDrawable(t,
R.color.inval_region_start);
ValueAnimator tileAnimator = ObjectAnimator.ofInt(invalShape,
@@ -186,26 +203,20 @@
}
}
- mRenderStrings[0] = getResources().getString(R.string.format_stat_name,
- getResources().getString(R.string.ready_tiles), readyTiles);
- mRenderStrings[1] = getResources().getString(R.string.format_stat_name,
- getResources().getString(R.string.unready_tiles), unreadyTiles);
- mRenderStrings[2] = getResources().getString(R.string.format_stat_name,
- getResources().getString(R.string.unplaced_tiles),
- unplacedTiles);
- mRenderStrings[3] = getResources().getString(R.string.format_stat_name,
- getResources().getString(R.string.number_invalidates),
- numInvals);
+ mRenderStrings.add(statString(R.string.ready_tiles, readyTiles));
+ mRenderStrings.add(statString(R.string.unready_tiles, unreadyTiles));
+ mRenderStrings.add(statString(R.string.unplaced_tiles, unplacedTiles));
+ mRenderStrings.add(statString(R.string.number_invalidates, numInvals));
// draw view rect (using first TileData object, on top)
- TileDrawable viewShape = new TileDrawable(mProfData[frame][0],
+ TileDrawable viewShape = new TileDrawable(mProfData.frames[frame][0],
R.color.view);
mTempShapes.add(viewShape);
this.invalidate();
return frame;
}
- public void setData(TileData[][] tileProfilingData) {
+ public void setData(RunData tileProfilingData) {
mProfData = tileProfilingData;
mGraphs.setData(mProfData);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
index 1521807..82a7e82 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
@@ -51,11 +51,11 @@
public class ProfileActivity extends Activity {
public interface ProfileCallback {
- public void profileCallback(TileData data[][]);
+ public void profileCallback(RunData data);
}
public static final String TEMP_FILENAME = "profile.tiles";
- private static final int LOAD_TEST_DELAY = 2000; // nr of millis after load,
+ private static final int LOAD_TEST_DELAY = 1000; // nr of millis after load,
// before test
Button mInspectButton;
@@ -135,6 +135,7 @@
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.requestFocus();
+
new CountDownTimer(LOAD_TEST_DELAY, LOAD_TEST_DELAY) {
@Override
public void onTick(long millisUntilFinished) {
@@ -155,10 +156,10 @@
}
private class StoreFileTask extends
- AsyncTask<Pair<String, TileData[][]>, Void, Void> {
+ AsyncTask<Pair<String, RunData>, Void, Void> {
@Override
- protected Void doInBackground(Pair<String, TileData[][]>... params) {
+ protected Void doInBackground(Pair<String, RunData>... params) {
try {
FileOutputStream fos = openFileOutput(params[0].first,
Context.MODE_PRIVATE);
@@ -205,10 +206,8 @@
/** auto - automatically scroll. */
private void startViewProfiling(boolean auto) {
- if (!auto) {
- // manual, toggle capture button to indicate capture state to user
- mCaptureButton.setChecked(true);
- }
+ // toggle capture button to indicate capture state to user
+ mCaptureButton.setChecked(true);
mWeb.startScrollTest(mCallback, auto);
setTestingState(TestingState.START_TESTING);
}
@@ -224,16 +223,16 @@
mMovementSpinner = (Spinner) findViewById(R.id.movement);
mUrl = (EditText) findViewById(R.id.url);
mWeb = (ProfiledWebView) findViewById(R.id.web);
- mCallback = new ProfileCallback() {
+ setCallback(new ProfileCallback() {
@SuppressWarnings("unchecked")
@Override
- public void profileCallback(TileData[][] data) {
- new StoreFileTask().execute(new Pair<String, TileData[][]>(
+ public void profileCallback(RunData data) {
+ new StoreFileTask().execute(new Pair<String, RunData>(
TEMP_FILENAME, data));
mCaptureButton.setChecked(false);
setTestingState(TestingState.STOP_TESTING);
}
- };
+ });
// Inspect button (opens PlaybackActivity)
mInspectButton.setOnClickListener(new OnClickListener() {
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index d3941be..3fc4665 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -18,15 +18,19 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
import android.webkit.WebView;
import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
+import com.test.tilebenchmark.RunData.TileData;
public class ProfiledWebView extends WebView {
private int mSpeed;
+ private boolean isTesting = false;
private boolean isScrolling = false;
private ProfileCallback mCallback;
+ private long mContentInvalMillis;
public ProfiledWebView(Context context) {
super(context);
@@ -47,7 +51,7 @@
@Override
protected void onDraw(android.graphics.Canvas canvas) {
- if (isScrolling) {
+ if (isTesting && isScrolling) {
if (canScrollVertically(1)) {
scrollBy(0, mSpeed);
} else {
@@ -60,31 +64,53 @@
/*
* Called once the page is loaded to start scrolling for evaluating tiles.
- * If autoScrolling isn't set, stop must be called manually.
+ * If autoScrolling isn't set, stop must be called manually. Before
+ * scrolling, invalidate all content and redraw it, measuring time taken.
*/
public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
isScrolling = autoScrolling;
mCallback = callback;
- tileProfilingStart();
+ isTesting = false;
+ mContentInvalMillis = System.currentTimeMillis();
+ registerPageSwapCallback();
+ contentInvalidateAll();
invalidate();
}
/*
+ * Called after the manual contentInvalidateAll, after the tiles have all
+ * been redrawn.
+ */
+ @Override
+ protected void pageSwapCallback() {
+ mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
+ super.pageSwapCallback();
+ Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis
+ + "millis");
+ isTesting = true;
+ invalidate(); // ensure a redraw so that auto-scrolling can occur
+ tileProfilingStart();
+ }
+
+ /*
* Called once the page has stopped scrolling
*/
public void stopScrollTest() {
- super.tileProfilingStop();
+ tileProfilingStop();
+ isTesting = false;
if (mCallback == null) {
tileProfilingClear();
return;
}
- TileData data[][] = new TileData[super.tileProfilingNumFrames()][];
- for (int frame = 0; frame < data.length; frame++) {
- data[frame] = new TileData[
+ RunData data = new RunData(super.tileProfilingNumFrames());
+ data.singleStats.put(getResources().getString(R.string.render_millis),
+ (double)mContentInvalMillis);
+ for (int frame = 0; frame < data.frames.length; frame++) {
+ data.frames[frame] = new TileData[
tileProfilingNumTilesInFrame(frame)];
- for (int tile = 0; tile < data[frame].length; tile++) {
+ for (int tile = 0; tile < data.frames[frame].length; tile++) {
int left = tileProfilingGetInt(frame, tile, "left");
int top = tileProfilingGetInt(frame, tile, "top");
int right = tileProfilingGetInt(frame, tile, "right");
@@ -96,18 +122,18 @@
float scale = tileProfilingGetFloat(frame, tile, "scale");
- data[frame][tile] = new TileData(left, top, right, bottom,
+ data.frames[frame][tile] = data.new TileData(left, top, right, bottom,
isReady, level, scale);
}
}
- super.tileProfilingClear();
+ tileProfilingClear();
mCallback.profileCallback(data);
}
@Override
public void loadUrl(String url) {
- if (!url.startsWith("http://")) {
+ if (!url.startsWith("http://") && !url.startsWith("file://")) {
url = "http://" + url;
}
super.loadUrl(url);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java
new file mode 100644
index 0000000..2da61cc
--- /dev/null
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.test.tilebenchmark;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+public class RunData implements Serializable {
+ public TileData[][] frames;
+ public HashMap<String, Double> singleStats = new HashMap<String, Double>();
+
+ public RunData(int frames) {
+ this.frames = new TileData[frames][];
+ }
+
+ public class TileData implements Serializable {
+ public int left, top, right, bottom;
+ public boolean isReady;
+ public int level;
+ public float scale;
+
+ public TileData(int left, int top, int right, int bottom,
+ boolean isReady, int level, float scale) {
+ this.left = left;
+ this.right = right;
+ this.top = top;
+ this.bottom = bottom;
+ this.isReady = isReady;
+ this.level = level;
+ this.scale = scale;
+ }
+
+ public String toString() {
+ return "Tile (" + left + "," + top + ")->("
+ + right + "," + bottom + ")";
+ }
+ }
+
+}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
deleted file mode 100644
index 3e729a6..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.test.tilebenchmark;
-
-import java.io.Serializable;
-
-public class TileData implements Serializable {
- int left, top, right, bottom;
- public boolean isReady;
- public int level;
- public float scale;
-
- public TileData(int left, int top, int right, int bottom, boolean isReady,
- int level, float scale) {
- this.left = left;
- this.right = right;
- this.top = top;
- this.bottom = bottom;
- this.isReady = isReady;
- this.level = level;
- this.scale = scale;
- }
-
- public String toString() {
- return "Tile (" + left + "," + top + ")->("
- + right + "," + bottom + ")";
- }
-}
diff --git a/tests/TileBenchmark/tests/Android.mk b/tests/TileBenchmark/tests/Android.mk
new file mode 100644
index 0000000..8b235ec
--- /dev/null
+++ b/tests/TileBenchmark/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := TileBenchmarkTests
+
+LOCAL_INSTRUMENTATION_FOR := TileBenchmark
+
+include $(BUILD_PACKAGE)
diff --git a/tests/TileBenchmark/tests/AndroidManifest.xml b/tests/TileBenchmark/tests/AndroidManifest.xml
new file mode 100644
index 0000000..703b152
--- /dev/null
+++ b/tests/TileBenchmark/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.test.tilebenchmark.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.test.tilebenchmark"
+ android:label="Tests for WebView Tiles."/>
+</manifest>
diff --git a/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java
new file mode 100644
index 0000000..0f02239
--- /dev/null
+++ b/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.test.tilebenchmark;
+
+import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+public class PerformanceTest extends
+ ActivityInstrumentationTestCase2<ProfileActivity> {
+
+ private class StatAggregator extends PlaybackGraphs {
+ private HashMap<String, Double> mDataMap = new HashMap<String, Double>();
+ private int mCount = 0;
+
+ public void aggregate() {
+ mCount++;
+ Resources resources = mView.getResources();
+ for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
+ for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
+ String metricLabel = resources.getString(
+ Metrics[metricIndex].getLabelId());
+ String statLabel = resources.getString(
+ Stats[statIndex].getLabelId());
+
+ String label = metricLabel + " " + statLabel;
+ double aggVal = mDataMap.containsKey(label) ? mDataMap
+ .get(label) : 0;
+
+ aggVal += mStats[metricIndex][statIndex];
+ mDataMap.put(label, aggVal);
+ }
+ }
+ for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
+ double aggVal = mDataMap.containsKey(e.getKey())
+ ? mDataMap.get(e.getKey()) : 0;
+ mDataMap.put(e.getKey(), aggVal + e.getValue());
+ }
+ }
+
+ public Bundle getBundle() {
+ Bundle b = new Bundle();
+ int count = 0 == mCount ? Integer.MAX_VALUE : mCount;
+ for (Map.Entry<String, Double> e : mDataMap.entrySet()) {
+ b.putDouble(e.getKey(), e.getValue() / count);
+ }
+ return b;
+ }
+ }
+
+ ProfileActivity mActivity;
+ ProfiledWebView mView;
+ StatAggregator mStats = new StatAggregator();
+
+ private static final String LOGTAG = "PerformanceTest";
+ private static final String TEST_LOCATION = "webkit/page_cycler";
+ private static final String URL_PREFIX = "file://";
+ private static final String URL_POSTFIX = "/index.html?skip=true";
+ private static final int MAX_ITERATIONS = 4;
+ private static final String TEST_DIRS[] = {
+ "alexa_us"//, "android", "dom", "intl1", "intl2", "moz", "moz2"
+ };
+
+ public PerformanceTest() {
+ super(ProfileActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mView = (ProfiledWebView) mActivity.findViewById(R.id.web);
+ }
+
+ private boolean loadUrl(final String url) {
+ try {
+ Log.d(LOGTAG, "test starting for url " + url);
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mView.loadUrl(url);
+ }
+ });
+ synchronized (mStats) {
+ mStats.wait();
+ }
+ mStats.aggregate();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ private boolean runIteration() {
+ File sdFile = Environment.getExternalStorageDirectory();
+ for (String testDirName : TEST_DIRS) {
+ File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName);
+ Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath()
+ + "', exists=" + testDir.exists());
+ for (File siteDir : testDir.listFiles()) {
+ if (!siteDir.isDirectory())
+ continue;
+
+ if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath()
+ + URL_POSTFIX)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public void testMetrics() {
+ String state = Environment.getExternalStorageState();
+
+ if (!Environment.MEDIA_MOUNTED.equals(state)
+ && !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ Log.d(LOGTAG, "ARG Can't access sd card!");
+ // Can't read the SD card, fail and die!
+ getInstrumentation().sendStatus(1, null);
+ return;
+ }
+
+ // use mGraphs as a condition variable between the UI thread and
+ // this(the testing) thread
+ mActivity.setCallback(new ProfileCallback() {
+ @Override
+ public void profileCallback(RunData data) {
+ Log.d(LOGTAG, "test completion callback");
+ mStats.setData(data);
+ synchronized (mStats) {
+ mStats.notify();
+ }
+ }
+ });
+
+ for (int i = 0; i < MAX_ITERATIONS; i++)
+ if (!runIteration()) {
+ getInstrumentation().sendStatus(1, null);
+ return;
+ }
+ getInstrumentation().sendStatus(0, mStats.getBundle());
+ }
+}