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