QuickSettingsModel.java revision 4f49d9450fe919868f9a9a9a44db59ca2497150c
1/* 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; 26import android.content.pm.PackageManager; 27import android.content.res.Resources; 28import android.database.ContentObserver; 29import android.graphics.drawable.Drawable; 30import android.hardware.display.WifiDisplayStatus; 31import android.os.Handler; 32import android.provider.Settings; 33import android.text.TextUtils; 34import android.view.View; 35import android.view.inputmethod.InputMethodInfo; 36import android.view.inputmethod.InputMethodManager; 37import android.view.inputmethod.InputMethodSubtype; 38 39import com.android.internal.view.RotationPolicy; 40import com.android.systemui.R; 41import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; 42import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback; 43import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; 44 45import java.util.List; 46 47 48class QuickSettingsModel implements BluetoothStateChangeCallback, 49 NetworkSignalChangedCallback, 50 BatteryStateChangeCallback, 51 LocationGpsStateChangeCallback { 52 53 /** Represents the state of a given attribute. */ 54 static class State { 55 int iconId; 56 String label; 57 boolean enabled = false; 58 } 59 static class BatteryState extends State { 60 int batteryLevel; 61 boolean pluggedIn; 62 } 63 static class RSSIState extends State { 64 int signalIconId; 65 int dataTypeIconId; 66 } 67 static class UserState extends State { 68 Drawable avatar; 69 } 70 71 /** The callback to update a given tile. */ 72 interface RefreshCallback { 73 public void refreshView(QuickSettingsTileView view, State state); 74 } 75 76 /** Broadcast receive to determine if there is an alarm set. */ 77 private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() { 78 @Override 79 public void onReceive(Context context, Intent intent) { 80 String action = intent.getAction(); 81 if (action.equals(Intent.ACTION_ALARM_CHANGED)) { 82 onAlarmChanged(intent); 83 onNextAlarmChanged(); 84 } 85 } 86 }; 87 88 /** ContentObserver to determine the next alarm */ 89 private class NextAlarmObserver extends ContentObserver { 90 public NextAlarmObserver(Handler handler) { 91 super(handler); 92 } 93 94 @Override public void onChange(boolean selfChange) { 95 onNextAlarmChanged(); 96 } 97 98 public void startObserving() { 99 final ContentResolver cr = mContext.getContentResolver(); 100 cr.registerContentObserver( 101 Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this); 102 } 103 } 104 105 private Context mContext; 106 private Handler mHandler; 107 private NextAlarmObserver mNextAlarmObserver; 108 109 private QuickSettingsTileView mUserTile; 110 private RefreshCallback mUserCallback; 111 private UserState mUserState = new UserState(); 112 113 private QuickSettingsTileView mTimeTile; 114 private RefreshCallback mTimeAlarmCallback; 115 private State mTimeAlarmState = new State(); 116 117 private QuickSettingsTileView mAirplaneModeTile; 118 private RefreshCallback mAirplaneModeCallback; 119 private State mAirplaneModeState = new State(); 120 121 private QuickSettingsTileView mWifiTile; 122 private RefreshCallback mWifiCallback; 123 private State mWifiState = new State(); 124 125 private QuickSettingsTileView mWifiDisplayTile; 126 private RefreshCallback mWifiDisplayCallback; 127 private State mWifiDisplayState = new State(); 128 129 private QuickSettingsTileView mRSSITile; 130 private RefreshCallback mRSSICallback; 131 private RSSIState mRSSIState = new RSSIState(); 132 133 private QuickSettingsTileView mBluetoothTile; 134 private RefreshCallback mBluetoothCallback; 135 private State mBluetoothState = new State(); 136 137 private QuickSettingsTileView mBatteryTile; 138 private RefreshCallback mBatteryCallback; 139 private BatteryState mBatteryState = new BatteryState(); 140 141 private QuickSettingsTileView mLocationTile; 142 private RefreshCallback mLocationCallback; 143 private State mLocationState = new State(); 144 145 private QuickSettingsTileView mImeTile; 146 private RefreshCallback mImeCallback; 147 private State mImeState = new State(); 148 149 private QuickSettingsTileView mRotationLockTile; 150 private RefreshCallback mRotationLockCallback; 151 private State mRotationLockState = new State(); 152 153 public QuickSettingsModel(Context context) { 154 mContext = context; 155 mHandler = new Handler(); 156 mNextAlarmObserver = new NextAlarmObserver(mHandler); 157 mNextAlarmObserver.startObserving(); 158 159 IntentFilter alarmIntentFilter = new IntentFilter(); 160 alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED); 161 context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter); 162 } 163 164 // User 165 void addUserTile(QuickSettingsTileView view, RefreshCallback cb) { 166 mUserTile = view; 167 mUserCallback = cb; 168 mUserCallback.refreshView(mUserTile, mUserState); 169 } 170 void setUserTileInfo(String name, Drawable avatar) { 171 mUserState.label = name; 172 mUserState.avatar = avatar; 173 mUserCallback.refreshView(mUserTile, mUserState); 174 } 175 176 // Time 177 void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) { 178 mTimeTile = view; 179 mTimeAlarmCallback = cb; 180 mTimeAlarmCallback.refreshView(view, mTimeAlarmState); 181 } 182 void onAlarmChanged(Intent intent) { 183 mTimeAlarmState.enabled = intent.getBooleanExtra("alarmSet", false); 184 mTimeAlarmCallback.refreshView(mTimeTile, mTimeAlarmState); 185 } 186 void onNextAlarmChanged() { 187 mTimeAlarmState.label = Settings.System.getString(mContext.getContentResolver(), 188 Settings.System.NEXT_ALARM_FORMATTED); 189 mTimeAlarmCallback.refreshView(mTimeTile, mTimeAlarmState); 190 } 191 192 // Airplane Mode 193 void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) { 194 mAirplaneModeTile = view; 195 mAirplaneModeTile.setOnClickListener(new View.OnClickListener() { 196 @Override 197 public void onClick(View v) { 198 if (mAirplaneModeState.enabled) { 199 setAirplaneModeState(false); 200 } else { 201 setAirplaneModeState(true); 202 } 203 } 204 }); 205 mAirplaneModeCallback = cb; 206 mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState); 207 } 208 private void setAirplaneModeState(boolean enabled) { 209 // TODO: Sets the view to be "awaiting" if not already awaiting 210 211 // Change the system setting 212 Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 213 enabled ? 1 : 0); 214 215 // Post the intent 216 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); 217 intent.putExtra("state", enabled); 218 mContext.sendBroadcast(intent); 219 } 220 // NetworkSignalChanged callback 221 @Override 222 public void onAirplaneModeChanged(boolean enabled) { 223 // TODO: If view is in awaiting state, disable 224 Resources r = mContext.getResources(); 225 mAirplaneModeState.enabled = enabled; 226 mAirplaneModeState.iconId = (enabled ? 227 R.drawable.ic_qs_airplane_on : 228 R.drawable.ic_qs_airplane_off); 229 mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState); 230 } 231 232 // Wifi 233 void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) { 234 mWifiTile = view; 235 mWifiCallback = cb; 236 mWifiCallback.refreshView(mWifiTile, mWifiState); 237 } 238 // NetworkSignalChanged callback 239 @Override 240 public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, String enabledDesc) { 241 // TODO: If view is in awaiting state, disable 242 Resources r = mContext.getResources(); 243 mWifiState.iconId = enabled && (wifiSignalIconId > 0) 244 ? wifiSignalIconId 245 : R.drawable.ic_qs_wifi_no_network; 246 mWifiState.label = enabled 247 ? enabledDesc 248 : r.getString(R.string.quick_settings_wifi_no_network); 249 mWifiCallback.refreshView(mWifiTile, mWifiState); 250 } 251 252 // RSSI 253 void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) { 254 mRSSITile = view; 255 mRSSICallback = cb; 256 mRSSICallback.refreshView(mRSSITile, mRSSIState); 257 } 258 boolean deviceSupportsTelephony() { 259 PackageManager pm = mContext.getPackageManager(); 260 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); 261 } 262 // NetworkSignalChanged callback 263 @Override 264 public void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId, 265 int dataTypeIconId, String enabledDesc) { 266 if (deviceSupportsTelephony()) { 267 // TODO: If view is in awaiting state, disable 268 Resources r = mContext.getResources(); 269 mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0) 270 ? mobileSignalIconId 271 : R.drawable.ic_qs_signal_no_signal; 272 mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) 273 ? dataTypeIconId 274 : 0; 275 mRSSIState.label = enabled 276 ? enabledDesc 277 : r.getString(R.string.quick_settings_rssi_emergency_only); 278 mRSSICallback.refreshView(mRSSITile, mRSSIState); 279 } 280 } 281 282 // Bluetooth 283 void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) { 284 mBluetoothTile = view; 285 mBluetoothCallback = cb; 286 287 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 288 onBluetoothStateChange(adapter.isEnabled()); 289 } 290 boolean deviceSupportsBluetooth() { 291 return (BluetoothAdapter.getDefaultAdapter() != null); 292 } 293 // BluetoothController callback 294 @Override 295 public void onBluetoothStateChange(boolean on) { 296 // TODO: If view is in awaiting state, disable 297 Resources r = mContext.getResources(); 298 mBluetoothState.enabled = on; 299 if (on) { 300 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on; 301 } else { 302 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off; 303 } 304 mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState); 305 } 306 307 // Battery 308 void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) { 309 mBatteryTile = view; 310 mBatteryCallback = cb; 311 mBatteryCallback.refreshView(mBatteryTile, mBatteryState); 312 } 313 // BatteryController callback 314 @Override 315 public void onBatteryLevelChanged(int level, boolean pluggedIn) { 316 mBatteryState.batteryLevel = level; 317 mBatteryState.pluggedIn = pluggedIn; 318 mBatteryCallback.refreshView(mBatteryTile, mBatteryState); 319 } 320 321 // Location 322 void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) { 323 mLocationTile = view; 324 mLocationCallback = cb; 325 mLocationCallback.refreshView(mLocationTile, mLocationState); 326 } 327 // LocationController callback 328 @Override 329 public void onLocationGpsStateChanged(boolean inUse, String description) { 330 mLocationState.enabled = inUse; 331 mLocationState.label = description; 332 mLocationCallback.refreshView(mLocationTile, mLocationState); 333 } 334 335 // Wifi Display 336 void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) { 337 mWifiDisplayTile = view; 338 mWifiDisplayCallback = cb; 339 } 340 public void onWifiDisplayStateChanged(WifiDisplayStatus status) { 341 mWifiDisplayState.enabled = status.isEnabled(); 342 if (status.getActiveDisplay() != null) { 343 mWifiDisplayState.label = status.getActiveDisplay().getDeviceName(); 344 } else { 345 mWifiDisplayState.label = mContext.getString( 346 R.string.quick_settings_wifi_display_no_connection_label); 347 } 348 mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState); 349 350 } 351 352 // IME 353 void addImeTile(QuickSettingsTileView view, RefreshCallback cb) { 354 mImeTile = view; 355 mImeCallback = cb; 356 mImeCallback.refreshView(mImeTile, mImeState); 357 } 358 void onImeWindowStatusChanged(boolean visible) { 359 InputMethodManager imm = 360 (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); 361 List<InputMethodInfo> imis = imm.getInputMethodList(); 362 363 mImeState.enabled = visible; 364 mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(), 365 imm, imis, mContext.getPackageManager()); 366 mImeCallback.refreshView(mImeTile, mImeState); 367 } 368 private static String getCurrentInputMethodName(Context context, ContentResolver resolver, 369 InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) { 370 if (resolver == null || imis == null) return null; 371 final String currentInputMethodId = Settings.Secure.getString(resolver, 372 Settings.Secure.DEFAULT_INPUT_METHOD); 373 if (TextUtils.isEmpty(currentInputMethodId)) return null; 374 for (InputMethodInfo imi : imis) { 375 if (currentInputMethodId.equals(imi.getId())) { 376 final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype(); 377 final CharSequence summary = subtype != null 378 ? subtype.getDisplayName(context, imi.getPackageName(), 379 imi.getServiceInfo().applicationInfo) 380 : context.getString(R.string.quick_settings_ime_label); 381 return summary.toString(); 382 } 383 } 384 return null; 385 } 386 387 // Rotation lock 388 void addRotationLockTile(QuickSettingsTileView view, RefreshCallback cb) { 389 mRotationLockTile = view; 390 mRotationLockCallback = cb; 391 onRotationLockChanged(); 392 } 393 void onRotationLockChanged() { 394 boolean locked = RotationPolicy.isRotationLocked(mContext); 395 mRotationLockState.enabled = locked; 396 mRotationLockState.iconId = locked 397 ? R.drawable.ic_qs_rotation_locked 398 : R.drawable.ic_qs_auto_rotate; 399 mRotationLockState.label = locked 400 ? mContext.getString(R.string.quick_settings_rotation_locked_label) 401 : mContext.getString(R.string.quick_settings_rotation_unlocked_label); 402 mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState); 403 } 404 405}