1843fbc4b10a2c62cb3848836907630f0d56c647eroger xue/* 2843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * Copyright (C) 2017 The Android Open Source Project 3843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * 4843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * Licensed under the Apache License, Version 2.0 (the "License"); 5843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * you may not use this file except in compliance with the License. 6843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * You may obtain a copy of the License at 7843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * 8843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * http://www.apache.org/licenses/LICENSE-2.0 9843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * 10843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * Unless required by applicable law or agreed to in writing, software 11843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * distributed under the License is distributed on an "AS IS" BASIS, 12843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * See the License for the specific language governing permissions and 14843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * limitations under the License. 15843fbc4b10a2c62cb3848836907630f0d56c647eroger xue */ 16843fbc4b10a2c62cb3848836907630f0d56c647eroger xuepackage com.android.car.settings.bluetooth; 17843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 18843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.annotation.NonNull; 19843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.bluetooth.BluetoothAdapter; 20843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.bluetooth.BluetoothClass; 21843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.bluetooth.BluetoothDevice; 22843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.content.Context; 23843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.content.res.Resources; 24843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.os.AsyncTask; 25843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.os.Handler; 26843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.os.Looper; 27262c78bd157917a1898cf46fdbf1d2c02c8493d7Lujiang Xueimport android.text.TextUtils; 28843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.util.Log; 29843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.util.Pair; 30843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.support.v7.widget.RecyclerView; 31843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.view.LayoutInflater; 32843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.view.View; 33843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.view.View.OnClickListener; 34843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.view.ViewGroup; 35843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.widget.ImageButton; 36843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.widget.ImageView; 37843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.widget.TextView; 38843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport android.widget.Toast; 39843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 40843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.car.settings.R; 4124b50803fa603b04e74752beb19f85038515919aroger xueimport com.android.car.settings.common.BaseFragment; 42d28162c2c6c760c760125f444069841f1e4d21d9Rakesh Iyerimport com.android.car.view.PagedListView; 43843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.settingslib.bluetooth.BluetoothCallback; 44843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.settingslib.bluetooth.BluetoothDeviceFilter; 45843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.settingslib.bluetooth.CachedBluetoothDevice; 46843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; 47843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.settingslib.bluetooth.LocalBluetoothAdapter; 48843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.settingslib.bluetooth.LocalBluetoothManager; 49843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.settingslib.bluetooth.LocalBluetoothProfile; 50843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport com.android.settingslib.bluetooth.HidProfile; 51843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 52843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport java.util.ArrayList; 53843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport java.util.Collection; 54843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport java.util.Collections; 55843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport java.util.HashSet; 56843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport java.util.List; 57843fbc4b10a2c62cb3848836907630f0d56c647eroger xueimport java.util.Set; 58843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 59843fbc4b10a2c62cb3848836907630f0d56c647eroger xue/** 60843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * Renders {@link android.bluetooth.BluetoothDevice} to a view to be displayed as a row in a list. 61843fbc4b10a2c62cb3848836907630f0d56c647eroger xue */ 62843fbc4b10a2c62cb3848836907630f0d56c647eroger xuepublic class BluetoothDeviceListAdapter 63843fbc4b10a2c62cb3848836907630f0d56c647eroger xue extends RecyclerView.Adapter<BluetoothDeviceListAdapter.ViewHolder> 64843fbc4b10a2c62cb3848836907630f0d56c647eroger xue implements PagedListView.ItemCap, BluetoothCallback { 65843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private static final String TAG = "BluetoothDeviceListAdapter"; 66843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private static final int DEVICE_ROW_TYPE = 1; 67843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private static final int BONDED_DEVICE_HEADER_TYPE = 2; 68843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private static final int AVAILABLE_DEVICE_HEADER_TYPE = 3; 69843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private static final int NUM_OF_HEADERS = 2; 70843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public static final int DELAY_MILLIS = 1000; 71843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 72843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final Handler mHandler = new Handler(Looper.getMainLooper()); 73843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final HashSet<CachedBluetoothDevice> mBondedDevices = new HashSet<>(); 74843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final HashSet<CachedBluetoothDevice> mAvailableDevices = new HashSet<>(); 75843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final LocalBluetoothAdapter mLocalAdapter; 76843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final LocalBluetoothManager mLocalManager; 77843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final CachedBluetoothDeviceManager mDeviceManager; 78843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final Context mContext; 7924b50803fa603b04e74752beb19f85038515919aroger xue private final BaseFragment.FragmentController mFragmentController; 80843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 81843fbc4b10a2c62cb3848836907630f0d56c647eroger xue /* Talk-back descriptions for various BT icons */ 82843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public final String mComputerDescription; 83843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public final String mInputPeripheralDescription; 84843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public final String mHeadsetDescription; 85843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public final String mPhoneDescription; 86843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public final String mImagingDescription; 87843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public final String mHeadphoneDescription; 88843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public final String mBluetoothDescription; 89843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 90c232398a88c4caffafc601dc2482ed3ad430df3bLujiang Xue private SortTask mSortTask; 91843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 92843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private ArrayList<CachedBluetoothDevice> mBondedDevicesSorted = new ArrayList<>(); 93843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private ArrayList<CachedBluetoothDevice> mAvailableDevicesSorted = new ArrayList<>(); 94843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 95843fbc4b10a2c62cb3848836907630f0d56c647eroger xue class ViewHolder extends RecyclerView.ViewHolder { 96843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final ImageView mIcon; 97b9104e0e877d1f2334e1cbb1715c7fd320f62345roger xue private final TextView mTitle; 98843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final TextView mDesc; 99843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final ImageButton mActionButton; 100843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final DeviceAttributeChangeCallback mCallback = 101843fbc4b10a2c62cb3848836907630f0d56c647eroger xue new DeviceAttributeChangeCallback(this); 102843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 103843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public ViewHolder(View view) { 104843fbc4b10a2c62cb3848836907630f0d56c647eroger xue super(view); 105b9104e0e877d1f2334e1cbb1715c7fd320f62345roger xue mTitle = (TextView) view.findViewById(R.id.title); 106843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mDesc = (TextView) view.findViewById(R.id.desc); 107843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mIcon = (ImageView) view.findViewById(R.id.icon); 108843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mActionButton = (ImageButton) view.findViewById(R.id.action); 109843fbc4b10a2c62cb3848836907630f0d56c647eroger xue view.setOnClickListener(new BluetoothClickListener(this)); 110843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 111843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 112843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 113843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public BluetoothDeviceListAdapter( 11424b50803fa603b04e74752beb19f85038515919aroger xue Context context, 11524b50803fa603b04e74752beb19f85038515919aroger xue LocalBluetoothManager localBluetoothManager, 11624b50803fa603b04e74752beb19f85038515919aroger xue BaseFragment.FragmentController fragmentController) { 117843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mContext = context; 118843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mLocalManager = localBluetoothManager; 11924b50803fa603b04e74752beb19f85038515919aroger xue mFragmentController = fragmentController; 120843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mLocalAdapter = mLocalManager.getBluetoothAdapter(); 121843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mDeviceManager = mLocalManager.getCachedDeviceManager(); 122843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 123843fbc4b10a2c62cb3848836907630f0d56c647eroger xue Resources r = context.getResources(); 124843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mComputerDescription = r.getString(R.string.bluetooth_talkback_computer); 125843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mInputPeripheralDescription = r.getString( 126843fbc4b10a2c62cb3848836907630f0d56c647eroger xue R.string.bluetooth_talkback_input_peripheral); 127843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mHeadsetDescription = r.getString(R.string.bluetooth_talkback_headset); 128843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mPhoneDescription = r.getString(R.string.bluetooth_talkback_phone); 129843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mImagingDescription = r.getString(R.string.bluetooth_talkback_imaging); 130843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mHeadphoneDescription = r.getString(R.string.bluetooth_talkback_headphone); 131843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mBluetoothDescription = r.getString(R.string.bluetooth_talkback_bluetooth); 132843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 133843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 134843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void start() { 135843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mLocalManager.getEventManager().registerCallback(this); 136843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (mLocalAdapter.isEnabled()) { 137843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mLocalAdapter.startScanning(true); 138843fbc4b10a2c62cb3848836907630f0d56c647eroger xue addBondDevices(); 139843fbc4b10a2c62cb3848836907630f0d56c647eroger xue addCachedDevices(); 140843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 141c232398a88c4caffafc601dc2482ed3ad430df3bLujiang Xue // create task here to avoid re-executing existing tasks. 142c232398a88c4caffafc601dc2482ed3ad430df3bLujiang Xue mSortTask = new SortTask(); 143843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mSortTask.execute(); 144843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 145843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 146843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void stop() { 147843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mLocalAdapter.stopScanning(); 148843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mDeviceManager.clearNonBondedDevices(); 149843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mLocalManager.getEventManager().unregisterCallback(this); 150843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mBondedDevices.clear(); 151843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mAvailableDevices.clear(); 152843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mSortTask.cancel(true); 153843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 154843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 155843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 156843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public BluetoothDeviceListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, 157843fbc4b10a2c62cb3848836907630f0d56c647eroger xue int viewType) { 158843fbc4b10a2c62cb3848836907630f0d56c647eroger xue View v; 159843fbc4b10a2c62cb3848836907630f0d56c647eroger xue LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); 160843fbc4b10a2c62cb3848836907630f0d56c647eroger xue switch (viewType) { 161843fbc4b10a2c62cb3848836907630f0d56c647eroger xue case BONDED_DEVICE_HEADER_TYPE: 1621e632a5036e3d29d7fbf9078939ba247aec1ea57roger xue v = layoutInflater.inflate(R.layout.single_text_line_item, parent, false); 1635e02a7c64fa4dbcbbef81e1e582ff381287f2e34roger xue v.setEnabled(false); 1641e632a5036e3d29d7fbf9078939ba247aec1ea57roger xue ((TextView) v.findViewById(R.id.title)).setText( 16524b50803fa603b04e74752beb19f85038515919aroger xue R.string.bluetooth_preference_paired_devices); 166843fbc4b10a2c62cb3848836907630f0d56c647eroger xue break; 167843fbc4b10a2c62cb3848836907630f0d56c647eroger xue case AVAILABLE_DEVICE_HEADER_TYPE: 1681e632a5036e3d29d7fbf9078939ba247aec1ea57roger xue v = layoutInflater.inflate(R.layout.single_text_line_item, parent, false); 1695e02a7c64fa4dbcbbef81e1e582ff381287f2e34roger xue v.setEnabled(false); 1701e632a5036e3d29d7fbf9078939ba247aec1ea57roger xue ((TextView) v.findViewById(R.id.title)).setText( 17124b50803fa603b04e74752beb19f85038515919aroger xue R.string.bluetooth_preference_found_devices); 172843fbc4b10a2c62cb3848836907630f0d56c647eroger xue break; 173843fbc4b10a2c62cb3848836907630f0d56c647eroger xue default: 174ddb7544cfc9f5263d719c9d2760451e9316d3bderoger xue v = layoutInflater.inflate(R.layout.icon_widget_line_item, parent, false); 175843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 176843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new ViewHolder(v); 177843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 178843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 179843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 180843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public int getItemCount() { 181843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return mAvailableDevicesSorted.size() + NUM_OF_HEADERS + mBondedDevicesSorted.size(); 182843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 183843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 184843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 185843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void setMaxItems(int maxItems) { 186843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // no limit in this list. 187843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 188843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 189843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 190843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onBindViewHolder(ViewHolder holder, int position) { 191843fbc4b10a2c62cb3848836907630f0d56c647eroger xue final CachedBluetoothDevice bluetoothDevice = getItem(position); 192843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (bluetoothDevice == null) { 193843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // this row is for in-list headers 194843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return; 195843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 196843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (holder.getOldPosition() != RecyclerView.NO_POSITION) { 197843fbc4b10a2c62cb3848836907630f0d56c647eroger xue getItem(holder.getOldPosition()).unregisterCallback(holder.mCallback); 198843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 199843fbc4b10a2c62cb3848836907630f0d56c647eroger xue bluetoothDevice.registerCallback(holder.mCallback); 200b9104e0e877d1f2334e1cbb1715c7fd320f62345roger xue holder.mTitle.setText(bluetoothDevice.getName()); 201843fbc4b10a2c62cb3848836907630f0d56c647eroger xue Pair<Integer, String> pair = getBtClassDrawableWithDescription(bluetoothDevice); 202843fbc4b10a2c62cb3848836907630f0d56c647eroger xue holder.mIcon.setImageResource(pair.first); 20309a303c04a4e679d752e7469dfcdce41e8e02debJack He String summaryText = bluetoothDevice.getConnectionSummary(); 20409a303c04a4e679d752e7469dfcdce41e8e02debJack He if (summaryText != null) { 20509a303c04a4e679d752e7469dfcdce41e8e02debJack He holder.mDesc.setText(summaryText); 206843fbc4b10a2c62cb3848836907630f0d56c647eroger xue holder.mDesc.setVisibility(View.VISIBLE); 207843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } else { 208843fbc4b10a2c62cb3848836907630f0d56c647eroger xue holder.mDesc.setVisibility(View.GONE); 209843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 210843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (BluetoothDeviceFilter.BONDED_DEVICE_FILTER.matches(bluetoothDevice.getDevice())) { 211843fbc4b10a2c62cb3848836907630f0d56c647eroger xue holder.mActionButton.setVisibility(View.VISIBLE); 212843fbc4b10a2c62cb3848836907630f0d56c647eroger xue holder.mActionButton.setOnClickListener(v -> { 21324b50803fa603b04e74752beb19f85038515919aroger xue mFragmentController.launchFragment( 21424b50803fa603b04e74752beb19f85038515919aroger xue BluetoothDetailFragment.getInstance(bluetoothDevice.getDevice())); 215843fbc4b10a2c62cb3848836907630f0d56c647eroger xue }); 216843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } else { 217843fbc4b10a2c62cb3848836907630f0d56c647eroger xue holder.mActionButton.setVisibility(View.GONE); 218843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 219843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 220843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 221843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 222843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public int getItemViewType(int position) { 223843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // the first row is the header for the bonded device list; 224843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (position == 0) { 225843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return BONDED_DEVICE_HEADER_TYPE; 226843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 227843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // after the end of the bonded device list is the header of the available device list. 228843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (position == mBondedDevicesSorted.size() + 1) { 229843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return AVAILABLE_DEVICE_HEADER_TYPE; 230843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 231843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return DEVICE_ROW_TYPE; 232843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 233843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 234843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private CachedBluetoothDevice getItem(int position) { 235843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (position > 0 && position <= mBondedDevicesSorted.size()) { 236843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // off set the header row 237843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return mBondedDevicesSorted.get(position - 1); 238843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 239843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (position > mBondedDevicesSorted.size() + 1 240843fbc4b10a2c62cb3848836907630f0d56c647eroger xue && position <= mBondedDevicesSorted.size() + 1 + mAvailableDevicesSorted.size()) { 241843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // off set two header row and the size of bonded device list. 242843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return mAvailableDevicesSorted.get( 243843fbc4b10a2c62cb3848836907630f0d56c647eroger xue position - NUM_OF_HEADERS - mBondedDevicesSorted.size()); 244843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 245843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // otherwise it's a in list header 246843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return null; 247843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 248843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 249843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // callback functions 250843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 251843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { 252843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (addDevice(cachedDevice)) { 253843fbc4b10a2c62cb3848836907630f0d56c647eroger xue ArrayList<CachedBluetoothDevice> devices = new ArrayList<>(mBondedDevices); 254843fbc4b10a2c62cb3848836907630f0d56c647eroger xue Collections.sort(devices); 255843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mBondedDevicesSorted = devices; 256843fbc4b10a2c62cb3848836907630f0d56c647eroger xue notifyDataSetChanged(); 257843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 258843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 259843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 260843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 261843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { 262a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue onDeviceDeleted(cachedDevice, true /* reset */); 263843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 264843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 265843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 266843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onBluetoothStateChanged(int bluetoothState) { 267843fbc4b10a2c62cb3848836907630f0d56c647eroger xue switch (bluetoothState) { 268843fbc4b10a2c62cb3848836907630f0d56c647eroger xue case BluetoothAdapter.STATE_OFF: 269843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mBondedDevices.clear(); 270843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mBondedDevicesSorted.clear(); 271843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mAvailableDevices.clear(); 272843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mAvailableDevicesSorted.clear(); 273843fbc4b10a2c62cb3848836907630f0d56c647eroger xue notifyDataSetChanged(); 274843fbc4b10a2c62cb3848836907630f0d56c647eroger xue break; 275843fbc4b10a2c62cb3848836907630f0d56c647eroger xue case BluetoothAdapter.STATE_ON: 276843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mLocalAdapter.startScanning(true); 277843fbc4b10a2c62cb3848836907630f0d56c647eroger xue addBondDevices(); 278843fbc4b10a2c62cb3848836907630f0d56c647eroger xue addCachedDevices(); 279843fbc4b10a2c62cb3848836907630f0d56c647eroger xue break; 280843fbc4b10a2c62cb3848836907630f0d56c647eroger xue default: 281843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 282843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 283843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 284a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue public void reset() { 285a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue mBondedDevices.clear(); 286a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue mBondedDevicesSorted.clear(); 287a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue mAvailableDevices.clear(); 288a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue mAvailableDevicesSorted.clear(); 289a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue mLocalAdapter.startScanning(true); 290a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue addBondDevices(); 291a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue addCachedDevices(); 292a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue } 293a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue 294843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 295843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onScanningStateChanged(boolean started) { 296843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // don't care 297843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 298843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 299843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 300843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) { 301a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue onDeviceDeleted(cachedDevice, false /* reset */); 302843fbc4b10a2c62cb3848836907630f0d56c647eroger xue onDeviceAdded(cachedDevice); 303843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 304843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 305843fbc4b10a2c62cb3848836907630f0d56c647eroger xue /** 306843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * Call back for the first connection or the last connection to ANY device/profile. Not 307843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * suitable for monitor per device level connection. 308843fbc4b10a2c62cb3848836907630f0d56c647eroger xue */ 309843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 310843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { 311843fbc4b10a2c62cb3848836907630f0d56c647eroger xue onDeviceDeleted(cachedDevice, false); 312843fbc4b10a2c62cb3848836907630f0d56c647eroger xue onDeviceAdded(cachedDevice); 313843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 314843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 315843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private void onDeviceDeleted(CachedBluetoothDevice cachedDevice, boolean refresh) { 316843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // the device might changed bonding state, so need to remove from both sets. 317843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (mBondedDevices.remove(cachedDevice)) { 318843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mBondedDevicesSorted.remove(cachedDevice); 319843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 320843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mAvailableDevices.remove(cachedDevice); 321843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (refresh) { 322843fbc4b10a2c62cb3848836907630f0d56c647eroger xue notifyDataSetChanged(); 323843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 324843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 325843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 326843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private void addDevices(Collection<CachedBluetoothDevice> cachedDevices) { 327843fbc4b10a2c62cb3848836907630f0d56c647eroger xue boolean needSort = false; 328843fbc4b10a2c62cb3848836907630f0d56c647eroger xue for (CachedBluetoothDevice device : cachedDevices) { 329843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (addDevice(device)) { 330843fbc4b10a2c62cb3848836907630f0d56c647eroger xue needSort = true; 331843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 332843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 333843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (needSort) { 334843fbc4b10a2c62cb3848836907630f0d56c647eroger xue ArrayList<CachedBluetoothDevice> devices = 335843fbc4b10a2c62cb3848836907630f0d56c647eroger xue new ArrayList<CachedBluetoothDevice>(mBondedDevices); 336843fbc4b10a2c62cb3848836907630f0d56c647eroger xue Collections.sort(devices); 337843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mBondedDevicesSorted = devices; 338843fbc4b10a2c62cb3848836907630f0d56c647eroger xue notifyDataSetChanged(); 339843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 340843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 341843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 342843fbc4b10a2c62cb3848836907630f0d56c647eroger xue /** 343843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * @return {@code true} if list changed and needed sort again. 344843fbc4b10a2c62cb3848836907630f0d56c647eroger xue */ 345843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private boolean addDevice(CachedBluetoothDevice cachedDevice) { 346843fbc4b10a2c62cb3848836907630f0d56c647eroger xue boolean needSort = false; 347843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (BluetoothDeviceFilter.BONDED_DEVICE_FILTER.matches(cachedDevice.getDevice())) { 348843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (mBondedDevices.add(cachedDevice)) { 349843fbc4b10a2c62cb3848836907630f0d56c647eroger xue needSort = true; 350843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 351843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 352843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER.matches(cachedDevice.getDevice())) { 353a76987ecf243fa3ff76f7ea8a40597baeb763e3croger xue // reset is done at SortTask. 354843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mAvailableDevices.add(cachedDevice); 355843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 356843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return needSort; 357843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 358843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 359843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private void addBondDevices() { 360843fbc4b10a2c62cb3848836907630f0d56c647eroger xue Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices(); 361843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (bondedDevices == null) { 362843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return; 363843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 364843fbc4b10a2c62cb3848836907630f0d56c647eroger xue ArrayList<CachedBluetoothDevice> cachedBluetoothDevices = new ArrayList<>(); 365843fbc4b10a2c62cb3848836907630f0d56c647eroger xue for (BluetoothDevice device : bondedDevices) { 366843fbc4b10a2c62cb3848836907630f0d56c647eroger xue CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); 367843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (cachedDevice == null) { 368843fbc4b10a2c62cb3848836907630f0d56c647eroger xue cachedDevice = mDeviceManager.addDevice( 369843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mLocalAdapter, mLocalManager.getProfileManager(), device); 370843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 371843fbc4b10a2c62cb3848836907630f0d56c647eroger xue cachedBluetoothDevices.add(cachedDevice); 372843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 373843fbc4b10a2c62cb3848836907630f0d56c647eroger xue addDevices(cachedBluetoothDevices); 374843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 375843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 376843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private void addCachedDevices() { 377843fbc4b10a2c62cb3848836907630f0d56c647eroger xue addDevices(mDeviceManager.getCachedDevicesCopy()); 378843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 379843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 380843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private Pair<Integer, String> getBtClassDrawableWithDescription( 381843fbc4b10a2c62cb3848836907630f0d56c647eroger xue CachedBluetoothDevice bluetoothDevice) { 382843fbc4b10a2c62cb3848836907630f0d56c647eroger xue BluetoothClass btClass = bluetoothDevice.getBtClass(); 383843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (btClass != null) { 384843fbc4b10a2c62cb3848836907630f0d56c647eroger xue switch (btClass.getMajorDeviceClass()) { 385843fbc4b10a2c62cb3848836907630f0d56c647eroger xue case BluetoothClass.Device.Major.COMPUTER: 386843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new Pair<>(R.drawable.ic_bt_laptop, mComputerDescription); 387843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 388843fbc4b10a2c62cb3848836907630f0d56c647eroger xue case BluetoothClass.Device.Major.PHONE: 389843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new Pair<>(R.drawable.ic_bt_cellphone, mPhoneDescription); 390843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 391843fbc4b10a2c62cb3848836907630f0d56c647eroger xue case BluetoothClass.Device.Major.PERIPHERAL: 392843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new Pair<>(HidProfile.getHidClassDrawable(btClass), 393843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mInputPeripheralDescription); 394843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 395843fbc4b10a2c62cb3848836907630f0d56c647eroger xue case BluetoothClass.Device.Major.IMAGING: 396843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new Pair<>(R.drawable.ic_bt_imaging, mImagingDescription); 397843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 398843fbc4b10a2c62cb3848836907630f0d56c647eroger xue default: 399843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // unrecognized device class; continue 400843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 401843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } else { 402843fbc4b10a2c62cb3848836907630f0d56c647eroger xue Log.w(TAG, "btClass is null"); 403843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 404843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 405843fbc4b10a2c62cb3848836907630f0d56c647eroger xue List<LocalBluetoothProfile> profiles = bluetoothDevice.getProfiles(); 406843fbc4b10a2c62cb3848836907630f0d56c647eroger xue for (LocalBluetoothProfile profile : profiles) { 407843fbc4b10a2c62cb3848836907630f0d56c647eroger xue int resId = profile.getDrawableResource(btClass); 408843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (resId != 0) { 409843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new Pair<Integer, String>(resId, null); 410843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 411843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 412843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (btClass != null) { 413843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { 414843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new Pair<Integer, String>(R.drawable.ic_bt_headset_hfp, mHeadsetDescription); 415843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 416843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) { 417843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new Pair<Integer, String>(R.drawable.ic_bt_headphones_a2dp, 418843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mHeadphoneDescription); 419843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 420843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 421843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return new Pair<Integer, String>(R.drawable.ic_settings_bluetooth, mBluetoothDescription); 422843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 423843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 424843fbc4b10a2c62cb3848836907630f0d56c647eroger xue /** 425843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * Updates device render upon device attribute change. 426843fbc4b10a2c62cb3848836907630f0d56c647eroger xue */ 427843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // TODO: This is a walk around for handling attribute callback. Since the callback doesn't 428843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // contain the information about which device needs to be updated, we have to maintain a 429843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // local reference to the device. Fix the code in CachedBluetoothDevice.Callback to return 430843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // a reference of the device been updated. 431843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback { 432843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 433843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final ViewHolder mViewHolder; 434843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 435843fbc4b10a2c62cb3848836907630f0d56c647eroger xue DeviceAttributeChangeCallback(ViewHolder viewHolder) { 436843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mViewHolder = viewHolder; 437843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 438843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 439843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 440843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onDeviceAttributesChanged() { 441843fbc4b10a2c62cb3848836907630f0d56c647eroger xue notifyItemChanged(mViewHolder.getAdapterPosition()); 442843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 443843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 444843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 445843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private class BluetoothClickListener implements OnClickListener { 446843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private final ViewHolder mViewHolder; 447843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 448843fbc4b10a2c62cb3848836907630f0d56c647eroger xue BluetoothClickListener(ViewHolder viewHolder) { 449843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mViewHolder = viewHolder; 450843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 451843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 452843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 453843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void onClick(View v) { 454843fbc4b10a2c62cb3848836907630f0d56c647eroger xue CachedBluetoothDevice device = getItem(mViewHolder.getAdapterPosition()); 455843fbc4b10a2c62cb3848836907630f0d56c647eroger xue int bondState = device.getBondState(); 456843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 457843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (device.isConnected()) { 458843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // TODO: ask user for confirmation 459843fbc4b10a2c62cb3848836907630f0d56c647eroger xue device.disconnect(); 460843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } else if (bondState == BluetoothDevice.BOND_BONDED) { 461843fbc4b10a2c62cb3848836907630f0d56c647eroger xue device.connect(true); 462843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } else if (bondState == BluetoothDevice.BOND_NONE) { 463843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (!device.startPairing()) { 464843fbc4b10a2c62cb3848836907630f0d56c647eroger xue showError(device.getName(), 465843fbc4b10a2c62cb3848836907630f0d56c647eroger xue R.string.bluetooth_pairing_error_message); 4661a97e52eb4864e79f1b643dbb3cf64ca9658f7cdLujiang Xue return; 467843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 4681a97e52eb4864e79f1b643dbb3cf64ca9658f7cdLujiang Xue // allow MAP and PBAP since this is client side, permission should be handled on 4691a97e52eb4864e79f1b643dbb3cf64ca9658f7cdLujiang Xue // server side. i.e. the phone side. 4701a97e52eb4864e79f1b643dbb3cf64ca9658f7cdLujiang Xue device.setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED); 4711a97e52eb4864e79f1b643dbb3cf64ca9658f7cdLujiang Xue device.setMessagePermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED); 472843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 473843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 474843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 475843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 476843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private void showError(String name, int messageResId) { 477843fbc4b10a2c62cb3848836907630f0d56c647eroger xue String message = mContext.getString(messageResId, name); 478843fbc4b10a2c62cb3848836907630f0d56c647eroger xue Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show(); 479843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 480843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 481843fbc4b10a2c62cb3848836907630f0d56c647eroger xue /** 482843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * Provides an ordered bt device list periodically. 483843fbc4b10a2c62cb3848836907630f0d56c647eroger xue */ 484843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // TODO: improve the way we sort BT devices. Ideally we should keep all devices in a TreeSet 485843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // and as devices are added the correct order is maintained, that requires a consistent 486843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // logic between equals and compareTo function, unfortunately it's not the case in 487843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // CachedBluetoothDevice class. Fix that and improve the way we order devices. 488843fbc4b10a2c62cb3848836907630f0d56c647eroger xue private class SortTask extends AsyncTask<Void, Void, ArrayList<CachedBluetoothDevice>> { 489843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 490843fbc4b10a2c62cb3848836907630f0d56c647eroger xue /** 491843fbc4b10a2c62cb3848836907630f0d56c647eroger xue * Returns {code null} if no changed are made. 492843fbc4b10a2c62cb3848836907630f0d56c647eroger xue */ 493843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 494843fbc4b10a2c62cb3848836907630f0d56c647eroger xue protected ArrayList<CachedBluetoothDevice> doInBackground(Void... v) { 495843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (mAvailableDevicesSorted != null 496843fbc4b10a2c62cb3848836907630f0d56c647eroger xue && mAvailableDevicesSorted.size() == mAvailableDevices.size()) { 497843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return null; 498843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 499843fbc4b10a2c62cb3848836907630f0d56c647eroger xue ArrayList<CachedBluetoothDevice> devices = 500843fbc4b10a2c62cb3848836907630f0d56c647eroger xue new ArrayList<CachedBluetoothDevice>(mAvailableDevices); 501843fbc4b10a2c62cb3848836907630f0d56c647eroger xue Collections.sort(devices); 502843fbc4b10a2c62cb3848836907630f0d56c647eroger xue return devices; 503843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 504843fbc4b10a2c62cb3848836907630f0d56c647eroger xue 505843fbc4b10a2c62cb3848836907630f0d56c647eroger xue @Override 506843fbc4b10a2c62cb3848836907630f0d56c647eroger xue protected void onPostExecute(ArrayList<CachedBluetoothDevice> devices) { 507843fbc4b10a2c62cb3848836907630f0d56c647eroger xue // skip if no changes are made. 508843fbc4b10a2c62cb3848836907630f0d56c647eroger xue if (devices != null) { 509843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mAvailableDevicesSorted = devices; 510843fbc4b10a2c62cb3848836907630f0d56c647eroger xue notifyDataSetChanged(); 511843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 512843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mHandler.postDelayed(new Runnable() { 513843fbc4b10a2c62cb3848836907630f0d56c647eroger xue public void run() { 514843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mSortTask = new SortTask(); 515843fbc4b10a2c62cb3848836907630f0d56c647eroger xue mSortTask.execute(); 516843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 517843fbc4b10a2c62cb3848836907630f0d56c647eroger xue }, DELAY_MILLIS); 518843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 519843fbc4b10a2c62cb3848836907630f0d56c647eroger xue } 520843fbc4b10a2c62cb3848836907630f0d56c647eroger xue} 521