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 17 package com.android.systemui.statusbar.phone; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback; 21 import android.content.BroadcastReceiver; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.PackageManager; 27 import android.content.res.Resources; 28 import android.database.ContentObserver; 29 import android.graphics.drawable.Drawable; 30 import android.media.MediaRouter; 31 import android.media.MediaRouter.RouteInfo; 32 import android.net.ConnectivityManager; 33 import android.os.Handler; 34 import android.os.UserHandle; 35 import android.provider.Settings; 36 import android.provider.Settings.SettingNotFoundException; 37 import android.text.TextUtils; 38 import android.view.LayoutInflater; 39 import android.view.View; 40 import android.view.inputmethod.InputMethodInfo; 41 import android.view.inputmethod.InputMethodManager; 42 import android.view.inputmethod.InputMethodSubtype; 43 44 import com.android.systemui.R; 45 import com.android.systemui.settings.BrightnessController.BrightnessStateChangeCallback; 46 import com.android.systemui.settings.CurrentUserTracker; 47 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; 48 import com.android.systemui.statusbar.policy.LocationController.LocationSettingsChangeCallback; 49 import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback; 50 import com.android.systemui.statusbar.policy.RotationLockController; 51 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; 52 53 import java.util.List; 54 55 class QuickSettingsModel implements BluetoothStateChangeCallback, 56 NetworkSignalChangedCallback, 57 BatteryStateChangeCallback, 58 BrightnessStateChangeCallback, 59 RotationLockControllerCallback, 60 LocationSettingsChangeCallback { 61 // Sett InputMethoManagerService 62 private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher"; 63 64 /** Represents the state of a given attribute. */ 65 static class State { 66 int iconId; 67 String label; 68 boolean enabled = false; 69 } 70 static class BatteryState extends State { 71 int batteryLevel; 72 boolean pluggedIn; 73 } 74 static class ActivityState extends State { 75 boolean activityIn; 76 boolean activityOut; 77 } 78 static class RSSIState extends ActivityState { 79 int signalIconId; 80 String signalContentDescription; 81 int dataTypeIconId; 82 String dataContentDescription; 83 } 84 static class WifiState extends ActivityState { 85 String signalContentDescription; 86 boolean connected; 87 } 88 static class UserState extends State { 89 Drawable avatar; 90 } 91 static class BrightnessState extends State { 92 boolean autoBrightness; 93 } 94 public static class BluetoothState extends State { 95 boolean connected = false; 96 String stateContentDescription; 97 } 98 public static class RotationLockState extends State { 99 boolean visible = false; 100 } 101 102 /** The callback to update a given tile. */ 103 interface RefreshCallback { 104 public void refreshView(QuickSettingsTileView view, State state); 105 } 106 107 public static class BasicRefreshCallback implements RefreshCallback { 108 private final QuickSettingsBasicTile mView; 109 private boolean mShowWhenEnabled; 110 111 public BasicRefreshCallback(QuickSettingsBasicTile v) { 112 mView = v; 113 } 114 public void refreshView(QuickSettingsTileView ignored, State state) { 115 if (mShowWhenEnabled) { 116 mView.setVisibility(state.enabled ? View.VISIBLE : View.GONE); 117 } 118 if (state.iconId != 0) { 119 mView.setImageDrawable(null); // needed to flush any cached IDs 120 mView.setImageResource(state.iconId); 121 } 122 if (state.label != null) { 123 mView.setText(state.label); 124 } 125 } 126 public BasicRefreshCallback setShowWhenEnabled(boolean swe) { 127 mShowWhenEnabled = swe; 128 return this; 129 } 130 } 131 132 /** Broadcast receive to determine if there is an alarm set. */ 133 private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() { 134 @Override 135 public void onReceive(Context context, Intent intent) { 136 String action = intent.getAction(); 137 if (action.equals(Intent.ACTION_ALARM_CHANGED)) { 138 onAlarmChanged(intent); 139 onNextAlarmChanged(); 140 } 141 } 142 }; 143 144 /** ContentObserver to determine the next alarm */ 145 private class NextAlarmObserver extends ContentObserver { 146 public NextAlarmObserver(Handler handler) { 147 super(handler); 148 } 149 150 @Override public void onChange(boolean selfChange) { 151 onNextAlarmChanged(); 152 } 153 154 public void startObserving() { 155 final ContentResolver cr = mContext.getContentResolver(); 156 cr.registerContentObserver( 157 Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this, 158 UserHandle.USER_ALL); 159 } 160 } 161 162 /** ContentObserver to watch adb */ 163 private class BugreportObserver extends ContentObserver { 164 public BugreportObserver(Handler handler) { 165 super(handler); 166 } 167 168 @Override public void onChange(boolean selfChange) { 169 onBugreportChanged(); 170 } 171 172 public void startObserving() { 173 final ContentResolver cr = mContext.getContentResolver(); 174 cr.registerContentObserver( 175 Settings.Global.getUriFor(Settings.Global.BUGREPORT_IN_POWER_MENU), false, this); 176 } 177 } 178 179 /** ContentObserver to watch brightness **/ 180 private class BrightnessObserver extends ContentObserver { 181 public BrightnessObserver(Handler handler) { 182 super(handler); 183 } 184 185 @Override 186 public void onChange(boolean selfChange) { 187 onBrightnessLevelChanged(); 188 } 189 190 public void startObserving() { 191 final ContentResolver cr = mContext.getContentResolver(); 192 cr.unregisterContentObserver(this); 193 cr.registerContentObserver( 194 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), 195 false, this, mUserTracker.getCurrentUserId()); 196 cr.registerContentObserver( 197 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), 198 false, this, mUserTracker.getCurrentUserId()); 199 } 200 } 201 202 /** Callback for changes to remote display routes. */ 203 private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback { 204 @Override 205 public void onRouteAdded(MediaRouter router, RouteInfo route) { 206 updateRemoteDisplays(); 207 } 208 @Override 209 public void onRouteChanged(MediaRouter router, RouteInfo route) { 210 updateRemoteDisplays(); 211 } 212 @Override 213 public void onRouteRemoved(MediaRouter router, RouteInfo route) { 214 updateRemoteDisplays(); 215 } 216 @Override 217 public void onRouteSelected(MediaRouter router, int type, RouteInfo route) { 218 updateRemoteDisplays(); 219 } 220 @Override 221 public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) { 222 updateRemoteDisplays(); 223 } 224 } 225 226 private final Context mContext; 227 private final Handler mHandler; 228 private final CurrentUserTracker mUserTracker; 229 private final NextAlarmObserver mNextAlarmObserver; 230 private final BugreportObserver mBugreportObserver; 231 private final BrightnessObserver mBrightnessObserver; 232 233 private final MediaRouter mMediaRouter; 234 private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback; 235 236 private final boolean mHasMobileData; 237 238 private QuickSettingsTileView mUserTile; 239 private RefreshCallback mUserCallback; 240 private UserState mUserState = new UserState(); 241 242 private QuickSettingsTileView mTimeTile; 243 private RefreshCallback mTimeCallback; 244 private State mTimeState = new State(); 245 246 private QuickSettingsTileView mAlarmTile; 247 private RefreshCallback mAlarmCallback; 248 private State mAlarmState = new State(); 249 250 private QuickSettingsTileView mAirplaneModeTile; 251 private RefreshCallback mAirplaneModeCallback; 252 private State mAirplaneModeState = new State(); 253 254 private QuickSettingsTileView mWifiTile; 255 private RefreshCallback mWifiCallback; 256 private WifiState mWifiState = new WifiState(); 257 258 private QuickSettingsTileView mRemoteDisplayTile; 259 private RefreshCallback mRemoteDisplayCallback; 260 private State mRemoteDisplayState = new State(); 261 262 private QuickSettingsTileView mRSSITile; 263 private RefreshCallback mRSSICallback; 264 private RSSIState mRSSIState = new RSSIState(); 265 266 private QuickSettingsTileView mBluetoothTile; 267 private RefreshCallback mBluetoothCallback; 268 private BluetoothState mBluetoothState = new BluetoothState(); 269 270 private QuickSettingsTileView mBatteryTile; 271 private RefreshCallback mBatteryCallback; 272 private BatteryState mBatteryState = new BatteryState(); 273 274 private QuickSettingsTileView mLocationTile; 275 private RefreshCallback mLocationCallback; 276 private State mLocationState = new State(); 277 278 private QuickSettingsTileView mImeTile; 279 private RefreshCallback mImeCallback = null; 280 private State mImeState = new State(); 281 282 private QuickSettingsTileView mRotationLockTile; 283 private RefreshCallback mRotationLockCallback; 284 private RotationLockState mRotationLockState = new RotationLockState(); 285 286 private QuickSettingsTileView mBrightnessTile; 287 private RefreshCallback mBrightnessCallback; 288 private BrightnessState mBrightnessState = new BrightnessState(); 289 290 private QuickSettingsTileView mBugreportTile; 291 private RefreshCallback mBugreportCallback; 292 private State mBugreportState = new State(); 293 294 private QuickSettingsTileView mSettingsTile; 295 private RefreshCallback mSettingsCallback; 296 private State mSettingsState = new State(); 297 298 private QuickSettingsTileView mSslCaCertWarningTile; 299 private RefreshCallback mSslCaCertWarningCallback; 300 private State mSslCaCertWarningState = new State(); 301 302 private RotationLockController mRotationLockController; 303 304 public QuickSettingsModel(Context context) { 305 mContext = context; 306 mHandler = new Handler(); 307 mUserTracker = new CurrentUserTracker(mContext) { 308 @Override 309 public void onUserSwitched(int newUserId) { 310 mBrightnessObserver.startObserving(); 311 refreshRotationLockTile(); 312 onBrightnessLevelChanged(); 313 onNextAlarmChanged(); 314 onBugreportChanged(); 315 rebindMediaRouterAsCurrentUser(); 316 } 317 }; 318 319 mNextAlarmObserver = new NextAlarmObserver(mHandler); 320 mNextAlarmObserver.startObserving(); 321 mBugreportObserver = new BugreportObserver(mHandler); 322 mBugreportObserver.startObserving(); 323 mBrightnessObserver = new BrightnessObserver(mHandler); 324 mBrightnessObserver.startObserving(); 325 326 mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE); 327 rebindMediaRouterAsCurrentUser(); 328 329 mRemoteDisplayRouteCallback = new RemoteDisplayRouteCallback(); 330 331 ConnectivityManager cm = (ConnectivityManager) 332 context.getSystemService(Context.CONNECTIVITY_SERVICE); 333 mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); 334 335 IntentFilter alarmIntentFilter = new IntentFilter(); 336 alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED); 337 context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter); 338 } 339 340 void updateResources() { 341 refreshSettingsTile(); 342 refreshBatteryTile(); 343 refreshBluetoothTile(); 344 refreshBrightnessTile(); 345 refreshRotationLockTile(); 346 refreshRssiTile(); 347 refreshLocationTile(); 348 } 349 350 // Settings 351 void addSettingsTile(QuickSettingsTileView view, RefreshCallback cb) { 352 mSettingsTile = view; 353 mSettingsCallback = cb; 354 refreshSettingsTile(); 355 } 356 void refreshSettingsTile() { 357 Resources r = mContext.getResources(); 358 mSettingsState.label = r.getString(R.string.quick_settings_settings_label); 359 mSettingsCallback.refreshView(mSettingsTile, mSettingsState); 360 } 361 362 // User 363 void addUserTile(QuickSettingsTileView view, RefreshCallback cb) { 364 mUserTile = view; 365 mUserCallback = cb; 366 mUserCallback.refreshView(mUserTile, mUserState); 367 } 368 void setUserTileInfo(String name, Drawable avatar) { 369 mUserState.label = name; 370 mUserState.avatar = avatar; 371 mUserCallback.refreshView(mUserTile, mUserState); 372 } 373 374 // Time 375 void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) { 376 mTimeTile = view; 377 mTimeCallback = cb; 378 mTimeCallback.refreshView(view, mTimeState); 379 } 380 381 // Alarm 382 void addAlarmTile(QuickSettingsTileView view, RefreshCallback cb) { 383 mAlarmTile = view; 384 mAlarmCallback = cb; 385 mAlarmCallback.refreshView(view, mAlarmState); 386 } 387 void onAlarmChanged(Intent intent) { 388 mAlarmState.enabled = intent.getBooleanExtra("alarmSet", false); 389 mAlarmCallback.refreshView(mAlarmTile, mAlarmState); 390 } 391 void onNextAlarmChanged() { 392 final String alarmText = Settings.System.getStringForUser(mContext.getContentResolver(), 393 Settings.System.NEXT_ALARM_FORMATTED, 394 UserHandle.USER_CURRENT); 395 mAlarmState.label = alarmText; 396 397 // When switching users, this is the only clue we're going to get about whether the 398 // alarm is actually set, since we won't get the ACTION_ALARM_CHANGED broadcast 399 mAlarmState.enabled = ! TextUtils.isEmpty(alarmText); 400 401 mAlarmCallback.refreshView(mAlarmTile, mAlarmState); 402 } 403 404 // Airplane Mode 405 void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) { 406 mAirplaneModeTile = view; 407 mAirplaneModeTile.setOnClickListener(new View.OnClickListener() { 408 @Override 409 public void onClick(View v) { 410 if (mAirplaneModeState.enabled) { 411 setAirplaneModeState(false); 412 } else { 413 setAirplaneModeState(true); 414 } 415 } 416 }); 417 mAirplaneModeCallback = cb; 418 int airplaneMode = Settings.Global.getInt(mContext.getContentResolver(), 419 Settings.Global.AIRPLANE_MODE_ON, 0); 420 onAirplaneModeChanged(airplaneMode != 0); 421 } 422 private void setAirplaneModeState(boolean enabled) { 423 // TODO: Sets the view to be "awaiting" if not already awaiting 424 425 // Change the system setting 426 Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 427 enabled ? 1 : 0); 428 429 // Post the intent 430 Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); 431 intent.putExtra("state", enabled); 432 mContext.sendBroadcast(intent); 433 } 434 // NetworkSignalChanged callback 435 @Override 436 public void onAirplaneModeChanged(boolean enabled) { 437 // TODO: If view is in awaiting state, disable 438 Resources r = mContext.getResources(); 439 mAirplaneModeState.enabled = enabled; 440 mAirplaneModeState.iconId = (enabled ? 441 R.drawable.ic_qs_airplane_on : 442 R.drawable.ic_qs_airplane_off); 443 mAirplaneModeState.label = r.getString(R.string.quick_settings_airplane_mode_label); 444 mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState); 445 } 446 447 // Wifi 448 void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) { 449 mWifiTile = view; 450 mWifiCallback = cb; 451 mWifiCallback.refreshView(mWifiTile, mWifiState); 452 } 453 // Remove the double quotes that the SSID may contain 454 public static String removeDoubleQuotes(String string) { 455 if (string == null) return null; 456 final int length = string.length(); 457 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { 458 return string.substring(1, length - 1); 459 } 460 return string; 461 } 462 // Remove the period from the network name 463 public static String removeTrailingPeriod(String string) { 464 if (string == null) return null; 465 final int length = string.length(); 466 if (string.endsWith(".")) { 467 return string.substring(0, length - 1); 468 } 469 return string; 470 } 471 // NetworkSignalChanged callback 472 @Override 473 public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, 474 boolean activityIn, boolean activityOut, 475 String wifiSignalContentDescription, String enabledDesc) { 476 // TODO: If view is in awaiting state, disable 477 Resources r = mContext.getResources(); 478 479 boolean wifiConnected = enabled && (wifiSignalIconId > 0) && (enabledDesc != null); 480 boolean wifiNotConnected = (wifiSignalIconId > 0) && (enabledDesc == null); 481 mWifiState.enabled = enabled; 482 mWifiState.connected = wifiConnected; 483 mWifiState.activityIn = enabled && activityIn; 484 mWifiState.activityOut = enabled && activityOut; 485 if (wifiConnected) { 486 mWifiState.iconId = wifiSignalIconId; 487 mWifiState.label = removeDoubleQuotes(enabledDesc); 488 mWifiState.signalContentDescription = wifiSignalContentDescription; 489 } else if (wifiNotConnected) { 490 mWifiState.iconId = R.drawable.ic_qs_wifi_0; 491 mWifiState.label = r.getString(R.string.quick_settings_wifi_label); 492 mWifiState.signalContentDescription = r.getString(R.string.accessibility_no_wifi); 493 } else { 494 mWifiState.iconId = R.drawable.ic_qs_wifi_no_network; 495 mWifiState.label = r.getString(R.string.quick_settings_wifi_off_label); 496 mWifiState.signalContentDescription = r.getString(R.string.accessibility_wifi_off); 497 } 498 mWifiCallback.refreshView(mWifiTile, mWifiState); 499 } 500 501 boolean deviceHasMobileData() { 502 return mHasMobileData; 503 } 504 505 // RSSI 506 void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) { 507 mRSSITile = view; 508 mRSSICallback = cb; 509 mRSSICallback.refreshView(mRSSITile, mRSSIState); 510 } 511 // NetworkSignalChanged callback 512 @Override 513 public void onMobileDataSignalChanged( 514 boolean enabled, int mobileSignalIconId, String signalContentDescription, 515 int dataTypeIconId, boolean activityIn, boolean activityOut, 516 String dataContentDescription,String enabledDesc) { 517 if (deviceHasMobileData()) { 518 // TODO: If view is in awaiting state, disable 519 Resources r = mContext.getResources(); 520 mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0) 521 ? mobileSignalIconId 522 : R.drawable.ic_qs_signal_no_signal; 523 mRSSIState.signalContentDescription = enabled && (mobileSignalIconId > 0) 524 ? signalContentDescription 525 : r.getString(R.string.accessibility_no_signal); 526 mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0) && !mWifiState.enabled 527 ? dataTypeIconId 528 : 0; 529 mRSSIState.activityIn = enabled && activityIn; 530 mRSSIState.activityOut = enabled && activityOut; 531 mRSSIState.dataContentDescription = enabled && (dataTypeIconId > 0) && !mWifiState.enabled 532 ? dataContentDescription 533 : r.getString(R.string.accessibility_no_data); 534 mRSSIState.label = enabled 535 ? removeTrailingPeriod(enabledDesc) 536 : r.getString(R.string.quick_settings_rssi_emergency_only); 537 mRSSICallback.refreshView(mRSSITile, mRSSIState); 538 } 539 } 540 541 void refreshRssiTile() { 542 if (mRSSITile != null) { 543 // We reinflate the original view due to potential styling changes that may have 544 // taken place due to a configuration change. 545 mRSSITile.reinflateContent(LayoutInflater.from(mContext)); 546 } 547 } 548 549 // Bluetooth 550 void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) { 551 mBluetoothTile = view; 552 mBluetoothCallback = cb; 553 554 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 555 mBluetoothState.enabled = adapter.isEnabled(); 556 mBluetoothState.connected = 557 (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED); 558 onBluetoothStateChange(mBluetoothState); 559 } 560 boolean deviceSupportsBluetooth() { 561 return (BluetoothAdapter.getDefaultAdapter() != null); 562 } 563 // BluetoothController callback 564 @Override 565 public void onBluetoothStateChange(boolean on) { 566 mBluetoothState.enabled = on; 567 onBluetoothStateChange(mBluetoothState); 568 } 569 public void onBluetoothStateChange(BluetoothState bluetoothStateIn) { 570 // TODO: If view is in awaiting state, disable 571 Resources r = mContext.getResources(); 572 mBluetoothState.enabled = bluetoothStateIn.enabled; 573 mBluetoothState.connected = bluetoothStateIn.connected; 574 if (mBluetoothState.enabled) { 575 if (mBluetoothState.connected) { 576 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on; 577 mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_connected); 578 } else { 579 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_not_connected; 580 mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_on); 581 } 582 mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_label); 583 } else { 584 mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off; 585 mBluetoothState.label = r.getString(R.string.quick_settings_bluetooth_off_label); 586 mBluetoothState.stateContentDescription = r.getString(R.string.accessibility_desc_off); 587 } 588 mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState); 589 } 590 void refreshBluetoothTile() { 591 if (mBluetoothTile != null) { 592 onBluetoothStateChange(mBluetoothState.enabled); 593 } 594 } 595 596 // Battery 597 void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) { 598 mBatteryTile = view; 599 mBatteryCallback = cb; 600 mBatteryCallback.refreshView(mBatteryTile, mBatteryState); 601 } 602 // BatteryController callback 603 @Override 604 public void onBatteryLevelChanged(int level, boolean pluggedIn) { 605 mBatteryState.batteryLevel = level; 606 mBatteryState.pluggedIn = pluggedIn; 607 mBatteryCallback.refreshView(mBatteryTile, mBatteryState); 608 } 609 void refreshBatteryTile() { 610 mBatteryCallback.refreshView(mBatteryTile, mBatteryState); 611 } 612 613 // Location 614 void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) { 615 mLocationTile = view; 616 mLocationCallback = cb; 617 mLocationCallback.refreshView(mLocationTile, mLocationState); 618 } 619 620 void refreshLocationTile() { 621 if (mLocationTile != null) { 622 onLocationSettingsChanged(mLocationState.enabled); 623 } 624 } 625 626 @Override 627 public void onLocationSettingsChanged(boolean locationEnabled) { 628 int textResId = locationEnabled ? R.string.quick_settings_location_label 629 : R.string.quick_settings_location_off_label; 630 String label = mContext.getText(textResId).toString(); 631 int locationIconId = locationEnabled 632 ? R.drawable.ic_qs_location_on : R.drawable.ic_qs_location_off; 633 mLocationState.enabled = locationEnabled; 634 mLocationState.label = label; 635 mLocationState.iconId = locationIconId; 636 mLocationCallback.refreshView(mLocationTile, mLocationState); 637 } 638 639 // Bug report 640 void addBugreportTile(QuickSettingsTileView view, RefreshCallback cb) { 641 mBugreportTile = view; 642 mBugreportCallback = cb; 643 onBugreportChanged(); 644 } 645 // SettingsObserver callback 646 public void onBugreportChanged() { 647 final ContentResolver cr = mContext.getContentResolver(); 648 boolean enabled = false; 649 try { 650 enabled = (Settings.Global.getInt(cr, Settings.Global.BUGREPORT_IN_POWER_MENU) != 0); 651 } catch (SettingNotFoundException e) { 652 } 653 654 mBugreportState.enabled = enabled && mUserTracker.isCurrentUserOwner(); 655 mBugreportCallback.refreshView(mBugreportTile, mBugreportState); 656 } 657 658 // Remote Display 659 void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) { 660 mRemoteDisplayTile = view; 661 mRemoteDisplayCallback = cb; 662 final int[] count = new int[1]; 663 mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() { 664 @Override 665 public void onPrepare() { 666 mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, 667 mRemoteDisplayRouteCallback, 668 MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); 669 updateRemoteDisplays(); 670 } 671 @Override 672 public void onUnprepare() { 673 mMediaRouter.removeCallback(mRemoteDisplayRouteCallback); 674 } 675 }); 676 677 updateRemoteDisplays(); 678 } 679 680 private void rebindMediaRouterAsCurrentUser() { 681 mMediaRouter.rebindAsUser(mUserTracker.getCurrentUserId()); 682 } 683 684 private void updateRemoteDisplays() { 685 MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute( 686 MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); 687 boolean enabled = connectedRoute != null 688 && connectedRoute.matchesTypes(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY); 689 boolean connecting; 690 if (enabled) { 691 connecting = connectedRoute.isConnecting(); 692 } else { 693 connectedRoute = null; 694 connecting = false; 695 enabled = mMediaRouter.isRouteAvailable(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, 696 MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE); 697 } 698 699 mRemoteDisplayState.enabled = enabled; 700 if (connectedRoute != null) { 701 mRemoteDisplayState.label = connectedRoute.getName().toString(); 702 mRemoteDisplayState.iconId = connecting ? 703 R.drawable.ic_qs_cast_connecting : R.drawable.ic_qs_cast_connected; 704 } else { 705 mRemoteDisplayState.label = mContext.getString( 706 R.string.quick_settings_remote_display_no_connection_label); 707 mRemoteDisplayState.iconId = R.drawable.ic_qs_cast_available; 708 } 709 mRemoteDisplayCallback.refreshView(mRemoteDisplayTile, mRemoteDisplayState); 710 } 711 712 // IME 713 void addImeTile(QuickSettingsTileView view, RefreshCallback cb) { 714 mImeTile = view; 715 mImeCallback = cb; 716 mImeCallback.refreshView(mImeTile, mImeState); 717 } 718 /* This implementation is taken from 719 InputMethodManagerService.needsToShowImeSwitchOngoingNotification(). */ 720 private boolean needsToShowImeSwitchOngoingNotification(InputMethodManager imm) { 721 List<InputMethodInfo> imis = imm.getEnabledInputMethodList(); 722 final int N = imis.size(); 723 if (N > 2) return true; 724 if (N < 1) return false; 725 int nonAuxCount = 0; 726 int auxCount = 0; 727 InputMethodSubtype nonAuxSubtype = null; 728 InputMethodSubtype auxSubtype = null; 729 for(int i = 0; i < N; ++i) { 730 final InputMethodInfo imi = imis.get(i); 731 final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(imi, 732 true); 733 final int subtypeCount = subtypes.size(); 734 if (subtypeCount == 0) { 735 ++nonAuxCount; 736 } else { 737 for (int j = 0; j < subtypeCount; ++j) { 738 final InputMethodSubtype subtype = subtypes.get(j); 739 if (!subtype.isAuxiliary()) { 740 ++nonAuxCount; 741 nonAuxSubtype = subtype; 742 } else { 743 ++auxCount; 744 auxSubtype = subtype; 745 } 746 } 747 } 748 } 749 if (nonAuxCount > 1 || auxCount > 1) { 750 return true; 751 } else if (nonAuxCount == 1 && auxCount == 1) { 752 if (nonAuxSubtype != null && auxSubtype != null 753 && (nonAuxSubtype.getLocale().equals(auxSubtype.getLocale()) 754 || auxSubtype.overridesImplicitlyEnabledSubtype() 755 || nonAuxSubtype.overridesImplicitlyEnabledSubtype()) 756 && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) { 757 return false; 758 } 759 return true; 760 } 761 return false; 762 } 763 void onImeWindowStatusChanged(boolean visible) { 764 InputMethodManager imm = 765 (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); 766 List<InputMethodInfo> imis = imm.getInputMethodList(); 767 768 mImeState.enabled = (visible && needsToShowImeSwitchOngoingNotification(imm)); 769 mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(), 770 imm, imis, mContext.getPackageManager()); 771 if (mImeCallback != null) { 772 mImeCallback.refreshView(mImeTile, mImeState); 773 } 774 } 775 private static String getCurrentInputMethodName(Context context, ContentResolver resolver, 776 InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) { 777 if (resolver == null || imis == null) return null; 778 final String currentInputMethodId = Settings.Secure.getString(resolver, 779 Settings.Secure.DEFAULT_INPUT_METHOD); 780 if (TextUtils.isEmpty(currentInputMethodId)) return null; 781 for (InputMethodInfo imi : imis) { 782 if (currentInputMethodId.equals(imi.getId())) { 783 final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype(); 784 final CharSequence summary = subtype != null 785 ? subtype.getDisplayName(context, imi.getPackageName(), 786 imi.getServiceInfo().applicationInfo) 787 : context.getString(R.string.quick_settings_ime_label); 788 return summary.toString(); 789 } 790 } 791 return null; 792 } 793 794 // Rotation lock 795 void addRotationLockTile(QuickSettingsTileView view, 796 RotationLockController rotationLockController, 797 RefreshCallback cb) { 798 mRotationLockTile = view; 799 mRotationLockCallback = cb; 800 mRotationLockController = rotationLockController; 801 onRotationLockChanged(); 802 } 803 void onRotationLockChanged() { 804 onRotationLockStateChanged(mRotationLockController.isRotationLocked(), 805 mRotationLockController.isRotationLockAffordanceVisible()); 806 } 807 @Override 808 public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) { 809 mRotationLockState.visible = affordanceVisible; 810 mRotationLockState.enabled = rotationLocked; 811 mRotationLockState.iconId = rotationLocked 812 ? R.drawable.ic_qs_rotation_locked 813 : R.drawable.ic_qs_auto_rotate; 814 mRotationLockState.label = rotationLocked 815 ? mContext.getString(R.string.quick_settings_rotation_locked_label) 816 : mContext.getString(R.string.quick_settings_rotation_unlocked_label); 817 mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState); 818 } 819 void refreshRotationLockTile() { 820 if (mRotationLockTile != null) { 821 onRotationLockChanged(); 822 } 823 } 824 825 // Brightness 826 void addBrightnessTile(QuickSettingsTileView view, RefreshCallback cb) { 827 mBrightnessTile = view; 828 mBrightnessCallback = cb; 829 onBrightnessLevelChanged(); 830 } 831 @Override 832 public void onBrightnessLevelChanged() { 833 Resources r = mContext.getResources(); 834 int mode = Settings.System.getIntForUser(mContext.getContentResolver(), 835 Settings.System.SCREEN_BRIGHTNESS_MODE, 836 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, 837 mUserTracker.getCurrentUserId()); 838 mBrightnessState.autoBrightness = 839 (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); 840 mBrightnessState.iconId = mBrightnessState.autoBrightness 841 ? R.drawable.ic_qs_brightness_auto_on 842 : R.drawable.ic_qs_brightness_auto_off; 843 mBrightnessState.label = r.getString(R.string.quick_settings_brightness_label); 844 mBrightnessCallback.refreshView(mBrightnessTile, mBrightnessState); 845 } 846 void refreshBrightnessTile() { 847 onBrightnessLevelChanged(); 848 } 849 850 // SSL CA Cert warning. 851 public void addSslCaCertWarningTile(QuickSettingsTileView view, RefreshCallback cb) { 852 mSslCaCertWarningTile = view; 853 mSslCaCertWarningCallback = cb; 854 // Set a sane default while we wait for the AsyncTask to finish (no cert). 855 setSslCaCertWarningTileInfo(false, true); 856 } 857 public void setSslCaCertWarningTileInfo(boolean hasCert, boolean isManaged) { 858 Resources r = mContext.getResources(); 859 mSslCaCertWarningState.enabled = hasCert; 860 if (isManaged) { 861 mSslCaCertWarningState.iconId = R.drawable.ic_qs_certificate_info; 862 } else { 863 mSslCaCertWarningState.iconId = android.R.drawable.stat_notify_error; 864 } 865 mSslCaCertWarningState.label = r.getString(R.string.ssl_ca_cert_warning); 866 mSslCaCertWarningCallback.refreshView(mSslCaCertWarningTile, mSslCaCertWarningState); 867 } 868 } 869