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