QuickSettings.java revision d63c59786509aadd6a8d0c5cb45ed696339f16b7
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.Context; 22import android.content.CursorLoader; 23import android.content.Intent; 24import android.content.Loader; 25import android.content.res.Resources; 26import android.database.Cursor; 27import android.graphics.drawable.ClipDrawable; 28import android.net.Uri; 29import android.provider.ContactsContract; 30import android.provider.Settings; 31import android.view.LayoutInflater; 32import android.view.View; 33import android.view.ViewGroup; 34import android.widget.TextView; 35 36import java.util.ArrayList; 37 38import com.android.systemui.R; 39import com.android.systemui.statusbar.phone.QuickSettingsModel.State; 40import com.android.systemui.statusbar.policy.BatteryController; 41import com.android.systemui.statusbar.policy.BluetoothController; 42import com.android.systemui.statusbar.policy.LocationController; 43import com.android.systemui.statusbar.policy.NetworkController; 44 45class QuickSettingsModel implements BluetoothStateChangeCallback, 46 NetworkController.NetworkSignalChangedCallback, 47 BatteryController.BatteryStateChangeCallback, 48 LocationController.LocationGpsStateChangeCallback { 49 50 /** Represents the state of a given attribute. */ 51 static class State { 52 int iconId; 53 String label; 54 boolean enabled; 55 } 56 static class BatteryState extends State { 57 int batteryLevel; 58 boolean pluggedIn; 59 } 60 61 /** The callback to update a given tile. */ 62 interface RefreshCallback { 63 public void refreshView(QuickSettingsTileView view, State state); 64 } 65 66 private Context mContext; 67 68 private QuickSettingsTileView mUserTile; 69 private RefreshCallback mUserCallback; 70 private State mUserState = new State(); 71 72 private QuickSettingsTileView mAirplaneModeTile; 73 private RefreshCallback mAirplaneModeCallback; 74 private State mAirplaneModeState = new State(); 75 76 private QuickSettingsTileView mWifiTile; 77 private RefreshCallback mWifiCallback; 78 private State mWifiState = new State(); 79 80 private QuickSettingsTileView mRSSITile; 81 private RefreshCallback mRSSICallback; 82 private State mRSSIState = new State(); 83 84 private QuickSettingsTileView mBluetoothTile; 85 private RefreshCallback mBluetoothCallback; 86 private State mBluetoothState = new State(); 87 88 private QuickSettingsTileView mBatteryTile; 89 private RefreshCallback mBatteryCallback; 90 private BatteryState mBatteryState = new BatteryState(); 91 92 private QuickSettingsTileView mLocationTile; 93 private RefreshCallback mLocationCallback; 94 private State mLocationState = new State(); 95 96 public QuickSettingsModel(Context context) { 97 mContext = context; 98 } 99 100 // User 101 void addUserTile(QuickSettingsTileView view, RefreshCallback cb) { 102 mUserTile = view; 103 mUserCallback = cb; 104 mUserCallback.refreshView(mUserTile, mUserState); 105 } 106 void setUserTileInfo(String name) { 107 mUserState.label = name; 108 mUserCallback.refreshView(mUserTile, mUserState); 109 } 110 111 // Airplane Mode 112 void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) { 113 mAirplaneModeTile = view; 114 mAirplaneModeTile.setOnClickListener(new View.OnClickListener() { 115 @Override 116 public void onClick(View v) { 117 if (mAirplaneModeState.enabled) { 118 setAirplaneModeState(false); 119 } else { 120 setAirplaneModeState(true); 121 } 122 } 123 }); 124 mAirplaneModeCallback = cb; 125 mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState); 126 } 127 private void setAirplaneModeState(boolean enabled) { 128 // TODO: Sets the view to be "awaiting" if not already awaiting 129 130 // Change the system setting 131 Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 132 enabled ? 1 : 0); 133 134 // TODO: Update the UI to reflect system setting 135 // mCheckBoxPref.setChecked(enabled); 136 137 // Post the intent 138 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); 139 intent.putExtra("state", enabled); 140 mContext.sendBroadcast(intent); 141 } 142 // NetworkSignalChanged callback 143 @Override 144 public void onAirplaneModeChanged(boolean enabled) { 145 // TODO: If view is in awaiting state, disable 146 Resources r = mContext.getResources(); 147 mAirplaneModeState.enabled = enabled; 148 mAirplaneModeState.iconId = (enabled ? 149 R.drawable.ic_qs_airplane_enabled : 150 R.drawable.ic_qs_airplane_normal); 151 mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState); 152 } 153 154 // Wifi 155 void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) { 156 mWifiTile = view; 157 mWifiCallback = cb; 158 mWifiCallback.refreshView(mWifiTile, mWifiState); 159 } 160 // NetworkSignalChanged callback 161 @Override 162 public void onWifiSignalChanged(boolean enabled, String description) { 163 // TODO: If view is in awaiting state, disable 164 Resources r = mContext.getResources(); 165 // TODO: Check if wifi is enabled 166 mWifiState.enabled = enabled; 167 mWifiState.iconId = (enabled ? 168 R.drawable.ic_qs_wifi_enabled : 169 R.drawable.ic_qs_wifi_normal); 170 mWifiState.label = (enabled ? 171 description : 172 r.getString(R.string.quick_settings_wifi_no_network)); 173 mWifiCallback.refreshView(mWifiTile, mWifiState); 174 } 175 176 // RSSI 177 void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) { 178 mRSSITile = view; 179 mRSSICallback = cb; 180 mRSSICallback.refreshView(mRSSITile, mRSSIState); 181 } 182 private void setRSSIState(boolean enabled) { 183 // TODO: Set RSSI enabled 184 // TODO: Sets the view to be "awaiting" if not already awaiting 185 } 186 // NetworkSignalChanged callback 187 @Override 188 public void onMobileDataSignalChanged(boolean enabled, String description) { 189 // TODO: If view is in awaiting state, disable 190 Resources r = mContext.getResources(); 191 // TODO: Check if RSSI is enabled 192 mRSSIState.enabled = enabled; 193 mRSSIState.iconId = (enabled ? 194 R.drawable.ic_qs_rssi_enabled : 195 R.drawable.ic_qs_rssi_normal); 196 mRSSIState.label = (enabled ? 197 description : 198 r.getString(R.string.quick_settings_rssi_emergency_only)); 199 mRSSICallback.refreshView(mRSSITile, mRSSIState); 200 } 201 202 // Bluetooth 203 void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) { 204 mBluetoothTile = view; 205 mBluetoothTile.setOnClickListener(new View.OnClickListener() { 206 @Override 207 public void onClick(View v) { 208 if (mBluetoothState.enabled) { 209 setBluetoothState(false); 210 } else { 211 setBluetoothState(true); 212 } 213 } 214 }); 215 mBluetoothCallback = cb; 216 217 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 218 onBluetoothStateChange(adapter.isEnabled()); 219 } 220 private void setBluetoothState(boolean enabled) { 221 // TODO: Sets the view to be "awaiting" if not already awaiting 222 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 223 if (adapter != null) { 224 if (enabled) { 225 adapter.enable(); 226 } else { 227 adapter.disable(); 228 } 229 } 230 } 231 // BluetoothController callback 232 @Override 233 public void onBluetoothStateChange(boolean on) { 234 // TODO: If view is in awaiting state, disable 235 Resources r = mContext.getResources(); 236 mBluetoothState.enabled = on; 237 if (on) { 238 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_enabled; 239 } else { 240 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_normal; 241 } 242 mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState); 243 } 244 245 // Battery 246 void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) { 247 mBatteryTile = view; 248 mBatteryCallback = cb; 249 mBatteryCallback.refreshView(mBatteryTile, mBatteryState); 250 } 251 // BatteryController callback 252 @Override 253 public void onBatteryLevelChanged(int level, boolean pluggedIn) { 254 mBatteryState.batteryLevel = level; 255 mBatteryState.pluggedIn = pluggedIn; 256 mBatteryCallback.refreshView(mBatteryTile, mBatteryState); 257 } 258 259 // Location 260 void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) { 261 mLocationTile = view; 262 mLocationCallback = cb; 263 mLocationCallback.refreshView(mLocationTile, mLocationState); 264 disableLocationTile(); 265 } 266 private void enableLocationTile() { 267 mLocationTile.setVisibility(View.VISIBLE); 268 } 269 private void disableLocationTile() { 270 mLocationTile.setVisibility(View.GONE); 271 } 272 // LocationController callback 273 @Override 274 public void onLocationGpsStateChanged(boolean inUse, String description) { 275 if (inUse) { 276 mLocationState.enabled = inUse; 277 mLocationState.label = description; 278 mLocationCallback.refreshView(mLocationTile, mLocationState); 279 enableLocationTile(); 280 } else { 281 disableLocationTile(); 282 } 283 } 284 285} 286 287/** 288 * 289 */ 290class QuickSettings { 291 292 private Context mContext; 293 private PanelBar mBar; 294 private QuickSettingsModel mModel; 295 private QuickSettingsContainerView mContainerView; 296 297 private CursorLoader mUserInfoLoader; 298 299 // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on 300 // configuration change) 301 private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles = 302 new ArrayList<QuickSettingsTileView>(); 303 304 public QuickSettings(Context context, QuickSettingsContainerView container) { 305 mContext = context; 306 mModel = new QuickSettingsModel(context); 307 mContainerView = container; 308 309 setupQuickSettings(); 310 updateResources(); 311 } 312 313 void setBar(PanelBar bar) { 314 mBar = bar; 315 } 316 317 void setup(NetworkController networkController, BluetoothController bluetoothController, 318 BatteryController batteryController, LocationController locationController) { 319 networkController.addNetworkSignalChangedCallback(mModel); 320 bluetoothController.addStateChangedCallback(mModel); 321 batteryController.addStateChangedCallback(mModel); 322 locationController.addStateChangedCallback(mModel); 323 } 324 325 private void queryForUserInformation() { 326 Uri userContactUri = Uri.withAppendedPath( 327 ContactsContract.Profile.CONTENT_URI, 328 ContactsContract.Contacts.Data.CONTENT_DIRECTORY); 329 330 String[] selectArgs = { 331 ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, 332 ContactsContract.CommonDataKinds.Photo.PHOTO 333 }; 334 String where = String.format("(%s = ? OR %s = ?) AND %s IS NULL", 335 ContactsContract.Contacts.Data.MIMETYPE, 336 ContactsContract.Contacts.Data.MIMETYPE, 337 ContactsContract.RawContacts.ACCOUNT_TYPE); 338 String[] whereArgs = { 339 ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, 340 ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE 341 }; 342 343 mUserInfoLoader = new CursorLoader(mContext, userContactUri, selectArgs, where, whereArgs, 344 null); 345 mUserInfoLoader.registerListener(0, 346 new Loader.OnLoadCompleteListener<Cursor>() { 347 @Override 348 public void onLoadComplete(Loader<Cursor> loader, 349 Cursor cursor) { 350 if (cursor.moveToFirst()) { 351 String name = cursor.getString(0); // DISPLAY_NAME 352 mModel.setUserTileInfo(name); 353 /* 354 byte[] photoData = cursor.getBlob(0); 355 Bitmap b = 356 BitmapFactory.decodeByteArray(photoData, 0, photoData.length); 357 */ 358 } 359 mUserInfoLoader.stopLoading(); 360 } 361 }); 362 mUserInfoLoader.startLoading(); 363 } 364 365 private void setupQuickSettings() { 366 // Setup the tiles that we are going to be showing (including the temporary ones) 367 LayoutInflater inflater = LayoutInflater.from(mContext); 368 369 addUserTiles(mContainerView, inflater); 370 addSystemTiles(mContainerView, inflater); 371 addTemporaryTiles(mContainerView, inflater); 372 373 queryForUserInformation(); 374 } 375 376 private void addUserTiles(ViewGroup parent, LayoutInflater inflater) { 377 QuickSettingsTileView userTile = (QuickSettingsTileView) 378 inflater.inflate(R.layout.quick_settings_tile, parent, false); 379 userTile.setContent(R.layout.quick_settings_tile_user, inflater); 380 mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() { 381 @Override 382 public void refreshView(QuickSettingsTileView view, State state) { 383 TextView tv = (TextView) view.findViewById(R.id.user_textview); 384 tv.setText(state.label); 385 } 386 }); 387 parent.addView(userTile); 388 mDynamicSpannedTiles.add(userTile); 389 390 // Time tile 391 QuickSettingsTileView timeTile = (QuickSettingsTileView) 392 inflater.inflate(R.layout.quick_settings_tile, parent, false); 393 timeTile.setContent(R.layout.quick_settings_tile_time, inflater); 394 parent.addView(timeTile); 395 mDynamicSpannedTiles.add(timeTile); 396 397 // Settings tile 398 QuickSettingsTileView settingsTile = (QuickSettingsTileView) 399 inflater.inflate(R.layout.quick_settings_tile, parent, false); 400 settingsTile.setContent(R.layout.quick_settings_tile_settings, inflater); 401 settingsTile.setOnClickListener(new View.OnClickListener() { 402 @Override 403 public void onClick(View v) { 404 Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS); 405 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 406 mContext.startActivity(intent); 407 mBar.collapseAllPanels(true); 408 } 409 }); 410 parent.addView(settingsTile); 411 mDynamicSpannedTiles.add(settingsTile); 412 } 413 414 private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) { 415 // Wi-fi 416 QuickSettingsTileView wifiTile = (QuickSettingsTileView) 417 inflater.inflate(R.layout.quick_settings_tile, parent, false); 418 wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater); 419 wifiTile.setOnClickListener(new View.OnClickListener() { 420 @Override 421 public void onClick(View v) { 422 Intent intent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS); 423 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 424 mContext.startActivity(intent); 425 mBar.collapseAllPanels(true); 426 } 427 }); 428 mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() { 429 @Override 430 public void refreshView(QuickSettingsTileView view, State state) { 431 TextView tv = (TextView) view.findViewById(R.id.wifi_textview); 432 tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0); 433 tv.setText(state.label); 434 } 435 }); 436 parent.addView(wifiTile); 437 438 // RSSI 439 QuickSettingsTileView rssiTile = (QuickSettingsTileView) 440 inflater.inflate(R.layout.quick_settings_tile, parent, false); 441 rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater); 442 rssiTile.setOnClickListener(new View.OnClickListener() { 443 @Override 444 public void onClick(View v) { 445 Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS); 446 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 447 mContext.startActivity(intent); 448 mBar.collapseAllPanels(true); 449 } 450 }); 451 mModel.addRSSITile(rssiTile, new QuickSettingsModel.RefreshCallback() { 452 @Override 453 public void refreshView(QuickSettingsTileView view, State state) { 454 TextView tv = (TextView) view.findViewById(R.id.rssi_textview); 455 tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0); 456 tv.setText(state.label); 457 } 458 }); 459 parent.addView(rssiTile); 460 461 // Battery 462 QuickSettingsTileView batteryTile = (QuickSettingsTileView) 463 inflater.inflate(R.layout.quick_settings_tile, parent, false); 464 batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater); 465 batteryTile.setOnClickListener(new View.OnClickListener() { 466 @Override 467 public void onClick(View v) { 468 Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); 469 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 470 mContext.startActivity(intent); 471 mBar.collapseAllPanels(true); 472 } 473 }); 474 mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() { 475 @Override 476 public void refreshView(QuickSettingsTileView view, State state) { 477 QuickSettingsModel.BatteryState batteryState = 478 (QuickSettingsModel.BatteryState) state; 479 TextView tv = (TextView) view.findViewById(R.id.battery_textview); 480 ClipDrawable drawable = (ClipDrawable) tv.getCompoundDrawables()[1]; 481 drawable.setLevel((int) (10000 * (batteryState.batteryLevel / 100.0f))); 482 // TODO: use format string 483 tv.setText(batteryState.batteryLevel + "%"); 484 } 485 }); 486 parent.addView(batteryTile); 487 488 // Airplane Mode 489 QuickSettingsTileView airplaneTile = (QuickSettingsTileView) 490 inflater.inflate(R.layout.quick_settings_tile, parent, false); 491 airplaneTile.setContent(R.layout.quick_settings_tile_airplane, inflater); 492 mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() { 493 @Override 494 public void refreshView(QuickSettingsTileView view, State state) { 495 TextView tv = (TextView) view.findViewById(R.id.airplane_mode_textview); 496 tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0); 497 } 498 }); 499 parent.addView(airplaneTile); 500 501 // Bluetooth 502 QuickSettingsTileView bluetoothTile = (QuickSettingsTileView) 503 inflater.inflate(R.layout.quick_settings_tile, parent, false); 504 bluetoothTile.setContent(R.layout.quick_settings_tile_bluetooth, inflater); 505 mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() { 506 @Override 507 public void refreshView(QuickSettingsTileView view, State state) { 508 TextView tv = (TextView) view.findViewById(R.id.bluetooth_textview); 509 tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0); 510 } 511 }); 512 parent.addView(bluetoothTile); 513 514 // Brightness 515 QuickSettingsTileView brightnessTile = (QuickSettingsTileView) 516 inflater.inflate(R.layout.quick_settings_tile, parent, false); 517 brightnessTile.setContent(R.layout.quick_settings_tile_brightness, inflater); 518 brightnessTile.setOnClickListener(new View.OnClickListener() { 519 @Override 520 public void onClick(View v) { 521 Intent intent = new Intent(android.provider.Settings.ACTION_DISPLAY_SETTINGS); 522 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 523 mContext.startActivity(intent); 524 mBar.collapseAllPanels(true); 525 } 526 }); 527 parent.addView(brightnessTile); 528 } 529 530 private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) { 531 // Location 532 QuickSettingsTileView locationTile = (QuickSettingsTileView) 533 inflater.inflate(R.layout.quick_settings_tile, parent, false); 534 locationTile.setContent(R.layout.quick_settings_tile_location, inflater); 535 locationTile.setOnClickListener(new View.OnClickListener() { 536 @Override 537 public void onClick(View v) { 538 Intent intent = 539 new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); 540 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 541 mContext.startActivity(intent); 542 mBar.collapseAllPanels(true); 543 } 544 }); 545 mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() { 546 @Override 547 public void refreshView(QuickSettingsTileView view, State state) { 548 TextView tv = (TextView) view.findViewById(R.id.location_textview); 549 tv.setText(state.label); 550 } 551 }); 552 parent.addView(locationTile); 553 554 /* 555 QuickSettingsTileView mediaTile = (QuickSettingsTileView) 556 inflater.inflate(R.layout.quick_settings_tile, parent, false); 557 mediaTile.setContent(R.layout.quick_settings_tile_media, inflater); 558 parent.addView(mediaTile); 559 QuickSettingsTileView imeTile = (QuickSettingsTileView) 560 inflater.inflate(R.layout.quick_settings_tile, parent, false); 561 imeTile.setContent(R.layout.quick_settings_tile_ime, inflater); 562 imeTile.setOnClickListener(new View.OnClickListener() { 563 @Override 564 public void onClick(View v) { 565 parent.removeViewAt(0); 566 } 567 }); 568 parent.addView(imeTile); 569 */ 570 } 571 572 void updateResources() { 573 Resources r = mContext.getResources(); 574 575 // Update the User, Time, and Settings tiles spans, and reset everything else 576 int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span); 577 for (QuickSettingsTileView v : mDynamicSpannedTiles) { 578 v.setColumnSpan(span); 579 } 580 mContainerView.requestLayout(); 581 } 582}