QuickSettingsModel.java revision ed1395f3981193c762e436cd1db725ce70022e43
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.text.TextUtils;
34import android.view.View;
35import android.view.inputmethod.InputMethodInfo;
36import android.view.inputmethod.InputMethodManager;
37import android.view.inputmethod.InputMethodSubtype;
38
39import com.android.systemui.R;
40import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
41import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
42import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
43
44import java.util.List;
45
46
47class QuickSettingsModel implements BluetoothStateChangeCallback,
48        NetworkSignalChangedCallback,
49        BatteryStateChangeCallback,
50        LocationGpsStateChangeCallback {
51
52    /** Represents the state of a given attribute. */
53    static class State {
54        int iconId;
55        String label;
56        boolean enabled = false;
57    }
58    static class BatteryState extends State {
59        int batteryLevel;
60        boolean pluggedIn;
61    }
62    static class UserState extends State {
63        Drawable avatar;
64    }
65
66    /** The callback to update a given tile. */
67    interface RefreshCallback {
68        public void refreshView(QuickSettingsTileView view, State state);
69    }
70
71    /** Broadcast receive to determine if there is an alarm set. */
72    private BroadcastReceiver mAlarmIntentReceiver = new BroadcastReceiver() {
73        @Override
74        public void onReceive(Context context, Intent intent) {
75            String action = intent.getAction();
76            if (action.equals(Intent.ACTION_ALARM_CHANGED)) {
77                onAlarmChanged(intent);
78                onNextAlarmChanged();
79            }
80        }
81    };
82
83    /** ContentObserver to determine the next alarm */
84    private class NextAlarmObserver extends ContentObserver {
85        public NextAlarmObserver(Handler handler) {
86            super(handler);
87        }
88
89        @Override public void onChange(boolean selfChange) {
90            onNextAlarmChanged();
91        }
92
93        public void startObserving() {
94            final ContentResolver cr = mContext.getContentResolver();
95            cr.registerContentObserver(
96                    Settings.System.getUriFor(Settings.System.NEXT_ALARM_FORMATTED), false, this);
97        }
98    }
99
100    private Context mContext;
101    private Handler mHandler;
102    private NextAlarmObserver mNextAlarmObserver;
103
104    private QuickSettingsTileView mUserTile;
105    private RefreshCallback mUserCallback;
106    private UserState mUserState = new UserState();
107
108    private QuickSettingsTileView mTimeTile;
109    private RefreshCallback mTimeAlarmCallback;
110    private State mTimeAlarmState = new State();
111
112    private QuickSettingsTileView mAirplaneModeTile;
113    private RefreshCallback mAirplaneModeCallback;
114    private State mAirplaneModeState = new State();
115
116    private QuickSettingsTileView mWifiTile;
117    private RefreshCallback mWifiCallback;
118    private State mWifiState = new State();
119
120    private QuickSettingsTileView mWifiDisplayTile;
121    private RefreshCallback mWifiDisplayCallback;
122    private State mWifiDisplayState = new State();
123
124    private QuickSettingsTileView mRSSITile;
125    private RefreshCallback mRSSICallback;
126    private State mRSSIState = new State();
127
128    private QuickSettingsTileView mBluetoothTile;
129    private RefreshCallback mBluetoothCallback;
130    private State mBluetoothState = new State();
131
132    private QuickSettingsTileView mBatteryTile;
133    private RefreshCallback mBatteryCallback;
134    private BatteryState mBatteryState = new BatteryState();
135
136    private QuickSettingsTileView mLocationTile;
137    private RefreshCallback mLocationCallback;
138    private State mLocationState = new State();
139
140    private QuickSettingsTileView mImeTile;
141    private RefreshCallback mImeCallback;
142    private State mImeState = new State();
143
144    public QuickSettingsModel(Context context) {
145        mContext = context;
146        mHandler = new Handler();
147        mNextAlarmObserver = new NextAlarmObserver(mHandler);
148        mNextAlarmObserver.startObserving();
149
150        IntentFilter alarmIntentFilter = new IntentFilter();
151        alarmIntentFilter.addAction(Intent.ACTION_ALARM_CHANGED);
152        context.registerReceiver(mAlarmIntentReceiver, alarmIntentFilter);
153    }
154
155    // User
156    void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
157        mUserTile = view;
158        mUserCallback = cb;
159        mUserCallback.refreshView(mUserTile, mUserState);
160    }
161    void setUserTileInfo(String name, Drawable avatar) {
162        mUserState.label = name;
163        mUserState.avatar = avatar;
164        mUserCallback.refreshView(mUserTile, mUserState);
165    }
166
167    // Time
168    void addTimeTile(QuickSettingsTileView view, RefreshCallback cb) {
169        mTimeTile = view;
170        mTimeAlarmCallback = cb;
171        mTimeAlarmCallback.refreshView(view, mTimeAlarmState);
172    }
173    void onAlarmChanged(Intent intent) {
174        mTimeAlarmState.enabled = intent.getBooleanExtra("alarmSet", false);
175        mTimeAlarmCallback.refreshView(mTimeTile, mTimeAlarmState);
176    }
177    void onNextAlarmChanged() {
178        mTimeAlarmState.label = Settings.System.getString(mContext.getContentResolver(),
179                Settings.System.NEXT_ALARM_FORMATTED);
180        mTimeAlarmCallback.refreshView(mTimeTile, mTimeAlarmState);
181    }
182
183    // Airplane Mode
184    void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
185        mAirplaneModeTile = view;
186        mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
187            @Override
188            public void onClick(View v) {
189                if (mAirplaneModeState.enabled) {
190                    setAirplaneModeState(false);
191                } else {
192                    setAirplaneModeState(true);
193                }
194            }
195        });
196        mAirplaneModeCallback = cb;
197        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
198    }
199    private void setAirplaneModeState(boolean enabled) {
200        // TODO: Sets the view to be "awaiting" if not already awaiting
201
202        // Change the system setting
203        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
204                                enabled ? 1 : 0);
205
206        // Post the intent
207        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
208        intent.putExtra("state", enabled);
209        mContext.sendBroadcast(intent);
210    }
211    // NetworkSignalChanged callback
212    @Override
213    public void onAirplaneModeChanged(boolean enabled) {
214        // TODO: If view is in awaiting state, disable
215        Resources r = mContext.getResources();
216        mAirplaneModeState.enabled = enabled;
217        mAirplaneModeState.iconId = (enabled ?
218                R.drawable.ic_qs_airplane_on :
219                R.drawable.ic_qs_airplane_off);
220        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
221    }
222
223    // Wifi
224    void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
225        mWifiTile = view;
226        mWifiCallback = cb;
227        mWifiCallback.refreshView(mWifiTile, mWifiState);
228    }
229    // NetworkSignalChanged callback
230    @Override
231    public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId, String enabledDesc) {
232        // TODO: If view is in awaiting state, disable
233        Resources r = mContext.getResources();
234        mWifiState.iconId = enabled && (wifiSignalIconId > 0)
235                ? wifiSignalIconId
236                : R.drawable.ic_qs_wifi_no_network;
237        mWifiState.label = enabled
238                ? enabledDesc
239                : r.getString(R.string.quick_settings_wifi_no_network);
240        mWifiCallback.refreshView(mWifiTile, mWifiState);
241    }
242
243    // RSSI
244    void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
245        mRSSITile = view;
246        mRSSICallback = cb;
247        mRSSICallback.refreshView(mRSSITile, mRSSIState);
248    }
249    boolean deviceSupportsTelephony() {
250        PackageManager pm = mContext.getPackageManager();
251        return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
252    }
253    // NetworkSignalChanged callback
254    @Override
255    public void onMobileDataSignalChanged(boolean enabled, int mobileSignalIconId,
256            String enabledDesc) {
257        if (deviceSupportsTelephony()) {
258            // TODO: If view is in awaiting state, disable
259            Resources r = mContext.getResources();
260            mRSSIState.iconId = enabled && (mobileSignalIconId > 0)
261                    ? mobileSignalIconId
262                    : R.drawable.ic_qs_signal_no_signal;
263            mRSSIState.label = enabled
264                    ? enabledDesc
265                    : r.getString(R.string.quick_settings_rssi_emergency_only);
266            mRSSICallback.refreshView(mRSSITile, mRSSIState);
267        }
268    }
269
270    // Bluetooth
271    void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
272        mBluetoothTile = view;
273        mBluetoothCallback = cb;
274
275        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
276        onBluetoothStateChange(adapter.isEnabled());
277    }
278    boolean deviceSupportsBluetooth() {
279        return (BluetoothAdapter.getDefaultAdapter() != null);
280    }
281    // BluetoothController callback
282    @Override
283    public void onBluetoothStateChange(boolean on) {
284        // TODO: If view is in awaiting state, disable
285        Resources r = mContext.getResources();
286        mBluetoothState.enabled = on;
287        if (on) {
288            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_on;
289        } else {
290            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_off;
291        }
292        mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
293    }
294
295    // Battery
296    void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
297        mBatteryTile = view;
298        mBatteryCallback = cb;
299        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
300    }
301    // BatteryController callback
302    @Override
303    public void onBatteryLevelChanged(int level, boolean pluggedIn) {
304        mBatteryState.batteryLevel = level;
305        mBatteryState.pluggedIn = pluggedIn;
306        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
307    }
308
309    // Location
310    void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
311        mLocationTile = view;
312        mLocationCallback = cb;
313        mLocationCallback.refreshView(mLocationTile, mLocationState);
314    }
315    // LocationController callback
316    @Override
317    public void onLocationGpsStateChanged(boolean inUse, String description) {
318        mLocationState.enabled = inUse;
319        mLocationState.label = description;
320        mLocationCallback.refreshView(mLocationTile, mLocationState);
321    }
322
323    // Wifi Display
324    void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
325        mWifiDisplayTile = view;
326        mWifiDisplayCallback = cb;
327    }
328    public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
329        mWifiDisplayState.enabled = status.isEnabled();
330        if (status.getActiveDisplay() != null) {
331            mWifiDisplayState.label = status.getActiveDisplay().getDeviceName();
332        } else {
333            mWifiDisplayState.label = mContext.getString(
334                    R.string.quick_settings_wifi_display_no_connection_label);
335        }
336        mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
337
338    }
339
340    // IME
341    void addImeTile(QuickSettingsTileView view, RefreshCallback cb) {
342        mImeTile = view;
343        mImeCallback = cb;
344        mImeCallback.refreshView(mImeTile, mImeState);
345    }
346    void onImeWindowStatusChanged(boolean visible) {
347        InputMethodManager imm =
348                (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
349        List<InputMethodInfo> imis = imm.getInputMethodList();
350
351        mImeState.enabled = visible;
352        mImeState.label = getCurrentInputMethodName(mContext, mContext.getContentResolver(),
353                imm, imis, mContext.getPackageManager());
354        mImeCallback.refreshView(mImeTile, mImeState);
355    }
356    private static String getCurrentInputMethodName(Context context, ContentResolver resolver,
357            InputMethodManager imm, List<InputMethodInfo> imis, PackageManager pm) {
358        if (resolver == null || imis == null) return null;
359        final String currentInputMethodId = Settings.Secure.getString(resolver,
360                Settings.Secure.DEFAULT_INPUT_METHOD);
361        if (TextUtils.isEmpty(currentInputMethodId)) return null;
362        for (InputMethodInfo imi : imis) {
363            if (currentInputMethodId.equals(imi.getId())) {
364                final InputMethodSubtype subtype = imm.getCurrentInputMethodSubtype();
365                final CharSequence summary = subtype != null
366                        ? subtype.getDisplayName(context, imi.getPackageName(),
367                                imi.getServiceInfo().applicationInfo)
368                        : context.getString(R.string.quick_settings_ime_label);
369                return summary.toString();
370            }
371        }
372        return null;
373    }
374
375}