ConnectedDeviceSignalController.java revision 2a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34
1package com.android.systemui.statusbar.car; 2 3import android.bluetooth.BluetoothAdapter; 4import android.bluetooth.BluetoothDevice; 5import android.bluetooth.BluetoothHeadsetClient; 6import android.bluetooth.BluetoothProfile; 7import android.bluetooth.BluetoothProfile.ServiceListener; 8import android.content.BroadcastReceiver; 9import android.content.Context; 10import android.content.Intent; 11import android.content.IntentFilter; 12import android.graphics.drawable.Drawable; 13import android.os.Bundle; 14import android.util.Log; 15import android.util.TypedValue; 16import android.view.View; 17import android.widget.ImageView; 18import com.android.systemui.Dependency; 19import com.android.systemui.R; 20import com.android.systemui.statusbar.ScalingDrawableWrapper; 21import com.android.systemui.statusbar.policy.BluetoothController; 22 23import static com.android.systemui.statusbar.phone.StatusBar.DEBUG; 24 25/** 26 * Controller that monitors signal strength for a device that is connected via bluetooth. 27 */ 28public class ConnectedDeviceSignalController extends BroadcastReceiver implements 29 BluetoothController.Callback { 30 private final static String TAG = "DeviceSignalCtlr"; 31 32 /** 33 * The value that indicates if a network is unavailable. This value is according ot the 34 * Bluetooth HFP 1.5 spec, which indicates this value is one of two: 0 or 1. These stand 35 * for network unavailable and available respectively. 36 */ 37 private static final int NETWORK_UNAVAILABLE = 0; 38 private static final int NETWORK_UNAVAILABLE_ICON_ID = R.drawable.stat_sys_signal_null; 39 40 /** 41 * All possible signal strength icons. According to the Bluetooth HFP 1.5 specification, 42 * signal strength is indicated by a value from 1-5, where these values represent the following: 43 * 44 * <p>0%% - 0, 1-25%% - 1, 26-50%% - 2, 51-75%% - 3, 76-99%% - 4, 100%% - 5 45 * 46 * <p>As a result, these are treated as an index into this array for the corresponding icon. 47 * Note that the icon is the same for 0 and 1. 48 */ 49 private static final int[] SIGNAL_STRENGTH_ICONS = { 50 R.drawable.stat_sys_signal_0_fully, 51 R.drawable.stat_sys_signal_0_fully, 52 R.drawable.stat_sys_signal_1_fully, 53 R.drawable.stat_sys_signal_2_fully, 54 R.drawable.stat_sys_signal_3_fully, 55 R.drawable.stat_sys_signal_4_fully, 56 }; 57 58 private static final int INVALID_SIGNAL = -1; 59 60 private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter(); 61 private final Context mContext; 62 private final BluetoothController mController; 63 64 private final View mSignalsView; 65 private final ImageView mNetworkSignalView; 66 67 private final float mIconScaleFactor; 68 69 private BluetoothHeadsetClient mBluetoothHeadsetClient; 70 71 public ConnectedDeviceSignalController(Context context, View signalsView) { 72 mContext = context; 73 mController = Dependency.get(BluetoothController.class); 74 75 mSignalsView = signalsView; 76 mNetworkSignalView = (ImageView) 77 mSignalsView.findViewById(R.id.connected_device_network_signal); 78 79 TypedValue typedValue = new TypedValue(); 80 context.getResources().getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true); 81 mIconScaleFactor = typedValue.getFloat(); 82 83 if (mAdapter == null) { 84 return; 85 } 86 87 mAdapter.getProfileProxy(context.getApplicationContext(), mHfpServiceListener, 88 BluetoothProfile.HEADSET_CLIENT); 89 } 90 91 public void startListening() { 92 IntentFilter filter = new IntentFilter(); 93 filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED); 94 filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT); 95 mContext.registerReceiver(this, filter); 96 97 mController.addCallback(this); 98 } 99 100 public void stopListening() { 101 mContext.unregisterReceiver(this); 102 mController.removeCallback(this); 103 } 104 105 @Override 106 public void onBluetoothDevicesChanged() { 107 // Nothing to do here because this Controller is not displaying a list of possible 108 // bluetooth devices. 109 } 110 111 @Override 112 public void onBluetoothStateChange(boolean enabled) { 113 if (DEBUG) { 114 Log.d(TAG, "onBluetoothStateChange(). enabled: " + enabled); 115 } 116 117 // Only need to handle the case if bluetooth has been disabled, in which case the 118 // signal indicators are hidden. If bluetooth has been enabled, then this class should 119 // receive updates to the connection state via onReceive(). 120 if (!enabled) { 121 mNetworkSignalView.setVisibility(View.GONE); 122 mSignalsView.setVisibility(View.GONE); 123 } 124 } 125 126 @Override 127 public void onReceive(Context context, Intent intent) { 128 String action = intent.getAction(); 129 130 if (DEBUG) { 131 Log.d(TAG, "onReceive(). action: " + action); 132 } 133 134 if (BluetoothHeadsetClient.ACTION_AG_EVENT.equals(action)) { 135 if (DEBUG) { 136 Log.d(TAG, "Received ACTION_AG_EVENT"); 137 } 138 139 processActionAgEvent(intent); 140 } else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { 141 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 142 143 if (DEBUG) { 144 int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); 145 Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED event: " 146 + oldState + " -> " + newState); 147 } 148 BluetoothDevice device = 149 (BluetoothDevice) intent.getExtra(BluetoothDevice.EXTRA_DEVICE); 150 updateViewVisibility(device, newState); 151 } 152 } 153 154 /** 155 * Processes an {@link Intent} that had an action of 156 * {@link BluetoothHeadsetClient#ACTION_AG_EVENT}. 157 */ 158 private void processActionAgEvent(Intent intent) { 159 int networkStatus = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_NETWORK_STATUS, 160 INVALID_SIGNAL); 161 if (networkStatus != INVALID_SIGNAL) { 162 if (DEBUG) { 163 Log.d(TAG, "EXTRA_NETWORK_STATUS: " + " " + networkStatus); 164 } 165 166 if (networkStatus == NETWORK_UNAVAILABLE) { 167 setNetworkSignalIcon(NETWORK_UNAVAILABLE_ICON_ID); 168 } 169 } 170 171 int signalStrength = intent.getIntExtra( 172 BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, INVALID_SIGNAL); 173 if (signalStrength != INVALID_SIGNAL) { 174 if (DEBUG) { 175 Log.d(TAG, "EXTRA_NETWORK_SIGNAL_STRENGTH: " + signalStrength); 176 } 177 178 setNetworkSignalIcon(SIGNAL_STRENGTH_ICONS[signalStrength]); 179 } 180 181 int roamingStatus = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_NETWORK_ROAMING, 182 INVALID_SIGNAL); 183 if (roamingStatus != INVALID_SIGNAL) { 184 if (DEBUG) { 185 Log.d(TAG, "EXTRA_NETWORK_ROAMING: " + roamingStatus); 186 } 187 } 188 } 189 190 private void setNetworkSignalIcon(int iconId) { 191 // Setting the icon on a child view of mSignalView, so toggle this container visible. 192 mSignalsView.setVisibility(View.VISIBLE); 193 194 // Using mNetworkSignalView's context to get the Drawable in order to preserve the theme. 195 Drawable icon = mNetworkSignalView.getContext().getDrawable(iconId); 196 197 mNetworkSignalView.setImageDrawable(new ScalingDrawableWrapper(icon, mIconScaleFactor)); 198 mNetworkSignalView.setVisibility(View.VISIBLE); 199 } 200 201 private void updateViewVisibility(BluetoothDevice device, int newState) { 202 if (newState == BluetoothProfile.STATE_CONNECTED) { 203 if (DEBUG) { 204 Log.d(TAG, "Device connected"); 205 } 206 207 if (mBluetoothHeadsetClient == null || device == null) { 208 return; 209 } 210 211 // Check if battery information is available and immediately update. 212 Bundle featuresBundle = mBluetoothHeadsetClient.getCurrentAgEvents(device); 213 if (featuresBundle == null) { 214 return; 215 } 216 217 int signalStrength = featuresBundle.getInt( 218 BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, INVALID_SIGNAL); 219 if (signalStrength != INVALID_SIGNAL) { 220 if (DEBUG) { 221 Log.d(TAG, "EXTRA_NETWORK_SIGNAL_STRENGTH: " + signalStrength); 222 } 223 224 setNetworkSignalIcon(SIGNAL_STRENGTH_ICONS[signalStrength]); 225 } 226 } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { 227 if (DEBUG) { 228 Log.d(TAG, "Device disconnected"); 229 } 230 231 mNetworkSignalView.setVisibility(View.GONE); 232 mSignalsView.setVisibility(View.GONE); 233 } 234 } 235 236 private final ServiceListener mHfpServiceListener = new ServiceListener() { 237 @Override 238 public void onServiceConnected(int profile, BluetoothProfile proxy) { 239 if (profile == BluetoothProfile.HEADSET_CLIENT) { 240 mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy; 241 } 242 } 243 244 @Override 245 public void onServiceDisconnected(int profile) { 246 if (profile == BluetoothProfile.HEADSET_CLIENT) { 247 mBluetoothHeadsetClient = null; 248 } 249 } 250 }; 251} 252