13cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler/* 23cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * Copyright (C) 2015 The Android Open Source Project 33cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * 43cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * Licensed under the Apache License, Version 2.0 (the "License"); 53cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * you may not use this file except in compliance with the License. 63cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * You may obtain a copy of the License at 73cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * 83cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * http://www.apache.org/licenses/LICENSE-2.0 93cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * 103cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * Unless required by applicable law or agreed to in writing, software 113cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * distributed under the License is distributed on an "AS IS" BASIS, 123cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * See the License for the specific language governing permissions and 143cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler * limitations under the License 153cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler */ 163cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 173cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerpackage com.android.tv.settings.accessories; 183cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 193cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.bluetooth.BluetoothAdapter; 203cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.bluetooth.BluetoothDevice; 213cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.bluetooth.BluetoothGatt; 223cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.bluetooth.BluetoothGattCallback; 233cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.bluetooth.BluetoothGattCharacteristic; 243cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.bluetooth.BluetoothGattService; 253cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.content.BroadcastReceiver; 263cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.content.Context; 273cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.content.Intent; 283cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.content.IntentFilter; 293cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.os.Bundle; 303cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.os.Handler; 313cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.support.annotation.DrawableRes; 323cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.support.annotation.NonNull; 333cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.support.v17.leanback.app.GuidedStepFragment; 343cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.support.v17.leanback.widget.GuidanceStylist; 353cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.support.v17.leanback.widget.GuidedAction; 363cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.support.v17.preference.LeanbackPreferenceFragment; 373cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.support.v7.preference.Preference; 383cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.support.v7.preference.PreferenceScreen; 393cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport android.util.Log; 403cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 413cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport com.android.tv.settings.R; 423cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 433cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport java.util.List; 443cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport java.util.Set; 453cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerimport java.util.UUID; 463cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 473cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantlerpublic class BluetoothAccessoryFragment extends LeanbackPreferenceFragment { 483cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 493cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final boolean DEBUG = false; 503cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final String TAG = "BluetoothAccessoryFrag"; 513cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 523cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final UUID GATT_BATTERY_SERVICE_UUID = 533cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb"); 543cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final UUID GATT_BATTERY_LEVEL_CHARACTERISTIC_UUID = 553cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb"); 563cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 573cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final String SAVE_STATE_UNPAIRING = "BluetoothAccessoryActivity.unpairing"; 583cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 593cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final int UNPAIR_TIMEOUT = 5000; 603cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 613cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final String ARG_ACCESSORY_ADDRESS = "accessory_address"; 623cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final String ARG_ACCESSORY_NAME = "accessory_name"; 633cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private static final String ARG_ACCESSORY_ICON_ID = "accessory_icon_res"; 643cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 653cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private BluetoothDevice mDevice; 663cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private BluetoothGatt mDeviceGatt; 673cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private String mDeviceAddress; 683cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private String mDeviceName; 693cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private @DrawableRes int mDeviceImgId; 703cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private boolean mUnpairing; 713cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private Preference mUnpairPref; 723cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private Preference mBatteryPref; 733cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 7405343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler private final Handler mHandler = new Handler(); 7505343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler private Runnable mBailoutRunnable = new Runnable() { 7605343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler @Override 7705343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler public void run() { 7805343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler if (isResumed() && !getFragmentManager().popBackStackImmediate()) { 7905343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler getActivity().onBackPressed(); 8005343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler } 8105343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler } 8205343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler }; 8305343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler 843cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler // Broadcast Receiver for Bluetooth related events 853cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 863cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 873cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onReceive(Context context, Intent intent) { 883cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler BluetoothDevice device = intent 893cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 903cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mUnpairing) { 913cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mDevice.equals(device)) { 923cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler // Done removing device, finish the activity 933cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mMsgHandler.removeCallbacks(mTimeoutRunnable); 943cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler navigateBack(); 953cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 963cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 973cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 983cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler }; 993cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1003cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler // Internal message handler 1013cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private final Handler mMsgHandler = new Handler(); 1023cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1033cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private final Runnable mTimeoutRunnable = new Runnable() { 1043cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 1053cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void run() { 1063cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler navigateBack(); 1073cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1083cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler }; 1093cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1103cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public static BluetoothAccessoryFragment newInstance(String deviceAddress, String deviceName, 1113cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler int deviceImgId) { 1123cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final Bundle b = new Bundle(3); 113440517f61de3f603755b1e99c7581fe274314b47Tony Mantler prepareArgs(b, deviceAddress, deviceName, deviceImgId); 1143cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final BluetoothAccessoryFragment f = new BluetoothAccessoryFragment(); 1153cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler f.setArguments(b); 1163cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler return f; 1173cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1183cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 119440517f61de3f603755b1e99c7581fe274314b47Tony Mantler public static void prepareArgs(Bundle b, String deviceAddress, String deviceName, 120440517f61de3f603755b1e99c7581fe274314b47Tony Mantler int deviceImgId) { 121440517f61de3f603755b1e99c7581fe274314b47Tony Mantler b.putString(ARG_ACCESSORY_ADDRESS, deviceAddress); 122440517f61de3f603755b1e99c7581fe274314b47Tony Mantler b.putString(ARG_ACCESSORY_NAME, deviceName); 123440517f61de3f603755b1e99c7581fe274314b47Tony Mantler b.putInt(ARG_ACCESSORY_ICON_ID, deviceImgId); 124440517f61de3f603755b1e99c7581fe274314b47Tony Mantler } 125440517f61de3f603755b1e99c7581fe274314b47Tony Mantler 1263cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 1273cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onCreate(Bundle savedInstanceState) { 1283cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Bundle bundle = getArguments(); 1293cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (bundle != null) { 1303cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDeviceAddress = bundle.getString(ARG_ACCESSORY_ADDRESS); 1313cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDeviceName = bundle.getString(ARG_ACCESSORY_NAME); 1323cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDeviceImgId = bundle.getInt(ARG_ACCESSORY_ICON_ID); 1333cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } else { 1343cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDeviceName = getString(R.string.accessory_options); 1353cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDeviceImgId = R.drawable.ic_qs_bluetooth_not_connected; 1363cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1373cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1383cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1393cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mUnpairing = savedInstanceState != null 1403cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler && savedInstanceState.getBoolean(SAVE_STATE_UNPAIRING); 1413cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1423cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter(); 1433cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (btAdapter != null) { 1443cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Set<BluetoothDevice> bondedDevices = btAdapter.getBondedDevices(); 1453cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler for (BluetoothDevice device : bondedDevices) { 1463cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mDeviceAddress.equals(device.getAddress())) { 1473cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDevice = device; 1483cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler break; 1493cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1503cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1513cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1523cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1533cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mDevice == null) { 1543cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler navigateBack(); 1553cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1563cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1573cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler super.onCreate(savedInstanceState); 1583cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1593cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1603cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 1613cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onStart() { 1623cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler super.onStart(); 1633cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mDevice != null && 1643cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler (mDevice.getType() == BluetoothDevice.DEVICE_TYPE_LE || 1653cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDevice.getType() == BluetoothDevice.DEVICE_TYPE_DUAL)) { 1663cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler // Only LE devices support GATT 1673cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDeviceGatt = mDevice.connectGatt(getActivity(), true, new GattBatteryCallbacks()); 1683cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1693cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler // Set a broadcast receiver to let us know when the device has been removed 1703cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler IntentFilter adapterIntentFilter = new IntentFilter(); 1713cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler adapterIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 1723cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler getActivity().registerReceiver(mBroadcastReceiver, adapterIntentFilter); 1733cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mDevice != null && mDevice.getBondState() == BluetoothDevice.BOND_NONE) { 1743cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mMsgHandler.removeCallbacks(mTimeoutRunnable); 1753cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler navigateBack(); 1763cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1773cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1783cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1793cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 18005343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler public void onPause() { 18105343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler super.onPause(); 18205343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler mHandler.removeCallbacks(mBailoutRunnable); 18305343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler } 18405343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler 18505343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler @Override 1863cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onSaveInstanceState(@NonNull Bundle savedInstanceState) { 1873cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler super.onSaveInstanceState(savedInstanceState); 1883cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler savedInstanceState.putBoolean(SAVE_STATE_UNPAIRING, mUnpairing); 1893cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1903cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 1913cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 1923cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onStop() { 1933cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler super.onStop(); 1943cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mDeviceGatt != null) { 1953cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDeviceGatt.close(); 1963cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 19723dc470d99fee1c31c86c7f15506b3c7df3f5035Tony Mantler getActivity().unregisterReceiver(mBroadcastReceiver); 1983cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 1993cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2003cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 2013cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 2023cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final Context themedContext = getPreferenceManager().getContext(); 2033cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final PreferenceScreen screen = 2043cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler getPreferenceManager().createPreferenceScreen(themedContext); 2053cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler screen.setTitle(mDeviceName); 2063cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2073cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mUnpairPref = new Preference(themedContext); 2083cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler updateUnpairPref(mUnpairPref); 2093cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mUnpairPref.setFragment(UnpairConfirmFragment.class.getName()); 2103cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler UnpairConfirmFragment.prepareArgs(mUnpairPref.getExtras(), mDeviceName, mDeviceImgId); 2113cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler screen.addPreference(mUnpairPref); 2123cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2133cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mBatteryPref = new Preference(themedContext); 2143cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler screen.addPreference(mBatteryPref); 2153cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mBatteryPref.setVisible(false); 2163cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2173cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler setPreferenceScreen(screen); 2183cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2193cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2203cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private void updateUnpairPref(Preference pref) { 2213cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mUnpairing) { 2223cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler pref.setTitle(R.string.accessory_unpairing); 2233cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler pref.setEnabled(false); 2243cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } else { 2253cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler pref.setTitle(R.string.accessory_unpair); 2263cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler pref.setEnabled(true); 2273cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2283cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2293cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2303cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private void navigateBack() { 23105343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler // need to post this to avoid recursing in the fragment manager. 23205343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler mHandler.removeCallbacks(mBailoutRunnable); 23305343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler mHandler.post(mBailoutRunnable); 2343cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2353cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 23605343fd6638c21c7c6287c7a18b41660be1121c9Tony Mantler private void unpairDevice() { 2373cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mDevice != null) { 2383cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler int state = mDevice.getBondState(); 2393cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2403cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (state == BluetoothDevice.BOND_BONDING) { 2413cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mDevice.cancelBondProcess(); 2423cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2433cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2443cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (state != BluetoothDevice.BOND_NONE) { 2453cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mUnpairing = true; 2463cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler // Set a timeout, just in case we don't receive the unpair notification we 2473cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler // use to finish the activity 2483cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mMsgHandler.postDelayed(mTimeoutRunnable, UNPAIR_TIMEOUT); 2493cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final boolean successful = mDevice.removeBond(); 2503cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (successful) { 2513cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (DEBUG) { 2523cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Log.d(TAG, "Bluetooth device successfully unpaired."); 2533cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2543cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler // set the dialog to a waiting state 2553cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mUnpairPref != null) { 2563cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler updateUnpairPref(mUnpairPref); 2573cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2583cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } else { 2593cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Log.e(TAG, "Failed to unpair Bluetooth Device: " + mDevice.getName()); 2603cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2613cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2623cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } else { 2633cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Log.e(TAG, "Bluetooth device not found. Address = " + mDeviceAddress); 2643cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2653cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2663cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2673cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler private class GattBatteryCallbacks extends BluetoothGattCallback { 2683cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 2693cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 2703cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (DEBUG) { 2713cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Log.d(TAG, "Connection status:" + status + " state:" + newState); 2723cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2733cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothGatt.STATE_CONNECTED) { 2743cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler gatt.discoverServices(); 2753cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2763cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2773cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2783cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 2793cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onServicesDiscovered(BluetoothGatt gatt, int status) { 2803cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (status != BluetoothGatt.GATT_SUCCESS) { 2813cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (DEBUG) { 2823cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Log.e(TAG, "Service discovery failure on " + gatt); 2833cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2843cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler return; 2853cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2863cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2873cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final BluetoothGattService battService = gatt.getService(GATT_BATTERY_SERVICE_UUID); 2883cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (battService == null) { 2893cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (DEBUG) { 2903cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Log.d(TAG, "No battery service"); 2913cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2923cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler return; 2933cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 2943cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 2953cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final BluetoothGattCharacteristic battLevel = 2963cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler battService.getCharacteristic(GATT_BATTERY_LEVEL_CHARACTERISTIC_UUID); 2973cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (battLevel == null) { 2983cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (DEBUG) { 2993cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Log.d(TAG, "No battery level"); 3003cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3013cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler return; 3023cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3033cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 3043cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler gatt.readCharacteristic(battLevel); 3053cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3063cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 3073cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 3083cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onCharacteristicRead(BluetoothGatt gatt, 3093cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler BluetoothGattCharacteristic characteristic, int status) { 3103cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (status != BluetoothGatt.GATT_SUCCESS) { 3113cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (DEBUG) { 3123cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Log.e(TAG, "Read characteristic failure on " + gatt + " " + characteristic); 3133cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3143cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler return; 3153cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3163cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 3173cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (GATT_BATTERY_LEVEL_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) { 3183cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final int batteryLevel = 3193cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); 3203cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mMsgHandler.post(new Runnable() { 3213cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 3223cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void run() { 3233cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (mBatteryPref != null && !mUnpairing) { 3243cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mBatteryPref.setTitle(getString(R.string.accessory_battery, 3253cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler batteryLevel)); 3263cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler mBatteryPref.setVisible(true); 3273cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3283cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3293cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler }); 3303cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3313cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3323cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3333cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 3343cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public static class UnpairConfirmFragment extends GuidedStepFragment { 3353cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 3363cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public static void prepareArgs(@NonNull Bundle args, String deviceName, 3373cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @DrawableRes int deviceImgId) { 3383cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler args.putString(ARG_ACCESSORY_NAME, deviceName); 3393cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler args.putInt(ARG_ACCESSORY_ICON_ID, deviceImgId); 3403cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3413cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 3423cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @NonNull 3433cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 3443cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) { 3453cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler return new GuidanceStylist.Guidance( 3463cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler getString(R.string.accessory_unpair), 3473cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler null, 3483cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler getArguments().getString(ARG_ACCESSORY_NAME), 3493cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler getContext().getDrawable(getArguments().getInt(ARG_ACCESSORY_ICON_ID, 3503cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler R.drawable.ic_qs_bluetooth_not_connected)) 3513cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler ); 3523cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3533cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 3543cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 3553cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onCreateActions(@NonNull List<GuidedAction> actions, 3563cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler Bundle savedInstanceState) { 3573cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final Context context = getContext(); 358846b83807749cd73aa1b75749e8d072e8f58860dDake Gu actions.add(new GuidedAction.Builder(context) 359846b83807749cd73aa1b75749e8d072e8f58860dDake Gu .clickAction(GuidedAction.ACTION_ID_OK).build()); 360846b83807749cd73aa1b75749e8d072e8f58860dDake Gu actions.add(new GuidedAction.Builder(context) 361846b83807749cd73aa1b75749e8d072e8f58860dDake Gu .clickAction(GuidedAction.ACTION_ID_CANCEL).build()); 3623cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3633cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler 3643cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler @Override 3653cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler public void onGuidedActionClicked(GuidedAction action) { 3663cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler if (action.getId() == GuidedAction.ACTION_ID_OK) { 3673cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler final BluetoothAccessoryFragment fragment = 3683cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler (BluetoothAccessoryFragment) getTargetFragment(); 3693cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler fragment.unpairDevice(); 3703cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } else if (action.getId() == GuidedAction.ACTION_ID_CANCEL) { 3713cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler getFragmentManager().popBackStack(); 3723cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } else { 3733cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler super.onGuidedActionClicked(action); 3743cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3753cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3763cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler } 3773cec83eb4ef203c51b172e13d1b79d4ee81c4d81Tony Mantler} 378