1 /* 2 * Copyright (C) 2014 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.tv.settings.accessories; 18 19 import static android.provider.Settings.Secure.TTS_DEFAULT_RATE; 20 21 import com.android.tv.settings.ActionBehavior; 22 import com.android.tv.settings.ActionKey; 23 import com.android.tv.settings.BaseSettingsActivity; 24 import com.android.tv.settings.R; 25 import com.android.tv.settings.dialog.old.Action; 26 import com.android.tv.settings.dialog.old.ActionAdapter; 27 28 import android.bluetooth.BluetoothAdapter; 29 import android.bluetooth.BluetoothDevice; 30 import android.content.BroadcastReceiver; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.IntentFilter; 34 import android.os.Bundle; 35 import android.os.Handler; 36 import android.os.Message; 37 import android.util.Log; 38 import java.util.Set; 39 40 public class BluetoothAccessoryActivity extends BaseSettingsActivity 41 implements ActionAdapter.Listener { 42 43 public static final String EXTRA_ACCESSORY_ADDRESS = "accessory_address"; 44 public static final String EXTRA_ACCESSORY_NAME = "accessory_name"; 45 public static final String EXTRA_ACCESSORY_ICON_ID = "accessory_icon_res"; 46 47 private static final int MSG_UNPAIR_TIMEOUT = 1; 48 49 private static final int UNPAIR_TIMEOUT = 5000; 50 51 private static final String TAG = "aah.BluetoothAccessoryActivity"; 52 private static final boolean DEBUG = false; 53 54 private BluetoothDevice mDevice; 55 protected String mDeviceAddress; 56 protected String mDeviceName; 57 protected int mDeviceImgId; 58 protected boolean mDone; 59 60 public static Intent getIntent(Context context, String deviceAddress, 61 String deviceName, int iconId) { 62 Intent i = new Intent(context, BluetoothAccessoryActivity.class); 63 i.putExtra(EXTRA_ACCESSORY_ADDRESS, deviceAddress); 64 i.putExtra(EXTRA_ACCESSORY_NAME, deviceName); 65 i.putExtra(EXTRA_ACCESSORY_ICON_ID, iconId); 66 return i; 67 } 68 69 // Broadcast Receiver for Bluetooth related events 70 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 71 @Override 72 public void onReceive(Context context, Intent intent) { 73 BluetoothDevice device = intent 74 .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 75 if (mDone) { 76 if (mDevice.equals(device)) { 77 // Done removing device, finish the activity 78 mMsgHandler.removeMessages(MSG_UNPAIR_TIMEOUT); 79 finish(); 80 } 81 } 82 } 83 }; 84 85 // Internal message handler 86 private Handler mMsgHandler = new Handler() { 87 @Override 88 public void handleMessage(Message msg) { 89 switch (msg.what) { 90 case MSG_UNPAIR_TIMEOUT: 91 finish(); 92 break; 93 default: 94 } 95 } 96 }; 97 98 @Override 99 public void onCreate(Bundle savedInstanceState) { 100 Bundle bundle = getIntent().getExtras(); 101 if (bundle != null) { 102 mDeviceAddress = bundle.getString(EXTRA_ACCESSORY_ADDRESS); 103 mDeviceName = bundle.getString(EXTRA_ACCESSORY_NAME); 104 mDeviceImgId = bundle.getInt(EXTRA_ACCESSORY_ICON_ID); 105 } else { 106 mDeviceName = getString(R.string.accessory_options); 107 mDeviceImgId = R.drawable.ic_qs_bluetooth_not_connected; 108 } 109 110 super.onCreate(savedInstanceState); 111 112 mDone = false; 113 114 BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter(); 115 if (btAdapter != null) { 116 Set<BluetoothDevice> bondedDevices = btAdapter.getBondedDevices(); 117 for (BluetoothDevice device : bondedDevices) { 118 if (mDeviceAddress.equals(device.getAddress())) { 119 mDevice = device; 120 break; 121 } 122 } 123 } 124 } 125 126 @Override 127 public void onResume() { 128 // Set a broadcast receiver to let us know when the device has been removed 129 IntentFilter adapterIntentFilter = new IntentFilter(); 130 adapterIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 131 registerReceiver(mBroadcastReceiver, adapterIntentFilter); 132 super.onResume(); 133 } 134 135 @Override 136 public void onPause() { 137 unregisterReceiver(mBroadcastReceiver); 138 super.onPause(); 139 } 140 141 @Override 142 public void onActionClicked(Action action) { 143 if (mDone) { 144 return; 145 } 146 /* 147 * For regular states 148 */ 149 ActionKey<ActionType, ActionBehavior> actionKey = new ActionKey<ActionType, ActionBehavior>( 150 ActionType.class, ActionBehavior.class, action.getKey()); 151 final ActionType type = actionKey.getType(); 152 if (type != null) { 153 switch (type) { 154 case BLUETOOTH_DEVICE_RENAME: 155 // TODO: Will be implemented in a separate CL 156 return; 157 case OK: 158 unpairDevice(); 159 return; 160 case CANCEL: 161 goBack(); // Cancelled request to STOP service 162 return; 163 default: 164 } 165 } 166 setState(type, true); 167 } 168 169 @Override 170 protected Object getInitialState() { 171 return ActionType.BLUETOOTH_DEVICE_OVERVIEW; 172 } 173 174 @Override 175 protected void goBack() { 176 if (!mDone) { 177 super.goBack(); 178 } 179 } 180 181 @Override 182 protected void refreshActionList() { 183 mActions.clear(); 184 switch ((ActionType) mState) { 185 case BLUETOOTH_DEVICE_OVERVIEW: 186 // Disabled for now, until the name input screen is implemented 187 // mActions.add(ActionType.BLUETOOTH_DEVICE_RENAME.toAction(mResources)); 188 mActions.add(ActionType.BLUETOOTH_DEVICE_UNPAIR.toAction(mResources)); 189 break; 190 case BLUETOOTH_DEVICE_UNPAIR: 191 mActions.add(ActionType.OK.toAction(mResources)); 192 mActions.add(ActionType.CANCEL.toAction(mResources)); 193 break; 194 default: 195 break; 196 } 197 } 198 199 @Override 200 protected void updateView() { 201 refreshActionList(); 202 switch ((ActionType) mState) { 203 case BLUETOOTH_DEVICE_OVERVIEW: 204 setView(mDeviceName, getString(R.string.header_category_accessories), null, 205 mDeviceImgId); 206 break; 207 case BLUETOOTH_DEVICE_UNPAIR: 208 setView(getString(R.string.accessory_unpair), mDeviceName, null, mDeviceImgId); 209 break; 210 default: 211 break; 212 } 213 } 214 215 void unpairDevice() { 216 if (mDevice != null) { 217 int state = mDevice.getBondState(); 218 219 if (state == BluetoothDevice.BOND_BONDING) { 220 mDevice.cancelBondProcess(); 221 } 222 223 if (state != BluetoothDevice.BOND_NONE) { 224 mDone = true; 225 // Set a timeout, just in case we don't receive the unpair notification we 226 // use to finish the activity 227 mMsgHandler.sendEmptyMessageDelayed(MSG_UNPAIR_TIMEOUT, UNPAIR_TIMEOUT); 228 final boolean successful = mDevice.removeBond(); 229 if (successful) { 230 if (DEBUG) { 231 Log.d(TAG, "Bluetooth device successfully unpaired."); 232 } 233 // set the dialog to a waiting state 234 mActions.clear(); 235 setView(getString(R.string.accessory_unpair), mDeviceName, 236 getString(R.string.accessory_unpairing), mDeviceImgId); 237 } else { 238 Log.e(TAG, "Failed to unpair Bluetooth Device: " + mDevice.getName()); 239 } 240 } 241 } else { 242 Log.e(TAG, "Bluetooth device not found. Address = " + mDeviceAddress); 243 } 244 } 245 246 @Override 247 protected void setProperty(boolean enable) { 248 } 249 } 250