• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

frameworks/base


Commit MetaInfo

修訂8f27b777331d888cf956dc6861125be677a63dfe (tree)
時間2016-10-11 04:38:36
作者Jaap Jan Meijer <jjmeijer88@gmai...>
CommiterJaap Jan Meijer

Log Message

Merge remote-tracking branch 'cm/cm-14.0' into cm-14.0-x86

Change Summary

差異

--- /dev/null
+++ b/core/res/res/values/cm_dimens.xml
@@ -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>
--- a/core/res/res/values/cm_strings.xml
+++ b/core/res/res/values/cm_strings.xml
@@ -43,6 +43,8 @@
4343
4444 <!-- label for item that reboots the phone in phone options dialog -->
4545 <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>
4648
4749 <!-- Reboot menu -->
4850 <!-- Button to reboot the phone, within the Reboot Options dialog -->
--- a/core/res/res/values/cm_symbols.xml
+++ b/core/res/res/values/cm_symbols.xml
@@ -72,4 +72,7 @@
7272 <!-- Automatic brightness enhancements -->
7373 <java-symbol type="integer" name="config_autoBrightnessBrighteningLightFastDebounce"/>
7474
75+ <java-symbol type="string" name="global_action_current_user" />
76+ <java-symbol type="dimen" name="global_actions_avatar_size" />
77+
7578 </resources>
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -34,6 +34,7 @@
3434 android:layout_height="wrap_content"
3535 android:layout_gravity="center_horizontal|top"
3636 android:orientation="vertical" >
37+
3738 <TextClock
3839 android:id="@+id/clock_view"
3940 android:layout_width="wrap_content"
@@ -47,6 +48,19 @@
4748 android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
4849
4950 <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+
5064 <TextView
5165 android:id="@+id/owner_info"
5266 android:layout_marginLeft="16dp"
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -165,9 +165,6 @@
165165 <!-- the ability to rename notifications posted by other apps -->
166166 <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
167167
168- <!-- Weather -->
169- <uses-permission android:name="com.cyanogenmod.lockclock.permission.READ_WEATHER" />
170-
171168 <!-- manage cmsettings -->
172169 <uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS" />
173170 <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" />
--- a/packages/SystemUI/AndroidManifest_cm.xml
+++ b/packages/SystemUI/AndroidManifest_cm.xml
@@ -20,11 +20,16 @@
2020 package="com.android.systemui">
2121
2222 <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" />
23+ <uses-permission android:name="cyanogenmod.permission.WRITE_SETTINGS" />
2324
2425 <!-- Visualizer -->
2526 <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
2627 <uses-permission android:name="android.permission.RECORD_AUDIO" />
2728
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+
2833 <application>
2934
3035 <activity-alias
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_on_priority.xml
@@ -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>
--- /dev/null
+++ b/packages/SystemUI/res/drawable/queue_bg.xml
@@ -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>
--- /dev/null
+++ b/packages/SystemUI/res/drawable/queue_row_background.xml
@@ -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>
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd_priority.xml
@@ -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>
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -184,4 +184,14 @@
184184 android:layout_marginEnd="8dp"
185185 android:focusable="true"/>
186186 </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+
187197 </com.android.systemui.statusbar.NotificationGuts>
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_guts_media_extension.xml
@@ -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>
--- /dev/null
+++ b/packages/SystemUI/res/layout/queue_adapter_row.xml
@@ -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>
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -113,7 +113,6 @@
113113 android:layout_width="wrap_content"
114114 android:layout_height="wrap_content"
115115 android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin"
116- android:background="@drawable/ripple_drawable"
117116 android:layout_alignParentBottom="true">
118117 <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed"
119118 android:layout_width="wrap_content"
@@ -121,6 +120,7 @@
121120 android:layout_marginStart="16dp"
122121 android:singleLine="true"
123122 android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
123+ android:background="@drawable/ripple_drawable"
124124 android:layout_below="@id/clock"
125125 systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm"
126126 />
@@ -131,6 +131,7 @@
131131 android:layout_marginStart="16dp"
132132 android:singleLine="true"
133133 android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
134+ android:background="@drawable/ripple_drawable"
134135 android:layout_below="@id/clock"
135136 systemui:datePattern="eeeeMMMMd"
136137 />
@@ -183,7 +184,7 @@
183184 android:layout_height="wrap_content"
184185 android:paddingEnd="16dp"
185186 android:gravity="right"
186- android:textColor="#ffffff"
187+ android:textColor="@color/status_bar_temperature_text_color"
187188 android:textSize="@dimen/weather_text_size"
188189 android:importantForAccessibility="noHideDescendants"/>
189190 <TextView
@@ -192,7 +193,7 @@
192193 android:layout_height="wrap_content"
193194 android:paddingEnd="16dp"
194195 android:gravity="right"
195- android:textColor="#ffffff"
196+ android:textColor="@color/status_bar_temperature_location_text_color"
196197 android:textSize="@dimen/weather_text_size"
197198 android:importantForAccessibility="noHideDescendants"/>
198199 </LinearLayout>
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_row_media.xml
@@ -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>
--- /dev/null
+++ b/packages/SystemUI/res/values/cm_colors.xml
@@ -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>
--- a/packages/SystemUI/res/values/cm_dimens.xml
+++ b/packages/SystemUI/res/values/cm_dimens.xml
@@ -23,4 +23,8 @@
2323 <dimen name="phone_bottom_padding">40dp</dimen>
2424 <dimen name="phone_width">320dp</dimen>
2525 <dimen name="phone_height">420dp</dimen>
26+
27+ <dimen name="queue_row_height">52dp</dimen>
28+ <dimen name="queue_top_shadow">3dp</dimen>
29+
2630 </resources>
--- a/packages/SystemUI/res/values/cm_strings.xml
+++ b/packages/SystemUI/res/values/cm_strings.xml
@@ -48,4 +48,11 @@
4848 <string name="select_application">Select application</string>
4949 <string name="lockscreen_choose_action_title">Choose action</string>
5050 <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+
5158 </resources>
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -309,9 +309,6 @@
309309 <!-- Show 4GLTE for LTE -->
310310 <bool name="show_4glte_icon_for_lte">false</bool>
311311
312- <!-- When true, show charging animation -->
313- <bool name="config_show_battery_charging_anim">false</bool>
314-
315312 <bool name="config_show4gForIWlan">false</bool>
316313 <bool name="config_showSignalForIWlan">false</bool>
317314 </resources>
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -369,4 +369,8 @@
369369 <item name="android:colorBackground">@color/qs_edit_overflow_bg</item>
370370 </style>
371371
372+ <style name="ThemeOverlay.SwitchBar.Secondary" parent="@android:style/ThemeOverlay">
373+ <item name="android:colorAccent">@color/system_secondary_color</item>
374+ </style>
375+
372376 </resources>
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -100,17 +100,6 @@ public class BatteryMeterDrawable extends Drawable implements
100100 private int mLevel = -1;
101101 private boolean mPluggedIn;
102102 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- };
114103
115104 public BatteryMeterDrawable(Context context, Handler handler, int frameColor) {
116105 mContext = context;
@@ -210,7 +199,12 @@ public class BatteryMeterDrawable extends Drawable implements
210199 }
211200
212201 private void postInvalidate() {
213- mHandler.post(mInvalidate);
202+ mHandler.post(new Runnable() {
203+ @Override
204+ public void run() {
205+ invalidateSelf();
206+ }
207+ });
214208 }
215209
216210 public void setBatteryController(BatteryController batteryController) {
@@ -222,7 +216,7 @@ public class BatteryMeterDrawable extends Drawable implements
222216 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
223217 mLevel = level;
224218 mPluggedIn = pluggedIn;
225- mCharging = charging;
219+
226220 postInvalidate();
227221 }
228222
@@ -232,26 +226,6 @@ public class BatteryMeterDrawable extends Drawable implements
232226 invalidateSelf();
233227 }
234228
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-
255229 private static float[] loadBoltPoints(Resources res) {
256230 final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
257231 int maxX = 0, maxY = 0;
@@ -349,11 +323,7 @@ public class BatteryMeterDrawable extends Drawable implements
349323
350324 @Override
351325 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;
357327
358328 if (level == -1) return;
359329
@@ -547,4 +517,5 @@ public class BatteryMeterDrawable extends Drawable implements
547517 postInvalidate();
548518 }
549519 }
520+
550521 }
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -34,6 +34,7 @@ import android.view.ViewConfiguration;
3434 import com.android.systemui.statusbar.ExpandableNotificationRow;
3535 import com.android.systemui.statusbar.ExpandableView;
3636 import com.android.systemui.statusbar.FlingAnimationUtils;
37+import com.android.systemui.statusbar.MediaExpandableNotificationRow;
3738 import com.android.systemui.statusbar.policy.ScrollAdapter;
3839
3940 public class ExpandHelper implements Gefingerpoken {
@@ -97,7 +98,7 @@ public class ExpandHelper implements Gefingerpoken {
9798 private float mCurrentHeight;
9899
99100 private int mSmallSize;
100- private int mLargeSize;
101+ private int mLargeSize, mInitialLargeSize;
101102 private float mMaximumStretch;
102103 private boolean mOnlyMovements;
103104
@@ -162,6 +163,7 @@ public class ExpandHelper implements Gefingerpoken {
162163 mSmallSize = small;
163164 mMaximumStretch = mSmallSize * STRETCH_INTERVAL;
164165 mLargeSize = large;
166+ mInitialLargeSize = large;
165167 mContext = context;
166168 mCallback = callback;
167169 mScaler = new ViewScaler();
@@ -515,8 +517,15 @@ public class ExpandHelper implements Gefingerpoken {
515517 boolean canBeExpanded = mCallback.canChildBeExpanded(v);
516518 if (canBeExpanded) {
517519 if (DEBUG) Log.d(TAG, "working on an expandable child");
518- mNaturalHeight = mScaler.getNaturalHeight();
519520 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+ }
520529 } else {
521530 if (DEBUG) Log.d(TAG, "working on a non-expandable child");
522531 mNaturalHeight = mOldHeight;
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -142,7 +142,7 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
142142 checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
143143 switch (zen) {
144144 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);
146146 state.label = mContext.getString(R.string.quick_settings_dnd_priority_label);
147147 state.contentDescription = mContext.getString(
148148 R.string.accessibility_quick_settings_dnd_priority_on);
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -44,6 +44,7 @@ import android.database.ContentObserver;
4444 import android.graphics.Rect;
4545 import android.graphics.drawable.Drawable;
4646 import android.graphics.drawable.Icon;
47+import android.media.session.MediaController;
4748 import android.os.AsyncTask;
4849 import android.os.Build;
4950 import android.os.Bundle;
@@ -906,6 +907,10 @@ public abstract class BaseStatusBar extends SystemUI implements
906907 return null;
907908 }
908909
910+ protected MediaController getCurrentMediaController() {
911+ return null;
912+ }
913+
909914 @Override
910915 public NotificationGroupManager getGroupManager() {
911916 return mGroupManager;
@@ -1157,6 +1162,10 @@ public abstract class BaseStatusBar extends SystemUI implements
11571162 }
11581163
11591164 final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
1165+ if (v instanceof MediaExpandableNotificationRow
1166+ && !((MediaExpandableNotificationRow) v).inflateGuts()) {
1167+ return false;
1168+ }
11601169 bindGuts(row);
11611170
11621171 // Assume we are a status_bar_notification_row
@@ -1618,8 +1627,20 @@ public abstract class BaseStatusBar extends SystemUI implements
16181627 // create the row view
16191628 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
16201629 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+ }
16231644 row.setExpansionLogger(this, entry.notification.getKey());
16241645 row.setGroupManager(mGroupManager);
16251646 row.setHeadsUpManager(mHeadsUpManager);
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -88,7 +88,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
8888 private boolean mSensitive;
8989 private boolean mSensitiveHiddenInGeneral;
9090 private boolean mShowingPublicInitialized;
91- private boolean mHideSensitiveForIntrinsicHeight;
91+ protected boolean mHideSensitiveForIntrinsicHeight;
9292
9393 /**
9494 * Is this notification expanded by the system. The expansion state can be overridden by the
@@ -103,10 +103,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
103103
104104 private Animator mTranslateAnim;
105105 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;
110110 private View mVetoButton;
111111 private int mNotificationColor;
112112 private ExpansionLogger mLogger;
@@ -124,7 +124,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
124124 private boolean mIsSummaryWithChildren;
125125 private NotificationChildrenContainer mChildrenContainer;
126126 private ViewStub mSettingsIconRowStub;
127- private ViewStub mGutsStub;
127+ protected ViewStub mGutsStub;
128128 private boolean mIsSystemChildExpanded;
129129 private boolean mIsPinned;
130130 private FalsingManager mFalsingManager;
@@ -1003,10 +1003,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
10031003 return mSettingsIconRow;
10041004 }
10051005
1006- public void inflateGuts() {
1006+ public boolean inflateGuts() {
10071007 if (mGuts == null) {
10081008 mGutsStub.inflate();
10091009 }
1010+ return false;
10101011 }
10111012
10121013 private void updateChildrenVisibility() {
@@ -1264,7 +1265,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
12641265 }
12651266 }
12661267
1267- private void updateMaxHeights() {
1268+ protected void updateMaxHeights() {
12681269 int intrinsicBefore = getIntrinsicHeight();
12691270 View expandedChild = mPrivateLayout.getExpandedChild();
12701271 if (expandedChild == null) {
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -38,7 +38,7 @@ public abstract class ExpandableView extends FrameLayout {
3838 protected int mClipTopAmount;
3939 private boolean mDark;
4040 private ArrayList<View> mMatchParentViews = new ArrayList<View>();
41- private static Rect mClipRect = new Rect();
41+ private Rect mClipRect = new Rect();
4242 private boolean mWillBeGone;
4343 private int mMinClipTopAmount = 0;
4444 private boolean mClipToActualHeight = true;
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaExpandableNotificationRow.java
@@ -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+}
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/MediaNotificationGuts.java
@@ -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+}
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -58,9 +58,9 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
5858
5959 private static final long CLOSE_GUTS_DELAY = 8000;
6060
61- private Drawable mBackground;
62- private int mClipTopAmount;
63- private int mActualHeight;
61+ protected Drawable mBackground;
62+ protected int mClipTopAmount;
63+ protected int mActualHeight;
6464 private boolean mExposed;
6565 private INotificationManager mINotificationManager;
6666 private int mStartingUserImportance;
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/QueueView.java
@@ -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+}
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/QueueViewRow.java
@@ -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+}
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -67,9 +67,12 @@ import com.android.systemui.statusbar.NotificationData;
6767 import com.android.systemui.statusbar.StatusBarState;
6868 import com.android.systemui.statusbar.policy.HeadsUpManager;
6969 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
70+import com.android.systemui.statusbar.policy.WeatherController;
71+import com.android.systemui.statusbar.policy.WeatherControllerImpl;
7072 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
7173 import com.android.systemui.statusbar.stack.StackStateAnimator;
7274 import cyanogenmod.providers.CMSettings;
75+import cyanogenmod.weather.util.WeatherUtils;
7376
7477 import java.util.List;
7578
@@ -79,7 +82,7 @@ public class NotificationPanelView extends PanelView implements
7982 ExpandableView.OnHeightChangedListener,
8083 View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
8184 KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
82- HeadsUpManager.OnHeadsUpChangedListener {
85+ HeadsUpManager.OnHeadsUpChangedListener, WeatherController.Callback {
8386
8487 private static final boolean DEBUG = false;
8588
@@ -218,11 +221,15 @@ public class NotificationPanelView extends PanelView implements
218221 private Handler mHandler = new Handler();
219222 private SettingsObserver mSettingsObserver;
220223
221- private boolean mOneFingerQuickSettingsIntercept;
224+ private int mOneFingerQuickSettingsIntercept;
222225 private boolean mDoubleTapToSleepEnabled;
223226 private int mStatusBarHeaderHeight;
224227 private GestureDetector mDoubleTapGesture;
225228
229+ private boolean mKeyguardWeatherEnabled;
230+ private TextView mKeyguardWeatherInfo;
231+ private WeatherControllerImpl mWeatherController;
232+
226233 public NotificationPanelView(Context context, AttributeSet attrs) {
227234 super(context, attrs);
228235 setWillNotDraw(!DEBUG);
@@ -244,6 +251,11 @@ public class NotificationPanelView extends PanelView implements
244251 mStatusBar = bar;
245252 }
246253
254+ public void setWeatherController(WeatherControllerImpl weatherController) {
255+ mWeatherController = weatherController;
256+ mWeatherController.addCallback(this);
257+ }
258+
247259 @Override
248260 protected void onFinishInflate() {
249261 super.onFinishInflate();
@@ -288,6 +300,8 @@ public class NotificationPanelView extends PanelView implements
288300 mNotificationStackScroller.setQsContainer(mQsContainer);
289301 }
290302 });
303+
304+ mKeyguardWeatherInfo = (TextView) mKeyguardStatusView.findViewById(R.id.weather_info);
291305 }
292306
293307 @Override
@@ -370,14 +384,16 @@ public class NotificationPanelView extends PanelView implements
370384 }
371385
372386 @Override
373- public void onAttachedToWindow() {
387+ protected void onAttachedToWindow() {
388+ super.onAttachedToWindow();
374389 mSettingsObserver.observe();
375-
376390 }
377391
378392 @Override
379- public void onDetachedFromWindow() {
393+ protected void onDetachedFromWindow() {
394+ super.onDetachedFromWindow();
380395 mSettingsObserver.unobserve();
396+ mWeatherController.removeCallback(this);
381397 }
382398
383399 private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
@@ -833,13 +849,7 @@ public class NotificationPanelView extends PanelView implements
833849 && mQsExpansionEnabled) {
834850 mTwoFingerQsExpandPossible = true;
835851 }
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)
843853 && event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
844854 MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1);
845855 mQsExpandImmediate = true;
@@ -874,7 +884,22 @@ public class NotificationPanelView extends PanelView implements
874884 && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
875885 || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
876886
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;
878903 }
879904
880905 private void handleQsDown(MotionEvent event) {
@@ -1399,30 +1424,18 @@ public class NotificationPanelView extends PanelView implements
13991424 * @return Whether we should intercept a gesture to open Quick Settings.
14001425 */
14011426 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) {
14091427 if (!mQsExpansionEnabled || mCollapsedOnDown) {
14101428 return false;
14111429 }
14121430 View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
1413- boolean onHeader = useHeader && x >= mQsAutoReinflateContainer.getX()
1431+ boolean onHeader = x >= mQsAutoReinflateContainer.getX()
14141432 && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth()
14151433 && y >= header.getTop() && y <= header.getBottom();
14161434
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-
14221435 if (mQsExpanded) {
14231436 return onHeader || (yDiff < 0 && isInQsArea(x, y));
14241437 } else {
1425- return onHeader || showQsOverride;
1438+ return onHeader;
14261439 }
14271440 }
14281441
@@ -2406,6 +2419,19 @@ public class NotificationPanelView extends PanelView implements
24062419 mGroupManager = groupManager;
24072420 }
24082421
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+
24092435 class SettingsObserver extends ContentObserver {
24102436 SettingsObserver(Handler handler) {
24112437 super(handler);
@@ -2417,6 +2443,8 @@ public class NotificationPanelView extends PanelView implements
24172443 CMSettings.System.STATUS_BAR_QUICK_QS_PULLDOWN), false, this);
24182444 resolver.registerContentObserver(CMSettings.System.getUriFor(
24192445 CMSettings.System.DOUBLE_TAP_SLEEP_GESTURE), false, this);
2446+ resolver.registerContentObserver(CMSettings.Secure.getUriFor(
2447+ CMSettings.Secure.LOCK_SCREEN_WEATHER_ENABLED), false, this);
24202448 update();
24212449 }
24222450
@@ -2438,9 +2466,17 @@ public class NotificationPanelView extends PanelView implements
24382466 public void update() {
24392467 ContentResolver resolver = mContext.getContentResolver();
24402468 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);
24422470 mDoubleTapToSleepEnabled = CMSettings.System.getInt(
24432471 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+ }
24442480 }
24452481 }
24462482 }
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -151,6 +151,7 @@ import com.android.systemui.statusbar.ExpandableNotificationRow;
151151 import com.android.systemui.statusbar.GestureRecorder;
152152 import com.android.systemui.statusbar.KeyboardShortcuts;
153153 import com.android.systemui.statusbar.KeyguardIndicationController;
154+import com.android.systemui.statusbar.MediaExpandableNotificationRow;
154155 import com.android.systemui.statusbar.NotificationData;
155156 import com.android.systemui.statusbar.NotificationData.Entry;
156157 import com.android.systemui.statusbar.NotificationOverflowContainer;
@@ -1136,6 +1137,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
11361137 mKeyguardStatusBar.setBatteryController(mBatteryController);
11371138 mHeader.setWeatherController(mWeatherController);
11381139
1140+ mNotificationPanel.setWeatherController(mWeatherController);
1141+
11391142 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
11401143 mBroadcastReceiver.onReceive(mContext,
11411144 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
@@ -2223,6 +2226,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
22232226 Log.v(TAG, "DEBUG_MEDIA: insert listener, receive metadata: "
22242227 + mMediaMetadata);
22252228 }
2229+ if (mediaNotification != null
2230+ && mediaNotification.row != null
2231+ && mediaNotification.row instanceof MediaExpandableNotificationRow) {
2232+ ((MediaExpandableNotificationRow) mediaNotification.row)
2233+ .setMediaController(controller);
2234+ }
22262235
22272236 if (mediaNotification != null) {
22282237 mMediaNotificationKey = mediaNotification.notification.getKey();
@@ -2636,6 +2645,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
26362645 return mMediaNotificationKey;
26372646 }
26382647
2648+ @Override
2649+ protected MediaController getCurrentMediaController() {
2650+ return mMediaController;
2651+ }
2652+
26392653 public boolean isScrimSrcModeEnabled() {
26402654 return mScrimSrcModeEnabled;
26412655 }
@@ -3008,7 +3022,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
30083022 ServiceManager.getService("power"));
30093023 if (power != null) {
30103024 if (mAutomaticBrightness) {
3011- float adj = (value * 100) / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
3025+ float adj = (2 * value) - 1;
30123026 adj = Math.max(adj, -1);
30133027 adj = Math.min(adj, 1);
30143028 final float val = adj;
@@ -3130,19 +3144,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
31303144 }
31313145 if (mBrightnessChanged && upOrCancel) {
31323146 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) {
31383148 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;
31463149 }
31473150 }
31483151 return false;
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -258,8 +258,17 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro
258258
259259 if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) {
260260 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+ }
263272 zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
264273 } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
265274 zenVisible = true;
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -16,34 +16,22 @@
1616
1717 package com.android.systemui.statusbar.phone;
1818
19-import android.app.ActivityManager;
20-import android.app.ActivityManagerNative;
2119 import android.app.AlarmManager;
22-import android.app.IUserSwitchObserver;
2320 import android.app.PendingIntent;
2421 import android.content.ContentUris;
25-import android.content.ContentResolver;
2622 import android.content.Context;
2723 import android.content.Intent;
2824 import android.content.res.Configuration;
2925 import android.content.res.Resources;
30-import android.database.ContentObserver;
3126 import android.graphics.Outline;
3227 import android.graphics.Rect;
3328 import android.graphics.drawable.Animatable;
3429 import android.graphics.drawable.Drawable;
3530 import android.graphics.drawable.RippleDrawable;
3631 import android.net.Uri;
37-import android.os.Handler;
38-import android.os.IRemoteCallback;
39-import android.os.RemoteException;
40-import android.os.UserHandle;
4132 import android.provider.AlarmClock;
4233 import android.provider.CalendarContract;
43-import android.provider.Settings;
44-import android.net.Uri;
4534 import android.util.AttributeSet;
46-import android.util.Log;
4735 import android.util.MathUtils;
4836 import android.util.TypedValue;
4937 import android.view.View;
@@ -55,11 +43,11 @@ import android.widget.RelativeLayout;
5543 import android.widget.Switch;
5644 import android.widget.TextView;
5745 import android.widget.Toast;
46+
5847 import com.android.keyguard.KeyguardStatusView;
5948 import com.android.systemui.BatteryMeterView;
6049 import com.android.systemui.FontSizeUtils;
6150 import com.android.systemui.R;
62-import com.android.systemui.cm.UserContentObserver;
6351 import com.android.systemui.qs.QSPanel;
6452 import com.android.systemui.qs.QSPanel.Callback;
6553 import com.android.systemui.qs.QSTile;
@@ -75,13 +63,14 @@ import com.android.systemui.tuner.TunerService;
7563 import java.text.NumberFormat;
7664
7765 import cyanogenmod.providers.CMSettings;
66+import cyanogenmod.weather.util.WeatherUtils;
7867
7968 /**
8069 * The view to manage the header area in the expanded status bar.
8170 */
8271 public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnClickListener,
8372 BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback,
84- EmergencyListener, WeatherController.Callback {
73+ EmergencyListener, WeatherController.Callback, TunerService.Tunable {
8574
8675 private boolean mExpanded;
8776 private boolean mListening;
@@ -152,7 +141,6 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC
152141 private float mCurrentT;
153142 private boolean mShowingDetail;
154143 private boolean mDetailTransitioning;
155- private SettingsObserver mSettingsObserver;
156144 private boolean mShowWeather;
157145
158146 private boolean mAllowExpand = true;
@@ -195,7 +183,6 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC
195183 mWeatherContainer.setOnClickListener(this);
196184 mWeatherLine1 = (TextView) findViewById(R.id.weather_line_1);
197185 mWeatherLine2 = (TextView) findViewById(R.id.weather_line_2);
198- mSettingsObserver = new SettingsObserver(new Handler());
199186 loadDimens();
200187 updateVisibilities();
201188 updateClockScale();
@@ -419,7 +406,8 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC
419406
420407 private void updateListeners() {
421408 if (mListening) {
422- mSettingsObserver.observe();
409+ TunerService.get(getContext()).addTunable(this,
410+ "cmsystem:" + CMSettings.System.STATUS_BAR_SHOW_WEATHER);
423411 mBatteryController.addStateChangedCallback(this);
424412 mNextAlarmController.addStateChangedCallback(this);
425413 mWeatherController.addCallback(this);
@@ -427,7 +415,7 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC
427415 mBatteryController.removeStateChangedCallback(this);
428416 mNextAlarmController.removeStateChangedCallback(this);
429417 mWeatherController.removeCallback(this);
430- mSettingsObserver.unobserve();
418+ TunerService.get(getContext()).removeTunable(this);
431419 }
432420 }
433421
@@ -479,12 +467,12 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC
479467
480468 @Override
481469 public void onWeatherChanged(WeatherController.WeatherInfo info) {
482- if (info.temp == null || info.condition == null) {
470+ if (Double.isNaN(info.temp) || info.condition == null) {
483471 mWeatherLine1.setText(null);
484472 } else {
485473 mWeatherLine1.setText(mContext.getString(
486474 R.string.status_bar_expanded_header_weather_format,
487- info.temp,
475+ WeatherUtils.formatTemperature(info.temp, info.tempUnit),
488476 info.condition));
489477 }
490478 mWeatherLine2.setText(info.city);
@@ -930,35 +918,10 @@ public class StatusBarHeaderView extends BaseStatusBarHeader implements View.OnC
930918 }
931919 };
932920
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);
962925 updateVisibilities();
963926 }
964927 }
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherController.java
@@ -25,8 +25,9 @@ public interface WeatherController {
2525 void onWeatherChanged(WeatherInfo temp);
2626 }
2727 public static class WeatherInfo {
28- public String temp = null;
28+ public double temp = Double.NaN;
2929 public String city = null;
3030 public String condition = null;
31+ public int tempUnit;
3132 }
3233 }
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WeatherControllerImpl.java
@@ -16,43 +16,49 @@
1616
1717 package com.android.systemui.statusbar.policy;
1818
19-import android.content.BroadcastReceiver;
2019 import android.content.ComponentName;
21-import android.content.ContentResolver;
2220 import android.content.Context;
2321 import android.content.Intent;
24-import android.content.IntentFilter;
2522 import android.database.ContentObserver;
2623 import android.database.Cursor;
2724 import android.net.Uri;
2825 import android.os.Handler;
29-import android.provider.Settings;
3026 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;
3131
3232 import java.util.ArrayList;
3333
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+
3441 public class WeatherControllerImpl implements WeatherController {
3542
3643 private static final String TAG = WeatherController.class.getSimpleName();
3744 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;
3849
3950 public static final ComponentName COMPONENT_WEATHER_FORECAST = new ComponentName(
4051 "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";
4452 public static final String ACTION_FORCE_WEATHER_UPDATE
4553 = "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
5259 };
5360
5461 private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
55- private final Receiver mReceiver = new Receiver();
5662 private final Context mContext;
5763
5864 private WeatherInfo mCachedInfo = new WeatherInfo();
@@ -60,10 +66,16 @@ public class WeatherControllerImpl implements WeatherController {
6066 public WeatherControllerImpl(Context context) {
6167 mContext = context;
6268 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();
6378 queryWeather();
64- final IntentFilter filter = new IntentFilter();
65- filter.addAction(ACTION_UPDATE_FINISHED);
66- mContext.registerReceiver(mReceiver, filter);
6779 }
6880
6981 public void addCallback(Callback callback) {
@@ -85,17 +97,29 @@ public class WeatherControllerImpl implements WeatherController {
8597 }
8698
8799 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,
89102 null, null, null);
90103 if (c == null) {
91104 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
92107 mContext.sendBroadcast(new Intent(ACTION_FORCE_WEATHER_UPDATE));
93108 } else {
94109 try {
95110 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);
99123 } finally {
100124 c.close();
101125 }
@@ -108,19 +132,53 @@ public class WeatherControllerImpl implements WeatherController {
108132 }
109133 }
110134
111- private final class Receiver extends BroadcastReceiver {
135+ private class WeatherContentObserver extends ContentObserver {
136+
137+ public WeatherContentObserver(Handler handler) {
138+ super(handler);
139+ }
140+
112141 @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);
119153 }
120154 }
121- queryWeather();
122- fireCallback();
155+ }
156+
157+ @Override
158+ public void onChange(boolean selfChange) {
159+ onChange(selfChange, null);
123160 }
124161 }
125162
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+ }
126184 }
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -22,6 +22,7 @@ import android.support.v14.preference.PreferenceFragment;
2222 import android.support.v7.preference.Preference;
2323 import android.support.v7.preference.PreferenceScreen;
2424 import android.util.Log;
25+import android.view.MenuItem;
2526
2627 import com.android.settingslib.drawer.SettingsDrawerActivity;
2728 import com.android.systemui.R;
@@ -73,6 +74,15 @@ public class TunerActivity extends SettingsDrawerActivity implements
7374 }
7475
7576 @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
7686 public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
7787 try {
7888 Class<?> cls = Class.forName(pref.getFragment());
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -143,6 +143,7 @@ import java.util.Collections;
143143 import java.util.HashMap;
144144 import java.util.List;
145145
146+import cyanogenmod.hardware.CMHardwareManager;
146147 import cyanogenmod.providers.CMSettings;
147148
148149 /**
@@ -236,6 +237,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
236237 private boolean mNotificationShown;
237238 private final boolean mImeSelectedOnBoot;
238239
240+ private CMHardwareManager mCMHardware;
241+
239242 static class SessionState {
240243 final ClientState client;
241244 final IInputMethod method;
@@ -521,6 +524,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
521524 updateFromSettingsLocked(true);
522525 }
523526 }, 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+ }
524535
525536 mRegistered = true;
526537 }
@@ -530,6 +541,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
530541 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
531542 final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
532543 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);
533548 synchronized (mMethodMap) {
534549 if (showImeUri.equals(uri)) {
535550 updateKeyboardFromSettingsLocked();
@@ -545,6 +560,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
545560 } else if (mShowRequested) {
546561 showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
547562 }
563+ } else if (touchSensitivityUri.equals(uri)) {
564+ updateTouchSensitivity();
565+ } else if (touchHoveringUri.equals(uri)) {
566+ updateTouchHovering();
548567 } else {
549568 boolean enabledChanged = false;
550569 String newEnabled = mSettings.getEnabledInputMethodsStr();
@@ -941,11 +960,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
941960 }
942961 }
943962
944- synchronized (mMethodMap) {
945- mSettingsObserver.registerContentObserverLocked(userId);
946- updateFromSettingsLocked(true);
947- }
948-
949963 // IMMS wants to receive Intent.ACTION_LOCALE_CHANGED in order to update the current IME
950964 // according to the new system locale.
951965 final IntentFilter filter = new IntentFilter();
@@ -1056,6 +1070,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
10561070 mContext.getBasePackageName());
10571071 }
10581072
1073+ updateTouchHovering();
1074+ updateTouchSensitivity();
1075+
10591076 if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
10601077 + " selectedIme=" + mSettings.getSelectedInputMethod());
10611078 }
@@ -1090,6 +1107,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
10901107 final int currentUserId = mSettings.getCurrentUserId();
10911108 mSettings.switchCurrentUser(currentUserId,
10921109 !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+
10931120 mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
10941121 mNotificationManager = mContext.getSystemService(NotificationManager.class);
10951122 mStatusBar = statusBar;
@@ -1989,6 +2016,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
19892016
19902017 }
19912018
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+
19922037 public void updateKeyboardFromSettingsLocked() {
19932038 mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
19942039 if (mSwitchingDialog != null
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -213,6 +213,7 @@ public class InputManagerService extends IInputManager.Stub
213213 InputChannel fromChannel, InputChannel toChannel);
214214 private static native void nativeSetPointerSpeed(long ptr, int speed);
215215 private static native void nativeSetShowTouches(long ptr, boolean enabled);
216+ private static native void nativeSetStylusIconEnabled(long ptr, boolean enabled);
216217 private static native void nativeSetVolumeKeysRotation(long ptr, int mode);
217218 private static native void nativeSetInteractive(long ptr, boolean interactive);
218219 private static native void nativeReloadCalibration(long ptr);
@@ -344,6 +345,7 @@ public class InputManagerService extends IInputManager.Stub
344345 registerPointerSpeedSettingObserver();
345346 registerShowTouchesSettingObserver();
346347 registerAccessibilityLargePointerSettingObserver();
348+ registerStylusIconEnabledSettingObserver();
347349 registerVolumeKeysRotationSettingObserver();
348350
349351 mContext.registerReceiver(new BroadcastReceiver() {
@@ -352,6 +354,7 @@ public class InputManagerService extends IInputManager.Stub
352354 updatePointerSpeedFromSettings();
353355 updateShowTouchesFromSettings();
354356 updateAccessibilityLargePointerFromSettings();
357+ updateStylusIconEnabledFromSettings();
355358 updateVolumeKeysRotationFromSettings();
356359 }
357360 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
@@ -359,6 +362,7 @@ public class InputManagerService extends IInputManager.Stub
359362 updatePointerSpeedFromSettings();
360363 updateShowTouchesFromSettings();
361364 updateAccessibilityLargePointerFromSettings();
365+ updateStylusIconEnabledFromSettings();
362366 updateVolumeKeysRotationFromSettings();
363367 }
364368
@@ -1686,6 +1690,32 @@ public class InputManagerService extends IInputManager.Stub
16861690 return result;
16871691 }
16881692
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+
16891719 public void updateVolumeKeysRotationFromSettings() {
16901720 int mode = getVolumeKeysRotationSetting(0);
16911721 nativeSetVolumeKeysRotation(mPtr, mode);
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -24,6 +24,7 @@ import com.android.internal.logging.MetricsProto.MetricsEvent;
2424 import com.android.internal.telephony.TelephonyIntents;
2525 import com.android.internal.telephony.TelephonyProperties;
2626 import com.android.internal.R;
27+import com.android.internal.util.UserIcons;
2728 import com.android.internal.widget.LockPatternUtils;
2829
2930 import android.app.ActivityManager;
@@ -40,6 +41,14 @@ import android.content.IntentFilter;
4041 import android.content.pm.UserInfo;
4142 import android.content.ServiceConnection;
4243 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;
4352 import android.graphics.drawable.Drawable;
4453 import android.Manifest;
4554 import android.media.AudioManager;
@@ -617,16 +626,24 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
617626 if (um.isUserSwitcherEnabled()) {
618627 List<UserInfo> users = um.getUsers();
619628 UserInfo currentUser = getCurrentUser();
629+ final int avatarSize = mContext.getResources().getDimensionPixelSize(
630+ com.android.internal.R.dimen.global_actions_avatar_size);
620631 for (final UserInfo user : users) {
621632 if (user.supportsSwitchToByUser()) {
622633 boolean isCurrentUser = currentUser == null
623634 ? 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+
626644 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")) {
630647 public void onPress() {
631648 try {
632649 ActivityManagerNative.getDefault().switchUser(user.id);
@@ -643,6 +660,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
643660 return false;
644661 }
645662 };
663+ if (isCurrentUser) {
664+ switchToUser.setStatus(mContext.getString(
665+ R.string.global_action_current_user));
666+ }
646667 items.add(switchToUser);
647668 }
648669 }
@@ -894,6 +915,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
894915 private final Drawable mIcon;
895916 private final int mMessageResId;
896917 private final CharSequence mMessage;
918+ private CharSequence mStatusMessage;
897919
898920 protected SinglePressAction(int iconResId, int messageResId) {
899921 mIconResId = iconResId;
@@ -913,8 +935,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
913935 return true;
914936 }
915937
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;
918944 }
919945
920946 abstract public void onPress();
@@ -935,7 +961,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
935961 TextView messageView = (TextView) v.findViewById(R.id.message);
936962
937963 TextView statusView = (TextView) v.findViewById(R.id.status);
938- final String status = getStatus();
964+ final CharSequence status = getStatus();
939965 if (!TextUtils.isEmpty(status)) {
940966 statusView.setText(status);
941967 } else {
@@ -943,7 +969,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
943969 }
944970 if (mIcon != null) {
945971 icon.setImageDrawable(mIcon);
946- icon.setScaleType(ScaleType.CENTER_CROP);
972+ icon.setScaleType(ScaleType.CENTER);
947973 } else if (mIconResId != 0) {
948974 icon.setImageDrawable(context.getDrawable(mIconResId));
949975 }
@@ -1296,6 +1322,33 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
12961322 }
12971323 }
12981324
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+
12991352 private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
13001353 private final Context mContext;
13011354 private final int mWindowTouchSlop;
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -202,6 +202,7 @@ public:
202202 void setSystemUiVisibility(int32_t visibility);
203203 void setPointerSpeed(int32_t speed);
204204 void setShowTouches(bool enabled);
205+ void setStylusIconEnabled(bool enabled);
205206 void setVolumeKeysRotation(int mode);
206207 void setInteractive(bool interactive);
207208 void reloadCalibration();
@@ -277,6 +278,9 @@ private:
277278 // Show touches feature enable/disable.
278279 bool showTouches;
279280
281+ // Show icon when stylus is used
282+ bool stylusIconEnabled;
283+
280284 // Volume keys rotation mode (0 - off, 1 - phone, 2 - tablet)
281285 int32_t volumeKeysRotationMode;
282286
@@ -316,6 +320,7 @@ NativeInputManager::NativeInputManager(jobject contextObj,
316320 mLocked.pointerSpeed = 0;
317321 mLocked.pointerGesturesEnabled = true;
318322 mLocked.showTouches = false;
323+ mLocked.stylusIconEnabled = false;
319324 mLocked.volumeKeysRotationMode = 0;
320325 }
321326 mInteractive = true;
@@ -464,6 +469,7 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon
464469 outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;
465470
466471 outConfig->showTouches = mLocked.showTouches;
472+ outConfig->stylusIconEnabled = mLocked.stylusIconEnabled;
467473 outConfig->volumeKeysRotationMode = mLocked.volumeKeysRotationMode;
468474
469475 outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
@@ -773,6 +779,22 @@ void NativeInputManager::setShowTouches(bool enabled) {
773779 InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
774780 }
775781
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+
776798 void NativeInputManager::setVolumeKeysRotation(int mode) {
777799 { // acquire lock
778800 AutoMutex _l(mLock);
@@ -1394,6 +1416,13 @@ static void nativeSetShowTouches(JNIEnv* /* env */,
13941416 im->setShowTouches(enabled);
13951417 }
13961418
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+
13971426 static void nativeSetVolumeKeysRotation(JNIEnv* env,
13981427 jclass clazz, jlong ptr, int mode) {
13991428 NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1544,6 +1573,8 @@ static const JNINativeMethod gInputManagerMethods[] = {
15441573 (void*) nativeSetPointerSpeed },
15451574 { "nativeSetShowTouches", "(JZ)V",
15461575 (void*) nativeSetShowTouches },
1576+ { "nativeSetStylusIconEnabled", "(JZ)V",
1577+ (void*) nativeSetStylusIconEnabled },
15471578 { "nativeSetVolumeKeysRotation", "(JI)V",
15481579 (void*) nativeSetVolumeKeysRotation },
15491580 { "nativeSetInteractive", "(JZ)V",