1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.statusbar.phone;
18
19import android.bluetooth.BluetoothAdapter;
20import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
21import android.content.BroadcastReceiver;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.PackageManager;
27import android.content.res.Resources;
28import android.database.ContentObserver;
29import android.graphics.drawable.Drawable;
30import android.hardware.display.WifiDisplayStatus;
31import android.net.ConnectivityManager;
32import android.os.Handler;
33import android.os.UserHandle;
34import android.provider.Settings;
35import android.provider.Settings.SettingNotFoundException;
36import android.text.TextUtils;
37import android.view.View;
38import android.view.inputmethod.InputMethodInfo;
39import android.view.inputmethod.InputMethodManager;
40import android.view.inputmethod.InputMethodSubtype;
41
42import com.android.internal.view.RotationPolicy;
43import com.android.systemui.R;
44import com.android.systemui.settings.CurrentUserTracker;
45import com.android.systemui.settings.BrightnessController.BrightnessStateChangeCallback;
46import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
47import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
48import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
49
50import java.util.List;
51
52
53class 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