PhoneStatusBarPolicy.java revision 661f2cf45860d2e10924e6b69966a9afe255f28b
1/*
2 * Copyright (C) 2008 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.app.AlarmManager;
20import android.app.StatusBarManager;
21import android.bluetooth.BluetoothAdapter;
22import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.media.AudioManager;
27import android.os.Handler;
28import android.os.UserHandle;
29import android.provider.Settings.Global;
30import android.telecom.TelecomManager;
31import android.util.Log;
32
33import com.android.internal.telephony.IccCardConstants;
34import com.android.internal.telephony.TelephonyIntents;
35import com.android.systemui.R;
36import com.android.systemui.statusbar.policy.CastController;
37import com.android.systemui.statusbar.policy.CastController.CastDevice;
38import com.android.systemui.statusbar.policy.HotspotController;
39
40/**
41 * This class contains all of the policy about which icons are installed in the status
42 * bar at boot time.  It goes through the normal API for icons, even though it probably
43 * strictly doesn't need to.
44 */
45public class PhoneStatusBarPolicy {
46    private static final String TAG = "PhoneStatusBarPolicy";
47    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
48
49    private static final boolean SHOW_SYNC_ICON = false;
50
51    private static final String SLOT_SYNC_ACTIVE = "sync_active";
52    private static final String SLOT_CAST = "cast";
53    private static final String SLOT_HOTSPOT = "hotspot";
54    private static final String SLOT_BLUETOOTH = "bluetooth";
55    private static final String SLOT_TTY = "tty";
56    private static final String SLOT_ZEN = "zen";
57    private static final String SLOT_VOLUME = "volume";
58    private static final String SLOT_CDMA_ERI = "cdma_eri";
59    private static final String SLOT_ALARM_CLOCK = "alarm_clock";
60
61    private final Context mContext;
62    private final StatusBarManager mService;
63    private final Handler mHandler = new Handler();
64    private final CastController mCast;
65    private final HotspotController mHotspot;
66
67    // Assume it's all good unless we hear otherwise.  We don't always seem
68    // to get broadcasts that it *is* there.
69    IccCardConstants.State mSimState = IccCardConstants.State.READY;
70
71    private boolean mZenVisible;
72    private boolean mVolumeVisible;
73
74    private int mZen;
75
76    private boolean mBluetoothEnabled = false;
77
78
79    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
80        @Override
81        public void onReceive(Context context, Intent intent) {
82            String action = intent.getAction();
83            if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
84                updateAlarm();
85            }
86            else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
87                updateSyncState(intent);
88            }
89            else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
90                    action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
91                updateBluetooth();
92            }
93            else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
94                updateVolumeZen();
95            }
96            else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
97                updateSimState(intent);
98            }
99            else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
100                updateTTY(intent);
101            }
102            else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
103                updateAlarm();
104            }
105        }
106    };
107
108    public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot) {
109        mContext = context;
110        mCast = cast;
111        mHotspot = hotspot;
112        mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
113
114        // listen for broadcasts
115        IntentFilter filter = new IntentFilter();
116        filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
117        filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
118        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
119        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
120        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
121        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
122        filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
123        filter.addAction(Intent.ACTION_USER_SWITCHED);
124        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
125
126        // TTY status
127        mService.setIcon(SLOT_TTY,  R.drawable.stat_sys_tty_mode, 0, null);
128        mService.setIconVisibility(SLOT_TTY, false);
129
130        // Cdma Roaming Indicator, ERI
131        mService.setIcon(SLOT_CDMA_ERI, R.drawable.stat_sys_roaming_cdma_0, 0, null);
132        mService.setIconVisibility(SLOT_CDMA_ERI, false);
133
134        // bluetooth status
135        updateBluetooth();
136
137        // Alarm clock
138        mService.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, 0, null);
139        mService.setIconVisibility(SLOT_ALARM_CLOCK, false);
140
141        // Sync state
142        mService.setIcon(SLOT_SYNC_ACTIVE, R.drawable.stat_sys_sync, 0, null);
143        mService.setIconVisibility(SLOT_SYNC_ACTIVE, false);
144        // "sync_failing" is obsolete: b/1297963
145
146        // zen
147        mService.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, 0, null);
148        mService.setIconVisibility(SLOT_ZEN, false);
149
150        // volume
151        mService.setIcon(SLOT_VOLUME, R.drawable.stat_sys_ringer_vibrate, 0, null);
152        mService.setIconVisibility(SLOT_VOLUME, false);
153        updateVolumeZen();
154
155        // cast
156        mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, null);
157        mService.setIconVisibility(SLOT_CAST, false);
158        mCast.addCallback(mCastCallback);
159
160        // hotspot
161        mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, null);
162        mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled());
163        mHotspot.addCallback(mHotspotCallback);
164    }
165
166    public void setZenMode(int zen) {
167        mZen = zen;
168        updateVolumeZen();
169    }
170
171    private void updateAlarm() {
172        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
173	boolean alarmSet = alarmManager.getNextAlarmClock(UserHandle.USER_CURRENT) != null;
174        mService.setIconVisibility(SLOT_ALARM_CLOCK, alarmSet);
175    }
176
177    private final void updateSyncState(Intent intent) {
178        if (!SHOW_SYNC_ICON) return;
179        boolean isActive = intent.getBooleanExtra("active", false);
180        mService.setIconVisibility(SLOT_SYNC_ACTIVE, isActive);
181    }
182
183    private final void updateSimState(Intent intent) {
184        String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
185        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
186            mSimState = IccCardConstants.State.ABSENT;
187        }
188        else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
189            mSimState = IccCardConstants.State.CARD_IO_ERROR;
190        }
191        else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
192            mSimState = IccCardConstants.State.READY;
193        }
194        else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
195            final String lockedReason =
196                    intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
197            if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
198                mSimState = IccCardConstants.State.PIN_REQUIRED;
199            }
200            else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
201                mSimState = IccCardConstants.State.PUK_REQUIRED;
202            }
203            else {
204                mSimState = IccCardConstants.State.NETWORK_LOCKED;
205            }
206        } else {
207            mSimState = IccCardConstants.State.UNKNOWN;
208        }
209    }
210
211    public final void updateVolumeZen() {
212        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
213
214        boolean zenVisible = false;
215        int zenIconId = 0;
216        String zenDescription = null;
217
218        boolean volumeVisible = false;
219        int volumeIconId = 0;
220        String volumeDescription = null;
221
222        if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
223            zenVisible = true;
224            zenIconId = R.drawable.stat_sys_zen_none;
225            zenDescription = mContext.getString(R.string.zen_no_interruptions);
226        } else if (mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
227            zenVisible = true;
228            zenIconId = R.drawable.stat_sys_zen_important;
229            zenDescription = mContext.getString(R.string.zen_important_interruptions);
230        }
231
232        if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS &&
233                audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
234            volumeVisible = true;
235            volumeIconId = R.drawable.stat_sys_ringer_vibrate;
236            volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
237        }
238
239        if (zenVisible) {
240            mService.setIcon(SLOT_ZEN, zenIconId, 0, zenDescription);
241        }
242        if (zenVisible != mZenVisible) {
243            mService.setIconVisibility(SLOT_ZEN, zenVisible);
244            mZenVisible = zenVisible;
245        }
246
247        if (volumeVisible) {
248            mService.setIcon(SLOT_VOLUME, volumeIconId, 0, volumeDescription);
249        }
250        if (volumeVisible != mVolumeVisible) {
251            mService.setIconVisibility(SLOT_VOLUME, volumeVisible);
252            mVolumeVisible = volumeVisible;
253        }
254    }
255
256    private final void updateBluetooth() {
257        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
258        int iconId = R.drawable.stat_sys_data_bluetooth;
259        String contentDescription =
260                mContext.getString(R.string.accessibility_bluetooth_disconnected);
261        if (adapter != null) {
262            mBluetoothEnabled = (adapter.getState() == BluetoothAdapter.STATE_ON);
263            if (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED) {
264                iconId = R.drawable.stat_sys_data_bluetooth_connected;
265                contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected);
266            }
267        } else {
268            mBluetoothEnabled = false;
269        }
270
271        mService.setIcon(SLOT_BLUETOOTH, iconId, 0, contentDescription);
272        mService.setIconVisibility(SLOT_BLUETOOTH, mBluetoothEnabled);
273    }
274
275    private final void updateTTY(Intent intent) {
276        int currentTtyMode = intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,
277                TelecomManager.TTY_MODE_OFF);
278        boolean enabled = currentTtyMode != TelecomManager.TTY_MODE_OFF;
279
280        if (DEBUG) Log.v(TAG, "updateTTY: enabled: " + enabled);
281
282        if (enabled) {
283            // TTY is on
284            if (DEBUG) Log.v(TAG, "updateTTY: set TTY on");
285            mService.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, 0,
286                    mContext.getString(R.string.accessibility_tty_enabled));
287            mService.setIconVisibility(SLOT_TTY, true);
288        } else {
289            // TTY is off
290            if (DEBUG) Log.v(TAG, "updateTTY: set TTY off");
291            mService.setIconVisibility(SLOT_TTY, false);
292        }
293    }
294
295    private void updateCast() {
296        boolean isCasting = false;
297        for (CastDevice device : mCast.getCastDevices()) {
298            if (device.state == CastDevice.STATE_CONNECTING
299                    || device.state == CastDevice.STATE_CONNECTED) {
300                isCasting = true;
301                break;
302            }
303        }
304        if (DEBUG) Log.v(TAG, "updateCast: isCasting: " + isCasting);
305        if (isCasting) {
306            mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0,
307                    mContext.getString(R.string.accessibility_casting));
308        }
309        mService.setIconVisibility(SLOT_CAST, isCasting);
310    }
311
312    private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() {
313        @Override
314        public void onHotspotChanged(boolean enabled) {
315            mService.setIconVisibility(SLOT_HOTSPOT, enabled);
316        }
317    };
318
319    private final CastController.Callback mCastCallback = new CastController.Callback() {
320        @Override
321        public void onCastDevicesChanged() {
322            updateCast();
323        }
324    };
325}
326