blob: 00991c1dd67317b4bc500ff9f18a44acacacece2 [file] [log] [blame]
Winson Chunge641b6a2012-09-10 17:30:27 -07001/*
2 * Copyright (C) 2012 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
17package com.android.systemui.statusbar.phone;
18
John Spurlock48f37ec2012-10-05 16:32:51 -040019import android.app.ActivityManager;
Winson Chunge641b6a2012-09-10 17:30:27 -070020import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
22import android.content.BroadcastReceiver;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
Winson Chung43229d72012-09-12 18:04:18 -070027import android.content.pm.PackageManager;
Winson Chunge641b6a2012-09-10 17:30:27 -070028import android.content.res.Resources;
29import android.database.ContentObserver;
Winson Chungeaa5ab02012-09-13 16:36:41 -070030import android.graphics.drawable.Drawable;
Winson Chunge641b6a2012-09-10 17:30:27 -070031import android.hardware.display.WifiDisplayStatus;
Daniel Sandler50528052012-11-07 23:39:41 -050032import android.net.ConnectivityManager;
Winson Chunge641b6a2012-09-10 17:30:27 -070033import android.os.Handler;
Christopher Tate5e08af02012-09-21 17:17:22 -070034import android.os.UserHandle;
Winson Chunge641b6a2012-09-10 17:30:27 -070035import android.provider.Settings;
Daniel Sandlerc19d4482012-09-19 16:26:39 -040036import android.provider.Settings.SettingNotFoundException;
Winson Chung2a4057d2012-09-12 18:30:06 -070037import android.text.TextUtils;
Winson Chunge641b6a2012-09-10 17:30:27 -070038import android.view.View;
Winson Chung2a4057d2012-09-12 18:30:06 -070039import android.view.inputmethod.InputMethodInfo;
40import android.view.inputmethod.InputMethodManager;
41import android.view.inputmethod.InputMethodSubtype;
Winson Chunge641b6a2012-09-10 17:30:27 -070042
Winson Chungd4726d02012-09-14 12:27:29 -070043import com.android.internal.view.RotationPolicy;
Winson Chunge641b6a2012-09-10 17:30:27 -070044import com.android.systemui.R;
45import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
Winson Chung5f623012012-09-14 14:58:43 -070046import com.android.systemui.statusbar.policy.BrightnessController.BrightnessStateChangeCallback;
John Spurlock48f37ec2012-10-05 16:32:51 -040047import com.android.systemui.statusbar.policy.CurrentUserTracker;
Winson Chunge641b6a2012-09-10 17:30:27 -070048import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
49import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
50
Winson Chung2a4057d2012-09-12 18:30:06 -070051import java.util.List;
52
Winson Chunge641b6a2012-09-10 17:30:27 -070053
54class QuickSettingsModel implements BluetoothStateChangeCallback,
55 NetworkSignalChangedCallback,
56 BatteryStateChangeCallback,
Winson Chung5f623012012-09-14 14:58:43 -070057 LocationGpsStateChangeCallback,
58 BrightnessStateChangeCallback {
Winson Chunge641b6a2012-09-10 17:30:27 -070059
Winson Chung34563e22012-09-21 17:19:49 -070060 // Sett InputMethoManagerService
61 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
62
Winson Chunge641b6a2012-09-10 17:30:27 -070063 /** Represents the state of a given attribute. */
64 static class State {
65 int iconId;
66 String label;
67 boolean enabled = false;
68 }
69 static class BatteryState extends State {
70 int batteryLevel;
71 boolean pluggedIn;
72 }
Winson Chung4f49d942012-09-14 14:01:40 -070073 static class RSSIState extends State {
74 int signalIconId;
Casey Burkhardtbac221f2012-10-03 18:13:58 -070075 String signalContentDescription;
Winson Chung4f49d942012-09-14 14:01:40 -070076 int dataTypeIconId;
Casey Burkhardtbac221f2012-10-03 18:13:58 -070077 String dataContentDescription;
78 }
79 static class WifiState extends State {
80 String signalContentDescription;
81 boolean connected;
Winson Chung4f49d942012-09-14 14:01:40 -070082 }
Winson Chungeaa5ab02012-09-13 16:36:41 -070083 static class UserState extends State {
84 Drawable avatar;
85 }
Winson Chung5f623012012-09-14 14:58:43 -070086 static class BrightnessState extends State {
87 boolean autoBrightness;
88 }
Chris Wrenb2a7d272012-10-03 10:16:51 -040089 public static class BluetoothState extends State {
90 boolean connected = false;
Casey Burkhardtbac221f2012-10-03 18:13:58 -070091 String stateContentDescription;
Chris Wrenb2a7d272012-10-03 10:16:51 -040092 }
Winson Chunge641b6a2012-09-10 17:30:27 -070093
94 /** The callback to update a given tile. */
95 interface RefreshCallback {
96 public void refreshView(QuickSettingsTileView view, State state);
97 }
98
99 /** Broadcast receive to determine if there is an alarm set. */
100 private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() {
101 @Override
102 public void onReceive(Context context, Intent intent) {
103 String action = intent.getAction();
104 if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
105 onAlarmChanged(intent);
106 onNextAlarmChanged();
107 }
108 }
109 };
110
111 /** ContentObserver to determine the next alarm */
112 private class NextAlarmObserver extends ContentObserver {
113 public NextAlarmObserver(Handler handler) {
114 super(handler);
115 }
116
117 @Override public void onChange(boolean selfChange) {
118 onNextAlarmChanged();
119 }
120
121 public void startObserving() {
122 final ContentResolver cr = mContext.getContentResolver();
123 cr.registerContentObserver(
Daniel Sandler0f92a802012-12-03 12:33:41 -0500124 Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this,
125 UserHandle.USER_ALL);
Winson Chunge641b6a2012-09-10 17:30:27 -0700126 }
127 }
128
Daniel Sandlerc19d4482012-09-19 16:26:39 -0400129 /** ContentObserver to watch adb */
130 private class BugreportObserver extends ContentObserver {
131 public BugreportObserver(Handler handler) {
132 super(handler);
133 }
134
135 @Override public void onChange(boolean selfChange) {
136 onBugreportChanged();
137 }
138
139 public void startObserving() {
140 final ContentResolver cr = mContext.getContentResolver();
141 cr.registerContentObserver(
142 Settings.Secure.getUriFor(Settings.Secure.BUGREPORT_IN_POWER_MENU), false, this);
143 }
144 }
John Spurlock48f37ec2012-10-05 16:32:51 -0400145
146 /** ContentObserver to watch brightness **/
147 private class BrightnessObserver extends ContentObserver {
148 public BrightnessObserver(Handler handler) {
149 super(handler);
150 }
151
152 @Override
153 public void onChange(boolean selfChange) {
154 onBrightnessLevelChanged();
155 }
156
157 public void startObserving() {
158 final ContentResolver cr = mContext.getContentResolver();
159 cr.unregisterContentObserver(this);
160 cr.registerContentObserver(
161 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE),
162 false, this, mUserTracker.getCurrentUserId());
163 cr.registerContentObserver(
164 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS),
165 false, this, mUserTracker.getCurrentUserId());
166 }
167 }
168
169 private final Context mContext;
170 private final Handler mHandler;
171 private final CurrentUserTracker mUserTracker;
172 private final NextAlarmObserver mNextAlarmObserver;
173 private final BugreportObserver mBugreportObserver;
174 private final BrightnessObserver mBrightnessObserver;
Winson Chunge641b6a2012-09-10 17:30:27 -0700175
Daniel Sandler50528052012-11-07 23:39:41 -0500176 private final boolean mHasMobileData;
177
Winson Chunge641b6a2012-09-10 17:30:27 -0700178 private QuickSettingsTileView mUserTile;
179 private RefreshCallback mUserCallback;
Winson Chungeaa5ab02012-09-13 16:36:41 -0700180 private UserState mUserState = new UserState();
Winson Chunge641b6a2012-09-10 17:30:27 -0700181
182 private QuickSettingsTileView mTimeTile;
Winson Chungc86b23b2012-09-24 11:24:28 -0700183 private RefreshCallback mTimeCallback;
184 private State mTimeState = new State();
185
186 private QuickSettingsTileView mAlarmTile;
187 private RefreshCallback mAlarmCallback;
188 private State mAlarmState = new State();
Winson Chunge641b6a2012-09-10 17:30:27 -0700189
190 private QuickSettingsTileView mAirplaneModeTile;
191 private RefreshCallback mAirplaneModeCallback;
192 private State mAirplaneModeState = new State();
193
194 private QuickSettingsTileView mWifiTile;
195 private RefreshCallback mWifiCallback;
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700196 private WifiState mWifiState = new WifiState();
Winson Chunge641b6a2012-09-10 17:30:27 -0700197
198 private QuickSettingsTileView mWifiDisplayTile;
199 private RefreshCallback mWifiDisplayCallback;
200 private State mWifiDisplayState = new State();
201
202 private QuickSettingsTileView mRSSITile;
203 private RefreshCallback mRSSICallback;
Winson Chung4f49d942012-09-14 14:01:40 -0700204 private RSSIState mRSSIState = new RSSIState();
Winson Chunge641b6a2012-09-10 17:30:27 -0700205
206 private QuickSettingsTileView mBluetoothTile;
207 private RefreshCallback mBluetoothCallback;
Chris Wrenb2a7d272012-10-03 10:16:51 -0400208 private BluetoothState mBluetoothState = new BluetoothState();
Winson Chunge641b6a2012-09-10 17:30:27 -0700209
210 private QuickSettingsTileView mBatteryTile;
211 private RefreshCallback mBatteryCallback;
212 private BatteryState mBatteryState = new BatteryState();
213
214 private QuickSettingsTileView mLocationTile;
215 private RefreshCallback mLocationCallback;
216 private State mLocationState = new State();
217
Winson Chung43229d72012-09-12 18:04:18 -0700218 private QuickSettingsTileView mImeTile;
Daniel Sandleraca0c752012-10-01 12:59:36 -0400219 private RefreshCallback mImeCallback = null;
Winson Chung43229d72012-09-12 18:04:18 -0700220 private State mImeState = new State();
221
Winson Chungd4726d02012-09-14 12:27:29 -0700222 private QuickSettingsTileView mRotationLockTile;
223 private RefreshCallback mRotationLockCallback;
224 private State mRotationLockState = new State();
225
Winson Chung5f623012012-09-14 14:58:43 -0700226 private QuickSettingsTileView mBrightnessTile;
227 private RefreshCallback mBrightnessCallback;
228 private BrightnessState mBrightnessState = new BrightnessState();
229
Daniel Sandlerc19d4482012-09-19 16:26:39 -0400230 private QuickSettingsTileView mBugreportTile;
231 private RefreshCallback mBugreportCallback;
232 private State mBugreportState = new State();
233
Winson Chungefba3232012-09-27 16:56:42 -0700234 private QuickSettingsTileView mSettingsTile;
235 private RefreshCallback mSettingsCallback;
236 private State mSettingsState = new State();
237
Winson Chunge641b6a2012-09-10 17:30:27 -0700238 public QuickSettingsModel(Context context) {
239 mContext = context;
240 mHandler = new Handler();
John Spurlock48f37ec2012-10-05 16:32:51 -0400241 mUserTracker = new CurrentUserTracker(mContext) {
242 @Override
243 public void onReceive(Context context, Intent intent) {
244 super.onReceive(context, intent);
245 onUserSwitched();
246 }
247 };
248
Winson Chunge641b6a2012-09-10 17:30:27 -0700249 mNextAlarmObserver = new NextAlarmObserver(mHandler);
250 mNextAlarmObserver.startObserving();
Daniel Sandlerc19d4482012-09-19 16:26:39 -0400251 mBugreportObserver = new BugreportObserver(mHandler);
252 mBugreportObserver.startObserving();
John Spurlock48f37ec2012-10-05 16:32:51 -0400253 mBrightnessObserver = new BrightnessObserver(mHandler);
254 mBrightnessObserver.startObserving();
Winson Chunge641b6a2012-09-10 17:30:27 -0700255
Daniel Sandler50528052012-11-07 23:39:41 -0500256 ConnectivityManager cm = (ConnectivityManager)
257 context.getSystemService(Context.CONNECTIVITY_SERVICE);
258 mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
259
Winson Chunge641b6a2012-09-10 17:30:27 -0700260 IntentFilter alarmIntentFilter = new IntentFilter();
261 alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
262 context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
263 }
264
Winson Chungefba3232012-09-27 16:56:42 -0700265 void updateResources() {
266 refreshSettingsTile();
267 refreshBatteryTile();
268 refreshBluetoothTile();
269 refreshBrightnessTile();
270 refreshRotationLockTile();
271 }
272
273 // Settings
274 void addSettingsTile(QuickSettingsTileView view, RefreshCallback cb) {
275 mSettingsTile = view;
276 mSettingsCallback = cb;
277 refreshSettingsTile();
278 }
279 void refreshSettingsTile() {
280 Resources r = mContext.getResources();
281 mSettingsState.label = r.getString(R.string.quick_settings_settings_label);
282 mSettingsCallback.refreshView(mSettingsTile, mSettingsState);
283 }
284
Winson Chunge641b6a2012-09-10 17:30:27 -0700285 // User
286 void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
287 mUserTile = view;
288 mUserCallback = cb;
289 mUserCallback.refreshView(mUserTile, mUserState);
290 }
Winson Chungeaa5ab02012-09-13 16:36:41 -0700291 void setUserTileInfo(String name, Drawable avatar) {
Winson Chunge641b6a2012-09-10 17:30:27 -0700292 mUserState.label = name;
Winson Chungeaa5ab02012-09-13 16:36:41 -0700293 mUserState.avatar = avatar;
Winson Chunge641b6a2012-09-10 17:30:27 -0700294 mUserCallback.refreshView(mUserTile, mUserState);
295 }
296
297 // Time
298 void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) {
299 mTimeTile = view;
Winson Chungc86b23b2012-09-24 11:24:28 -0700300 mTimeCallback = cb;
301 mTimeCallback.refreshView(view, mTimeState);
302 }
303
304 // Alarm
305 void addAlarmTile(QuickSettingsTileView view, RefreshCallback cb) {
306 mAlarmTile = view;
307 mAlarmCallback = cb;
308 mAlarmCallback.refreshView(view, mAlarmState);
Winson Chunge641b6a2012-09-10 17:30:27 -0700309 }
310 void onAlarmChanged(Intent intent) {
Winson Chungc86b23b2012-09-24 11:24:28 -0700311 mAlarmState.enabled = intent.getBooleanExtra("alarmSet", false);
312 mAlarmCallback.refreshView(mAlarmTile, mAlarmState);
Winson Chunge641b6a2012-09-10 17:30:27 -0700313 }
314 void onNextAlarmChanged() {
Daniel Sandler0f92a802012-12-03 12:33:41 -0500315 final String alarmText = Settings.System.getStringForUser(mContext.getContentResolver(),
316 Settings.System.NEXT_ALARM_FORMATTED,
317 UserHandle.USER_CURRENT);
318 mAlarmState.label = alarmText;
319
320 // When switching users, this is the only clue we're going to get about whether the
321 // alarm is actually set, since we won't get the ACTION_ALARM_CHANGED broadcast
322 mAlarmState.enabled = ! TextUtils.isEmpty(alarmText);
323
Winson Chungc86b23b2012-09-24 11:24:28 -0700324 mAlarmCallback.refreshView(mAlarmTile, mAlarmState);
Winson Chunge641b6a2012-09-10 17:30:27 -0700325 }
326
327 // Airplane Mode
328 void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
329 mAirplaneModeTile = view;
330 mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
331 @Override
332 public void onClick(View v) {
333 if (mAirplaneModeState.enabled) {
334 setAirplaneModeState(false);
335 } else {
336 setAirplaneModeState(true);
337 }
338 }
339 });
340 mAirplaneModeCallback = cb;
Winson Chungefba3232012-09-27 16:56:42 -0700341 int airplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
342 Settings.Global.AIRPLANE_MODE_ON, 0);
343 onAirplaneModeChanged(airplaneMode != 0);
Winson Chunge641b6a2012-09-10 17:30:27 -0700344 }
345 private void setAirplaneModeState(boolean enabled) {
346 // TODO: Sets the view to be "awaiting" if not already awaiting
347
348 // Change the system setting
Winson Chung08b1cc82012-09-11 10:00:53 -0700349 Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
Winson Chunge641b6a2012-09-10 17:30:27 -0700350 enabled ? 1 : 0);
351
352 // Post the intent
353 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
354 intent.putExtra("state", enabled);
355 mContext.sendBroadcast(intent);
356 }
357 // NetworkSignalChanged callback
358 @Override
359 public void onAirplaneModeChanged(boolean enabled) {
360 // TODO: If view is in awaiting state, disable
361 Resources r = mContext.getResources();
362 mAirplaneModeState.enabled = enabled;
363 mAirplaneModeState.iconId = (enabled ?
Winson Chungeaa5ab02012-09-13 16:36:41 -0700364 R.drawable.ic_qs_airplane_on :
365 R.drawable.ic_qs_airplane_off);
Winson Chungefba3232012-09-27 16:56:42 -0700366 mAirplaneModeState.label = r.getString(R.string.quick_settings_airplane_mode_label);
Winson Chunge641b6a2012-09-10 17:30:27 -0700367 mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
368 }
369
370 // Wifi
371 void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
372 mWifiTile = view;
373 mWifiCallback = cb;
374 mWifiCallback.refreshView(mWifiTile, mWifiState);
375 }
Winson Chung34563e22012-09-21 17:19:49 -0700376 // Remove the double quotes that the SSID may contain
377 public static String removeDoubleQuotes(String string) {
378 if (string == null) return null;
379 final int length = string.length();
380 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
381 return string.substring(1, length - 1);
382 }
383 return string;
384 }
Winson Chungf4b5ab12012-09-24 16:47:46 -0700385 // Remove the period from the network name
386 public static String removeTrailingPeriod(String string) {
387 if (string == null) return null;
388 final int length = string.length();
389 if (string.endsWith(".")) {
390 string.substring(0, length - 1);
391 }
392 return string;
393 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700394 // NetworkSignalChanged callback
395 @Override
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700396 public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
397 String wifiSignalContentDescription, String enabledDesc) {
Winson Chunge641b6a2012-09-10 17:30:27 -0700398 // TODO: If view is in awaiting state, disable
399 Resources r = mContext.getResources();
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700400
Winson Chungf4b5ab12012-09-24 16:47:46 -0700401 boolean wifiConnected = enabled && (wifiSignalIconId > 0) && (enabledDesc != null);
Winson Chungefba3232012-09-27 16:56:42 -0700402 boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700403 mWifiState.enabled = enabled;
404 mWifiState.connected = wifiConnected;
Winson Chungf4b5ab12012-09-24 16:47:46 -0700405 if (wifiConnected) {
406 mWifiState.iconId = wifiSignalIconId;
407 mWifiState.label = removeDoubleQuotes(enabledDesc);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700408 mWifiState.signalContentDescription = wifiSignalContentDescription;
Winson Chungf4b5ab12012-09-24 16:47:46 -0700409 } else if (wifiNotConnected) {
410 mWifiState.iconId = R.drawable.ic_qs_wifi_0;
Chris Wrendaab6af2012-10-03 15:13:10 -0400411 mWifiState.label = r.getString(R.string.quick_settings_wifi_label);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700412 mWifiState.signalContentDescription = r.getString(R.string.accessibility_no_wifi);
Winson Chungf4b5ab12012-09-24 16:47:46 -0700413 } else {
414 mWifiState.iconId = R.drawable.ic_qs_wifi_no_network;
415 mWifiState.label = r.getString(R.string.quick_settings_wifi_off_label);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700416 mWifiState.signalContentDescription = r.getString(R.string.accessibility_wifi_off);
Winson Chungf4b5ab12012-09-24 16:47:46 -0700417 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700418 mWifiCallback.refreshView(mWifiTile, mWifiState);
419 }
420
Daniel Sandler50528052012-11-07 23:39:41 -0500421 boolean deviceHasMobileData() {
422 return mHasMobileData;
423 }
424
Winson Chunge641b6a2012-09-10 17:30:27 -0700425 // RSSI
426 void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
427 mRSSITile = view;
428 mRSSICallback = cb;
429 mRSSICallback.refreshView(mRSSITile, mRSSIState);
430 }
431 // NetworkSignalChanged callback
432 @Override
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700433 public void onMobileDataSignalChanged(
434 boolean enabled, int mobileSignalIconId, String signalContentDescription,
435 int dataTypeIconId, String dataContentDescription, String enabledDesc) {
Daniel Sandler50528052012-11-07 23:39:41 -0500436 if (deviceHasMobileData()) {
Winson Chung43229d72012-09-12 18:04:18 -0700437 // TODO: If view is in awaiting state, disable
438 Resources r = mContext.getResources();
Winson Chung4f49d942012-09-14 14:01:40 -0700439 mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0)
Winson Chunged1395f2012-09-13 18:13:44 -0700440 ? mobileSignalIconId
441 : R.drawable.ic_qs_signal_no_signal;
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700442 mRSSIState.signalContentDescription = enabled && (mobileSignalIconId > 0)
443 ? signalContentDescription
444 : r.getString(R.string.accessibility_no_signal);
Winson Chungc86b23b2012-09-24 11:24:28 -0700445 mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
Winson Chung4f49d942012-09-14 14:01:40 -0700446 ? dataTypeIconId
447 : 0;
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700448 mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled
449 ? dataContentDescription
450 : r.getString(R.string.accessibility_no_data);
Winson Chunged1395f2012-09-13 18:13:44 -0700451 mRSSIState.label = enabled
Winson Chungf4b5ab12012-09-24 16:47:46 -0700452 ? removeTrailingPeriod(enabledDesc)
Winson Chunged1395f2012-09-13 18:13:44 -0700453 : r.getString(R.string.quick_settings_rssi_emergency_only);
Winson Chung43229d72012-09-12 18:04:18 -0700454 mRSSICallback.refreshView(mRSSITile, mRSSIState);
455 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700456 }
457
458 // Bluetooth
459 void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
460 mBluetoothTile = view;
461 mBluetoothCallback = cb;
462
463 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
Chris Wrenb2a7d272012-10-03 10:16:51 -0400464 mBluetoothState.enabled = adapter.isEnabled();
465 mBluetoothState.connected =
466 (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED);
467 onBluetoothStateChange(mBluetoothState);
Winson Chunge641b6a2012-09-10 17:30:27 -0700468 }
Winson Chung6072b002012-09-11 17:10:10 -0700469 boolean deviceSupportsBluetooth() {
470 return (BluetoothAdapter.getDefaultAdapter() != null);
471 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700472 // BluetoothController callback
473 @Override
474 public void onBluetoothStateChange(boolean on) {
Chris Wrenb2a7d272012-10-03 10:16:51 -0400475 mBluetoothState.enabled = on;
476 onBluetoothStateChange(mBluetoothState);
477 }
478 public void onBluetoothStateChange(BluetoothState bluetoothStateIn) {
Winson Chunge641b6a2012-09-10 17:30:27 -0700479 // TODO: If view is in awaiting state, disable
480 Resources r = mContext.getResources();
Chris Wrenb2a7d272012-10-03 10:16:51 -0400481 mBluetoothState.enabled = bluetoothStateIn.enabled;
482 mBluetoothState.connected = bluetoothStateIn.connected;
483 if (mBluetoothState.enabled) {
484 if (mBluetoothState.connected) {
485 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on;
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700486 mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_connected);
Chris Wrenb2a7d272012-10-03 10:16:51 -0400487 } else {
488 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_not_connected;
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700489 mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_on);
Chris Wrenb2a7d272012-10-03 10:16:51 -0400490 }
Winson Chung34563e22012-09-21 17:19:49 -0700491 mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_label);
Winson Chunge641b6a2012-09-10 17:30:27 -0700492 } else {
Winson Chungeaa5ab02012-09-13 16:36:41 -0700493 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off;
Winson Chung34563e22012-09-21 17:19:49 -0700494 mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_off_label);
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700495 mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_off);
Winson Chunge641b6a2012-09-10 17:30:27 -0700496 }
497 mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
498 }
Winson Chungefba3232012-09-27 16:56:42 -0700499 void refreshBluetoothTile() {
500 if (mBluetoothTile != null) {
501 onBluetoothStateChange(mBluetoothState.enabled);
502 }
503 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700504
505 // Battery
506 void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
507 mBatteryTile = view;
508 mBatteryCallback = cb;
509 mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
510 }
511 // BatteryController callback
512 @Override
513 public void onBatteryLevelChanged(int level, boolean pluggedIn) {
514 mBatteryState.batteryLevel = level;
515 mBatteryState.pluggedIn = pluggedIn;
516 mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
517 }
Winson Chungefba3232012-09-27 16:56:42 -0700518 void refreshBatteryTile() {
519 mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
520 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700521
522 // Location
523 void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
524 mLocationTile = view;
525 mLocationCallback = cb;
526 mLocationCallback.refreshView(mLocationTile, mLocationState);
527 }
528 // LocationController callback
529 @Override
530 public void onLocationGpsStateChanged(boolean inUse, String description) {
531 mLocationState.enabled = inUse;
532 mLocationState.label = description;
533 mLocationCallback.refreshView(mLocationTile, mLocationState);
534 }
535
Daniel Sandlerc19d4482012-09-19 16:26:39 -0400536 // Bug report
537 void addBugreportTile(QuickSettingsTileView view, RefreshCallback cb) {
538 mBugreportTile = view;
539 mBugreportCallback = cb;
540 onBugreportChanged();
541 }
542 // SettingsObserver callback
543 public void onBugreportChanged() {
544 final ContentResolver cr = mContext.getContentResolver();
545 boolean enabled = false;
546 try {
547 enabled = (Settings.Secure.getInt(cr, Settings.Secure.BUGREPORT_IN_POWER_MENU) != 0);
548 } catch (SettingNotFoundException e) {
549 }
550
551 mBugreportState.enabled = enabled;
552 mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
553 }
554
Winson Chunge641b6a2012-09-10 17:30:27 -0700555 // Wifi Display
556 void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
557 mWifiDisplayTile = view;
558 mWifiDisplayCallback = cb;
559 }
560 public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
Jeff Brown89d55462012-09-19 11:33:42 -0700561 mWifiDisplayState.enabled =
Winson Chung3ed6f942012-09-20 16:07:11 -0700562 (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON);
Winson Chunge641b6a2012-09-10 17:30:27 -0700563 if (status.getActiveDisplay() != null) {
Jeff Brown89d55462012-09-19 11:33:42 -0700564 mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
John Spurlock01e2f4f2012-10-05 17:33:31 -0400565 mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display_connected;
Winson Chunge641b6a2012-09-10 17:30:27 -0700566 } else {
567 mWifiDisplayState.label = mContext.getString(
568 R.string.quick_settings_wifi_display_no_connection_label);
John Spurlock01e2f4f2012-10-05 17:33:31 -0400569 mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display;
Winson Chunge641b6a2012-09-10 17:30:27 -0700570 }
571 mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
572
573 }
574
Winson Chung43229d72012-09-12 18:04:18 -0700575 // IME
576 void addImeTile(QuickSettingsTileView view, RefreshCallback cb) {
577 mImeTile = view;
578 mImeCallback = cb;
579 mImeCallback.refreshView(mImeTile, mImeState);
580 }
Winson Chung34563e22012-09-21 17:19:49 -0700581 /* This implementation is taken from
582 InputMethodManagerService.needsToShowImeSwitchOngoingNotification(). */
583 private boolean needsToShowImeSwitchOngoingNotification(InputMethodManager imm) {
584 List<InputMethodInfo> imis = imm.getEnabledInputMethodList();
585 final int N = imis.size();
586 if (N > 2) return true;
587 if (N < 1) return false;
588 int nonAuxCount = 0;
589 int auxCount = 0;
590 InputMethodSubtype nonAuxSubtype = null;
591 InputMethodSubtype auxSubtype = null;
592 for(int i = 0; i < N; ++i) {
593 final InputMethodInfo imi = imis.get(i);
594 final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(imi,
595 true);
596 final int subtypeCount = subtypes.size();
597 if (subtypeCount == 0) {
598 ++nonAuxCount;
599 } else {
600 for (int j = 0; j < subtypeCount; ++j) {
601 final InputMethodSubtype subtype = subtypes.get(j);
602 if (!subtype.isAuxiliary()) {
603 ++nonAuxCount;
604 nonAuxSubtype = subtype;
605 } else {
606 ++auxCount;
607 auxSubtype = subtype;
608 }
609 }
610 }
611 }
612 if (nonAuxCount > 1 || auxCount > 1) {
613 return true;
614 } else if (nonAuxCount == 1 && auxCount == 1) {
615 if (nonAuxSubtype != null && auxSubtype != null
616 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
617 || auxSubtype.overridesImplicitlyEnabledSubtype()
618 || nonAuxSubtype.overridesImplicitlyEnabledSubtype())
619 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
620 return false;
621 }
622 return true;
623 }
624 return false;
625 }
Winson Chung43229d72012-09-12 18:04:18 -0700626 void onImeWindowStatusChanged(boolean visible) {
Winson Chung2a4057d2012-09-12 18:30:06 -0700627 InputMethodManager imm =
628 (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
629 List<InputMethodInfo> imis = imm.getInputMethodList();
630
Winson Chung34563e22012-09-21 17:19:49 -0700631 mImeState.enabled = (visible && needsToShowImeSwitchOngoingNotification(imm));
Winson Chung2a4057d2012-09-12 18:30:06 -0700632 mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(),
633 imm, imis, mContext.getPackageManager());
Daniel Sandleraca0c752012-10-01 12:59:36 -0400634 if (mImeCallback != null) {
635 mImeCallback.refreshView(mImeTile, mImeState);
636 }
Winson Chung43229d72012-09-12 18:04:18 -0700637 }
Winson Chung2a4057d2012-09-12 18:30:06 -0700638 private static String getCurrentInputMethodName(Context context, ContentResolver resolver,
639 InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) {
640 if (resolver == null || imis == null) return null;
641 final String currentInputMethodId = Settings.Secure.getString(resolver,
642 Settings.Secure.DEFAULT_INPUT_METHOD);
643 if (TextUtils.isEmpty(currentInputMethodId)) return null;
644 for (InputMethodInfo imi : imis) {
645 if (currentInputMethodId.equals(imi.getId())) {
646 final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype();
647 final CharSequence summary = subtype != null
648 ? subtype.getDisplayName(context, imi.getPackageName(),
649 imi.getServiceInfo().applicationInfo)
650 : context.getString(R.string.quick_settings_ime_label);
651 return summary.toString();
652 }
653 }
654 return null;
655 }
Winson Chung43229d72012-09-12 18:04:18 -0700656
Winson Chungd4726d02012-09-14 12:27:29 -0700657 // Rotation lock
658 void addRotationLockTile(QuickSettingsTileView view, RefreshCallback cb) {
659 mRotationLockTile = view;
660 mRotationLockCallback = cb;
661 onRotationLockChanged();
662 }
663 void onRotationLockChanged() {
664 boolean locked = RotationPolicy.isRotationLocked(mContext);
665 mRotationLockState.enabled = locked;
666 mRotationLockState.iconId = locked
667 ? R.drawable.ic_qs_rotation_locked
668 : R.drawable.ic_qs_auto_rotate;
669 mRotationLockState.label = locked
670 ? mContext.getString(R.string.quick_settings_rotation_locked_label)
671 : mContext.getString(R.string.quick_settings_rotation_unlocked_label);
Daniel Sandler8dd92062012-09-14 17:29:12 -0700672
Casey Burkhardtbac221f2012-10-03 18:13:58 -0700673 // may be called before addRotationLockTile due to RotationPolicyListener in QuickSettings
Daniel Sandler8dd92062012-09-14 17:29:12 -0700674 if (mRotationLockTile != null && mRotationLockCallback != null) {
675 mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
676 }
Winson Chungd4726d02012-09-14 12:27:29 -0700677 }
Winson Chungefba3232012-09-27 16:56:42 -0700678 void refreshRotationLockTile() {
679 if (mRotationLockTile != null) {
680 onRotationLockChanged();
681 }
682 }
Winson Chungd4726d02012-09-14 12:27:29 -0700683
Winson Chung5f623012012-09-14 14:58:43 -0700684 // Brightness
685 void addBrightnessTile(QuickSettingsTileView view, RefreshCallback cb) {
686 mBrightnessTile = view;
687 mBrightnessCallback = cb;
688 onBrightnessLevelChanged();
689 }
690 @Override
691 public void onBrightnessLevelChanged() {
Winson Chungefba3232012-09-27 16:56:42 -0700692 Resources r = mContext.getResources();
John Spurlock48f37ec2012-10-05 16:32:51 -0400693 int mode = Settings.System.getIntForUser(mContext.getContentResolver(),
Winson Chung5f623012012-09-14 14:58:43 -0700694 Settings.System.SCREEN_BRIGHTNESS_MODE,
John Spurlock48f37ec2012-10-05 16:32:51 -0400695 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
696 mUserTracker.getCurrentUserId());
Winson Chung5f623012012-09-14 14:58:43 -0700697 mBrightnessState.autoBrightness =
698 (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
699 mBrightnessState.iconId = mBrightnessState.autoBrightness
700 ? R.drawable.ic_qs_brightness_auto_on
701 : R.drawable.ic_qs_brightness_auto_off;
Winson Chungefba3232012-09-27 16:56:42 -0700702 mBrightnessState.label = r.getString(R.string.quick_settings_brightness_label);
Winson Chung5f623012012-09-14 14:58:43 -0700703 mBrightnessCallback.refreshView(mBrightnessTile, mBrightnessState);
704 }
Winson Chungefba3232012-09-27 16:56:42 -0700705 void refreshBrightnessTile() {
706 onBrightnessLevelChanged();
707 }
Winson Chung5f623012012-09-14 14:58:43 -0700708
Christopher Tate5e08af02012-09-21 17:17:22 -0700709 // User switch: need to update visuals of all tiles known to have per-user state
John Spurlock48f37ec2012-10-05 16:32:51 -0400710 void onUserSwitched() {
711 mBrightnessObserver.startObserving();
Christopher Tate5e08af02012-09-21 17:17:22 -0700712 onRotationLockChanged();
713 onBrightnessLevelChanged();
714 onNextAlarmChanged();
715 onBugreportChanged();
716 }
Christopher Tate5e08af02012-09-21 17:17:22 -0700717}