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