blob: 724df340e11582ed86835c32645378a232bd8c20 [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
19import android.bluetooth.BluetoothAdapter;
20import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
21import android.content.BroadcastReceiver;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
Winson Chung43229d72012-09-12 18:04:18 -070026import android.content.pm.PackageManager;
Winson Chunge641b6a2012-09-10 17:30:27 -070027import android.content.res.Resources;
28import android.database.ContentObserver;
Winson Chungeaa5ab02012-09-13 16:36:41 -070029import android.graphics.drawable.Drawable;
Winson Chunge641b6a2012-09-10 17:30:27 -070030import android.hardware.display.WifiDisplayStatus;
31import android.os.Handler;
32import android.provider.Settings;
Winson Chung2a4057d2012-09-12 18:30:06 -070033import android.text.TextUtils;
Winson Chunge641b6a2012-09-10 17:30:27 -070034import android.view.View;
Winson Chung2a4057d2012-09-12 18:30:06 -070035import android.view.inputmethod.InputMethodInfo;
36import android.view.inputmethod.InputMethodManager;
37import android.view.inputmethod.InputMethodSubtype;
Winson Chunge641b6a2012-09-10 17:30:27 -070038
Winson Chungd4726d02012-09-14 12:27:29 -070039import com.android.internal.view.RotationPolicy;
Winson Chunge641b6a2012-09-10 17:30:27 -070040import com.android.systemui.R;
41import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
Winson Chung5f623012012-09-14 14:58:43 -070042import com.android.systemui.statusbar.policy.BrightnessController.BrightnessStateChangeCallback;
Winson Chunge641b6a2012-09-10 17:30:27 -070043import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
44import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
45
Winson Chung2a4057d2012-09-12 18:30:06 -070046import java.util.List;
47
Winson Chunge641b6a2012-09-10 17:30:27 -070048
49class QuickSettingsModel implements BluetoothStateChangeCallback,
50 NetworkSignalChangedCallback,
51 BatteryStateChangeCallback,
Winson Chung5f623012012-09-14 14:58:43 -070052 LocationGpsStateChangeCallback,
53 BrightnessStateChangeCallback {
Winson Chunge641b6a2012-09-10 17:30:27 -070054
55 /** Represents the state of a given attribute. */
56 static class State {
57 int iconId;
58 String label;
59 boolean enabled = false;
60 }
61 static class BatteryState extends State {
62 int batteryLevel;
63 boolean pluggedIn;
64 }
Winson Chung4f49d942012-09-14 14:01:40 -070065 static class RSSIState extends State {
66 int signalIconId;
67 int dataTypeIconId;
68 }
Winson Chungeaa5ab02012-09-13 16:36:41 -070069 static class UserState extends State {
70 Drawable avatar;
71 }
Winson Chung5f623012012-09-14 14:58:43 -070072 static class BrightnessState extends State {
73 boolean autoBrightness;
74 }
Winson Chunge641b6a2012-09-10 17:30:27 -070075
76 /** The callback to update a given tile. */
77 interface RefreshCallback {
78 public void refreshView(QuickSettingsTileView view, State state);
79 }
80
81 /** Broadcast receive to determine if there is an alarm set. */
82 private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() {
83 @Override
84 public void onReceive(Context context, Intent intent) {
85 String action = intent.getAction();
86 if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
87 onAlarmChanged(intent);
88 onNextAlarmChanged();
89 }
90 }
91 };
92
93 /** ContentObserver to determine the next alarm */
94 private class NextAlarmObserver extends ContentObserver {
95 public NextAlarmObserver(Handler handler) {
96 super(handler);
97 }
98
99 @Override public void onChange(boolean selfChange) {
100 onNextAlarmChanged();
101 }
102
103 public void startObserving() {
104 final ContentResolver cr = mContext.getContentResolver();
105 cr.registerContentObserver(
106 Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this);
107 }
108 }
109
110 private Context mContext;
111 private Handler mHandler;
112 private NextAlarmObserver mNextAlarmObserver;
113
114 private QuickSettingsTileView mUserTile;
115 private RefreshCallback mUserCallback;
Winson Chungeaa5ab02012-09-13 16:36:41 -0700116 private UserState mUserState = new UserState();
Winson Chunge641b6a2012-09-10 17:30:27 -0700117
118 private QuickSettingsTileView mTimeTile;
119 private RefreshCallback mTimeAlarmCallback;
120 private State mTimeAlarmState = new State();
121
122 private QuickSettingsTileView mAirplaneModeTile;
123 private RefreshCallback mAirplaneModeCallback;
124 private State mAirplaneModeState = new State();
125
126 private QuickSettingsTileView mWifiTile;
127 private RefreshCallback mWifiCallback;
128 private State mWifiState = new State();
129
130 private QuickSettingsTileView mWifiDisplayTile;
131 private RefreshCallback mWifiDisplayCallback;
132 private State mWifiDisplayState = new State();
133
134 private QuickSettingsTileView mRSSITile;
135 private RefreshCallback mRSSICallback;
Winson Chung4f49d942012-09-14 14:01:40 -0700136 private RSSIState mRSSIState = new RSSIState();
Winson Chunge641b6a2012-09-10 17:30:27 -0700137
138 private QuickSettingsTileView mBluetoothTile;
139 private RefreshCallback mBluetoothCallback;
140 private State mBluetoothState = new State();
141
142 private QuickSettingsTileView mBatteryTile;
143 private RefreshCallback mBatteryCallback;
144 private BatteryState mBatteryState = new BatteryState();
145
146 private QuickSettingsTileView mLocationTile;
147 private RefreshCallback mLocationCallback;
148 private State mLocationState = new State();
149
Winson Chung43229d72012-09-12 18:04:18 -0700150 private QuickSettingsTileView mImeTile;
151 private RefreshCallback mImeCallback;
152 private State mImeState = new State();
153
Winson Chungd4726d02012-09-14 12:27:29 -0700154 private QuickSettingsTileView mRotationLockTile;
155 private RefreshCallback mRotationLockCallback;
156 private State mRotationLockState = new State();
157
Winson Chung5f623012012-09-14 14:58:43 -0700158 private QuickSettingsTileView mBrightnessTile;
159 private RefreshCallback mBrightnessCallback;
160 private BrightnessState mBrightnessState = new BrightnessState();
161
Winson Chunge641b6a2012-09-10 17:30:27 -0700162 public QuickSettingsModel(Context context) {
163 mContext = context;
164 mHandler = new Handler();
165 mNextAlarmObserver = new NextAlarmObserver(mHandler);
166 mNextAlarmObserver.startObserving();
167
168 IntentFilter alarmIntentFilter = new IntentFilter();
169 alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
170 context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
171 }
172
173 // User
174 void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
175 mUserTile = view;
176 mUserCallback = cb;
177 mUserCallback.refreshView(mUserTile, mUserState);
178 }
Winson Chungeaa5ab02012-09-13 16:36:41 -0700179 void setUserTileInfo(String name, Drawable avatar) {
Winson Chunge641b6a2012-09-10 17:30:27 -0700180 mUserState.label = name;
Winson Chungeaa5ab02012-09-13 16:36:41 -0700181 mUserState.avatar = avatar;
Winson Chunge641b6a2012-09-10 17:30:27 -0700182 mUserCallback.refreshView(mUserTile, mUserState);
183 }
184
185 // Time
186 void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) {
187 mTimeTile = view;
188 mTimeAlarmCallback = cb;
189 mTimeAlarmCallback.refreshView(view, mTimeAlarmState);
190 }
191 void onAlarmChanged(Intent intent) {
192 mTimeAlarmState.enabled = intent.getBooleanExtra("alarmSet", false);
Winson Chunge641b6a2012-09-10 17:30:27 -0700193 mTimeAlarmCallback.refreshView(mTimeTile, mTimeAlarmState);
194 }
195 void onNextAlarmChanged() {
196 mTimeAlarmState.label = Settings.System.getString(mContext.getContentResolver(),
197 Settings.System.NEXT_ALARM_FORMATTED);
Winson Chunge641b6a2012-09-10 17:30:27 -0700198 mTimeAlarmCallback.refreshView(mTimeTile, mTimeAlarmState);
199 }
200
201 // Airplane Mode
202 void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
203 mAirplaneModeTile = view;
204 mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
205 @Override
206 public void onClick(View v) {
207 if (mAirplaneModeState.enabled) {
208 setAirplaneModeState(false);
209 } else {
210 setAirplaneModeState(true);
211 }
212 }
213 });
214 mAirplaneModeCallback = cb;
215 mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
216 }
217 private void setAirplaneModeState(boolean enabled) {
218 // TODO: Sets the view to be "awaiting" if not already awaiting
219
220 // Change the system setting
Winson Chung08b1cc82012-09-11 10:00:53 -0700221 Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
Winson Chunge641b6a2012-09-10 17:30:27 -0700222 enabled ? 1 : 0);
223
224 // Post the intent
225 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
226 intent.putExtra("state", enabled);
227 mContext.sendBroadcast(intent);
228 }
229 // NetworkSignalChanged callback
230 @Override
231 public void onAirplaneModeChanged(boolean enabled) {
232 // TODO: If view is in awaiting state, disable
233 Resources r = mContext.getResources();
234 mAirplaneModeState.enabled = enabled;
235 mAirplaneModeState.iconId = (enabled ?
Winson Chungeaa5ab02012-09-13 16:36:41 -0700236 R.drawable.ic_qs_airplane_on :
237 R.drawable.ic_qs_airplane_off);
Winson Chunge641b6a2012-09-10 17:30:27 -0700238 mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
239 }
240
241 // Wifi
242 void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
243 mWifiTile = view;
244 mWifiCallback = cb;
245 mWifiCallback.refreshView(mWifiTile, mWifiState);
246 }
247 // NetworkSignalChanged callback
248 @Override
Winson Chunged1395f2012-09-13 18:13:44 -0700249 public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, String enabledDesc) {
Winson Chunge641b6a2012-09-10 17:30:27 -0700250 // TODO: If view is in awaiting state, disable
251 Resources r = mContext.getResources();
Winson Chunged1395f2012-09-13 18:13:44 -0700252 mWifiState.iconId = enabled && (wifiSignalIconId > 0)
253 ? wifiSignalIconId
254 : R.drawable.ic_qs_wifi_no_network;
255 mWifiState.label = enabled
256 ? enabledDesc
257 : r.getString(R.string.quick_settings_wifi_no_network);
Winson Chunge641b6a2012-09-10 17:30:27 -0700258 mWifiCallback.refreshView(mWifiTile, mWifiState);
259 }
260
261 // RSSI
262 void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
263 mRSSITile = view;
264 mRSSICallback = cb;
265 mRSSICallback.refreshView(mRSSITile, mRSSIState);
266 }
Winson Chung43229d72012-09-12 18:04:18 -0700267 boolean deviceSupportsTelephony() {
268 PackageManager pm = mContext.getPackageManager();
269 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
270 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700271 // NetworkSignalChanged callback
272 @Override
Winson Chunged1395f2012-09-13 18:13:44 -0700273 public void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
Winson Chung4f49d942012-09-14 14:01:40 -0700274 int dataTypeIconId, String enabledDesc) {
Winson Chung43229d72012-09-12 18:04:18 -0700275 if (deviceSupportsTelephony()) {
276 // TODO: If view is in awaiting state, disable
277 Resources r = mContext.getResources();
Winson Chung4f49d942012-09-14 14:01:40 -0700278 mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0)
Winson Chunged1395f2012-09-13 18:13:44 -0700279 ? mobileSignalIconId
280 : R.drawable.ic_qs_signal_no_signal;
Winson Chung4f49d942012-09-14 14:01:40 -0700281 mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0)
282 ? dataTypeIconId
283 : 0;
Winson Chunged1395f2012-09-13 18:13:44 -0700284 mRSSIState.label = enabled
285 ? enabledDesc
286 : r.getString(R.string.quick_settings_rssi_emergency_only);
Winson Chung43229d72012-09-12 18:04:18 -0700287 mRSSICallback.refreshView(mRSSITile, mRSSIState);
288 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700289 }
290
291 // Bluetooth
292 void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
293 mBluetoothTile = view;
294 mBluetoothCallback = cb;
295
296 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
297 onBluetoothStateChange(adapter.isEnabled());
298 }
Winson Chung6072b002012-09-11 17:10:10 -0700299 boolean deviceSupportsBluetooth() {
300 return (BluetoothAdapter.getDefaultAdapter() != null);
301 }
Winson Chunge641b6a2012-09-10 17:30:27 -0700302 // BluetoothController callback
303 @Override
304 public void onBluetoothStateChange(boolean on) {
305 // TODO: If view is in awaiting state, disable
306 Resources r = mContext.getResources();
307 mBluetoothState.enabled = on;
308 if (on) {
Winson Chungeaa5ab02012-09-13 16:36:41 -0700309 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on;
Winson Chunge641b6a2012-09-10 17:30:27 -0700310 } else {
Winson Chungeaa5ab02012-09-13 16:36:41 -0700311 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off;
Winson Chunge641b6a2012-09-10 17:30:27 -0700312 }
313 mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
314 }
315
316 // Battery
317 void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
318 mBatteryTile = view;
319 mBatteryCallback = cb;
320 mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
321 }
322 // BatteryController callback
323 @Override
324 public void onBatteryLevelChanged(int level, boolean pluggedIn) {
325 mBatteryState.batteryLevel = level;
326 mBatteryState.pluggedIn = pluggedIn;
327 mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
328 }
329
330 // Location
331 void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
332 mLocationTile = view;
333 mLocationCallback = cb;
334 mLocationCallback.refreshView(mLocationTile, mLocationState);
335 }
336 // LocationController callback
337 @Override
338 public void onLocationGpsStateChanged(boolean inUse, String description) {
339 mLocationState.enabled = inUse;
340 mLocationState.label = description;
341 mLocationCallback.refreshView(mLocationTile, mLocationState);
342 }
343
344 // Wifi Display
345 void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
346 mWifiDisplayTile = view;
347 mWifiDisplayCallback = cb;
348 }
349 public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
Jeff Brown89d55462012-09-19 11:33:42 -0700350 mWifiDisplayState.enabled =
351 (status.getFeatureState() != WifiDisplayStatus.FEATURE_STATE_UNAVAILABLE);
Winson Chunge641b6a2012-09-10 17:30:27 -0700352 if (status.getActiveDisplay() != null) {
Jeff Brown89d55462012-09-19 11:33:42 -0700353 mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
Winson Chunge641b6a2012-09-10 17:30:27 -0700354 } else {
355 mWifiDisplayState.label = mContext.getString(
356 R.string.quick_settings_wifi_display_no_connection_label);
357 }
358 mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
359
360 }
361
Winson Chung43229d72012-09-12 18:04:18 -0700362 // IME
363 void addImeTile(QuickSettingsTileView view, RefreshCallback cb) {
364 mImeTile = view;
365 mImeCallback = cb;
366 mImeCallback.refreshView(mImeTile, mImeState);
367 }
368 void onImeWindowStatusChanged(boolean visible) {
Winson Chung2a4057d2012-09-12 18:30:06 -0700369 InputMethodManager imm =
370 (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
371 List<InputMethodInfo> imis = imm.getInputMethodList();
372
Winson Chung43229d72012-09-12 18:04:18 -0700373 mImeState.enabled = visible;
Winson Chung2a4057d2012-09-12 18:30:06 -0700374 mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(),
375 imm, imis, mContext.getPackageManager());
Winson Chung43229d72012-09-12 18:04:18 -0700376 mImeCallback.refreshView(mImeTile, mImeState);
377 }
Winson Chung2a4057d2012-09-12 18:30:06 -0700378 private static String getCurrentInputMethodName(Context context, ContentResolver resolver,
379 InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) {
380 if (resolver == null || imis == null) return null;
381 final String currentInputMethodId = Settings.Secure.getString(resolver,
382 Settings.Secure.DEFAULT_INPUT_METHOD);
383 if (TextUtils.isEmpty(currentInputMethodId)) return null;
384 for (InputMethodInfo imi : imis) {
385 if (currentInputMethodId.equals(imi.getId())) {
386 final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype();
387 final CharSequence summary = subtype != null
388 ? subtype.getDisplayName(context, imi.getPackageName(),
389 imi.getServiceInfo().applicationInfo)
390 : context.getString(R.string.quick_settings_ime_label);
391 return summary.toString();
392 }
393 }
394 return null;
395 }
Winson Chung43229d72012-09-12 18:04:18 -0700396
Winson Chungd4726d02012-09-14 12:27:29 -0700397 // Rotation lock
398 void addRotationLockTile(QuickSettingsTileView view, RefreshCallback cb) {
399 mRotationLockTile = view;
400 mRotationLockCallback = cb;
401 onRotationLockChanged();
402 }
403 void onRotationLockChanged() {
404 boolean locked = RotationPolicy.isRotationLocked(mContext);
405 mRotationLockState.enabled = locked;
406 mRotationLockState.iconId = locked
407 ? R.drawable.ic_qs_rotation_locked
408 : R.drawable.ic_qs_auto_rotate;
409 mRotationLockState.label = locked
410 ? mContext.getString(R.string.quick_settings_rotation_locked_label)
411 : mContext.getString(R.string.quick_settings_rotation_unlocked_label);
Daniel Sandler8dd92062012-09-14 17:29:12 -0700412
413 // may be called before addRotationLockTile due to RotationPolicyListener in QuickSettings
414 if (mRotationLockTile != null && mRotationLockCallback != null) {
415 mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
416 }
Winson Chungd4726d02012-09-14 12:27:29 -0700417 }
418
Winson Chung5f623012012-09-14 14:58:43 -0700419 // Brightness
420 void addBrightnessTile(QuickSettingsTileView view, RefreshCallback cb) {
421 mBrightnessTile = view;
422 mBrightnessCallback = cb;
423 onBrightnessLevelChanged();
424 }
425 @Override
426 public void onBrightnessLevelChanged() {
427 int mode = Settings.System.getInt(mContext.getContentResolver(),
428 Settings.System.SCREEN_BRIGHTNESS_MODE,
429 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
430 mBrightnessState.autoBrightness =
431 (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
432 mBrightnessState.iconId = mBrightnessState.autoBrightness
433 ? R.drawable.ic_qs_brightness_auto_on
434 : R.drawable.ic_qs_brightness_auto_off;
435 mBrightnessCallback.refreshView(mBrightnessTile, mBrightnessState);
436 }
437
Winson Chunge641b6a2012-09-10 17:30:27 -0700438}