QuickSettingsModel.java revision 3ed6f9456a60cb3a2cf4166a7fa19e30b9bbd972
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.os.Handler;
32import android.provider.Settings;
33import android.provider.Settings.SettingNotFoundException;
34import android.text.TextUtils;
35import android.view.View;
36import android.view.inputmethod.InputMethodInfo;
37import android.view.inputmethod.InputMethodManager;
38import android.view.inputmethod.InputMethodSubtype;
39
40import com.android.internal.view.RotationPolicy;
41import com.android.systemui.R;
42import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
43import com.android.systemui.statusbar.policy.BrightnessController.BrightnessStateChangeCallback;
44import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
45import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
46
47import java.util.List;
48
49
50class QuickSettingsModel implements BluetoothStateChangeCallback,
51        NetworkSignalChangedCallback,
52        BatteryStateChangeCallback,
53        LocationGpsStateChangeCallback,
54        BrightnessStateChangeCallback {
55
56    /** Represents the state of a given attribute. */
57    static class State {
58        int iconId;
59        String label;
60        boolean enabled = false;
61    }
62    static class BatteryState extends State {
63        int batteryLevel;
64        boolean pluggedIn;
65    }
66    static class RSSIState extends State {
67        int signalIconId;
68        int dataTypeIconId;
69    }
70    static class UserState extends State {
71        Drawable avatar;
72    }
73    static class BrightnessState extends State {
74        boolean autoBrightness;
75    }
76
77    /** The callback to update a given tile. */
78    interface RefreshCallback {
79        public void refreshView(QuickSettingsTileView view, State state);
80    }
81
82    /** Broadcast receive to determine if there is an alarm set. */
83    private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() {
84        @Override
85        public void onReceive(Context context, Intent intent) {
86            String action = intent.getAction();
87            if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
88                onAlarmChanged(intent);
89                onNextAlarmChanged();
90            }
91        }
92    };
93
94    /** ContentObserver to determine the next alarm */
95    private class NextAlarmObserver extends ContentObserver {
96        public NextAlarmObserver(Handler handler) {
97            super(handler);
98        }
99
100        @Override public void onChange(boolean selfChange) {
101            onNextAlarmChanged();
102        }
103
104        public void startObserving() {
105            final ContentResolver cr = mContext.getContentResolver();
106            cr.registerContentObserver(
107                    Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this);
108        }
109    }
110
111    /** ContentObserver to watch adb */
112    private class BugreportObserver extends ContentObserver {
113        public BugreportObserver(Handler handler) {
114            super(handler);
115        }
116
117        @Override public void onChange(boolean selfChange) {
118            onBugreportChanged();
119        }
120
121        public void startObserving() {
122            final ContentResolver cr = mContext.getContentResolver();
123            cr.registerContentObserver(
124                    Settings.Secure.getUriFor(Settings.Secure.BUGREPORT_IN_POWER_MENU), false, this);
125        }
126    }
127    private Context mContext;
128    private Handler mHandler;
129    private NextAlarmObserver mNextAlarmObserver;
130    private BugreportObserver mBugreportObserver;
131
132    private QuickSettingsTileView mUserTile;
133    private RefreshCallback mUserCallback;
134    private UserState mUserState = new UserState();
135
136    private QuickSettingsTileView mTimeTile;
137    private RefreshCallback mTimeAlarmCallback;
138    private State mTimeAlarmState = new State();
139
140    private QuickSettingsTileView mAirplaneModeTile;
141    private RefreshCallback mAirplaneModeCallback;
142    private State mAirplaneModeState = new State();
143
144    private QuickSettingsTileView mWifiTile;
145    private RefreshCallback mWifiCallback;
146    private State mWifiState = new State();
147
148    private QuickSettingsTileView mWifiDisplayTile;
149    private RefreshCallback mWifiDisplayCallback;
150    private State mWifiDisplayState = new State();
151
152    private QuickSettingsTileView mRSSITile;
153    private RefreshCallback mRSSICallback;
154    private RSSIState mRSSIState = new RSSIState();
155
156    private QuickSettingsTileView mBluetoothTile;
157    private RefreshCallback mBluetoothCallback;
158    private State mBluetoothState = new State();
159
160    private QuickSettingsTileView mBatteryTile;
161    private RefreshCallback mBatteryCallback;
162    private BatteryState mBatteryState = new BatteryState();
163
164    private QuickSettingsTileView mLocationTile;
165    private RefreshCallback mLocationCallback;
166    private State mLocationState = new State();
167
168    private QuickSettingsTileView mImeTile;
169    private RefreshCallback mImeCallback;
170    private State mImeState = new State();
171
172    private QuickSettingsTileView mRotationLockTile;
173    private RefreshCallback mRotationLockCallback;
174    private State mRotationLockState = new State();
175
176    private QuickSettingsTileView mBrightnessTile;
177    private RefreshCallback mBrightnessCallback;
178    private BrightnessState mBrightnessState = new BrightnessState();
179
180    private QuickSettingsTileView mBugreportTile;
181    private RefreshCallback mBugreportCallback;
182    private State mBugreportState = new State();
183
184    public QuickSettingsModel(Context context) {
185        mContext = context;
186        mHandler = new Handler();
187        mNextAlarmObserver = new NextAlarmObserver(mHandler);
188        mNextAlarmObserver.startObserving();
189        mBugreportObserver = new BugreportObserver(mHandler);
190        mBugreportObserver.startObserving();
191
192        IntentFilter alarmIntentFilter = new IntentFilter();
193        alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
194        context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
195    }
196
197    // User
198    void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
199        mUserTile = view;
200        mUserCallback = cb;
201        mUserCallback.refreshView(mUserTile, mUserState);
202    }
203    void setUserTileInfo(String name, Drawable avatar) {
204        mUserState.label = name;
205        mUserState.avatar = avatar;
206        mUserCallback.refreshView(mUserTile, mUserState);
207    }
208
209    // Time
210    void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) {
211        mTimeTile = view;
212        mTimeAlarmCallback = cb;
213        mTimeAlarmCallback.refreshView(view, mTimeAlarmState);
214    }
215    void onAlarmChanged(Intent intent) {
216        mTimeAlarmState.enabled = intent.getBooleanExtra("alarmSet", false);
217        mTimeAlarmCallback.refreshView(mTimeTile, mTimeAlarmState);
218    }
219    void onNextAlarmChanged() {
220        mTimeAlarmState.label = Settings.System.getString(mContext.getContentResolver(),
221                Settings.System.NEXT_ALARM_FORMATTED);
222        mTimeAlarmCallback.refreshView(mTimeTile, mTimeAlarmState);
223    }
224
225    // Airplane Mode
226    void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
227        mAirplaneModeTile = view;
228        mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
229            @Override
230            public void onClick(View v) {
231                if (mAirplaneModeState.enabled) {
232                    setAirplaneModeState(false);
233                } else {
234                    setAirplaneModeState(true);
235                }
236            }
237        });
238        mAirplaneModeCallback = cb;
239        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
240    }
241    private void setAirplaneModeState(boolean enabled) {
242        // TODO: Sets the view to be "awaiting" if not already awaiting
243
244        // Change the system setting
245        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
246                                enabled ? 1 : 0);
247
248        // Post the intent
249        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
250        intent.putExtra("state", enabled);
251        mContext.sendBroadcast(intent);
252    }
253    // NetworkSignalChanged callback
254    @Override
255    public void onAirplaneModeChanged(boolean enabled) {
256        // TODO: If view is in awaiting state, disable
257        Resources r = mContext.getResources();
258        mAirplaneModeState.enabled = enabled;
259        mAirplaneModeState.iconId = (enabled ?
260                R.drawable.ic_qs_airplane_on :
261                R.drawable.ic_qs_airplane_off);
262        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
263    }
264
265    // Wifi
266    void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
267        mWifiTile = view;
268        mWifiCallback = cb;
269        mWifiCallback.refreshView(mWifiTile, mWifiState);
270    }
271    // NetworkSignalChanged callback
272    @Override
273    public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, String enabledDesc) {
274        // TODO: If view is in awaiting state, disable
275        Resources r = mContext.getResources();
276        mWifiState.iconId = enabled && (wifiSignalIconId > 0)
277                ? wifiSignalIconId
278                : R.drawable.ic_qs_wifi_no_network;
279        mWifiState.label = enabled
280                ? enabledDesc
281                : r.getString(R.string.quick_settings_wifi_no_network);
282        mWifiCallback.refreshView(mWifiTile, mWifiState);
283    }
284
285    // RSSI
286    void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
287        mRSSITile = view;
288        mRSSICallback = cb;
289        mRSSICallback.refreshView(mRSSITile, mRSSIState);
290    }
291    boolean deviceSupportsTelephony() {
292        PackageManager pm = mContext.getPackageManager();
293        return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
294    }
295    // NetworkSignalChanged callback
296    @Override
297    public void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
298            int dataTypeIconId, String enabledDesc) {
299        if (deviceSupportsTelephony()) {
300            // TODO: If view is in awaiting state, disable
301            Resources r = mContext.getResources();
302            mRSSIState.signalIconId = enabled && (mobileSignalIconId > 0)
303                    ? mobileSignalIconId
304                    : R.drawable.ic_qs_signal_no_signal;
305            mRSSIState.dataTypeIconId = enabled && (dataTypeIconId > 0)
306                    ? dataTypeIconId
307                    : 0;
308            mRSSIState.label = enabled
309                    ? enabledDesc
310                    : r.getString(R.string.quick_settings_rssi_emergency_only);
311            mRSSICallback.refreshView(mRSSITile, mRSSIState);
312        }
313    }
314
315    // Bluetooth
316    void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
317        mBluetoothTile = view;
318        mBluetoothCallback = cb;
319
320        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
321        onBluetoothStateChange(adapter.isEnabled());
322    }
323    boolean deviceSupportsBluetooth() {
324        return (BluetoothAdapter.getDefaultAdapter() != null);
325    }
326    // BluetoothController callback
327    @Override
328    public void onBluetoothStateChange(boolean on) {
329        // TODO: If view is in awaiting state, disable
330        Resources r = mContext.getResources();
331        mBluetoothState.enabled = on;
332        if (on) {
333            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on;
334        } else {
335            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off;
336        }
337        mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
338    }
339
340    // Battery
341    void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
342        mBatteryTile = view;
343        mBatteryCallback = cb;
344        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
345    }
346    // BatteryController callback
347    @Override
348    public void onBatteryLevelChanged(int level, boolean pluggedIn) {
349        mBatteryState.batteryLevel = level;
350        mBatteryState.pluggedIn = pluggedIn;
351        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
352    }
353
354    // Location
355    void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
356        mLocationTile = view;
357        mLocationCallback = cb;
358        mLocationCallback.refreshView(mLocationTile, mLocationState);
359    }
360    // LocationController callback
361    @Override
362    public void onLocationGpsStateChanged(boolean inUse, String description) {
363        mLocationState.enabled = inUse;
364        mLocationState.label = description;
365        mLocationCallback.refreshView(mLocationTile, mLocationState);
366    }
367
368    // Bug report
369    void addBugreportTile(QuickSettingsTileView view, RefreshCallback cb) {
370        mBugreportTile = view;
371        mBugreportCallback = cb;
372        onBugreportChanged();
373    }
374    // SettingsObserver callback
375    public void onBugreportChanged() {
376        final ContentResolver cr = mContext.getContentResolver();
377        boolean enabled = false;
378        try {
379            enabled = (Settings.Secure.getInt(cr, Settings.Secure.BUGREPORT_IN_POWER_MENU) != 0);
380        } catch (SettingNotFoundException e) {
381        }
382
383        mBugreportState.enabled = enabled;
384        mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
385    }
386
387    // Wifi Display
388    void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
389        mWifiDisplayTile = view;
390        mWifiDisplayCallback = cb;
391    }
392    public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
393        mWifiDisplayState.enabled =
394                (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON);
395        if (status.getActiveDisplay() != null) {
396            mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
397        } else {
398            mWifiDisplayState.label = mContext.getString(
399                    R.string.quick_settings_wifi_display_no_connection_label);
400        }
401        mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
402
403    }
404
405    // IME
406    void addImeTile(QuickSettingsTileView view, RefreshCallback cb) {
407        mImeTile = view;
408        mImeCallback = cb;
409        mImeCallback.refreshView(mImeTile, mImeState);
410    }
411    void onImeWindowStatusChanged(boolean visible) {
412        InputMethodManager imm =
413                (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
414        List<InputMethodInfo> imis = imm.getInputMethodList();
415
416        mImeState.enabled = visible;
417        mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(),
418                imm, imis, mContext.getPackageManager());
419        mImeCallback.refreshView(mImeTile, mImeState);
420    }
421    private static String getCurrentInputMethodName(Context context, ContentResolver resolver,
422            InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) {
423        if (resolver == null || imis == null) return null;
424        final String currentInputMethodId = Settings.Secure.getString(resolver,
425                Settings.Secure.DEFAULT_INPUT_METHOD);
426        if (TextUtils.isEmpty(currentInputMethodId)) return null;
427        for (InputMethodInfo imi : imis) {
428            if (currentInputMethodId.equals(imi.getId())) {
429                final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype();
430                final CharSequence summary = subtype != null
431                        ? subtype.getDisplayName(context, imi.getPackageName(),
432                                imi.getServiceInfo().applicationInfo)
433                        : context.getString(R.string.quick_settings_ime_label);
434                return summary.toString();
435            }
436        }
437        return null;
438    }
439
440    // Rotation lock
441    void addRotationLockTile(QuickSettingsTileView view, RefreshCallback cb) {
442        mRotationLockTile = view;
443        mRotationLockCallback = cb;
444        onRotationLockChanged();
445    }
446    void onRotationLockChanged() {
447        boolean locked = RotationPolicy.isRotationLocked(mContext);
448        mRotationLockState.enabled = locked;
449        mRotationLockState.iconId = locked
450                ? R.drawable.ic_qs_rotation_locked
451                : R.drawable.ic_qs_auto_rotate;
452        mRotationLockState.label = locked
453                ? mContext.getString(R.string.quick_settings_rotation_locked_label)
454                : mContext.getString(R.string.quick_settings_rotation_unlocked_label);
455
456        // may be called before addRotationLockTile due to RotationPolicyListener in QuickSettings
457        if (mRotationLockTile != null && mRotationLockCallback != null) {
458            mRotationLockCallback.refreshView(mRotationLockTile, mRotationLockState);
459        }
460    }
461
462    // Brightness
463    void addBrightnessTile(QuickSettingsTileView view, RefreshCallback cb) {
464        mBrightnessTile = view;
465        mBrightnessCallback = cb;
466        onBrightnessLevelChanged();
467    }
468    @Override
469    public void onBrightnessLevelChanged() {
470        int mode = Settings.System.getInt(mContext.getContentResolver(),
471                Settings.System.SCREEN_BRIGHTNESS_MODE,
472                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
473        mBrightnessState.autoBrightness =
474                (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
475        mBrightnessState.iconId = mBrightnessState.autoBrightness
476                ? R.drawable.ic_qs_brightness_auto_on
477                : R.drawable.ic_qs_brightness_auto_off;
478        mBrightnessCallback.refreshView(mBrightnessTile, mBrightnessState);
479    }
480
481}