frameworks/base
修訂 | 8f27b777331d888cf956dc6861125be677a63dfe (tree) |
---|---|
時間 | 2016-10-11 04:38:36 |
作者 | Jaap Jan Meijer <jjmeijer88@gmai...> |
Commiter | Jaap Jan Meijer |
Merge remote-tracking branch 'cm/cm-14.0' into cm-14.0-x86
@@ -0,0 +1,20 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2016 The CyanogenMod Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | +--> | |
17 | +<resources> | |
18 | + <!-- Largest size an avatar might need to be drawn in the power menu user picker --> | |
19 | + <dimen name="global_actions_avatar_size">40dp</dimen> | |
20 | +</resources> |
@@ -43,6 +43,8 @@ | ||
43 | 43 | |
44 | 44 | <!-- label for item that reboots the phone in phone options dialog --> |
45 | 45 | <string name="global_action_reboot">Reboot</string> |
46 | + <!-- label for current user in phone options dialog --> | |
47 | + <string name="global_action_current_user">Current</string> | |
46 | 48 | |
47 | 49 | <!-- Reboot menu --> |
48 | 50 | <!-- Button to reboot the phone, within the Reboot Options dialog --> |
@@ -72,4 +72,7 @@ | ||
72 | 72 | <!-- Automatic brightness enhancements --> |
73 | 73 | <java-symbol type="integer" name="config_autoBrightnessBrighteningLightFastDebounce"/> |
74 | 74 | |
75 | + <java-symbol type="string" name="global_action_current_user" /> | |
76 | + <java-symbol type="dimen" name="global_actions_avatar_size" /> | |
77 | + | |
75 | 78 | </resources> |
@@ -34,6 +34,7 @@ | ||
34 | 34 | android:layout_height="wrap_content" |
35 | 35 | android:layout_gravity="center_horizontal|top" |
36 | 36 | android:orientation="vertical" > |
37 | + | |
37 | 38 | <TextClock |
38 | 39 | android:id="@+id/clock_view" |
39 | 40 | android:layout_width="wrap_content" |
@@ -47,6 +48,19 @@ | ||
47 | 48 | android:layout_marginBottom="@dimen/bottom_text_spacing_digital" /> |
48 | 49 | |
49 | 50 | <include layout="@layout/keyguard_status_area" /> |
51 | + | |
52 | + <TextView android:id="@+id/weather_info" | |
53 | + android:layout_width="wrap_content" | |
54 | + android:layout_height="wrap_content" | |
55 | + android:layout_gravity="center_horizontal" | |
56 | + android:textColor="@color/clock_white" | |
57 | + style="@style/widget_label" | |
58 | + android:textAllCaps="true" | |
59 | + android:letterSpacing="0.15" | |
60 | + android:gravity="center" | |
61 | + android:singleLine="true" | |
62 | + android:visibility="gone"/> | |
63 | + | |
50 | 64 | <TextView |
51 | 65 | android:id="@+id/owner_info" |
52 | 66 | android:layout_marginLeft="16dp" |
@@ -165,9 +165,6 @@ | ||
165 | 165 | <!-- the ability to rename notifications posted by other apps --> |
166 | 166 | <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" /> |
167 | 167 | |
168 | - <!-- Weather --> | |
169 | - <uses-permission android:name="com.cyanogenmod.lockclock.permission.READ_WEATHER" /> | |
170 | - | |
171 | 168 | <!-- manage cmsettings --> |
172 | 169 | <uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS" /> |
173 | 170 | <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" /> |
@@ -20,11 +20,16 @@ | ||
20 | 20 | package="com.android.systemui"> |
21 | 21 | |
22 | 22 | <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" /> |
23 | + <uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS" /> | |
23 | 24 | |
24 | 25 | <!-- Visualizer --> |
25 | 26 | <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> |
26 | 27 | <uses-permission android:name="android.permission.RECORD_AUDIO" /> |
27 | 28 | |
29 | + <!-- Weather Provider --> | |
30 | + <uses-permission android:name="cyanogenmod.permission.READ_WEATHER" /> | |
31 | + <protected-broadcast android:name="com.cyanogenmod.lockclock.action.FORCE_WEATHER_UPDATE" /> | |
32 | + | |
28 | 33 | <application> |
29 | 34 | |
30 | 35 | <activity-alias |
@@ -0,0 +1,25 @@ | ||
1 | +<!-- | |
2 | + Copyright (C) 2015 The Android Open Source Project | |
3 | + | |
4 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + you may not use this file except in compliance with the License. | |
6 | + You may obtain a copy of the License at | |
7 | + | |
8 | + http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + | |
10 | + Unless required by applicable law or agreed to in writing, software | |
11 | + distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + See the License for the specific language governing permissions and | |
14 | + limitations under the License. | |
15 | +--> | |
16 | +<vector | |
17 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
18 | + android:width="64dp" | |
19 | + android:height="64dp" | |
20 | + android:viewportWidth="48" | |
21 | + android:viewportHeight="48"> | |
22 | + <path | |
23 | + android:fillColor="#FFFFFFFF" | |
24 | + android:pathData="M24,4C12.95,4,4,12.95,4,24s8.95,20,20,20s20-8.95,20-20S35.05,4,24,4z M34,26h-8v8h-4v-8h-8v-4h8v-8h4v8h8V26z" /> | |
25 | +</vector> |
@@ -0,0 +1,44 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2015 The CyanogenMod Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | +--> | |
17 | +<selector xmlns:android="http://schemas.android.com/apk/res/android"> | |
18 | + <ripple android:color="?android:colorControlHighlight"> | |
19 | + <item android:state_pressed="true"> | |
20 | + <shape android:shape="rectangle"> | |
21 | + <solid android:color="@color/notification_ripple_untinted_color"/> | |
22 | + </shape> | |
23 | + </item> | |
24 | + </ripple> | |
25 | + <ripple android:color="?android:colorControlHighlight"> | |
26 | + <item android:state_selected="true"> | |
27 | + <shape android:shape="rectangle"> | |
28 | + <solid android:color="@color/notification_ripple_untinted_color"/> | |
29 | + </shape> | |
30 | + </item> | |
31 | + </ripple> | |
32 | + <ripple android:color="?android:colorControlHighlight"> | |
33 | + <item android:state_focused="true"> | |
34 | + <shape android:shape="rectangle"> | |
35 | + <solid android:color="@color/notification_ripple_untinted_color"/> | |
36 | + </shape> | |
37 | + </item> | |
38 | + </ripple> | |
39 | + <item> | |
40 | + <shape android:shape="rectangle"> | |
41 | + <solid android:color="@color/notification_guts_bg_color"/> | |
42 | + </shape> | |
43 | + </item> | |
44 | +</selector> |
@@ -0,0 +1,22 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2015 The CyanogenMod Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | +--> | |
17 | +<ripple xmlns:android="http://schemas.android.com/apk/res/android" | |
18 | + android:color="?android:attr/colorControlHighlight"> | |
19 | + <item android:id="@+id/mask"> | |
20 | + <color android:color="@color/system_secondary_color"/> | |
21 | + </item> | |
22 | +</ripple> |
@@ -0,0 +1,28 @@ | ||
1 | +<!-- | |
2 | + Copyright (C) 2015 The Android Open Source Project | |
3 | + | |
4 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + you may not use this file except in compliance with the License. | |
6 | + You may obtain a copy of the License at | |
7 | + | |
8 | + http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + | |
10 | + Unless required by applicable law or agreed to in writing, software | |
11 | + distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + See the License for the specific language governing permissions and | |
14 | + limitations under the License. | |
15 | +--> | |
16 | +<inset xmlns:android="http://schemas.android.com/apk/res/android" | |
17 | + android:insetLeft="2.5dp" | |
18 | + android:insetRight="2.5dp"> | |
19 | + <vector | |
20 | + android:width="17dp" | |
21 | + android:height="17dp" | |
22 | + android:viewportHeight="48" | |
23 | + android:viewportWidth="48"> | |
24 | + <path | |
25 | + android:fillColor="#FFFFFFFF" | |
26 | + android:pathData="M24,4C12.95,4,4,12.95,4,24s8.95,20,20,20s20-8.95,20-20S35.05,4,24,4z M34,26h-8v8h-4v-8h-8v-4h8v-8h4v8h8V26z" /> | |
27 | + </vector> | |
28 | +</inset> |
@@ -184,4 +184,14 @@ | ||
184 | 184 | android:layout_marginEnd="8dp" |
185 | 185 | android:focusable="true"/> |
186 | 186 | </LinearLayout> |
187 | + | |
188 | + <!-- Stub for the media extension guts --> | |
189 | + <ViewStub | |
190 | + android:layout="@layout/notification_guts_media_extension" | |
191 | + android:id="@+id/notification_guts_media_stub" | |
192 | + android:inflatedId="@+id/notification_guts_media_extension" | |
193 | + android:layout_width="match_parent" | |
194 | + android:layout_height="wrap_content" | |
195 | + /> | |
196 | + | |
187 | 197 | </com.android.systemui.statusbar.NotificationGuts> |
@@ -0,0 +1,42 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright 2016, The CyanogenMod Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | +--> | |
17 | +<com.android.systemui.statusbar.MediaNotificationGuts | |
18 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
19 | + android:id="@+id/notification_guts_media_extension" | |
20 | + android:padding="8dp" | |
21 | + android:layout_width="match_parent" | |
22 | + android:layout_height="wrap_content" | |
23 | + android:gravity="end" | |
24 | + android:orientation="horizontal"> | |
25 | + <TextView | |
26 | + android:id="@+id/switch_label" | |
27 | + android:theme="@style/TextAppearance.NotificationGuts.Button" | |
28 | + android:layout_height="wrap_content" | |
29 | + android:layout_width="0dp" | |
30 | + android:layout_weight="1" | |
31 | + android:paddingEnd="8dp" | |
32 | + android:gravity="end" | |
33 | + android:text="@string/play_queue_extension"/> | |
34 | + <Switch | |
35 | + android:layout_width="wrap_content" | |
36 | + android:layout_height="wrap_content" | |
37 | + android:layout_weight="0" | |
38 | + android:theme="@style/ThemeOverlay.SwitchBar.Secondary" | |
39 | + android:paddingStart="8dp" | |
40 | + android:gravity="center" | |
41 | + android:id="@+id/queue_switch"/> | |
42 | +</com.android.systemui.statusbar.MediaNotificationGuts> |
@@ -0,0 +1,54 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2015 The CyanogenMod Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | +--> | |
17 | +<com.android.systemui.statusbar.QueueViewRow | |
18 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
19 | + android:layout_width="match_parent" | |
20 | + android:background="@drawable/queue_bg" | |
21 | + android:layout_height="@dimen/queue_row_height" | |
22 | + android:paddingTop="4dp" | |
23 | + android:paddingBottom="4dp" | |
24 | + android:paddingStart="16dp" | |
25 | + android:paddingEnd="16dp"> | |
26 | + | |
27 | + <ImageView | |
28 | + android:layout_width="wrap_content" | |
29 | + android:layout_height="wrap_content" | |
30 | + android:id="@+id/art" | |
31 | + android:layout_alignParentStart="true" | |
32 | + android:layout_centerVertical="true"/> | |
33 | + | |
34 | + <LinearLayout | |
35 | + android:orientation="vertical" | |
36 | + android:layout_width="wrap_content" | |
37 | + android:layout_height="wrap_content" | |
38 | + android:layout_toEndOf="@+id/action" | |
39 | + android:layout_centerVertical="true"> | |
40 | + | |
41 | + <TextView | |
42 | + android:layout_width="wrap_content" | |
43 | + android:layout_height="wrap_content" | |
44 | + style="@style/TextAppearance.NotificationGuts.Primary" | |
45 | + android:id="@+id/title"/> | |
46 | + | |
47 | + <TextView | |
48 | + android:layout_width="wrap_content" | |
49 | + android:layout_height="wrap_content" | |
50 | + style="@style/TextAppearance.NotificationGuts.Header" | |
51 | + android:id="@+id/summary"/> | |
52 | + </LinearLayout> | |
53 | + | |
54 | +</com.android.systemui.statusbar.QueueViewRow> |
@@ -113,7 +113,6 @@ | ||
113 | 113 | android:layout_width="wrap_content" |
114 | 114 | android:layout_height="wrap_content" |
115 | 115 | android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin" |
116 | - android:background="@drawable/ripple_drawable" | |
117 | 116 | android:layout_alignParentBottom="true"> |
118 | 117 | <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed" |
119 | 118 | android:layout_width="wrap_content" |
@@ -121,6 +120,7 @@ | ||
121 | 120 | android:layout_marginStart="16dp" |
122 | 121 | android:singleLine="true" |
123 | 122 | android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" |
123 | + android:background="@drawable/ripple_drawable" | |
124 | 124 | android:layout_below="@id/clock" |
125 | 125 | systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" |
126 | 126 | /> |
@@ -131,6 +131,7 @@ | ||
131 | 131 | android:layout_marginStart="16dp" |
132 | 132 | android:singleLine="true" |
133 | 133 | android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date" |
134 | + android:background="@drawable/ripple_drawable" | |
134 | 135 | android:layout_below="@id/clock" |
135 | 136 | systemui:datePattern="eeeeMMMMd" |
136 | 137 | /> |
@@ -183,7 +184,7 @@ | ||
183 | 184 | android:layout_height="wrap_content" |
184 | 185 | android:paddingEnd="16dp" |
185 | 186 | android:gravity="right" |
186 | - android:textColor="#ffffff" | |
187 | + android:textColor="@color/status_bar_temperature_text_color" | |
187 | 188 | android:textSize="@dimen/weather_text_size" |
188 | 189 | android:importantForAccessibility="noHideDescendants"/> |
189 | 190 | <TextView |
@@ -192,7 +193,7 @@ | ||
192 | 193 | android:layout_height="wrap_content" |
193 | 194 | android:paddingEnd="16dp" |
194 | 195 | android:gravity="right" |
195 | - android:textColor="#ffffff" | |
196 | + android:textColor="@color/status_bar_temperature_location_text_color" | |
196 | 197 | android:textSize="@dimen/weather_text_size" |
197 | 198 | android:importantForAccessibility="noHideDescendants"/> |
198 | 199 | </LinearLayout> |
@@ -0,0 +1,112 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright 2014, The Android Open Source Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | +--> | |
17 | + | |
18 | +<com.android.systemui.statusbar.MediaExpandableNotificationRow | |
19 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
20 | + android:layout_width="match_parent" | |
21 | + android:layout_height="wrap_content" | |
22 | + android:focusable="true" | |
23 | + android:clickable="true" | |
24 | + > | |
25 | + | |
26 | + <ViewStub | |
27 | + android:layout="@layout/notification_settings_icon_row" | |
28 | + android:id="@+id/settings_icon_row_stub" | |
29 | + android:inflatedId="@+id/notification_settings_icon_row" | |
30 | + android:layout_width="wrap_content" | |
31 | + android:layout_height="match_parent" | |
32 | + /> | |
33 | + | |
34 | + <com.android.systemui.statusbar.NotificationBackgroundView | |
35 | + android:id="@+id/backgroundNormal" | |
36 | + android:layout_width="match_parent" | |
37 | + android:layout_height="match_parent" /> | |
38 | + | |
39 | + <com.android.systemui.statusbar.NotificationBackgroundView | |
40 | + android:id="@+id/backgroundDimmed" | |
41 | + android:layout_width="match_parent" | |
42 | + android:layout_height="match_parent" /> | |
43 | + | |
44 | + <LinearLayout | |
45 | + android:orientation="vertical" | |
46 | + android:clipChildren="false" | |
47 | + android:layout_width="match_parent" | |
48 | + android:layout_height="wrap_content"> | |
49 | + | |
50 | + <FrameLayout | |
51 | + android:layout_width="match_parent" | |
52 | + android:layout_height="wrap_content" | |
53 | + android:elevation="10dp"> | |
54 | + | |
55 | + <com.android.systemui.statusbar.NotificationContentView android:id="@+id/expanded" | |
56 | + android:layout_width="match_parent" | |
57 | + android:layout_height="wrap_content" /> | |
58 | + | |
59 | + <com.android.systemui.statusbar.NotificationContentView android:id="@+id/expandedPublic" | |
60 | + android:layout_width="match_parent" | |
61 | + android:layout_height="wrap_content" /> | |
62 | + </FrameLayout> | |
63 | + | |
64 | + <com.android.systemui.statusbar.QueueView | |
65 | + android:id="@+id/queue_view" | |
66 | + android:clipChildren="false" | |
67 | + android:orientation="vertical" | |
68 | + android:background="@drawable/queue_bg" | |
69 | + android:layout_width="match_parent" | |
70 | + android:layout_height="wrap_content" | |
71 | + android:elevation="0dp"> | |
72 | + <ListView | |
73 | + android:id="@+id/queue_list" | |
74 | + android:layout_width="match_parent" | |
75 | + android:layout_height="wrap_content"/> | |
76 | + </com.android.systemui.statusbar.QueueView> | |
77 | + | |
78 | + </LinearLayout> | |
79 | + | |
80 | + <Button | |
81 | + android:id="@+id/veto" | |
82 | + android:layout_width="48dp" | |
83 | + android:layout_height="0dp" | |
84 | + android:gravity="end" | |
85 | + android:layout_marginEnd="-80dp" | |
86 | + android:background="@null" | |
87 | + android:paddingEnd="8dp" | |
88 | + android:paddingStart="8dp" | |
89 | + /> | |
90 | + | |
91 | + <ViewStub | |
92 | + android:layout="@layout/notification_children_container" | |
93 | + android:id="@+id/child_container_stub" | |
94 | + android:inflatedId="@+id/notification_children_container" | |
95 | + android:layout_width="match_parent" | |
96 | + android:layout_height="wrap_content" | |
97 | + /> | |
98 | + | |
99 | + <ViewStub | |
100 | + android:layout="@layout/notification_guts" | |
101 | + android:id="@+id/notification_guts_stub" | |
102 | + android:inflatedId="@+id/notification_guts" | |
103 | + android:layout_width="match_parent" | |
104 | + android:layout_height="wrap_content" | |
105 | + /> | |
106 | + | |
107 | + <com.android.systemui.statusbar.notification.FakeShadowView | |
108 | + android:id="@+id/fake_shadow" | |
109 | + android:layout_width="match_parent" | |
110 | + android:layout_height="match_parent" /> | |
111 | + | |
112 | +</com.android.systemui.statusbar.MediaExpandableNotificationRow> |
@@ -0,0 +1,23 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2016 The CyanogenMod Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | +--> | |
17 | +<resources> | |
18 | + | |
19 | + <!-- Expanded Status Bar Weather Text Colors --> | |
20 | + <color name="status_bar_temperature_text_color">#FFFFFFFF</color> | |
21 | + <color name="status_bar_temperature_location_text_color">#FFFFFFFF</color> | |
22 | + | |
23 | +</resources> |
@@ -23,4 +23,8 @@ | ||
23 | 23 | <dimen name="phone_bottom_padding">40dp</dimen> |
24 | 24 | <dimen name="phone_width">320dp</dimen> |
25 | 25 | <dimen name="phone_height">420dp</dimen> |
26 | + | |
27 | + <dimen name="queue_row_height">52dp</dimen> | |
28 | + <dimen name="queue_top_shadow">3dp</dimen> | |
29 | + | |
26 | 30 | </resources> |
@@ -48,4 +48,11 @@ | ||
48 | 48 | <string name="select_application">Select application</string> |
49 | 49 | <string name="lockscreen_choose_action_title">Choose action</string> |
50 | 50 | <string name="lockscreen_none_target">None</string> |
51 | + | |
52 | + <!-- Play queue --> | |
53 | + <string name="play_queue_extension">Show play queue</string> | |
54 | + | |
55 | + <!-- Weather string format in keyguard --> | |
56 | + <string name="keyguard_status_view_weather_format"><xliff:g id="temp">%1$s</xliff:g> <xliff:g id="condition">%2$s</xliff:g></string> | |
57 | + | |
51 | 58 | </resources> |
@@ -309,9 +309,6 @@ | ||
309 | 309 | <!-- Show 4GLTE for LTE --> |
310 | 310 | <bool name="show_4glte_icon_for_lte">false</bool> |
311 | 311 | |
312 | - <!-- When true, show charging animation --> | |
313 | - <bool name="config_show_battery_charging_anim">false</bool> | |
314 | - | |
315 | 312 | <bool name="config_show4gForIWlan">false</bool> |
316 | 313 | <bool name="config_showSignalForIWlan">false</bool> |
317 | 314 | </resources> |
@@ -369,4 +369,8 @@ | ||
369 | 369 | <item name="android:colorBackground">@color/qs_edit_overflow_bg</item> |
370 | 370 | </style> |
371 | 371 | |
372 | + <style name="ThemeOverlay.SwitchBar.Secondary" parent="@android:style/ThemeOverlay"> | |
373 | + <item name="android:colorAccent">@color/system_secondary_color</item> | |
374 | + </style> | |
375 | + | |
372 | 376 | </resources> |
@@ -100,17 +100,6 @@ public class BatteryMeterDrawable extends Drawable implements | ||
100 | 100 | private int mLevel = -1; |
101 | 101 | private boolean mPluggedIn; |
102 | 102 | private boolean mListening; |
103 | - private static final int ADD_LEVEL = 10; | |
104 | - private static final int ANIM_DURATION = 500; | |
105 | - private int mAnimOffset; | |
106 | - private boolean mCharging; | |
107 | - | |
108 | - private final Runnable mInvalidate = new Runnable() { | |
109 | - @Override | |
110 | - public void run() { | |
111 | - invalidateSelf(); | |
112 | - } | |
113 | - }; | |
114 | 103 | |
115 | 104 | public BatteryMeterDrawable(Context context, Handler handler, int frameColor) { |
116 | 105 | mContext = context; |
@@ -210,7 +199,12 @@ public class BatteryMeterDrawable extends Drawable implements | ||
210 | 199 | } |
211 | 200 | |
212 | 201 | private void postInvalidate() { |
213 | - mHandler.post(mInvalidate); | |
202 | + mHandler.post(new Runnable() { | |
203 | + @Override | |
204 | + public void run() { | |
205 | + invalidateSelf(); | |
206 | + } | |
207 | + }); | |
214 | 208 | } |
215 | 209 | |
216 | 210 | public void setBatteryController(BatteryController batteryController) { |
@@ -222,7 +216,7 @@ public class BatteryMeterDrawable extends Drawable implements | ||
222 | 216 | public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { |
223 | 217 | mLevel = level; |
224 | 218 | mPluggedIn = pluggedIn; |
225 | - mCharging = charging; | |
219 | + | |
226 | 220 | postInvalidate(); |
227 | 221 | } |
228 | 222 |
@@ -232,26 +226,6 @@ public class BatteryMeterDrawable extends Drawable implements | ||
232 | 226 | invalidateSelf(); |
233 | 227 | } |
234 | 228 | |
235 | - private int updateChargingAnimLevel() { | |
236 | - int curLevel = mLevel; | |
237 | - if (!mCharging) { | |
238 | - mAnimOffset = 0; | |
239 | - mHandler.removeCallbacks(mInvalidate); | |
240 | - } else { | |
241 | - curLevel += mAnimOffset; | |
242 | - if (curLevel >= FULL) { | |
243 | - curLevel = 100; | |
244 | - mAnimOffset = 0; | |
245 | - } else { | |
246 | - mAnimOffset += ADD_LEVEL; | |
247 | - } | |
248 | - | |
249 | - mHandler.removeCallbacks(mInvalidate); | |
250 | - mHandler.postDelayed(mInvalidate, ANIM_DURATION); | |
251 | - } | |
252 | - return curLevel; | |
253 | - } | |
254 | - | |
255 | 229 | private static float[] loadBoltPoints(Resources res) { |
256 | 230 | final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points); |
257 | 231 | int maxX = 0, maxY = 0; |
@@ -349,11 +323,7 @@ public class BatteryMeterDrawable extends Drawable implements | ||
349 | 323 | |
350 | 324 | @Override |
351 | 325 | public void draw(Canvas c) { |
352 | - final boolean showChargingAnim | |
353 | - = mContext.getResources().getBoolean(R.bool.config_show_battery_charging_anim); | |
354 | - final int level = showChargingAnim | |
355 | - ? updateChargingAnimLevel() | |
356 | - : mLevel; | |
326 | + final int level = mLevel; | |
357 | 327 | |
358 | 328 | if (level == -1) return; |
359 | 329 |
@@ -547,4 +517,5 @@ public class BatteryMeterDrawable extends Drawable implements | ||
547 | 517 | postInvalidate(); |
548 | 518 | } |
549 | 519 | } |
520 | + | |
550 | 521 | } |
@@ -34,6 +34,7 @@ import android.view.ViewConfiguration; | ||
34 | 34 | import com.android.systemui.statusbar.ExpandableNotificationRow; |
35 | 35 | import com.android.systemui.statusbar.ExpandableView; |
36 | 36 | import com.android.systemui.statusbar.FlingAnimationUtils; |
37 | +import com.android.systemui.statusbar.MediaExpandableNotificationRow; | |
37 | 38 | import com.android.systemui.statusbar.policy.ScrollAdapter; |
38 | 39 | |
39 | 40 | public class ExpandHelper implements Gefingerpoken { |
@@ -97,7 +98,7 @@ public class ExpandHelper implements Gefingerpoken { | ||
97 | 98 | private float mCurrentHeight; |
98 | 99 | |
99 | 100 | private int mSmallSize; |
100 | - private int mLargeSize; | |
101 | + private int mLargeSize, mInitialLargeSize; | |
101 | 102 | private float mMaximumStretch; |
102 | 103 | private boolean mOnlyMovements; |
103 | 104 |
@@ -162,6 +163,7 @@ public class ExpandHelper implements Gefingerpoken { | ||
162 | 163 | mSmallSize = small; |
163 | 164 | mMaximumStretch = mSmallSize * STRETCH_INTERVAL; |
164 | 165 | mLargeSize = large; |
166 | + mInitialLargeSize = large; | |
165 | 167 | mContext = context; |
166 | 168 | mCallback = callback; |
167 | 169 | mScaler = new ViewScaler(); |
@@ -515,8 +517,15 @@ public class ExpandHelper implements Gefingerpoken { | ||
515 | 517 | boolean canBeExpanded = mCallback.canChildBeExpanded(v); |
516 | 518 | if (canBeExpanded) { |
517 | 519 | if (DEBUG) Log.d(TAG, "working on an expandable child"); |
518 | - mNaturalHeight = mScaler.getNaturalHeight(); | |
519 | 520 | mSmallSize = v.getCollapsedHeight(); |
521 | + if (v instanceof MediaExpandableNotificationRow) { | |
522 | + final int maxHeight = ((MediaExpandableNotificationRow) v).getMaxContentHeight(); | |
523 | + mLargeSize = maxHeight; | |
524 | + mNaturalHeight = maxHeight; | |
525 | + } else { | |
526 | + mLargeSize = mInitialLargeSize; | |
527 | + mNaturalHeight = mScaler.getNaturalHeight(); | |
528 | + } | |
520 | 529 | } else { |
521 | 530 | if (DEBUG) Log.d(TAG, "working on a non-expandable child"); |
522 | 531 | mNaturalHeight = mOldHeight; |
@@ -142,7 +142,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> { | ||
142 | 142 | checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME); |
143 | 143 | switch (zen) { |
144 | 144 | case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: |
145 | - state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on); | |
145 | + state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on_priority); | |
146 | 146 | state.label = mContext.getString(R.string.quick_settings_dnd_priority_label); |
147 | 147 | state.contentDescription = mContext.getString( |
148 | 148 | R.string.accessibility_quick_settings_dnd_priority_on); |
@@ -44,6 +44,7 @@ import android.database.ContentObserver; | ||
44 | 44 | import android.graphics.Rect; |
45 | 45 | import android.graphics.drawable.Drawable; |
46 | 46 | import android.graphics.drawable.Icon; |
47 | +import android.media.session.MediaController; | |
47 | 48 | import android.os.AsyncTask; |
48 | 49 | import android.os.Build; |
49 | 50 | import android.os.Bundle; |
@@ -906,6 +907,10 @@ public abstract class BaseStatusBar extends SystemUI implements | ||
906 | 907 | return null; |
907 | 908 | } |
908 | 909 | |
910 | + protected MediaController getCurrentMediaController() { | |
911 | + return null; | |
912 | + } | |
913 | + | |
909 | 914 | @Override |
910 | 915 | public NotificationGroupManager getGroupManager() { |
911 | 916 | return mGroupManager; |
@@ -1157,6 +1162,10 @@ public abstract class BaseStatusBar extends SystemUI implements | ||
1157 | 1162 | } |
1158 | 1163 | |
1159 | 1164 | final ExpandableNotificationRow row = (ExpandableNotificationRow) v; |
1165 | + if (v instanceof MediaExpandableNotificationRow | |
1166 | + && !((MediaExpandableNotificationRow) v).inflateGuts()) { | |
1167 | + return false; | |
1168 | + } | |
1160 | 1169 | bindGuts(row); |
1161 | 1170 | |
1162 | 1171 | // Assume we are a status_bar_notification_row |
@@ -1618,8 +1627,20 @@ public abstract class BaseStatusBar extends SystemUI implements | ||
1618 | 1627 | // create the row view |
1619 | 1628 | LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( |
1620 | 1629 | Context.LAYOUT_INFLATER_SERVICE); |
1621 | - row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row, | |
1622 | - parent, false); | |
1630 | + | |
1631 | + // cannot use isMediaNotification() | |
1632 | + if (sbn.getNotification().category != null | |
1633 | + && sbn.getNotification().category.equals(Notification.CATEGORY_TRANSPORT)) { | |
1634 | + Log.d("ro", "inflating media notification"); | |
1635 | + row = (MediaExpandableNotificationRow) inflater.inflate( | |
1636 | + R.layout.status_bar_notification_row_media, parent, false); | |
1637 | + ((MediaExpandableNotificationRow)row).setMediaController( | |
1638 | + getCurrentMediaController()); | |
1639 | + } else { | |
1640 | + row = (ExpandableNotificationRow) inflater.inflate( | |
1641 | + R.layout.status_bar_notification_row, | |
1642 | + parent, false); | |
1643 | + } | |
1623 | 1644 | row.setExpansionLogger(this, entry.notification.getKey()); |
1624 | 1645 | row.setGroupManager(mGroupManager); |
1625 | 1646 | row.setHeadsUpManager(mHeadsUpManager); |
@@ -88,7 +88,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { | ||
88 | 88 | private boolean mSensitive; |
89 | 89 | private boolean mSensitiveHiddenInGeneral; |
90 | 90 | private boolean mShowingPublicInitialized; |
91 | - private boolean mHideSensitiveForIntrinsicHeight; | |
91 | + protected boolean mHideSensitiveForIntrinsicHeight; | |
92 | 92 | |
93 | 93 | /** |
94 | 94 | * Is this notification expanded by the system. The expansion state can be overridden by the |
@@ -103,10 +103,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { | ||
103 | 103 | |
104 | 104 | private Animator mTranslateAnim; |
105 | 105 | private ArrayList<View> mTranslateableViews; |
106 | - private NotificationContentView mPublicLayout; | |
107 | - private NotificationContentView mPrivateLayout; | |
108 | - private int mMaxExpandHeight; | |
109 | - private int mHeadsUpHeight; | |
106 | + protected NotificationContentView mPublicLayout; | |
107 | + protected NotificationContentView mPrivateLayout; | |
108 | + protected int mMaxExpandHeight; | |
109 | + protected int mHeadsUpHeight; | |
110 | 110 | private View mVetoButton; |
111 | 111 | private int mNotificationColor; |
112 | 112 | private ExpansionLogger mLogger; |
@@ -124,7 +124,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { | ||
124 | 124 | private boolean mIsSummaryWithChildren; |
125 | 125 | private NotificationChildrenContainer mChildrenContainer; |
126 | 126 | private ViewStub mSettingsIconRowStub; |
127 | - private ViewStub mGutsStub; | |
127 | + protected ViewStub mGutsStub; | |
128 | 128 | private boolean mIsSystemChildExpanded; |
129 | 129 | private boolean mIsPinned; |
130 | 130 | private FalsingManager mFalsingManager; |
@@ -1003,10 +1003,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { | ||
1003 | 1003 | return mSettingsIconRow; |
1004 | 1004 | } |
1005 | 1005 | |
1006 | - public void inflateGuts() { | |
1006 | + public boolean inflateGuts() { | |
1007 | 1007 | if (mGuts == null) { |
1008 | 1008 | mGutsStub.inflate(); |
1009 | 1009 | } |
1010 | + return false; | |
1010 | 1011 | } |
1011 | 1012 | |
1012 | 1013 | private void updateChildrenVisibility() { |
@@ -1264,7 +1265,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { | ||
1264 | 1265 | } |
1265 | 1266 | } |
1266 | 1267 | |
1267 | - private void updateMaxHeights() { | |
1268 | + protected void updateMaxHeights() { | |
1268 | 1269 | int intrinsicBefore = getIntrinsicHeight(); |
1269 | 1270 | View expandedChild = mPrivateLayout.getExpandedChild(); |
1270 | 1271 | if (expandedChild == null) { |
@@ -38,7 +38,7 @@ public abstract class ExpandableView extends FrameLayout { | ||
38 | 38 | protected int mClipTopAmount; |
39 | 39 | private boolean mDark; |
40 | 40 | private ArrayList<View> mMatchParentViews = new ArrayList<View>(); |
41 | - private static Rect mClipRect = new Rect(); | |
41 | + private Rect mClipRect = new Rect(); | |
42 | 42 | private boolean mWillBeGone; |
43 | 43 | private int mMinClipTopAmount = 0; |
44 | 44 | private boolean mClipToActualHeight = true; |
@@ -0,0 +1,161 @@ | ||
1 | +/* | |
2 | + * Copyright (C) 2015 The CyanogenMod Project | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License | |
15 | + */ | |
16 | +package com.android.systemui.statusbar; | |
17 | + | |
18 | +import android.content.Context; | |
19 | +import android.content.res.Resources; | |
20 | +import android.media.session.MediaController; | |
21 | +import android.util.AttributeSet; | |
22 | +import android.util.Log; | |
23 | +import android.view.MotionEvent; | |
24 | +import android.view.View; | |
25 | +import android.view.ViewStub; | |
26 | + | |
27 | +import com.android.systemui.R; | |
28 | +import com.android.systemui.tuner.TunerService; | |
29 | + | |
30 | +public class MediaExpandableNotificationRow extends ExpandableNotificationRow | |
31 | + implements TunerService.Tunable { | |
32 | + | |
33 | + private static final String TAG = MediaExpandableNotificationRow.class.getSimpleName(); | |
34 | + public static final boolean DEBUG = false; | |
35 | + | |
36 | + public static final int MAX_QUEUE_ENTRIES = 3; | |
37 | + | |
38 | + private QueueView mQueue; | |
39 | + | |
40 | + private int mMaxQueueHeight; | |
41 | + private int mRowHeight; | |
42 | + private int mShadowHeight; | |
43 | + private int mDisplayedRows; | |
44 | + | |
45 | + private boolean mQueueEnabled = false; | |
46 | + | |
47 | + private static final String NOTIFICATION_PLAY_QUEUE = "cmsystem:" + | |
48 | + cyanogenmod.providers.CMSettings.System.NOTIFICATION_PLAY_QUEUE; | |
49 | + | |
50 | + public MediaExpandableNotificationRow(Context context, AttributeSet attrs) { | |
51 | + super(context, attrs); | |
52 | + | |
53 | + Resources res = mContext.getResources(); | |
54 | + | |
55 | + // 3 * queue_row_height + shadow height | |
56 | + mRowHeight = res.getDimensionPixelSize(R.dimen.queue_row_height); | |
57 | + mShadowHeight = res.getDimensionPixelSize(R.dimen.queue_top_shadow); | |
58 | + } | |
59 | + | |
60 | + @Override | |
61 | + protected void onAttachedToWindow() { | |
62 | + super.onAttachedToWindow(); | |
63 | + TunerService.get(getContext()).addTunable(this, NOTIFICATION_PLAY_QUEUE); | |
64 | + } | |
65 | + | |
66 | + @Override | |
67 | + protected void onDetachedFromWindow() { | |
68 | + TunerService.get(getContext()).removeTunable(this); | |
69 | + super.onDetachedFromWindow(); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public void onTuningChanged(String key, String newValue) { | |
74 | + if (NOTIFICATION_PLAY_QUEUE.equals(key) && mQueue != null) { | |
75 | + boolean show = newValue == null || Integer.valueOf(newValue) == 1; | |
76 | + showQueue(show); | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + @Override | |
81 | + public boolean inflateGuts() { | |
82 | + if (getGuts() == null) { | |
83 | + View guts = mGutsStub.inflate(); | |
84 | + ViewStub mediaGuts = (ViewStub) guts.findViewById(R.id.notification_guts_media_stub); | |
85 | + mediaGuts.inflate(); | |
86 | + } | |
87 | + if (!mQueueEnabled) { | |
88 | + return true; | |
89 | + } | |
90 | + return !mQueue.isUserSelectingRow(); | |
91 | + } | |
92 | + | |
93 | + @Override | |
94 | + protected void onFinishInflate() { | |
95 | + super.onFinishInflate(); | |
96 | + mQueue = (QueueView) findViewById(R.id.queue_view); | |
97 | + showQueue(mQueueEnabled); | |
98 | + } | |
99 | + | |
100 | + private void showQueue(boolean show) { | |
101 | + if (show != mQueueEnabled) { | |
102 | + mQueueEnabled = show; | |
103 | + mQueue.setQueueEnabled(mQueueEnabled); | |
104 | + mQueue.setVisibility(mQueueEnabled ? View.VISIBLE : View.GONE); | |
105 | + requestLayout(); | |
106 | + } | |
107 | + } | |
108 | + | |
109 | + public void setMediaController(MediaController mediaController) { | |
110 | + if (DEBUG) Log.d(TAG, "setMediaController() called with " | |
111 | + + "mediaController = [" + mediaController + "]"); | |
112 | + if (mQueue != null && mQueue.setController(mediaController) && mQueueEnabled) { | |
113 | + notifyHeightChanged(true); | |
114 | + } | |
115 | + } | |
116 | + | |
117 | + @Override | |
118 | + protected void updateMaxHeights() { | |
119 | + // update queue height based on number of rows | |
120 | + int rows = mQueue != null ? mQueue.getCurrentQueueRowCount() : 0; | |
121 | + if (rows != mDisplayedRows) { | |
122 | + mMaxQueueHeight = rows * mRowHeight; | |
123 | + if (mMaxQueueHeight > 0) { | |
124 | + mMaxQueueHeight += mShadowHeight; | |
125 | + } | |
126 | + mDisplayedRows = rows; | |
127 | + } | |
128 | + | |
129 | + int intrinsicBefore = getIntrinsicHeight(); | |
130 | + View expandedChild = mPrivateLayout.getExpandedChild(); | |
131 | + if (expandedChild == null) { | |
132 | + expandedChild = mPrivateLayout.getContractedChild(); | |
133 | + } | |
134 | + mMaxExpandHeight = expandedChild.getHeight() + mMaxQueueHeight; | |
135 | + View headsUpChild = mPrivateLayout.getHeadsUpChild(); | |
136 | + if (headsUpChild == null) { | |
137 | + headsUpChild = mPrivateLayout.getContractedChild(); | |
138 | + } | |
139 | + mHeadsUpHeight = headsUpChild.getHeight(); | |
140 | + if (intrinsicBefore != getIntrinsicHeight()) { | |
141 | + notifyHeightChanged(false /* needsAnimation */); | |
142 | + } | |
143 | + } | |
144 | + | |
145 | + @Override | |
146 | + public int getMaxContentHeight() { | |
147 | + return super.getMaxContentHeight() + mMaxQueueHeight; | |
148 | + } | |
149 | + | |
150 | + @Override | |
151 | + public boolean dispatchTouchEvent(MotionEvent event) { | |
152 | + if (mQueueEnabled && isExpanded() && mQueue.isUserSelectingRow() | |
153 | + && event.getActionMasked() != MotionEvent.ACTION_DOWN | |
154 | + && event.getActionMasked() != MotionEvent.ACTION_UP | |
155 | + && event.getActionMasked() != MotionEvent.ACTION_CANCEL) { | |
156 | + // this is for hotspot propogation? | |
157 | + return false; | |
158 | + } | |
159 | + return super.dispatchTouchEvent(event); | |
160 | + } | |
161 | +} |
@@ -0,0 +1,82 @@ | ||
1 | +/* | |
2 | + * Copyright (C) 2015 The CyanogenMod Project | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License | |
15 | + */ | |
16 | + | |
17 | +package com.android.systemui.statusbar; | |
18 | + | |
19 | +import android.content.Context; | |
20 | +import android.graphics.Canvas; | |
21 | +import android.util.AttributeSet; | |
22 | +import android.view.View; | |
23 | +import android.view.ViewGroup; | |
24 | +import android.widget.CompoundButton; | |
25 | +import android.widget.LinearLayout; | |
26 | +import android.widget.Switch; | |
27 | +import android.widget.TextView; | |
28 | + | |
29 | +import com.android.systemui.R; | |
30 | + | |
31 | +import cyanogenmod.providers.CMSettings; | |
32 | + | |
33 | +/** | |
34 | + * The guts of a media notification revealed when performing a long press. | |
35 | + */ | |
36 | +public class MediaNotificationGuts extends LinearLayout { | |
37 | + | |
38 | + private static final String TAG = MediaNotificationGuts.class.getSimpleName(); | |
39 | + | |
40 | + private ViewGroup mQueueGroup; | |
41 | + private TextView mText; | |
42 | + private Switch mSwitch; | |
43 | + | |
44 | + public MediaNotificationGuts(Context context, AttributeSet attrs) { | |
45 | + super(context, attrs); | |
46 | + | |
47 | + setWillNotDraw(true); | |
48 | + } | |
49 | + | |
50 | + @Override | |
51 | + protected void onDraw(Canvas canvas) { | |
52 | + // do nothing! | |
53 | + } | |
54 | + | |
55 | + @Override | |
56 | + protected void onFinishInflate() { | |
57 | + super.onFinishInflate(); | |
58 | + mQueueGroup = (ViewGroup) findViewById(R.id.notification_guts_media_extension); | |
59 | + | |
60 | + mSwitch = (Switch) findViewById(R.id.queue_switch); | |
61 | + boolean enabled = CMSettings.System.getInt(getContext().getContentResolver(), | |
62 | + CMSettings.System.NOTIFICATION_PLAY_QUEUE, 1) == 1; | |
63 | + | |
64 | + mSwitch.setChecked(enabled); | |
65 | + mText = (TextView) findViewById(R.id.switch_label); | |
66 | + mText.setOnClickListener(new OnClickListener() { | |
67 | + @Override | |
68 | + public void onClick(View v) { | |
69 | + mSwitch.toggle(); | |
70 | + } | |
71 | + }); | |
72 | + mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { | |
73 | + @Override | |
74 | + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | |
75 | + buttonView.setChecked(isChecked); | |
76 | + CMSettings.System.putInt(getContext().getContentResolver(), | |
77 | + CMSettings.System.NOTIFICATION_PLAY_QUEUE, | |
78 | + isChecked ? 1 : 0); | |
79 | + } | |
80 | + }); | |
81 | + } | |
82 | +} |
@@ -58,9 +58,9 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab | ||
58 | 58 | |
59 | 59 | private static final long CLOSE_GUTS_DELAY = 8000; |
60 | 60 | |
61 | - private Drawable mBackground; | |
62 | - private int mClipTopAmount; | |
63 | - private int mActualHeight; | |
61 | + protected Drawable mBackground; | |
62 | + protected int mClipTopAmount; | |
63 | + protected int mActualHeight; | |
64 | 64 | private boolean mExposed; |
65 | 65 | private INotificationManager mINotificationManager; |
66 | 66 | private int mStartingUserImportance; |
@@ -0,0 +1,254 @@ | ||
1 | +/* | |
2 | + * Copyright (C) 2015 The CyanogenMod Project | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License | |
15 | + */ | |
16 | +package com.android.systemui.statusbar; | |
17 | + | |
18 | +import android.annotation.NonNull; | |
19 | +import android.annotation.Nullable; | |
20 | +import android.content.Context; | |
21 | +import android.media.MediaDescription; | |
22 | +import android.media.MediaMetadata; | |
23 | +import android.media.session.MediaController; | |
24 | +import android.media.session.MediaSession; | |
25 | +import android.media.session.PlaybackState; | |
26 | +import android.os.Handler; | |
27 | +import android.provider.Settings; | |
28 | +import android.util.AttributeSet; | |
29 | +import android.util.Log; | |
30 | +import android.view.LayoutInflater; | |
31 | +import android.view.View; | |
32 | +import android.view.ViewGroup; | |
33 | +import android.widget.AdapterView; | |
34 | +import android.widget.ArrayAdapter; | |
35 | +import android.widget.LinearLayout; | |
36 | +import android.widget.ListView; | |
37 | +import com.android.systemui.R; | |
38 | +import com.android.systemui.cm.UserContentObserver; | |
39 | + | |
40 | +import java.util.ArrayList; | |
41 | +import java.util.List; | |
42 | + | |
43 | +public class QueueView extends LinearLayout implements | |
44 | + QueueViewRow.UserRowInteractionListener, AdapterView.OnItemClickListener, | |
45 | + AdapterView.OnItemLongClickListener { | |
46 | + | |
47 | + private static final String TAG = QueueView.class.getSimpleName(); | |
48 | + private static final boolean DEBUG = MediaExpandableNotificationRow.DEBUG; | |
49 | + | |
50 | + private MediaController mController; | |
51 | + | |
52 | + private List<MediaSession.QueueItem> mQueue = new ArrayList<>(getMaxQueueRowCount()); | |
53 | + | |
54 | + private QueueItemAdapter mAdapter; | |
55 | + private ListView mList; | |
56 | + private boolean mQueueEnabled; | |
57 | + | |
58 | + long mLastUserInteraction = -1; | |
59 | + | |
60 | + private MediaController.Callback mCallback = new MediaController.Callback() { | |
61 | + @Override | |
62 | + public void onPlaybackStateChanged(@NonNull PlaybackState state) { | |
63 | + super.onPlaybackStateChanged(state); | |
64 | + | |
65 | + if (getParent() != null && updateQueue(mController.getQueue())) { | |
66 | + getParent().requestLayout(); | |
67 | + } | |
68 | + } | |
69 | + | |
70 | + @Override | |
71 | + public void onSessionDestroyed() { | |
72 | + if (DEBUG) Log.d(TAG, "onSessionDestroyed() called with " + ""); | |
73 | + super.onSessionDestroyed(); | |
74 | + setController(null); | |
75 | + } | |
76 | + }; | |
77 | + | |
78 | + public QueueView(Context context, AttributeSet attrs) { | |
79 | + super(context, attrs); | |
80 | + mAdapter = new QueueItemAdapter(context); | |
81 | + setClipToOutline(false); | |
82 | + setClipToPadding(false); | |
83 | + } | |
84 | + | |
85 | + public void setQueueEnabled(boolean enabled) { | |
86 | + mQueueEnabled = enabled; | |
87 | + mAdapter.notifyDataSetChanged(); | |
88 | + } | |
89 | + | |
90 | + @Override | |
91 | + protected void onFinishInflate() { | |
92 | + super.onFinishInflate(); | |
93 | + mList = (ListView) findViewById(R.id.queue_list); | |
94 | + mList.setItemsCanFocus(true); | |
95 | + mList.setDrawSelectorOnTop(true); | |
96 | + mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); | |
97 | + mList.setAdapter(mAdapter); | |
98 | + mList.setOnItemLongClickListener(this); | |
99 | + mList.setOnItemClickListener(this); | |
100 | + mList.setVerticalScrollBarEnabled(false); | |
101 | + } | |
102 | + | |
103 | + private class QueueItemAdapter extends ArrayAdapter<MediaSession.QueueItem> { | |
104 | + | |
105 | + public QueueItemAdapter(Context context) { | |
106 | + super(context, R.layout.queue_adapter_row, mQueue); | |
107 | + } | |
108 | + | |
109 | + @Override | |
110 | + public boolean hasStableIds() { | |
111 | + return true; | |
112 | + } | |
113 | + | |
114 | + @Override | |
115 | + public long getItemId(int position) { | |
116 | + if (position > getCount() - 1) { | |
117 | + return -1; | |
118 | + } | |
119 | + return getItem(position).getQueueId(); | |
120 | + } | |
121 | + | |
122 | + @Override | |
123 | + public View getView(int position, View convertView, ViewGroup parent) { | |
124 | + final MediaSession.QueueItem queueItem = getItem(position); | |
125 | + | |
126 | + if (convertView == null) { | |
127 | + convertView = LayoutInflater.from(parent.getContext()) | |
128 | + .inflate(R.layout.queue_adapter_row, parent, false); | |
129 | + } | |
130 | + | |
131 | + QueueViewRow row = (QueueViewRow) convertView; | |
132 | + row.setHotSpotChangeListener(QueueView.this); | |
133 | + | |
134 | + row.setQueueItem(queueItem); | |
135 | + | |
136 | + return convertView; | |
137 | + } | |
138 | + | |
139 | + @Override | |
140 | + public int getCount() { | |
141 | + if (!mQueueEnabled) { | |
142 | + return 0; | |
143 | + } | |
144 | + return super.getCount(); | |
145 | + } | |
146 | + } | |
147 | + | |
148 | + public boolean isUserSelectingRow() { | |
149 | + final long delta = System.currentTimeMillis() - mLastUserInteraction; | |
150 | + if (DEBUG) Log.i(TAG, "isUserSelectingRow() delta=" + delta); | |
151 | + | |
152 | + if (mLastUserInteraction > 0 && delta < 500) { | |
153 | + if (DEBUG) Log.w(TAG, "user selecting row bc of hotspot change."); | |
154 | + return true; | |
155 | + } | |
156 | + | |
157 | + return false; | |
158 | + } | |
159 | + | |
160 | + public int getMaxQueueRowCount() { | |
161 | + return MediaExpandableNotificationRow.MAX_QUEUE_ENTRIES; | |
162 | + } | |
163 | + | |
164 | + public int getCurrentQueueRowCount() { | |
165 | + if (mAdapter == null) { | |
166 | + return 0; | |
167 | + } | |
168 | + return mAdapter.getCount(); | |
169 | + } | |
170 | + | |
171 | + @Override | |
172 | + public void onHotSpotChanged(float x, float y) { | |
173 | + mLastUserInteraction = System.currentTimeMillis(); | |
174 | + } | |
175 | + | |
176 | + @Override | |
177 | + public void onDrawableStateChanged() { | |
178 | + mLastUserInteraction = System.currentTimeMillis(); | |
179 | + } | |
180 | + | |
181 | + /** | |
182 | + * @param queue | |
183 | + * @return whether the queue size has changed | |
184 | + */ | |
185 | + public boolean updateQueue(List<MediaSession.QueueItem> queue) { | |
186 | + int queueSizeBefore = mAdapter.getCount(); | |
187 | + | |
188 | + mQueue.clear(); | |
189 | + | |
190 | + if (queue != null) { | |
191 | + // add everything *after* the currently playing item | |
192 | + boolean foundNowPlaying = false; | |
193 | + | |
194 | + final PlaybackState playbackState = mController.getPlaybackState(); | |
195 | + | |
196 | + long activeQueueId = -1; | |
197 | + if (playbackState != null) { | |
198 | + activeQueueId = playbackState.getActiveQueueItemId(); | |
199 | + } | |
200 | + | |
201 | + for (int i = 0; i < queue.size() && mQueue.size() < getMaxQueueRowCount(); i++) { | |
202 | + final MediaSession.QueueItem item = queue.get(i); | |
203 | + if (!foundNowPlaying | |
204 | + && activeQueueId != -1 | |
205 | + && activeQueueId == item.getQueueId()) { | |
206 | + foundNowPlaying = true; | |
207 | + continue; | |
208 | + } | |
209 | + if (foundNowPlaying) { | |
210 | + mQueue.add(item); | |
211 | + } | |
212 | + } | |
213 | + | |
214 | + // add everything | |
215 | + if (!foundNowPlaying) { | |
216 | + for(int i = 0; i < getMaxQueueRowCount() && i < queue.size(); i++) { | |
217 | + mQueue.add(queue.get(i)); | |
218 | + } | |
219 | + } | |
220 | + } | |
221 | + mAdapter.notifyDataSetChanged(); | |
222 | + | |
223 | + return mAdapter.getCount() != queueSizeBefore; | |
224 | + } | |
225 | + | |
226 | + public boolean setController(MediaController controller) { | |
227 | + if (mController != null) { | |
228 | + mController.unregisterCallback(mCallback); | |
229 | + } | |
230 | + mController = controller; | |
231 | + if (mController != null) { | |
232 | + mController.registerCallback(mCallback); | |
233 | + } | |
234 | + | |
235 | + return updateQueue(mController != null | |
236 | + ? mController.getQueue() : null); | |
237 | + } | |
238 | + | |
239 | + @Override | |
240 | + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | |
241 | + final MediaSession.QueueItem itemAtPosition = (MediaSession.QueueItem) | |
242 | + parent.getItemAtPosition(position); | |
243 | + if (itemAtPosition != null && mController != null) { | |
244 | + mController.getTransportControls().skipToQueueItem(itemAtPosition.getQueueId()); | |
245 | + } | |
246 | + mAdapter.notifyDataSetChanged(); | |
247 | + } | |
248 | + | |
249 | + @Override | |
250 | + public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { | |
251 | + return true; | |
252 | + } | |
253 | + | |
254 | +} |
@@ -0,0 +1,100 @@ | ||
1 | +/* | |
2 | + * Copyright (C) 2015 The CyanogenMod Project | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License | |
15 | + */ | |
16 | +package com.android.systemui.statusbar; | |
17 | + | |
18 | +import android.content.Context; | |
19 | +import android.graphics.Bitmap; | |
20 | +import android.graphics.Canvas; | |
21 | +import android.graphics.Color; | |
22 | +import android.graphics.Paint; | |
23 | +import android.media.MediaDescription; | |
24 | +import android.media.session.MediaSession; | |
25 | +import android.util.AttributeSet; | |
26 | +import android.util.Log; | |
27 | +import android.view.View; | |
28 | +import android.widget.ImageView; | |
29 | +import android.widget.RelativeLayout; | |
30 | +import android.widget.TextView; | |
31 | +import com.android.systemui.R; | |
32 | + | |
33 | +public class QueueViewRow extends RelativeLayout { | |
34 | + | |
35 | + private static final String TAG = QueueViewRow.class.getSimpleName(); | |
36 | + | |
37 | + private UserRowInteractionListener mHotSpotChangeListener; | |
38 | + | |
39 | + private ImageView mArt; | |
40 | + private TextView mTitle; | |
41 | + private TextView mSummary; | |
42 | + | |
43 | + public QueueViewRow(Context context, AttributeSet attrs) { | |
44 | + super(context, attrs); | |
45 | + } | |
46 | + | |
47 | + @Override | |
48 | + protected void onFinishInflate() { | |
49 | + super.onFinishInflate(); | |
50 | + mArt = (ImageView) findViewById(R.id.art); | |
51 | + mTitle = (TextView) findViewById(R.id.title); | |
52 | + mSummary = (TextView) findViewById(R.id.summary); | |
53 | + } | |
54 | + | |
55 | + @Override | |
56 | + protected void drawableStateChanged() { | |
57 | + super.drawableStateChanged(); | |
58 | + if (mHotSpotChangeListener != null) { | |
59 | + mHotSpotChangeListener.onDrawableStateChanged(); | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + @Override | |
64 | + public void dispatchDrawableHotspotChanged(float x, float y) { | |
65 | + super.dispatchDrawableHotspotChanged(x, y); | |
66 | + if (mHotSpotChangeListener != null) { | |
67 | + mHotSpotChangeListener.onHotSpotChanged(x, y); | |
68 | + } | |
69 | + } | |
70 | + | |
71 | + public void setHotSpotChangeListener(UserRowInteractionListener listener) { | |
72 | + mHotSpotChangeListener = listener; | |
73 | + } | |
74 | + | |
75 | + public TextView getTitle() { | |
76 | + return mTitle; | |
77 | + } | |
78 | + | |
79 | + public TextView getSummary() { | |
80 | + return mSummary; | |
81 | + } | |
82 | + | |
83 | + public void setQueueItem(MediaSession.QueueItem queueItem) { | |
84 | + setTag(queueItem); | |
85 | + | |
86 | + MediaDescription metadata = queueItem.getDescription(); | |
87 | + | |
88 | + final Bitmap bitmap = metadata.getIconBitmap(); | |
89 | + mArt.setImageBitmap(bitmap); | |
90 | + mArt.setVisibility(bitmap != null ? View.VISIBLE : View.GONE); | |
91 | + | |
92 | + mTitle.setText(metadata.getTitle()); | |
93 | + mSummary.setText(metadata.getSubtitle()); | |
94 | + } | |
95 | + | |
96 | + /* package */ interface UserRowInteractionListener { | |
97 | + public void onHotSpotChanged(float x, float y); | |
98 | + public void onDrawableStateChanged(); | |
99 | + } | |
100 | +} |
@@ -67,9 +67,12 @@ import com.android.systemui.statusbar.NotificationData; | ||
67 | 67 | import com.android.systemui.statusbar.StatusBarState; |
68 | 68 | import com.android.systemui.statusbar.policy.HeadsUpManager; |
69 | 69 | import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; |
70 | +import com.android.systemui.statusbar.policy.WeatherController; | |
71 | +import com.android.systemui.statusbar.policy.WeatherControllerImpl; | |
70 | 72 | import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; |
71 | 73 | import com.android.systemui.statusbar.stack.StackStateAnimator; |
72 | 74 | import cyanogenmod.providers.CMSettings; |
75 | +import cyanogenmod.weather.util.WeatherUtils; | |
73 | 76 | |
74 | 77 | import java.util.List; |
75 | 78 |
@@ -79,7 +82,7 @@ public class NotificationPanelView extends PanelView implements | ||
79 | 82 | ExpandableView.OnHeightChangedListener, |
80 | 83 | View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener, |
81 | 84 | KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener, |
82 | - HeadsUpManager.OnHeadsUpChangedListener { | |
85 | + HeadsUpManager.OnHeadsUpChangedListener, WeatherController.Callback { | |
83 | 86 | |
84 | 87 | private static final boolean DEBUG = false; |
85 | 88 |
@@ -218,11 +221,15 @@ public class NotificationPanelView extends PanelView implements | ||
218 | 221 | private Handler mHandler = new Handler(); |
219 | 222 | private SettingsObserver mSettingsObserver; |
220 | 223 | |
221 | - private boolean mOneFingerQuickSettingsIntercept; | |
224 | + private int mOneFingerQuickSettingsIntercept; | |
222 | 225 | private boolean mDoubleTapToSleepEnabled; |
223 | 226 | private int mStatusBarHeaderHeight; |
224 | 227 | private GestureDetector mDoubleTapGesture; |
225 | 228 | |
229 | + private boolean mKeyguardWeatherEnabled; | |
230 | + private TextView mKeyguardWeatherInfo; | |
231 | + private WeatherControllerImpl mWeatherController; | |
232 | + | |
226 | 233 | public NotificationPanelView(Context context, AttributeSet attrs) { |
227 | 234 | super(context, attrs); |
228 | 235 | setWillNotDraw(!DEBUG); |
@@ -244,6 +251,11 @@ public class NotificationPanelView extends PanelView implements | ||
244 | 251 | mStatusBar = bar; |
245 | 252 | } |
246 | 253 | |
254 | + public void setWeatherController(WeatherControllerImpl weatherController) { | |
255 | + mWeatherController = weatherController; | |
256 | + mWeatherController.addCallback(this); | |
257 | + } | |
258 | + | |
247 | 259 | @Override |
248 | 260 | protected void onFinishInflate() { |
249 | 261 | super.onFinishInflate(); |
@@ -288,6 +300,8 @@ public class NotificationPanelView extends PanelView implements | ||
288 | 300 | mNotificationStackScroller.setQsContainer(mQsContainer); |
289 | 301 | } |
290 | 302 | }); |
303 | + | |
304 | + mKeyguardWeatherInfo = (TextView) mKeyguardStatusView.findViewById(R.id.weather_info); | |
291 | 305 | } |
292 | 306 | |
293 | 307 | @Override |
@@ -370,14 +384,16 @@ public class NotificationPanelView extends PanelView implements | ||
370 | 384 | } |
371 | 385 | |
372 | 386 | @Override |
373 | - public void onAttachedToWindow() { | |
387 | + protected void onAttachedToWindow() { | |
388 | + super.onAttachedToWindow(); | |
374 | 389 | mSettingsObserver.observe(); |
375 | - | |
376 | 390 | } |
377 | 391 | |
378 | 392 | @Override |
379 | - public void onDetachedFromWindow() { | |
393 | + protected void onDetachedFromWindow() { | |
394 | + super.onDetachedFromWindow(); | |
380 | 395 | mSettingsObserver.unobserve(); |
396 | + mWeatherController.removeCallback(this); | |
381 | 397 | } |
382 | 398 | |
383 | 399 | private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) { |
@@ -833,13 +849,7 @@ public class NotificationPanelView extends PanelView implements | ||
833 | 849 | && mQsExpansionEnabled) { |
834 | 850 | mTwoFingerQsExpandPossible = true; |
835 | 851 | } |
836 | - boolean twoFingerQsEvent = mTwoFingerQsExpandPossible | |
837 | - && (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN | |
838 | - && event.getPointerCount() == 2); | |
839 | - boolean oneFingerQsOverride = mOneFingerQuickSettingsIntercept | |
840 | - && event.getActionMasked() == MotionEvent.ACTION_DOWN | |
841 | - && shouldQuickSettingsIntercept(event.getX(), event.getY(), -1, false); | |
842 | - if ((twoFingerQsEvent || oneFingerQsOverride) && isOpenQsEvent(event) | |
852 | + if (mTwoFingerQsExpandPossible && isOpenQsEvent(event) | |
843 | 853 | && event.getY(event.getActionIndex()) < mStatusBarMinHeight) { |
844 | 854 | MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1); |
845 | 855 | mQsExpandImmediate = true; |
@@ -874,7 +884,22 @@ public class NotificationPanelView extends PanelView implements | ||
874 | 884 | && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY) |
875 | 885 | || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY)); |
876 | 886 | |
877 | - return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag; | |
887 | + final float w = getMeasuredWidth(); | |
888 | + final float x = event.getX(); | |
889 | + float region = w * 1.f / 4.f; // TODO overlay region fraction? | |
890 | + boolean showQsOverride = false; | |
891 | + | |
892 | + switch (mOneFingerQuickSettingsIntercept) { | |
893 | + case 1: // Right side pulldown | |
894 | + showQsOverride = isLayoutRtl() ? x < region : w - region < x; | |
895 | + break; | |
896 | + case 2: // Left side pulldown | |
897 | + showQsOverride = isLayoutRtl() ? w - region < x : x < region; | |
898 | + break; | |
899 | + } | |
900 | + showQsOverride &= mStatusBarState == StatusBarState.SHADE; | |
901 | + | |
902 | + return twoFingerDrag || showQsOverride || stylusButtonClickDrag || mouseButtonClickDrag; | |
878 | 903 | } |
879 | 904 | |
880 | 905 | private void handleQsDown(MotionEvent event) { |
@@ -1399,30 +1424,18 @@ public class NotificationPanelView extends PanelView implements | ||
1399 | 1424 | * @return Whether we should intercept a gesture to open Quick Settings. |
1400 | 1425 | */ |
1401 | 1426 | private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff) { |
1402 | - return shouldQuickSettingsIntercept(x, y, yDiff, true); | |
1403 | - } | |
1404 | - | |
1405 | - /** | |
1406 | - * @return Whether we should intercept a gesture to open Quick Settings. | |
1407 | - */ | |
1408 | - private boolean shouldQuickSettingsIntercept(float x, float y, float yDiff, boolean useHeader) { | |
1409 | 1427 | if (!mQsExpansionEnabled || mCollapsedOnDown) { |
1410 | 1428 | return false; |
1411 | 1429 | } |
1412 | 1430 | View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader(); |
1413 | - boolean onHeader = useHeader && x >= mQsAutoReinflateContainer.getX() | |
1431 | + boolean onHeader = x >= mQsAutoReinflateContainer.getX() | |
1414 | 1432 | && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth() |
1415 | 1433 | && y >= header.getTop() && y <= header.getBottom(); |
1416 | 1434 | |
1417 | - final float w = getMeasuredWidth(); | |
1418 | - float region = (w * (1.f/3.f)); // TODO overlay region fraction? | |
1419 | - final boolean showQsOverride = isLayoutRtl() ? (x < region) : (w - region < x) | |
1420 | - && mStatusBarState == StatusBarState.SHADE; | |
1421 | - | |
1422 | 1435 | if (mQsExpanded) { |
1423 | 1436 | return onHeader || (yDiff < 0 && isInQsArea(x, y)); |
1424 | 1437 | } else { |
1425 | - return onHeader || showQsOverride; | |
1438 | + return onHeader; | |
1426 | 1439 | } |
1427 | 1440 | } |
1428 | 1441 |
@@ -2406,6 +2419,19 @@ public class NotificationPanelView extends PanelView implements | ||
2406 | 2419 | mGroupManager = groupManager; |
2407 | 2420 | } |
2408 | 2421 | |
2422 | + @Override | |
2423 | + public void onWeatherChanged(WeatherController.WeatherInfo info) { | |
2424 | + if (!mKeyguardWeatherEnabled || Double.isNaN(info.temp) || info.condition == null) { | |
2425 | + mKeyguardWeatherInfo.setVisibility(GONE); | |
2426 | + } else { | |
2427 | + mKeyguardWeatherInfo.setText(mContext.getString( | |
2428 | + R.string.keyguard_status_view_weather_format, | |
2429 | + WeatherUtils.formatTemperature(info.temp, info.tempUnit), | |
2430 | + info.condition)); | |
2431 | + mKeyguardWeatherInfo.setVisibility(VISIBLE); | |
2432 | + } | |
2433 | + } | |
2434 | + | |
2409 | 2435 | class SettingsObserver extends ContentObserver { |
2410 | 2436 | SettingsObserver(Handler handler) { |
2411 | 2437 | super(handler); |
@@ -2417,6 +2443,8 @@ public class NotificationPanelView extends PanelView implements | ||
2417 | 2443 | CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN), false, this); |
2418 | 2444 | resolver.registerContentObserver(CMSettings.System.getUriFor( |
2419 | 2445 | CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE), false, this); |
2446 | + resolver.registerContentObserver(CMSettings.Secure.getUriFor( | |
2447 | + CMSettings.Secure.LOCK_SCREEN_WEATHER_ENABLED), false, this); | |
2420 | 2448 | update(); |
2421 | 2449 | } |
2422 | 2450 |
@@ -2438,9 +2466,17 @@ public class NotificationPanelView extends PanelView implements | ||
2438 | 2466 | public void update() { |
2439 | 2467 | ContentResolver resolver = mContext.getContentResolver(); |
2440 | 2468 | mOneFingerQuickSettingsIntercept = CMSettings.System.getInt( |
2441 | - resolver, CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN, 1) == 1; | |
2469 | + resolver, CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN, 1); | |
2442 | 2470 | mDoubleTapToSleepEnabled = CMSettings.System.getInt( |
2443 | 2471 | resolver, CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE, 1) == 1; |
2472 | + | |
2473 | + boolean wasKeyguardWeatherEnabled = mKeyguardWeatherEnabled; | |
2474 | + mKeyguardWeatherEnabled = CMSettings.Secure.getInt( | |
2475 | + resolver, CMSettings.Secure.LOCK_SCREEN_WEATHER_ENABLED, 0) == 1; | |
2476 | + if (mWeatherController != null | |
2477 | + && wasKeyguardWeatherEnabled != mKeyguardWeatherEnabled) { | |
2478 | + onWeatherChanged(mWeatherController.getWeatherInfo()); | |
2479 | + } | |
2444 | 2480 | } |
2445 | 2481 | } |
2446 | 2482 | } |
@@ -151,6 +151,7 @@ import com.android.systemui.statusbar.ExpandableNotificationRow; | ||
151 | 151 | import com.android.systemui.statusbar.GestureRecorder; |
152 | 152 | import com.android.systemui.statusbar.KeyboardShortcuts; |
153 | 153 | import com.android.systemui.statusbar.KeyguardIndicationController; |
154 | +import com.android.systemui.statusbar.MediaExpandableNotificationRow; | |
154 | 155 | import com.android.systemui.statusbar.NotificationData; |
155 | 156 | import com.android.systemui.statusbar.NotificationData.Entry; |
156 | 157 | import com.android.systemui.statusbar.NotificationOverflowContainer; |
@@ -1136,6 +1137,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, | ||
1136 | 1137 | mKeyguardStatusBar.setBatteryController(mBatteryController); |
1137 | 1138 | mHeader.setWeatherController(mWeatherController); |
1138 | 1139 | |
1140 | + mNotificationPanel.setWeatherController(mWeatherController); | |
1141 | + | |
1139 | 1142 | PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); |
1140 | 1143 | mBroadcastReceiver.onReceive(mContext, |
1141 | 1144 | new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); |
@@ -2223,6 +2226,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, | ||
2223 | 2226 | Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: " |
2224 | 2227 | + mMediaMetadata); |
2225 | 2228 | } |
2229 | + if (mediaNotification != null | |
2230 | + && mediaNotification.row != null | |
2231 | + && mediaNotification.row instanceof MediaExpandableNotificationRow) { | |
2232 | + ((MediaExpandableNotificationRow) mediaNotification.row) | |
2233 | + .setMediaController(controller); | |
2234 | + } | |
2226 | 2235 | |
2227 | 2236 | if (mediaNotification != null) { |
2228 | 2237 | mMediaNotificationKey = mediaNotification.notification.getKey(); |
@@ -2636,6 +2645,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, | ||
2636 | 2645 | return mMediaNotificationKey; |
2637 | 2646 | } |
2638 | 2647 | |
2648 | + @Override | |
2649 | + protected MediaController getCurrentMediaController() { | |
2650 | + return mMediaController; | |
2651 | + } | |
2652 | + | |
2639 | 2653 | public boolean isScrimSrcModeEnabled() { |
2640 | 2654 | return mScrimSrcModeEnabled; |
2641 | 2655 | } |
@@ -3008,7 +3022,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, | ||
3008 | 3022 | ServiceManager.getService("power")); |
3009 | 3023 | if (power != null) { |
3010 | 3024 | if (mAutomaticBrightness) { |
3011 | - float adj = (value * 100) / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1; | |
3025 | + float adj = (2 * value) - 1; | |
3012 | 3026 | adj = Math.max(adj, -1); |
3013 | 3027 | adj = Math.min(adj, 1); |
3014 | 3028 | final float val = adj; |
@@ -3130,19 +3144,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, | ||
3130 | 3144 | } |
3131 | 3145 | if (mBrightnessChanged && upOrCancel) { |
3132 | 3146 | mBrightnessChanged = false; |
3133 | - if (mJustPeeked) { | |
3134 | - /** | |
3135 | - * if we were just peeking, eat the event and collapse the status bar, otherwise | |
3136 | - * the event gets passed down and a full expand might happen. | |
3137 | - */ | |
3147 | + if (mJustPeeked && mExpandedVisible) { | |
3138 | 3148 | mNotificationPanel.fling(10, false); |
3139 | - if (mExpandedVisible) { | |
3140 | - mExpandedVisible = false; | |
3141 | - visibilityChanged(false); | |
3142 | - setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); | |
3143 | - } | |
3144 | - disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */); | |
3145 | - return true; | |
3146 | 3149 | } |
3147 | 3150 | } |
3148 | 3151 | return false; |
@@ -258,8 +258,17 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro | ||
258 | 258 | |
259 | 259 | if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) { |
260 | 260 | zenVisible = mZen != Global.ZEN_MODE_OFF; |
261 | - zenIconId = mZen == Global.ZEN_MODE_NO_INTERRUPTIONS | |
262 | - ? R.drawable.stat_sys_dnd_total_silence : R.drawable.stat_sys_dnd; | |
261 | + switch (mZen) { | |
262 | + case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: | |
263 | + zenIconId = R.drawable.stat_sys_dnd_priority; | |
264 | + break; | |
265 | + case Global.ZEN_MODE_NO_INTERRUPTIONS: | |
266 | + zenIconId = R.drawable.stat_sys_dnd_total_silence; | |
267 | + break; | |
268 | + default: | |
269 | + zenIconId = R.drawable.stat_sys_dnd; | |
270 | + break; | |
271 | + } | |
263 | 272 | zenDescription = mContext.getString(R.string.quick_settings_dnd_label); |
264 | 273 | } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) { |
265 | 274 | zenVisible = true; |
@@ -16,34 +16,22 @@ | ||
16 | 16 | |
17 | 17 | package com.android.systemui.statusbar.phone; |
18 | 18 | |
19 | -import android.app.ActivityManager; | |
20 | -import android.app.ActivityManagerNative; | |
21 | 19 | import android.app.AlarmManager; |
22 | -import android.app.IUserSwitchObserver; | |
23 | 20 | import android.app.PendingIntent; |
24 | 21 | import android.content.ContentUris; |
25 | -import android.content.ContentResolver; | |
26 | 22 | import android.content.Context; |
27 | 23 | import android.content.Intent; |
28 | 24 | import android.content.res.Configuration; |
29 | 25 | import android.content.res.Resources; |
30 | -import android.database.ContentObserver; | |
31 | 26 | import android.graphics.Outline; |
32 | 27 | import android.graphics.Rect; |
33 | 28 | import android.graphics.drawable.Animatable; |
34 | 29 | import android.graphics.drawable.Drawable; |
35 | 30 | import android.graphics.drawable.RippleDrawable; |
36 | 31 | import android.net.Uri; |
37 | -import android.os.Handler; | |
38 | -import android.os.IRemoteCallback; | |
39 | -import android.os.RemoteException; | |
40 | -import android.os.UserHandle; | |
41 | 32 | import android.provider.AlarmClock; |
42 | 33 | import android.provider.CalendarContract; |
43 | -import android.provider.Settings; | |
44 | -import android.net.Uri; | |
45 | 34 | import android.util.AttributeSet; |
46 | -import android.util.Log; | |
47 | 35 | import android.util.MathUtils; |
48 | 36 | import android.util.TypedValue; |
49 | 37 | import android.view.View; |
@@ -55,11 +43,11 @@ import android.widget.RelativeLayout; | ||
55 | 43 | import android.widget.Switch; |
56 | 44 | import android.widget.TextView; |
57 | 45 | import android.widget.Toast; |
46 | + | |
58 | 47 | import com.android.keyguard.KeyguardStatusView; |
59 | 48 | import com.android.systemui.BatteryMeterView; |
60 | 49 | import com.android.systemui.FontSizeUtils; |
61 | 50 | import com.android.systemui.R; |
62 | -import com.android.systemui.cm.UserContentObserver; | |
63 | 51 | import com.android.systemui.qs.QSPanel; |
64 | 52 | import com.android.systemui.qs.QSPanel.Callback; |
65 | 53 | import com.android.systemui.qs.QSTile; |
@@ -75,13 +63,14 @@ import com.android.systemui.tuner.TunerService; | ||
75 | 63 | import java.text.NumberFormat; |
76 | 64 | |
77 | 65 | import cyanogenmod.providers.CMSettings; |
66 | +import cyanogenmod.weather.util.WeatherUtils; | |
78 | 67 | |
79 | 68 | /** |
80 | 69 | * The view to manage the header area in the expanded status bar. |
81 | 70 | */ |
82 | 71 | public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnClickListener, |
83 | 72 | BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback, |
84 | - EmergencyListener, WeatherController.Callback { | |
73 | + EmergencyListener, WeatherController.Callback, TunerService.Tunable { | |
85 | 74 | |
86 | 75 | private boolean mExpanded; |
87 | 76 | private boolean mListening; |
@@ -152,7 +141,6 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC | ||
152 | 141 | private float mCurrentT; |
153 | 142 | private boolean mShowingDetail; |
154 | 143 | private boolean mDetailTransitioning; |
155 | - private SettingsObserver mSettingsObserver; | |
156 | 144 | private boolean mShowWeather; |
157 | 145 | |
158 | 146 | private boolean mAllowExpand = true; |
@@ -195,7 +183,6 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC | ||
195 | 183 | mWeatherContainer.setOnClickListener(this); |
196 | 184 | mWeatherLine1 = (TextView) findViewById(R.id.weather_line_1); |
197 | 185 | mWeatherLine2 = (TextView) findViewById(R.id.weather_line_2); |
198 | - mSettingsObserver = new SettingsObserver(new Handler()); | |
199 | 186 | loadDimens(); |
200 | 187 | updateVisibilities(); |
201 | 188 | updateClockScale(); |
@@ -419,7 +406,8 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC | ||
419 | 406 | |
420 | 407 | private void updateListeners() { |
421 | 408 | if (mListening) { |
422 | - mSettingsObserver.observe(); | |
409 | + TunerService.get(getContext()).addTunable(this, | |
410 | + "cmsystem:" + CMSettings.System.STATUS_BAR_SHOW_WEATHER); | |
423 | 411 | mBatteryController.addStateChangedCallback(this); |
424 | 412 | mNextAlarmController.addStateChangedCallback(this); |
425 | 413 | mWeatherController.addCallback(this); |
@@ -427,7 +415,7 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC | ||
427 | 415 | mBatteryController.removeStateChangedCallback(this); |
428 | 416 | mNextAlarmController.removeStateChangedCallback(this); |
429 | 417 | mWeatherController.removeCallback(this); |
430 | - mSettingsObserver.unobserve(); | |
418 | + TunerService.get(getContext()).removeTunable(this); | |
431 | 419 | } |
432 | 420 | } |
433 | 421 |
@@ -479,12 +467,12 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC | ||
479 | 467 | |
480 | 468 | @Override |
481 | 469 | public void onWeatherChanged(WeatherController.WeatherInfo info) { |
482 | - if (info.temp == null || info.condition == null) { | |
470 | + if (Double.isNaN(info.temp) || info.condition == null) { | |
483 | 471 | mWeatherLine1.setText(null); |
484 | 472 | } else { |
485 | 473 | mWeatherLine1.setText(mContext.getString( |
486 | 474 | R.string.status_bar_expanded_header_weather_format, |
487 | - info.temp, | |
475 | + WeatherUtils.formatTemperature(info.temp, info.tempUnit), | |
488 | 476 | info.condition)); |
489 | 477 | } |
490 | 478 | mWeatherLine2.setText(info.city); |
@@ -930,35 +918,10 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC | ||
930 | 918 | } |
931 | 919 | }; |
932 | 920 | |
933 | - class SettingsObserver extends UserContentObserver { | |
934 | - SettingsObserver(Handler handler) { | |
935 | - super(handler); | |
936 | - } | |
937 | - | |
938 | - @Override | |
939 | - protected void observe() { | |
940 | - super.observe(); | |
941 | - | |
942 | - ContentResolver resolver = mContext.getContentResolver(); | |
943 | - resolver.registerContentObserver(CMSettings.System.getUriFor( | |
944 | - CMSettings.System.STATUS_BAR_SHOW_WEATHER), false, this, UserHandle.USER_ALL); | |
945 | - update(); | |
946 | - } | |
947 | - | |
948 | - @Override | |
949 | - protected void unobserve() { | |
950 | - super.unobserve(); | |
951 | - | |
952 | - ContentResolver resolver = mContext.getContentResolver(); | |
953 | - resolver.unregisterContentObserver(this); | |
954 | - } | |
955 | - | |
956 | - @Override | |
957 | - public void update() { | |
958 | - | |
959 | - ContentResolver resolver = mContext.getContentResolver(); | |
960 | - mShowWeather = CMSettings.System.getInt( | |
961 | - resolver, CMSettings.System.STATUS_BAR_SHOW_WEATHER, 1) == 1; | |
921 | + @Override | |
922 | + public void onTuningChanged(String key, String newValue) { | |
923 | + if (key.endsWith(CMSettings.System.STATUS_BAR_SHOW_WEATHER)) { | |
924 | + mShowWeather = newValue == null || "1".equals(newValue); | |
962 | 925 | updateVisibilities(); |
963 | 926 | } |
964 | 927 | } |
@@ -25,8 +25,9 @@ public interface WeatherController { | ||
25 | 25 | void onWeatherChanged(WeatherInfo temp); |
26 | 26 | } |
27 | 27 | public static class WeatherInfo { |
28 | - public String temp = null; | |
28 | + public double temp = Double.NaN; | |
29 | 29 | public String city = null; |
30 | 30 | public String condition = null; |
31 | + public int tempUnit; | |
31 | 32 | } |
32 | 33 | } |
@@ -16,43 +16,49 @@ | ||
16 | 16 | |
17 | 17 | package com.android.systemui.statusbar.policy; |
18 | 18 | |
19 | -import android.content.BroadcastReceiver; | |
20 | 19 | import android.content.ComponentName; |
21 | -import android.content.ContentResolver; | |
22 | 20 | import android.content.Context; |
23 | 21 | import android.content.Intent; |
24 | -import android.content.IntentFilter; | |
25 | 22 | import android.database.ContentObserver; |
26 | 23 | import android.database.Cursor; |
27 | 24 | import android.net.Uri; |
28 | 25 | import android.os.Handler; |
29 | -import android.provider.Settings; | |
30 | 26 | import android.util.Log; |
27 | +import cyanogenmod.providers.CMSettings; | |
28 | +import cyanogenmod.providers.WeatherContract; | |
29 | +import cyanogenmod.weather.CMWeatherManager; | |
30 | +import cyanogenmod.weather.util.WeatherUtils; | |
31 | 31 | |
32 | 32 | import java.util.ArrayList; |
33 | 33 | |
34 | +import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_CITY; | |
35 | +import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_CONDITION; | |
36 | +import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_TEMPERATURE; | |
37 | +import static cyanogenmod.providers.WeatherContract.WeatherColumns.CURRENT_TEMPERATURE_UNIT; | |
38 | +import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.CELSIUS; | |
39 | +import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT; | |
40 | + | |
34 | 41 | public class WeatherControllerImpl implements WeatherController { |
35 | 42 | |
36 | 43 | private static final String TAG = WeatherController.class.getSimpleName(); |
37 | 44 | private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
45 | + private WeatherContentObserver mWeatherContentObserver; | |
46 | + private Handler mHandler; | |
47 | + private int mWeatherUnit; | |
48 | + private Uri mWeatherTempetarureUri; | |
38 | 49 | |
39 | 50 | public static final ComponentName COMPONENT_WEATHER_FORECAST = new ComponentName( |
40 | 51 | "com.cyanogenmod.lockclock", "com.cyanogenmod.lockclock.weather.ForecastActivity"); |
41 | - public static final String ACTION_UPDATE_FINISHED | |
42 | - = "com.cyanogenmod.lockclock.action.WEATHER_UPDATE_FINISHED"; | |
43 | - public static final String EXTRA_UPDATE_CANCELLED = "update_cancelled"; | |
44 | 52 | public static final String ACTION_FORCE_WEATHER_UPDATE |
45 | 53 | = "com.cyanogenmod.lockclock.action.FORCE_WEATHER_UPDATE"; |
46 | - public static final Uri CURRENT_WEATHER_URI | |
47 | - = Uri.parse("content://com.cyanogenmod.lockclock.weather.provider/weather/current"); | |
48 | - public static final String[] WEATHER_PROJECTION = new String[]{ | |
49 | - "temperature", | |
50 | - "city", | |
51 | - "condition" | |
54 | + private static final String[] WEATHER_PROJECTION = new String[]{ | |
55 | + CURRENT_TEMPERATURE, | |
56 | + CURRENT_TEMPERATURE_UNIT, | |
57 | + CURRENT_CITY, | |
58 | + CURRENT_CONDITION | |
52 | 59 | }; |
53 | 60 | |
54 | 61 | private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); |
55 | - private final Receiver mReceiver = new Receiver(); | |
56 | 62 | private final Context mContext; |
57 | 63 | |
58 | 64 | private WeatherInfo mCachedInfo = new WeatherInfo(); |
@@ -60,10 +66,16 @@ public class WeatherControllerImpl implements WeatherController { | ||
60 | 66 | public WeatherControllerImpl(Context context) { |
61 | 67 | mContext = context; |
62 | 68 | mContext.getSystemService(Context.CONNECTIVITY_SERVICE); |
69 | + mHandler = new Handler(); | |
70 | + mWeatherContentObserver = new WeatherContentObserver(mHandler); | |
71 | + mWeatherTempetarureUri | |
72 | + = CMSettings.Global.getUriFor(CMSettings.Global.WEATHER_TEMPERATURE_UNIT); | |
73 | + mContext.getContentResolver().registerContentObserver( | |
74 | + WeatherContract.WeatherColumns.CURRENT_WEATHER_URI,true, mWeatherContentObserver); | |
75 | + mContext.getContentResolver().registerContentObserver(mWeatherTempetarureUri, true, | |
76 | + mWeatherContentObserver); | |
77 | + queryWeatherTempUnit(); | |
63 | 78 | queryWeather(); |
64 | - final IntentFilter filter = new IntentFilter(); | |
65 | - filter.addAction(ACTION_UPDATE_FINISHED); | |
66 | - mContext.registerReceiver(mReceiver, filter); | |
67 | 79 | } |
68 | 80 | |
69 | 81 | public void addCallback(Callback callback) { |
@@ -85,17 +97,29 @@ public class WeatherControllerImpl implements WeatherController { | ||
85 | 97 | } |
86 | 98 | |
87 | 99 | private void queryWeather() { |
88 | - Cursor c = mContext.getContentResolver().query(CURRENT_WEATHER_URI, WEATHER_PROJECTION, | |
100 | + Cursor c = mContext.getContentResolver().query( | |
101 | + WeatherContract.WeatherColumns.CURRENT_WEATHER_URI, WEATHER_PROJECTION, | |
89 | 102 | null, null, null); |
90 | 103 | if (c == null) { |
91 | 104 | if(DEBUG) Log.e(TAG, "cursor was null for temperature, forcing weather update"); |
105 | + //LockClock keeps track of the user settings (temp unit, search by geo location/city) | |
106 | + //so we delegate the responsibility of handling a weather update to LockClock | |
92 | 107 | mContext.sendBroadcast(new Intent(ACTION_FORCE_WEATHER_UPDATE)); |
93 | 108 | } else { |
94 | 109 | try { |
95 | 110 | c.moveToFirst(); |
96 | - mCachedInfo.temp = c.getString(0); | |
97 | - mCachedInfo.city = c.getString(1); | |
98 | - mCachedInfo.condition = c.getString(2); | |
111 | + double temp = c.getDouble(0); | |
112 | + int reportedUnit = c.getInt(1); | |
113 | + if (reportedUnit == CELSIUS && mWeatherUnit == FAHRENHEIT) { | |
114 | + temp = WeatherUtils.celsiusToFahrenheit(temp); | |
115 | + } else if (reportedUnit == FAHRENHEIT && mWeatherUnit == CELSIUS) { | |
116 | + temp = WeatherUtils.fahrenheitToCelsius(temp); | |
117 | + } | |
118 | + | |
119 | + mCachedInfo.temp = temp; | |
120 | + mCachedInfo.tempUnit = mWeatherUnit; | |
121 | + mCachedInfo.city = c.getString(2); | |
122 | + mCachedInfo.condition = c.getString(3); | |
99 | 123 | } finally { |
100 | 124 | c.close(); |
101 | 125 | } |
@@ -108,19 +132,53 @@ public class WeatherControllerImpl implements WeatherController { | ||
108 | 132 | } |
109 | 133 | } |
110 | 134 | |
111 | - private final class Receiver extends BroadcastReceiver { | |
135 | + private class WeatherContentObserver extends ContentObserver { | |
136 | + | |
137 | + public WeatherContentObserver(Handler handler) { | |
138 | + super(handler); | |
139 | + } | |
140 | + | |
112 | 141 | @Override |
113 | - public void onReceive(Context context, Intent intent) { | |
114 | - if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction()); | |
115 | - if (intent.hasExtra(EXTRA_UPDATE_CANCELLED)) { | |
116 | - if (intent.getBooleanExtra(EXTRA_UPDATE_CANCELLED, false)) { | |
117 | - // no update | |
118 | - return; | |
142 | + public void onChange(boolean selfChange, Uri uri) { | |
143 | + if (uri != null) { | |
144 | + if (uri.compareTo(WeatherContract.WeatherColumns.CURRENT_WEATHER_URI) == 0) { | |
145 | + queryWeather(); | |
146 | + fireCallback(); | |
147 | + } else if (uri.compareTo(mWeatherTempetarureUri) == 0) { | |
148 | + queryWeatherTempUnit(); | |
149 | + fixCachedWeatherInfo(); | |
150 | + fireCallback(); | |
151 | + } else { | |
152 | + super.onChange(selfChange, uri); | |
119 | 153 | } |
120 | 154 | } |
121 | - queryWeather(); | |
122 | - fireCallback(); | |
155 | + } | |
156 | + | |
157 | + @Override | |
158 | + public void onChange(boolean selfChange) { | |
159 | + onChange(selfChange, null); | |
123 | 160 | } |
124 | 161 | } |
125 | 162 | |
163 | + private void queryWeatherTempUnit() { | |
164 | + try { | |
165 | + mWeatherUnit = CMSettings.Global.getInt(mContext.getContentResolver(), | |
166 | + CMSettings.Global.WEATHER_TEMPERATURE_UNIT); | |
167 | + } catch (CMSettings.CMSettingNotFoundException e) { | |
168 | + //CMSettingsProvider should have taken care of setting a default value for this setting | |
169 | + //so how is that we ended up here?? We need to set a valid temp unit anyway to keep | |
170 | + //this going | |
171 | + mWeatherUnit = WeatherContract.WeatherColumns.TempUnit.CELSIUS; | |
172 | + } | |
173 | + } | |
174 | + | |
175 | + private void fixCachedWeatherInfo() { | |
176 | + if (mCachedInfo.tempUnit == CELSIUS && mWeatherUnit == FAHRENHEIT) { | |
177 | + mCachedInfo.temp = WeatherUtils.celsiusToFahrenheit(mCachedInfo.temp); | |
178 | + mCachedInfo.tempUnit = FAHRENHEIT; | |
179 | + } else if (mCachedInfo.tempUnit == FAHRENHEIT && mWeatherUnit == CELSIUS) { | |
180 | + mCachedInfo.temp = WeatherUtils.fahrenheitToCelsius(mCachedInfo.temp); | |
181 | + mCachedInfo.tempUnit = CELSIUS; | |
182 | + } | |
183 | + } | |
126 | 184 | } |
@@ -22,6 +22,7 @@ import android.support.v14.preference.PreferenceFragment; | ||
22 | 22 | import android.support.v7.preference.Preference; |
23 | 23 | import android.support.v7.preference.PreferenceScreen; |
24 | 24 | import android.util.Log; |
25 | +import android.view.MenuItem; | |
25 | 26 | |
26 | 27 | import com.android.settingslib.drawer.SettingsDrawerActivity; |
27 | 28 | import com.android.systemui.R; |
@@ -73,6 +74,15 @@ public class TunerActivity extends SettingsDrawerActivity implements | ||
73 | 74 | } |
74 | 75 | |
75 | 76 | @Override |
77 | + public boolean onOptionsItemSelected(MenuItem item) { | |
78 | + if (item.getItemId() == android.R.id.home) { | |
79 | + onBackPressed(); | |
80 | + return true; | |
81 | + } | |
82 | + return super.onOptionsItemSelected(item); | |
83 | + } | |
84 | + | |
85 | + @Override | |
76 | 86 | public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) { |
77 | 87 | try { |
78 | 88 | Class<?> cls = Class.forName(pref.getFragment()); |
@@ -143,6 +143,7 @@ import java.util.Collections; | ||
143 | 143 | import java.util.HashMap; |
144 | 144 | import java.util.List; |
145 | 145 | |
146 | +import cyanogenmod.hardware.CMHardwareManager; | |
146 | 147 | import cyanogenmod.providers.CMSettings; |
147 | 148 | |
148 | 149 | /** |
@@ -236,6 +237,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub | ||
236 | 237 | private boolean mNotificationShown; |
237 | 238 | private final boolean mImeSelectedOnBoot; |
238 | 239 | |
240 | + private CMHardwareManager mCMHardware; | |
241 | + | |
239 | 242 | static class SessionState { |
240 | 243 | final ClientState client; |
241 | 244 | final IInputMethod method; |
@@ -521,6 +524,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub | ||
521 | 524 | updateFromSettingsLocked(true); |
522 | 525 | } |
523 | 526 | }, userId); |
527 | + if (mCMHardware.isSupported(CMHardwareManager.FEATURE_HIGH_TOUCH_SENSITIVITY)) { | |
528 | + resolver.registerContentObserver(CMSettings.System.getUriFor( | |
529 | + CMSettings.System.HIGH_TOUCH_SENSITIVITY_ENABLE), false, this, userId); | |
530 | + } | |
531 | + if (mCMHardware.isSupported(CMHardwareManager.FEATURE_TOUCH_HOVERING)) { | |
532 | + resolver.registerContentObserver(CMSettings.Secure.getUriFor( | |
533 | + CMSettings.Secure.FEATURE_TOUCH_HOVERING), false, this, userId); | |
534 | + } | |
524 | 535 | |
525 | 536 | mRegistered = true; |
526 | 537 | } |
@@ -530,6 +541,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub | ||
530 | 541 | Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); |
531 | 542 | final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor( |
532 | 543 | Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE); |
544 | + final Uri touchSensitivityUri = | |
545 | + CMSettings.System.getUriFor(CMSettings.System.HIGH_TOUCH_SENSITIVITY_ENABLE); | |
546 | + final Uri touchHoveringUri = | |
547 | + CMSettings.Secure.getUriFor(CMSettings.Secure.FEATURE_TOUCH_HOVERING); | |
533 | 548 | synchronized (mMethodMap) { |
534 | 549 | if (showImeUri.equals(uri)) { |
535 | 550 | updateKeyboardFromSettingsLocked(); |
@@ -545,6 +560,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub | ||
545 | 560 | } else if (mShowRequested) { |
546 | 561 | showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null); |
547 | 562 | } |
563 | + } else if (touchSensitivityUri.equals(uri)) { | |
564 | + updateTouchSensitivity(); | |
565 | + } else if (touchHoveringUri.equals(uri)) { | |
566 | + updateTouchHovering(); | |
548 | 567 | } else { |
549 | 568 | boolean enabledChanged = false; |
550 | 569 | String newEnabled = mSettings.getEnabledInputMethodsStr(); |
@@ -941,11 +960,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub | ||
941 | 960 | } |
942 | 961 | } |
943 | 962 | |
944 | - synchronized (mMethodMap) { | |
945 | - mSettingsObserver.registerContentObserverLocked(userId); | |
946 | - updateFromSettingsLocked(true); | |
947 | - } | |
948 | - | |
949 | 963 | // IMMS wants to receive Intent.ACTION_LOCALE_CHANGED in order to update the current IME |
950 | 964 | // according to the new system locale. |
951 | 965 | final IntentFilter filter = new IntentFilter(); |
@@ -1056,6 +1070,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub | ||
1056 | 1070 | mContext.getBasePackageName()); |
1057 | 1071 | } |
1058 | 1072 | |
1073 | + updateTouchHovering(); | |
1074 | + updateTouchSensitivity(); | |
1075 | + | |
1059 | 1076 | if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId |
1060 | 1077 | + " selectedIme=" + mSettings.getSelectedInputMethod()); |
1061 | 1078 | } |
@@ -1090,6 +1107,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub | ||
1090 | 1107 | final int currentUserId = mSettings.getCurrentUserId(); |
1091 | 1108 | mSettings.switchCurrentUser(currentUserId, |
1092 | 1109 | !mUserManager.isUserUnlockingOrUnlocked(currentUserId)); |
1110 | + | |
1111 | + // Must happen before registerContentObserverLocked | |
1112 | + mCMHardware = CMHardwareManager.getInstance(mContext); | |
1113 | + | |
1114 | + mSettingsObserver.registerContentObserverLocked(currentUserId); | |
1115 | + updateFromSettingsLocked(true); | |
1116 | + | |
1117 | + updateTouchHovering(); | |
1118 | + updateTouchSensitivity(); | |
1119 | + | |
1093 | 1120 | mKeyguardManager = mContext.getSystemService(KeyguardManager.class); |
1094 | 1121 | mNotificationManager = mContext.getSystemService(NotificationManager.class); |
1095 | 1122 | mStatusBar = statusBar; |
@@ -1989,6 +2016,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub | ||
1989 | 2016 | |
1990 | 2017 | } |
1991 | 2018 | |
2019 | + private void updateTouchSensitivity() { | |
2020 | + if (!mCMHardware.isSupported(CMHardwareManager.FEATURE_HIGH_TOUCH_SENSITIVITY)) { | |
2021 | + return; | |
2022 | + } | |
2023 | + final boolean enabled = CMSettings.System.getInt(mContext.getContentResolver(), | |
2024 | + CMSettings.System.HIGH_TOUCH_SENSITIVITY_ENABLE, 0) == 1; | |
2025 | + mCMHardware.set(CMHardwareManager.FEATURE_HIGH_TOUCH_SENSITIVITY, enabled); | |
2026 | + } | |
2027 | + | |
2028 | + private void updateTouchHovering() { | |
2029 | + if (!mCMHardware.isSupported(CMHardwareManager.FEATURE_TOUCH_HOVERING)) { | |
2030 | + return; | |
2031 | + } | |
2032 | + final boolean enabled = CMSettings.Secure.getInt(mContext.getContentResolver(), | |
2033 | + CMSettings.Secure.FEATURE_TOUCH_HOVERING, 0) == 1; | |
2034 | + mCMHardware.set(CMHardwareManager.FEATURE_TOUCH_HOVERING, enabled); | |
2035 | + } | |
2036 | + | |
1992 | 2037 | public void updateKeyboardFromSettingsLocked() { |
1993 | 2038 | mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled(); |
1994 | 2039 | if (mSwitchingDialog != null |
@@ -213,6 +213,7 @@ public class InputManagerService extends IInputManager.Stub | ||
213 | 213 | InputChannel fromChannel, InputChannel toChannel); |
214 | 214 | private static native void nativeSetPointerSpeed(long ptr, int speed); |
215 | 215 | private static native void nativeSetShowTouches(long ptr, boolean enabled); |
216 | + private static native void nativeSetStylusIconEnabled(long ptr, boolean enabled); | |
216 | 217 | private static native void nativeSetVolumeKeysRotation(long ptr, int mode); |
217 | 218 | private static native void nativeSetInteractive(long ptr, boolean interactive); |
218 | 219 | private static native void nativeReloadCalibration(long ptr); |
@@ -344,6 +345,7 @@ public class InputManagerService extends IInputManager.Stub | ||
344 | 345 | registerPointerSpeedSettingObserver(); |
345 | 346 | registerShowTouchesSettingObserver(); |
346 | 347 | registerAccessibilityLargePointerSettingObserver(); |
348 | + registerStylusIconEnabledSettingObserver(); | |
347 | 349 | registerVolumeKeysRotationSettingObserver(); |
348 | 350 | |
349 | 351 | mContext.registerReceiver(new BroadcastReceiver() { |
@@ -352,6 +354,7 @@ public class InputManagerService extends IInputManager.Stub | ||
352 | 354 | updatePointerSpeedFromSettings(); |
353 | 355 | updateShowTouchesFromSettings(); |
354 | 356 | updateAccessibilityLargePointerFromSettings(); |
357 | + updateStylusIconEnabledFromSettings(); | |
355 | 358 | updateVolumeKeysRotationFromSettings(); |
356 | 359 | } |
357 | 360 | }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); |
@@ -359,6 +362,7 @@ public class InputManagerService extends IInputManager.Stub | ||
359 | 362 | updatePointerSpeedFromSettings(); |
360 | 363 | updateShowTouchesFromSettings(); |
361 | 364 | updateAccessibilityLargePointerFromSettings(); |
365 | + updateStylusIconEnabledFromSettings(); | |
362 | 366 | updateVolumeKeysRotationFromSettings(); |
363 | 367 | } |
364 | 368 |
@@ -1686,6 +1690,32 @@ public class InputManagerService extends IInputManager.Stub | ||
1686 | 1690 | return result; |
1687 | 1691 | } |
1688 | 1692 | |
1693 | + public void updateStylusIconEnabledFromSettings() { | |
1694 | + int enabled = getStylusIconEnabled(0); | |
1695 | + nativeSetStylusIconEnabled(mPtr, enabled != 0); | |
1696 | + } | |
1697 | + | |
1698 | + public void registerStylusIconEnabledSettingObserver() { | |
1699 | + mContext.getContentResolver().registerContentObserver( | |
1700 | + CMSettings.System.getUriFor(CMSettings.System.STYLUS_ICON_ENABLED), false, | |
1701 | + new ContentObserver(mHandler) { | |
1702 | + @Override | |
1703 | + public void onChange(boolean selfChange) { | |
1704 | + updateStylusIconEnabledFromSettings(); | |
1705 | + } | |
1706 | + }); | |
1707 | + } | |
1708 | + | |
1709 | + private int getStylusIconEnabled(int defaultValue) { | |
1710 | + int result = defaultValue; | |
1711 | + try { | |
1712 | + result = CMSettings.System.getInt(mContext.getContentResolver(), | |
1713 | + CMSettings.System.STYLUS_ICON_ENABLED); | |
1714 | + } catch (CMSettings.CMSettingNotFoundException snfe) { | |
1715 | + } | |
1716 | + return result; | |
1717 | + } | |
1718 | + | |
1689 | 1719 | public void updateVolumeKeysRotationFromSettings() { |
1690 | 1720 | int mode = getVolumeKeysRotationSetting(0); |
1691 | 1721 | nativeSetVolumeKeysRotation(mPtr, mode); |
@@ -24,6 +24,7 @@ import com.android.internal.logging.MetricsProto.MetricsEvent; | ||
24 | 24 | import com.android.internal.telephony.TelephonyIntents; |
25 | 25 | import com.android.internal.telephony.TelephonyProperties; |
26 | 26 | import com.android.internal.R; |
27 | +import com.android.internal.util.UserIcons; | |
27 | 28 | import com.android.internal.widget.LockPatternUtils; |
28 | 29 | |
29 | 30 | import android.app.ActivityManager; |
@@ -40,6 +41,14 @@ import android.content.IntentFilter; | ||
40 | 41 | import android.content.pm.UserInfo; |
41 | 42 | import android.content.ServiceConnection; |
42 | 43 | import android.database.ContentObserver; |
44 | +import android.graphics.Bitmap; | |
45 | +import android.graphics.BitmapShader; | |
46 | +import android.graphics.Canvas; | |
47 | +import android.graphics.Matrix; | |
48 | +import android.graphics.Paint; | |
49 | +import android.graphics.RectF; | |
50 | +import android.graphics.Shader; | |
51 | +import android.graphics.drawable.BitmapDrawable; | |
43 | 52 | import android.graphics.drawable.Drawable; |
44 | 53 | import android.Manifest; |
45 | 54 | import android.media.AudioManager; |
@@ -617,16 +626,24 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac | ||
617 | 626 | if (um.isUserSwitcherEnabled()) { |
618 | 627 | List<UserInfo> users = um.getUsers(); |
619 | 628 | UserInfo currentUser = getCurrentUser(); |
629 | + final int avatarSize = mContext.getResources().getDimensionPixelSize( | |
630 | + com.android.internal.R.dimen.global_actions_avatar_size); | |
620 | 631 | for (final UserInfo user : users) { |
621 | 632 | if (user.supportsSwitchToByUser()) { |
622 | 633 | boolean isCurrentUser = currentUser == null |
623 | 634 | ? user.id == 0 : (currentUser.id == user.id); |
624 | - Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath) | |
625 | - : null; | |
635 | + Drawable avatar = null; | |
636 | + Bitmap rawAvatar = um.getUserIcon(user.id); | |
637 | + if (rawAvatar == null) { | |
638 | + rawAvatar = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon( | |
639 | + user.isGuest() ? UserHandle.USER_NULL : user.id, /*light=*/ false)); | |
640 | + } | |
641 | + avatar = new BitmapDrawable(mContext.getResources(), | |
642 | + createCircularClip(rawAvatar, avatarSize, avatarSize)); | |
643 | + | |
626 | 644 | SinglePressAction switchToUser = new SinglePressAction( |
627 | - com.android.internal.R.drawable.ic_lock_user, icon, | |
628 | - (user.name != null ? user.name : "Primary") | |
629 | - + (isCurrentUser ? " \u2714" : "")) { | |
645 | + com.android.internal.R.drawable.ic_lock_user, avatar, | |
646 | + (user.name != null ? user.name : "Primary")) { | |
630 | 647 | public void onPress() { |
631 | 648 | try { |
632 | 649 | ActivityManagerNative.getDefault().switchUser(user.id); |
@@ -643,6 +660,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac | ||
643 | 660 | return false; |
644 | 661 | } |
645 | 662 | }; |
663 | + if (isCurrentUser) { | |
664 | + switchToUser.setStatus(mContext.getString( | |
665 | + R.string.global_action_current_user)); | |
666 | + } | |
646 | 667 | items.add(switchToUser); |
647 | 668 | } |
648 | 669 | } |
@@ -894,6 +915,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac | ||
894 | 915 | private final Drawable mIcon; |
895 | 916 | private final int mMessageResId; |
896 | 917 | private final CharSequence mMessage; |
918 | + private CharSequence mStatusMessage; | |
897 | 919 | |
898 | 920 | protected SinglePressAction(int iconResId, int messageResId) { |
899 | 921 | mIconResId = iconResId; |
@@ -913,8 +935,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac | ||
913 | 935 | return true; |
914 | 936 | } |
915 | 937 | |
916 | - public String getStatus() { | |
917 | - return null; | |
938 | + public CharSequence getStatus() { | |
939 | + return mStatusMessage; | |
940 | + } | |
941 | + | |
942 | + public void setStatus(CharSequence status) { | |
943 | + mStatusMessage = status; | |
918 | 944 | } |
919 | 945 | |
920 | 946 | abstract public void onPress(); |
@@ -935,7 +961,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac | ||
935 | 961 | TextView messageView = (TextView) v.findViewById(R.id.message); |
936 | 962 | |
937 | 963 | TextView statusView = (TextView) v.findViewById(R.id.status); |
938 | - final String status = getStatus(); | |
964 | + final CharSequence status = getStatus(); | |
939 | 965 | if (!TextUtils.isEmpty(status)) { |
940 | 966 | statusView.setText(status); |
941 | 967 | } else { |
@@ -943,7 +969,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac | ||
943 | 969 | } |
944 | 970 | if (mIcon != null) { |
945 | 971 | icon.setImageDrawable(mIcon); |
946 | - icon.setScaleType(ScaleType.CENTER_CROP); | |
972 | + icon.setScaleType(ScaleType.CENTER); | |
947 | 973 | } else if (mIconResId != 0) { |
948 | 974 | icon.setImageDrawable(context.getDrawable(mIconResId)); |
949 | 975 | } |
@@ -1296,6 +1322,33 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac | ||
1296 | 1322 | } |
1297 | 1323 | } |
1298 | 1324 | |
1325 | + /** | |
1326 | + * Generate a new bitmap (width x height pixels, ARGB_8888) with the input bitmap scaled | |
1327 | + * to fit and clipped to an inscribed circle. | |
1328 | + * @param input Bitmap to resize and clip | |
1329 | + * @param width Width of output bitmap (and diameter of circle) | |
1330 | + * @param height Height of output bitmap | |
1331 | + * @return A shiny new bitmap for you to use | |
1332 | + */ | |
1333 | + private static Bitmap createCircularClip(Bitmap input, int width, int height) { | |
1334 | + if (input == null) return null; | |
1335 | + | |
1336 | + final int inWidth = input.getWidth(); | |
1337 | + final int inHeight = input.getHeight(); | |
1338 | + final Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); | |
1339 | + final Canvas canvas = new Canvas(output); | |
1340 | + final Paint paint = new Paint(); | |
1341 | + paint.setShader(new BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); | |
1342 | + paint.setAntiAlias(true); | |
1343 | + final RectF srcRect = new RectF(0, 0, inWidth, inHeight); | |
1344 | + final RectF dstRect = new RectF(0, 0, width, height); | |
1345 | + final Matrix m = new Matrix(); | |
1346 | + m.setRectToRect(srcRect, dstRect, Matrix.ScaleToFit.CENTER); | |
1347 | + canvas.setMatrix(m); | |
1348 | + canvas.drawCircle(inWidth / 2, inHeight / 2, inWidth / 2, paint); | |
1349 | + return output; | |
1350 | + } | |
1351 | + | |
1299 | 1352 | private static final class GlobalActionsDialog extends Dialog implements DialogInterface { |
1300 | 1353 | private final Context mContext; |
1301 | 1354 | private final int mWindowTouchSlop; |
@@ -202,6 +202,7 @@ public: | ||
202 | 202 | void setSystemUiVisibility(int32_t visibility); |
203 | 203 | void setPointerSpeed(int32_t speed); |
204 | 204 | void setShowTouches(bool enabled); |
205 | + void setStylusIconEnabled(bool enabled); | |
205 | 206 | void setVolumeKeysRotation(int mode); |
206 | 207 | void setInteractive(bool interactive); |
207 | 208 | void reloadCalibration(); |
@@ -277,6 +278,9 @@ private: | ||
277 | 278 | // Show touches feature enable/disable. |
278 | 279 | bool showTouches; |
279 | 280 | |
281 | + // Show icon when stylus is used | |
282 | + bool stylusIconEnabled; | |
283 | + | |
280 | 284 | // Volume keys rotation mode (0 - off, 1 - phone, 2 - tablet) |
281 | 285 | int32_t volumeKeysRotationMode; |
282 | 286 |
@@ -316,6 +320,7 @@ NativeInputManager::NativeInputManager(jobject contextObj, | ||
316 | 320 | mLocked.pointerSpeed = 0; |
317 | 321 | mLocked.pointerGesturesEnabled = true; |
318 | 322 | mLocked.showTouches = false; |
323 | + mLocked.stylusIconEnabled = false; | |
319 | 324 | mLocked.volumeKeysRotationMode = 0; |
320 | 325 | } |
321 | 326 | mInteractive = true; |
@@ -464,6 +469,7 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon | ||
464 | 469 | outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled; |
465 | 470 | |
466 | 471 | outConfig->showTouches = mLocked.showTouches; |
472 | + outConfig->stylusIconEnabled = mLocked.stylusIconEnabled; | |
467 | 473 | outConfig->volumeKeysRotationMode = mLocked.volumeKeysRotationMode; |
468 | 474 | |
469 | 475 | outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport); |
@@ -773,6 +779,22 @@ void NativeInputManager::setShowTouches(bool enabled) { | ||
773 | 779 | InputReaderConfiguration::CHANGE_SHOW_TOUCHES); |
774 | 780 | } |
775 | 781 | |
782 | +void NativeInputManager::setStylusIconEnabled(bool enabled) { | |
783 | + { // acquire lock | |
784 | + AutoMutex _l(mLock); | |
785 | + | |
786 | + if (mLocked.stylusIconEnabled == enabled) { | |
787 | + return; | |
788 | + } | |
789 | + | |
790 | + ALOGI("Setting stylus icon enabled to %s.", enabled ? "enabled" : "disabled"); | |
791 | + mLocked.stylusIconEnabled = enabled; | |
792 | + } // release lock | |
793 | + | |
794 | + mInputManager->getReader()->requestRefreshConfiguration( | |
795 | + InputReaderConfiguration::CHANGE_STYLUS_ICON_ENABLED); | |
796 | +} | |
797 | + | |
776 | 798 | void NativeInputManager::setVolumeKeysRotation(int mode) { |
777 | 799 | { // acquire lock |
778 | 800 | AutoMutex _l(mLock); |
@@ -1394,6 +1416,13 @@ static void nativeSetShowTouches(JNIEnv* /* env */, | ||
1394 | 1416 | im->setShowTouches(enabled); |
1395 | 1417 | } |
1396 | 1418 | |
1419 | +static void nativeSetStylusIconEnabled(JNIEnv* env, | |
1420 | + jclass clazz, jlong ptr, jboolean enabled) { | |
1421 | + NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); | |
1422 | + | |
1423 | + im->setStylusIconEnabled(enabled); | |
1424 | +} | |
1425 | + | |
1397 | 1426 | static void nativeSetVolumeKeysRotation(JNIEnv* env, |
1398 | 1427 | jclass clazz, jlong ptr, int mode) { |
1399 | 1428 | NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); |
@@ -1544,6 +1573,8 @@ static const JNINativeMethod gInputManagerMethods[] = { | ||
1544 | 1573 | (void*) nativeSetPointerSpeed }, |
1545 | 1574 | { "nativeSetShowTouches", "(JZ)V", |
1546 | 1575 | (void*) nativeSetShowTouches }, |
1576 | + { "nativeSetStylusIconEnabled", "(JZ)V", | |
1577 | + (void*) nativeSetStylusIconEnabled }, | |
1547 | 1578 | { "nativeSetVolumeKeysRotation", "(JI)V", |
1548 | 1579 | (void*) nativeSetVolumeKeysRotation }, |
1549 | 1580 | { "nativeSetInteractive", "(JZ)V", |