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