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 17 package com.android.systemui.statusbar.phone; 18 19 import android.app.AlarmManager; 20 import android.app.StatusBarManager; 21 import android.bluetooth.BluetoothAdapter; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.media.AudioManager; 27 import android.os.Handler; 28 import android.os.UserHandle; 29 import android.provider.Settings.Global; 30 import android.telecom.TelecomManager; 31 import android.util.Log; 32 33 import com.android.internal.telephony.IccCardConstants; 34 import com.android.internal.telephony.TelephonyIntents; 35 import com.android.systemui.R; 36 import com.android.systemui.statusbar.policy.CastController; 37 import com.android.systemui.statusbar.policy.CastController.CastDevice; 38 import 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 */ 45 public 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 action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) { 95 updateVolumeZen(); 96 } 97 else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { 98 updateSimState(intent); 99 } 100 else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) { 101 updateTTY(intent); 102 } 103 else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 104 updateAlarm(); 105 } 106 } 107 }; 108 109 public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot) { 110 mContext = context; 111 mCast = cast; 112 mHotspot = hotspot; 113 mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); 114 115 // listen for broadcasts 116 IntentFilter filter = new IntentFilter(); 117 filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); 118 filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED); 119 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 120 filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION); 121 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 122 filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 123 filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 124 filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); 125 filter.addAction(Intent.ACTION_USER_SWITCHED); 126 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); 127 128 // TTY status 129 mService.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, 0, null); 130 mService.setIconVisibility(SLOT_TTY, false); 131 132 // Cdma Roaming Indicator, ERI 133 mService.setIcon(SLOT_CDMA_ERI, R.drawable.stat_sys_roaming_cdma_0, 0, null); 134 mService.setIconVisibility(SLOT_CDMA_ERI, false); 135 136 // bluetooth status 137 updateBluetooth(); 138 139 // Alarm clock 140 mService.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, 0, null); 141 mService.setIconVisibility(SLOT_ALARM_CLOCK, false); 142 143 // Sync state 144 mService.setIcon(SLOT_SYNC_ACTIVE, R.drawable.stat_sys_sync, 0, null); 145 mService.setIconVisibility(SLOT_SYNC_ACTIVE, false); 146 // "sync_failing" is obsolete: b/1297963 147 148 // zen 149 mService.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, 0, null); 150 mService.setIconVisibility(SLOT_ZEN, false); 151 152 // volume 153 mService.setIcon(SLOT_VOLUME, R.drawable.stat_sys_ringer_vibrate, 0, null); 154 mService.setIconVisibility(SLOT_VOLUME, false); 155 updateVolumeZen(); 156 157 // cast 158 mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, null); 159 mService.setIconVisibility(SLOT_CAST, false); 160 mCast.addCallback(mCastCallback); 161 162 // hotspot 163 mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, null); 164 mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled()); 165 mHotspot.addCallback(mHotspotCallback); 166 } 167 168 public void setZenMode(int zen) { 169 mZen = zen; 170 updateVolumeZen(); 171 } 172 173 private void updateAlarm() { 174 AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 175 boolean alarmSet = alarmManager.getNextAlarmClock(UserHandle.USER_CURRENT) != null; 176 mService.setIconVisibility(SLOT_ALARM_CLOCK, alarmSet); 177 } 178 179 private final void updateSyncState(Intent intent) { 180 if (!SHOW_SYNC_ICON) return; 181 boolean isActive = intent.getBooleanExtra("active", false); 182 mService.setIconVisibility(SLOT_SYNC_ACTIVE, isActive); 183 } 184 185 private final void updateSimState(Intent intent) { 186 String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 187 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { 188 mSimState = IccCardConstants.State.ABSENT; 189 } 190 else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) { 191 mSimState = IccCardConstants.State.CARD_IO_ERROR; 192 } 193 else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { 194 mSimState = IccCardConstants.State.READY; 195 } 196 else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { 197 final String lockedReason = 198 intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); 199 if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { 200 mSimState = IccCardConstants.State.PIN_REQUIRED; 201 } 202 else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { 203 mSimState = IccCardConstants.State.PUK_REQUIRED; 204 } 205 else { 206 mSimState = IccCardConstants.State.NETWORK_LOCKED; 207 } 208 } else { 209 mSimState = IccCardConstants.State.UNKNOWN; 210 } 211 } 212 213 private final void updateVolumeZen() { 214 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 215 216 boolean zenVisible = false; 217 int zenIconId = 0; 218 String zenDescription = null; 219 220 boolean volumeVisible = false; 221 int volumeIconId = 0; 222 String volumeDescription = null; 223 224 if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) { 225 zenVisible = true; 226 zenIconId = R.drawable.stat_sys_zen_none; 227 zenDescription = mContext.getString(R.string.zen_no_interruptions); 228 } else if (mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) { 229 zenVisible = true; 230 zenIconId = R.drawable.stat_sys_zen_important; 231 zenDescription = mContext.getString(R.string.zen_important_interruptions); 232 } 233 234 if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS && 235 audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) { 236 volumeVisible = true; 237 volumeIconId = R.drawable.stat_sys_ringer_vibrate; 238 volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate); 239 } 240 241 if (zenVisible) { 242 mService.setIcon(SLOT_ZEN, zenIconId, 0, zenDescription); 243 } 244 if (zenVisible != mZenVisible) { 245 mService.setIconVisibility(SLOT_ZEN, zenVisible); 246 mZenVisible = zenVisible; 247 } 248 249 if (volumeVisible) { 250 mService.setIcon(SLOT_VOLUME, volumeIconId, 0, volumeDescription); 251 } 252 if (volumeVisible != mVolumeVisible) { 253 mService.setIconVisibility(SLOT_VOLUME, volumeVisible); 254 mVolumeVisible = volumeVisible; 255 } 256 } 257 258 private final void updateBluetooth() { 259 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 260 int iconId = R.drawable.stat_sys_data_bluetooth; 261 String contentDescription = 262 mContext.getString(R.string.accessibility_bluetooth_disconnected); 263 if (adapter != null) { 264 mBluetoothEnabled = (adapter.getState() == BluetoothAdapter.STATE_ON); 265 if (adapter.getConnectionState() == BluetoothAdapter.STATE_CONNECTED) { 266 iconId = R.drawable.stat_sys_data_bluetooth_connected; 267 contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected); 268 } 269 } else { 270 mBluetoothEnabled = false; 271 } 272 273 mService.setIcon(SLOT_BLUETOOTH, iconId, 0, contentDescription); 274 mService.setIconVisibility(SLOT_BLUETOOTH, mBluetoothEnabled); 275 } 276 277 private final void updateTTY(Intent intent) { 278 int currentTtyMode = intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE, 279 TelecomManager.TTY_MODE_OFF); 280 boolean enabled = currentTtyMode != TelecomManager.TTY_MODE_OFF; 281 282 if (DEBUG) Log.v(TAG, "updateTTY: enabled: " + enabled); 283 284 if (enabled) { 285 // TTY is on 286 if (DEBUG) Log.v(TAG, "updateTTY: set TTY on"); 287 mService.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, 0, 288 mContext.getString(R.string.accessibility_tty_enabled)); 289 mService.setIconVisibility(SLOT_TTY, true); 290 } else { 291 // TTY is off 292 if (DEBUG) Log.v(TAG, "updateTTY: set TTY off"); 293 mService.setIconVisibility(SLOT_TTY, false); 294 } 295 } 296 297 private void updateCast() { 298 boolean isCasting = false; 299 for (CastDevice device : mCast.getCastDevices()) { 300 if (device.state == CastDevice.STATE_CONNECTING 301 || device.state == CastDevice.STATE_CONNECTED) { 302 isCasting = true; 303 break; 304 } 305 } 306 if (DEBUG) Log.v(TAG, "updateCast: isCasting: " + isCasting); 307 if (isCasting) { 308 mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, 309 mContext.getString(R.string.accessibility_casting)); 310 } 311 mService.setIconVisibility(SLOT_CAST, isCasting); 312 } 313 314 private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() { 315 @Override 316 public void onHotspotChanged(boolean enabled) { 317 mService.setIconVisibility(SLOT_HOTSPOT, enabled); 318 } 319 }; 320 321 private final CastController.Callback mCastCallback = new CastController.Callback() { 322 @Override 323 public void onCastDevicesChanged() { 324 updateCast(); 325 } 326 }; 327 } 328