186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal/* 286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * Copyright (C) 2017 The Android Open Source Project 386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * 486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * Licensed under the Apache License, Version 2.0 (the "License"); 586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * you may not use this file except in compliance with the License. 686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * You may obtain a copy of the License at 786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * 886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * http://www.apache.org/licenses/LICENSE-2.0 986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * 1086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * Unless required by applicable law or agreed to in writing, software 1186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * distributed under the License is distributed on an "AS IS" BASIS, 1286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * See the License for the specific language governing permissions and 1486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal * limitations under the License. 1586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal */ 1686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 1786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalpackage com.android.bluetooth.btservice; 1886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 1986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.bluetooth.BluetoothA2dp; 2086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.bluetooth.BluetoothAdapter; 2186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.bluetooth.BluetoothDevice; 2286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.bluetooth.BluetoothHeadset; 2386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.bluetooth.BluetoothProfile; 2486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.bluetooth.BluetoothUuid; 2586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.content.BroadcastReceiver; 2686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.content.Context; 2786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.content.Intent; 2886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.content.IntentFilter; 2986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.os.Handler; 3086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.os.Looper; 3186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.os.Message; 3286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.os.ParcelUuid; 33c4fbd756e2645147470c486ae96f2253f5e13a52Jack Heimport android.os.Parcelable; 34928f14463ee51192039abef856495ecce418fe01Jack Heimport android.support.annotation.VisibleForTesting; 3586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport android.util.Log; 3686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 3786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport com.android.bluetooth.a2dp.A2dpService; 3809e97f4cfcca3564c8daa864ede0eee172e9d5aaHansong Zhangimport com.android.bluetooth.hearingaid.HearingAidService; 3986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport com.android.bluetooth.hfp.HeadsetService; 40f0429c92669aa388785a97f00985d63a83e509c2Hansong Zhangimport com.android.bluetooth.hid.HidHostService; 4186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport com.android.bluetooth.pan.PanService; 4286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport com.android.internal.R; 4386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 442cc754651ee7245e62fa247b1ca85acb6889e79eJack Heimport java.util.HashSet; 4586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalimport java.util.List; 4686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 4786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// Describes the phone policy 4886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// 4986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// The policy should be as decoupled from the stack as possible. In an ideal world we should not 5086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// need to have this policy talk with any non-public APIs and one way to enforce that would be to 5186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// keep this file outside the Bluetooth process. Unfortunately, keeping a separate process alive is 5286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// an expensive and a tedious task. 5386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// 5486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// Best practices: 5586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// a) PhonePolicy should be ALL private methods 5686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// -- Use broadcasts which can be listened in on the BroadcastReceiver 5786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// b) NEVER call from the PhonePolicy into the Java stack, unless public APIs. It is OK to call into 5886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// the non public versions as long as public versions exist (so that a 3rd party policy can mimick) 5986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// us. 6086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// 6186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// Policy description: 6286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// 6386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// Policies are usually governed by outside events that may warrant an action. We talk about various 6486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// events and the resulting outcome from this policy: 6586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// 6686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// 1. Adapter turned ON: At this point we will try to auto-connect the (device, profile) pairs which 6786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// have PRIORITY_AUTO_CONNECT. The fact that we *only* auto-connect Headset and A2DP is something 6886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// that is hardcoded and specific to phone policy (see autoConnect() function) 6986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// 2. When the profile connection-state changes: At this point if a new profile gets CONNECTED we 7086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// will try to connect other profiles on the same device. This is to avoid collision if devices 7186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal// somehow end up trying to connect at same time or general connection issues. 7286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwalclass PhonePolicy { 73dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private static final boolean DBG = true; 74dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private static final String TAG = "BluetoothPhonePolicy"; 7586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 7686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Message types for the handler (internal messages generated by intents or timeouts) 77dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private static final int MESSAGE_PROFILE_CONNECTION_STATE_CHANGED = 1; 78dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private static final int MESSAGE_PROFILE_INIT_PRIORITIES = 2; 79dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private static final int MESSAGE_CONNECT_OTHER_PROFILES = 3; 80dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private static final int MESSAGE_ADAPTER_STATE_TURNED_ON = 4; 810c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He private static final int MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED = 5; 8286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 8386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Timeouts 840c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He @VisibleForTesting static int sConnectOtherProfilesTimeoutMillis = 6000; // 6s 8586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 86dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private final AdapterService mAdapterService; 87dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private final ServiceFactory mFactory; 88dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private final Handler mHandler; 89dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private final HashSet<BluetoothDevice> mHeadsetRetrySet = new HashSet<>(); 90dbf5c4e1c9e57fa6e5cc96ee9f442da8aa391a5dJack He private final HashSet<BluetoothDevice> mA2dpRetrySet = new HashSet<>(); 91d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He private final HashSet<BluetoothDevice> mConnectOtherProfilesDeviceSet = new HashSet<>(); 9286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 9386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Broadcast receiver for all changes to states of various profiles 9486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 9586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal @Override 9686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal public void onReceive(Context context, Intent intent) { 97d94f6ddab1f088340d197086949409c144ec2b0aJack He String action = intent.getAction(); 98d94f6ddab1f088340d197086949409c144ec2b0aJack He if (action == null) { 99d94f6ddab1f088340d197086949409c144ec2b0aJack He errorLog("Received intent with null action"); 100d94f6ddab1f088340d197086949409c144ec2b0aJack He return; 101d94f6ddab1f088340d197086949409c144ec2b0aJack He } 102d94f6ddab1f088340d197086949409c144ec2b0aJack He switch (action) { 103d94f6ddab1f088340d197086949409c144ec2b0aJack He case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: 104d94f6ddab1f088340d197086949409c144ec2b0aJack He mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED, 105c4fbd756e2645147470c486ae96f2253f5e13a52Jack He BluetoothProfile.HEADSET, -1, // No-op argument 106c4fbd756e2645147470c486ae96f2253f5e13a52Jack He intent).sendToTarget(); 107d94f6ddab1f088340d197086949409c144ec2b0aJack He break; 108d94f6ddab1f088340d197086949409c144ec2b0aJack He case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED: 109d94f6ddab1f088340d197086949409c144ec2b0aJack He mHandler.obtainMessage(MESSAGE_PROFILE_CONNECTION_STATE_CHANGED, 110c4fbd756e2645147470c486ae96f2253f5e13a52Jack He BluetoothProfile.A2DP, -1, // No-op argument 111c4fbd756e2645147470c486ae96f2253f5e13a52Jack He intent).sendToTarget(); 112d94f6ddab1f088340d197086949409c144ec2b0aJack He break; 1130c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED: 1140c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He mHandler.obtainMessage(MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED, 1150c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He BluetoothProfile.A2DP, -1, // No-op argument 1160c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He intent).sendToTarget(); 1170c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He break; 118d94f6ddab1f088340d197086949409c144ec2b0aJack He case BluetoothAdapter.ACTION_STATE_CHANGED: 119d94f6ddab1f088340d197086949409c144ec2b0aJack He // Only pass the message on if the adapter has actually changed state from 120d94f6ddab1f088340d197086949409c144ec2b0aJack He // non-ON to ON. NOTE: ON is the state depicting BREDR ON and not just BLE ON. 121d94f6ddab1f088340d197086949409c144ec2b0aJack He int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); 122d94f6ddab1f088340d197086949409c144ec2b0aJack He if (newState == BluetoothAdapter.STATE_ON) { 123d94f6ddab1f088340d197086949409c144ec2b0aJack He mHandler.obtainMessage(MESSAGE_ADAPTER_STATE_TURNED_ON).sendToTarget(); 124d94f6ddab1f088340d197086949409c144ec2b0aJack He } 125d94f6ddab1f088340d197086949409c144ec2b0aJack He break; 126d94f6ddab1f088340d197086949409c144ec2b0aJack He case BluetoothDevice.ACTION_UUID: 127d94f6ddab1f088340d197086949409c144ec2b0aJack He mHandler.obtainMessage(MESSAGE_PROFILE_INIT_PRIORITIES, intent).sendToTarget(); 128d94f6ddab1f088340d197086949409c144ec2b0aJack He break; 129d94f6ddab1f088340d197086949409c144ec2b0aJack He default: 130d94f6ddab1f088340d197086949409c144ec2b0aJack He Log.e(TAG, "Received unexpected intent, action=" + action); 131d94f6ddab1f088340d197086949409c144ec2b0aJack He break; 13286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 13386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 13486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal }; 13586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 136928f14463ee51192039abef856495ecce418fe01Jack He @VisibleForTesting 137928f14463ee51192039abef856495ecce418fe01Jack He BroadcastReceiver getBroadcastReceiver() { 13886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal return mReceiver; 13986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 14086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 14186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Handler to handoff intents to class thread 14286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal class PhonePolicyHandler extends Handler { 14386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal PhonePolicyHandler(Looper looper) { 14486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal super(looper); 14586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 14686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 14786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal @Override 14886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal public void handleMessage(Message msg) { 14986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal switch (msg.what) { 15086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal case MESSAGE_PROFILE_INIT_PRIORITIES: { 151d94f6ddab1f088340d197086949409c144ec2b0aJack He Intent intent = (Intent) msg.obj; 15286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal BluetoothDevice device = 153d94f6ddab1f088340d197086949409c144ec2b0aJack He intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 154d94f6ddab1f088340d197086949409c144ec2b0aJack He Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID); 155d94f6ddab1f088340d197086949409c144ec2b0aJack He debugLog("Received ACTION_UUID for device " + device); 1560068bdad22ffd70c90de67b6e85c8a0dfa838d90Sanket Agarwal if (uuids != null) { 1570068bdad22ffd70c90de67b6e85c8a0dfa838d90Sanket Agarwal ParcelUuid[] uuidsToSend = new ParcelUuid[uuids.length]; 1580068bdad22ffd70c90de67b6e85c8a0dfa838d90Sanket Agarwal for (int i = 0; i < uuidsToSend.length; i++) { 1590068bdad22ffd70c90de67b6e85c8a0dfa838d90Sanket Agarwal uuidsToSend[i] = (ParcelUuid) uuids[i]; 160d94f6ddab1f088340d197086949409c144ec2b0aJack He debugLog("index=" + i + "uuid=" + uuidsToSend[i]); 1610068bdad22ffd70c90de67b6e85c8a0dfa838d90Sanket Agarwal } 1620068bdad22ffd70c90de67b6e85c8a0dfa838d90Sanket Agarwal processInitProfilePriorities(device, uuidsToSend); 1630068bdad22ffd70c90de67b6e85c8a0dfa838d90Sanket Agarwal } 164c4fbd756e2645147470c486ae96f2253f5e13a52Jack He } 165c4fbd756e2645147470c486ae96f2253f5e13a52Jack He break; 16686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 16786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal case MESSAGE_PROFILE_CONNECTION_STATE_CHANGED: { 16886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal Intent intent = (Intent) msg.obj; 16986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal BluetoothDevice device = 17086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 17186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); 17286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal int nextState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 17386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal processProfileStateChanged(device, msg.arg1, nextState, prevState); 174c4fbd756e2645147470c486ae96f2253f5e13a52Jack He } 175c4fbd756e2645147470c486ae96f2253f5e13a52Jack He break; 17686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 1770c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He case MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED: { 1780c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He Intent intent = (Intent) msg.obj; 1790c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He BluetoothDevice activeDevice = 1800c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 1810c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He processProfileActiveDeviceChanged(activeDevice, msg.arg1); 1820c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 1830c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He break; 1840c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He 185d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He case MESSAGE_CONNECT_OTHER_PROFILES: { 18686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Called when we try connect some profiles in processConnectOtherProfiles but 18786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // we send a delayed message to try connecting the remaining profiles 188d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He BluetoothDevice device = (BluetoothDevice) msg.obj; 189d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He processConnectOtherProfiles(device); 190d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He mConnectOtherProfilesDeviceSet.remove(device); 19186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal break; 192d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He } 19386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal case MESSAGE_ADAPTER_STATE_TURNED_ON: 19486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Call auto connect when adapter switches state to ON 1952cc754651ee7245e62fa247b1ca85acb6889e79eJack He resetStates(); 19686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal autoConnect(); 19786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal break; 19886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 19986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 200c4fbd756e2645147470c486ae96f2253f5e13a52Jack He } 201c4fbd756e2645147470c486ae96f2253f5e13a52Jack He 202c4fbd756e2645147470c486ae96f2253f5e13a52Jack He ; 20386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 20486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Policy API functions for lifecycle management (protected) 20586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal protected void start() { 20686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal IntentFilter filter = new IntentFilter(); 20786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 20886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 20986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal filter.addAction(BluetoothDevice.ACTION_UUID); 21086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 2110c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED); 21286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal mAdapterService.registerReceiver(mReceiver, filter); 21386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 214c4fbd756e2645147470c486ae96f2253f5e13a52Jack He 21586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal protected void cleanup() { 21686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal mAdapterService.unregisterReceiver(mReceiver); 2172cc754651ee7245e62fa247b1ca85acb6889e79eJack He resetStates(); 21886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 21986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 22086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal PhonePolicy(AdapterService service, ServiceFactory factory) { 22186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal mAdapterService = service; 22286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal mFactory = factory; 22386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal mHandler = new PhonePolicyHandler(service.getMainLooper()); 22486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 22586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 22686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Policy implementation, all functions MUST be private 22786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal private void processInitProfilePriorities(BluetoothDevice device, ParcelUuid[] uuids) { 228d94f6ddab1f088340d197086949409c144ec2b0aJack He debugLog("processInitProfilePriorities() - device " + device); 229f0429c92669aa388785a97f00985d63a83e509c2Hansong Zhang HidHostService hidService = mFactory.getHidHostService(); 23086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal A2dpService a2dpService = mFactory.getA2dpService(); 23186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal HeadsetService headsetService = mFactory.getHeadsetService(); 23286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal PanService panService = mFactory.getPanService(); 23309e97f4cfcca3564c8daa864ede0eee172e9d5aaHansong Zhang HearingAidService hearingAidService = mFactory.getHearingAidService(); 23486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 23586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // Set profile priorities only for the profiles discovered on the remote device. 23686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // This avoids needless auto-connect attempts to profiles non-existent on the remote device 237c4fbd756e2645147470c486ae96f2253f5e13a52Jack He if ((hidService != null) && (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) 238c4fbd756e2645147470c486ae96f2253f5e13a52Jack He || BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) && ( 239c4fbd756e2645147470c486ae96f2253f5e13a52Jack He hidService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)) { 24086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal hidService.setPriority(device, BluetoothProfile.PRIORITY_ON); 24186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 24286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 24386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // If we do not have a stored priority for HFP/A2DP (all roles) then default to on. 244c4fbd756e2645147470c486ae96f2253f5e13a52Jack He if ((headsetService != null) && ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP) 245c4fbd756e2645147470c486ae96f2253f5e13a52Jack He || BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree)) && ( 246c4fbd756e2645147470c486ae96f2253f5e13a52Jack He headsetService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED))) { 24786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal headsetService.setPriority(device, BluetoothProfile.PRIORITY_ON); 24886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 24986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 250c4fbd756e2645147470c486ae96f2253f5e13a52Jack He if ((a2dpService != null) && (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink) 251c4fbd756e2645147470c486ae96f2253f5e13a52Jack He || BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AdvAudioDist)) && ( 252c4fbd756e2645147470c486ae96f2253f5e13a52Jack He a2dpService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)) { 25386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON); 25486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 25586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 256c4fbd756e2645147470c486ae96f2253f5e13a52Jack He if ((panService != null) && (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU) && ( 257c4fbd756e2645147470c486ae96f2253f5e13a52Jack He panService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED) 258c4fbd756e2645147470c486ae96f2253f5e13a52Jack He && mAdapterService.getResources() 259c4fbd756e2645147470c486ae96f2253f5e13a52Jack He .getBoolean(R.bool.config_bluetooth_pan_enable_autoconnect))) { 26086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal panService.setPriority(device, BluetoothProfile.PRIORITY_ON); 26186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 26209e97f4cfcca3564c8daa864ede0eee172e9d5aaHansong Zhang 2630c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if ((hearingAidService != null) && BluetoothUuid.isUuidPresent(uuids, 2640c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He BluetoothUuid.HearingAid) && (hearingAidService.getPriority(device) 2650c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He == BluetoothProfile.PRIORITY_UNDEFINED)) { 26609e97f4cfcca3564c8daa864ede0eee172e9d5aaHansong Zhang debugLog("setting hearing aid profile priority for device " + device); 26709e97f4cfcca3564c8daa864ede0eee172e9d5aaHansong Zhang hearingAidService.setPriority(device, BluetoothProfile.PRIORITY_ON); 26809e97f4cfcca3564c8daa864ede0eee172e9d5aaHansong Zhang } 26986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 27086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 271c4fbd756e2645147470c486ae96f2253f5e13a52Jack He private void processProfileStateChanged(BluetoothDevice device, int profileId, int nextState, 272c4fbd756e2645147470c486ae96f2253f5e13a52Jack He int prevState) { 273d94f6ddab1f088340d197086949409c144ec2b0aJack He debugLog("processProfileStateChanged, device=" + device + ", profile=" + profileId + ", " 274d94f6ddab1f088340d197086949409c144ec2b0aJack He + prevState + " -> " + nextState); 275d8ae37693406af4fa2633092ec9500a484933a9eJack He if (((profileId == BluetoothProfile.A2DP) || (profileId == BluetoothProfile.HEADSET))) { 276d8ae37693406af4fa2633092ec9500a484933a9eJack He if (nextState == BluetoothProfile.STATE_CONNECTED) { 277d8ae37693406af4fa2633092ec9500a484933a9eJack He switch (profileId) { 278d8ae37693406af4fa2633092ec9500a484933a9eJack He case BluetoothProfile.A2DP: 279d8ae37693406af4fa2633092ec9500a484933a9eJack He mA2dpRetrySet.remove(device); 280d8ae37693406af4fa2633092ec9500a484933a9eJack He break; 281d8ae37693406af4fa2633092ec9500a484933a9eJack He case BluetoothProfile.HEADSET: 282d8ae37693406af4fa2633092ec9500a484933a9eJack He mHeadsetRetrySet.remove(device); 283d8ae37693406af4fa2633092ec9500a484933a9eJack He break; 284d8ae37693406af4fa2633092ec9500a484933a9eJack He } 285d8ae37693406af4fa2633092ec9500a484933a9eJack He connectOtherProfile(device); 286d8ae37693406af4fa2633092ec9500a484933a9eJack He } 287d8ae37693406af4fa2633092ec9500a484933a9eJack He if (prevState == BluetoothProfile.STATE_CONNECTING 288d8ae37693406af4fa2633092ec9500a484933a9eJack He && nextState == BluetoothProfile.STATE_DISCONNECTED) { 2890c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He HeadsetService hsService = mFactory.getHeadsetService(); 2900c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He boolean hsDisconnected = hsService == null || hsService.getConnectionState(device) 2910c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He == BluetoothProfile.STATE_DISCONNECTED; 2920c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He A2dpService a2dpService = mFactory.getA2dpService(); 2930c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He boolean a2dpDisconnected = a2dpService == null 2940c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He || a2dpService.getConnectionState(device) 2950c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He == BluetoothProfile.STATE_DISCONNECTED; 2960c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("processProfileStateChanged, device=" + device + ", a2dpDisconnected=" 2970c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He + a2dpDisconnected + ", hsDisconnected=" + hsDisconnected); 2980c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (hsDisconnected && a2dpDisconnected) { 2990c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He removeAutoConnectFromA2dpSink(device); 3000c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He removeAutoConnectFromHeadset(device); 3010c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 3022cc754651ee7245e62fa247b1ca85acb6889e79eJack He } 3030c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 3040c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 305d8ae37693406af4fa2633092ec9500a484933a9eJack He 3060c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He private void processProfileActiveDeviceChanged(BluetoothDevice activeDevice, int profileId) { 3070c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("processProfileActiveDeviceChanged, activeDevice=" + activeDevice + ", profile=" 3080c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He + profileId); 3090c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He switch (profileId) { 3100c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He // Tracking active device changed intent only for A2DP so that we always connect to a 3110c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He // single device after toggling Bluetooth 3120c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He case BluetoothProfile.A2DP: 3130c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He // Ignore null active device since we don't know if the change is triggered by 3140c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He // normal device disconnection during Bluetooth shutdown or user action 3150c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (activeDevice == null) { 3160c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He warnLog("processProfileActiveDeviceChanged: ignore null A2DP active device"); 3170c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He return; 3180c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 3190c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He for (BluetoothDevice device : mAdapterService.getBondedDevices()) { 3200c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He removeAutoConnectFromA2dpSink(device); 3210c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He removeAutoConnectFromHeadset(device); 3220c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 3230c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He setAutoConnectForA2dpSink(activeDevice); 3240c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He setAutoConnectForHeadset(activeDevice); 3250c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He break; 32686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 32786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 32886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 3292cc754651ee7245e62fa247b1ca85acb6889e79eJack He private void resetStates() { 3302cc754651ee7245e62fa247b1ca85acb6889e79eJack He mHeadsetRetrySet.clear(); 3312cc754651ee7245e62fa247b1ca85acb6889e79eJack He mA2dpRetrySet.clear(); 3322cc754651ee7245e62fa247b1ca85acb6889e79eJack He } 3332cc754651ee7245e62fa247b1ca85acb6889e79eJack He 33486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal private void autoConnect() { 33586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) { 3360c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He errorLog("autoConnect: BT is not ON. Exiting autoConnect"); 33786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal return; 33886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 33986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 340d94f6ddab1f088340d197086949409c144ec2b0aJack He if (!mAdapterService.isQuietModeEnabled()) { 3410c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("autoConnect: Initiate auto connection on BT on..."); 3420c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices(); 3430c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (bondedDevices == null) { 3440c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He errorLog("autoConnect: bondedDevices are null"); 3450c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He return; 3460c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 3470c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He for (BluetoothDevice device : bondedDevices) { 3480c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He autoConnectHeadset(device); 3490c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He autoConnectA2dp(device); 3500c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 35186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } else { 35286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal debugLog("autoConnect() - BT is in quiet mode. Not initiating auto connections"); 35386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 35486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 35586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 3560c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He private void autoConnectA2dp(BluetoothDevice device) { 3570c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He final A2dpService a2dpService = mFactory.getA2dpService(); 3580c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (a2dpService == null) { 3590c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He warnLog("autoConnectA2dp: service is null, failed to connect to " + device); 36086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal return; 36186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 3620c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He int a2dpPriority = a2dpService.getPriority(device); 3630c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (a2dpPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) { 3640c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("autoConnectA2dp: connecting A2DP with " + device); 3650c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He a2dpService.connect(device); 3660c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } else { 3670c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("autoConnectA2dp: skipped auto-connect A2DP with device " + device 3680c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He + " priority " + a2dpPriority); 36986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 37086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 37186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 3720c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He private void autoConnectHeadset(BluetoothDevice device) { 3730c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He final HeadsetService hsService = mFactory.getHeadsetService(); 3740c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (hsService == null) { 3750c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He warnLog("autoConnectHeadset: service is null, failed to connect to " + device); 37686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal return; 37786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 3780c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He int headsetPriority = hsService.getPriority(device); 3790c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (headsetPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) { 3800c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("autoConnectHeadset: Connecting HFP with " + device); 3810c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He hsService.connect(device); 3820c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } else { 3830c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("autoConnectHeadset: skipped auto-connect HFP with device " + device 3840c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He + " priority " + headsetPriority); 38586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 38686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 38786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 388d94f6ddab1f088340d197086949409c144ec2b0aJack He private void connectOtherProfile(BluetoothDevice device) { 389d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He if (mAdapterService.isQuietModeEnabled()) { 390d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He debugLog("connectOtherProfile: in quiet mode, skip connect other profile " + device); 391d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He return; 392d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He } 393d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He if (mConnectOtherProfilesDeviceSet.contains(device)) { 394d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He debugLog("connectOtherProfile: already scheduled callback for " + device); 395d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He return; 39686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 397d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He mConnectOtherProfilesDeviceSet.add(device); 398d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He Message m = mHandler.obtainMessage(MESSAGE_CONNECT_OTHER_PROFILES); 399d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He m.obj = device; 400d617142a6e7567c6ae46fbbbebb58e14900cb3a1Jack He mHandler.sendMessageDelayed(m, sConnectOtherProfilesTimeoutMillis); 40186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 40286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 40386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // This function is called whenever a profile is connected. This allows any other bluetooth 40486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // profiles which are not already connected or in the process of connecting to attempt to 40586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // connect to the device that initiated the connection. In the event that this function is 40686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal // invoked and there are no current bluetooth connections no new profiles will be connected. 40786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal private void processConnectOtherProfiles(BluetoothDevice device) { 408d94f6ddab1f088340d197086949409c144ec2b0aJack He debugLog("processConnectOtherProfiles, device=" + device); 40986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) { 410d94f6ddab1f088340d197086949409c144ec2b0aJack He warnLog("processConnectOtherProfiles, adapter is not ON " + mAdapterService.getState()); 41186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal return; 41286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 41386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal HeadsetService hsService = mFactory.getHeadsetService(); 41486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal A2dpService a2dpService = mFactory.getA2dpService(); 41586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal PanService panService = mFactory.getPanService(); 41686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 4173cc3ca76069837340db03751e64b6df230e5d8ccJack He boolean atLeastOneProfileConnectedForDevice = false; 41886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal boolean allProfilesEmpty = true; 41986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal List<BluetoothDevice> a2dpConnDevList = null; 42086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal List<BluetoothDevice> hsConnDevList = null; 42186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal List<BluetoothDevice> panConnDevList = null; 42286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 42386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal if (hsService != null) { 42486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal hsConnDevList = hsService.getConnectedDevices(); 4253cc3ca76069837340db03751e64b6df230e5d8ccJack He allProfilesEmpty &= hsConnDevList.isEmpty(); 4263cc3ca76069837340db03751e64b6df230e5d8ccJack He atLeastOneProfileConnectedForDevice |= hsConnDevList.contains(device); 42786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 42886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal if (a2dpService != null) { 42986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal a2dpConnDevList = a2dpService.getConnectedDevices(); 4303cc3ca76069837340db03751e64b6df230e5d8ccJack He allProfilesEmpty &= a2dpConnDevList.isEmpty(); 4313cc3ca76069837340db03751e64b6df230e5d8ccJack He atLeastOneProfileConnectedForDevice |= a2dpConnDevList.contains(device); 43286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 43386c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal if (panService != null) { 43486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal panConnDevList = panService.getConnectedDevices(); 4353cc3ca76069837340db03751e64b6df230e5d8ccJack He allProfilesEmpty &= panConnDevList.isEmpty(); 4363cc3ca76069837340db03751e64b6df230e5d8ccJack He atLeastOneProfileConnectedForDevice |= panConnDevList.contains(device); 43786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 43886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 4393cc3ca76069837340db03751e64b6df230e5d8ccJack He if (!atLeastOneProfileConnectedForDevice) { 4403cc3ca76069837340db03751e64b6df230e5d8ccJack He // Consider this device as fully disconnected, don't bother connecting others 441d94f6ddab1f088340d197086949409c144ec2b0aJack He debugLog("processConnectOtherProfiles, all profiles disconnected for " + device); 4423cc3ca76069837340db03751e64b6df230e5d8ccJack He mHeadsetRetrySet.remove(device); 4433cc3ca76069837340db03751e64b6df230e5d8ccJack He mA2dpRetrySet.remove(device); 4443cc3ca76069837340db03751e64b6df230e5d8ccJack He if (allProfilesEmpty) { 4453cc3ca76069837340db03751e64b6df230e5d8ccJack He debugLog("processConnectOtherProfiles, all profiles disconnected for all devices"); 4463cc3ca76069837340db03751e64b6df230e5d8ccJack He // reset retry status so that in the next round we can start retrying connections 4473cc3ca76069837340db03751e64b6df230e5d8ccJack He resetStates(); 4483cc3ca76069837340db03751e64b6df230e5d8ccJack He } 44986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal return; 45086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 45186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 45286c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal if (hsService != null) { 4533cc3ca76069837340db03751e64b6df230e5d8ccJack He if (!mHeadsetRetrySet.contains(device) && (hsService.getPriority(device) 4543cc3ca76069837340db03751e64b6df230e5d8ccJack He >= BluetoothProfile.PRIORITY_ON) && (hsService.getConnectionState(device) 4553cc3ca76069837340db03751e64b6df230e5d8ccJack He == BluetoothProfile.STATE_DISCONNECTED)) { 456d94f6ddab1f088340d197086949409c144ec2b0aJack He debugLog("Retrying connection to Headset with device " + device); 4572cc754651ee7245e62fa247b1ca85acb6889e79eJack He mHeadsetRetrySet.add(device); 45886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal hsService.connect(device); 45986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 46086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 46186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal if (a2dpService != null) { 4623cc3ca76069837340db03751e64b6df230e5d8ccJack He if (!mA2dpRetrySet.contains(device) && (a2dpService.getPriority(device) 4633cc3ca76069837340db03751e64b6df230e5d8ccJack He >= BluetoothProfile.PRIORITY_ON) && (a2dpService.getConnectionState(device) 4643cc3ca76069837340db03751e64b6df230e5d8ccJack He == BluetoothProfile.STATE_DISCONNECTED)) { 46586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal debugLog("Retrying connection to A2DP with device " + device); 4662cc754651ee7245e62fa247b1ca85acb6889e79eJack He mA2dpRetrySet.add(device); 46786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal a2dpService.connect(device); 46886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 46986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 47086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal if (panService != null) { 47144ef48a20624b290ae614af344c802d6e749eba2Pavlin Radoslavov // TODO: the panConnDevList.isEmpty() check below should be removed once 47244ef48a20624b290ae614af344c802d6e749eba2Pavlin Radoslavov // Multi-PAN is supported. 473c4fbd756e2645147470c486ae96f2253f5e13a52Jack He if (panConnDevList.isEmpty() && (panService.getPriority(device) 474c4fbd756e2645147470c486ae96f2253f5e13a52Jack He >= BluetoothProfile.PRIORITY_ON) && (panService.getConnectionState(device) 475c4fbd756e2645147470c486ae96f2253f5e13a52Jack He == BluetoothProfile.STATE_DISCONNECTED)) { 476d94f6ddab1f088340d197086949409c144ec2b0aJack He debugLog("Retrying connection to PAN with device " + device); 47786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal panService.connect(device); 47886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 47986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 48086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 48186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 4820c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He /** 4830c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * Set a device's headset profile priority to PRIORITY_AUTO_CONNECT if device support that 4840c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * profile 4850c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * 4860c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT 4870c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He */ 4880c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He private void setAutoConnectForHeadset(BluetoothDevice device) { 4890c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He HeadsetService hsService = mFactory.getHeadsetService(); 4900c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (hsService == null) { 4910c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He warnLog("setAutoConnectForHeadset: HEADSET service is null"); 4920c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He return; 4930c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 4940c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) { 4950c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("setAutoConnectForHeadset: device " + device + " PRIORITY_AUTO_CONNECT"); 4960c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He hsService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT); 49786c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 49886c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 49986c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 5000c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He /** 5010c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * Set a device's A2DP profile priority to PRIORITY_AUTO_CONNECT if device support that profile 5020c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * 5030c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT 5040c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He */ 5050c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He private void setAutoConnectForA2dpSink(BluetoothDevice device) { 5060c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He A2dpService a2dpService = mFactory.getA2dpService(); 5070c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (a2dpService == null) { 5080c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He warnLog("setAutoConnectForA2dpSink: A2DP service is null"); 5090c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He return; 5100c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 5110c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) { 5120c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("setAutoConnectForA2dpSink: device " + device + " PRIORITY_AUTO_CONNECT"); 5130c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He a2dpService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT); 51486c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 51586c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 51686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal 5170c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He /** 5180c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * Remove PRIORITY_AUTO_CONNECT from all headsets and set headset that used to have 5190c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * PRIORITY_AUTO_CONNECT to PRIORITY_ON 5200c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * 5210c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed 5220c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He */ 5230c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He private void removeAutoConnectFromHeadset(BluetoothDevice device) { 5240c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He HeadsetService hsService = mFactory.getHeadsetService(); 5250c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (hsService == null) { 5260c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He warnLog("removeAutoConnectFromHeadset: HEADSET service is null"); 5270c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He return; 5280c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 5290c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT) { 5300c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("removeAutoConnectFromHeadset: device " + device + " PRIORITY_ON"); 5310c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He hsService.setPriority(device, BluetoothProfile.PRIORITY_ON); 5320c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 5330c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 5340c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He 5350c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He /** 5360c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * Remove PRIORITY_AUTO_CONNECT from all A2DP sinks and set A2DP sink that used to have 5370c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * PRIORITY_AUTO_CONNECT to PRIORITY_ON 5380c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * 5390c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed 5400c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He */ 5410c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He private void removeAutoConnectFromA2dpSink(BluetoothDevice device) { 5420c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He A2dpService a2dpService = mFactory.getA2dpService(); 5430c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (a2dpService == null) { 5440c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He warnLog("removeAutoConnectFromA2dpSink: A2DP service is null"); 5450c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He return; 5460c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He } 5470c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT) { 5480c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He debugLog("removeAutoConnectFromA2dpSink: device " + device + " PRIORITY_ON"); 5490c3e89e90ff670dd4356e9e31565e15aaea3abc9Jack He a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON); 55086c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 55186c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal } 552d94f6ddab1f088340d197086949409c144ec2b0aJack He 553d94f6ddab1f088340d197086949409c144ec2b0aJack He private static void debugLog(String msg) { 554c4fbd756e2645147470c486ae96f2253f5e13a52Jack He if (DBG) { 55509e97f4cfcca3564c8daa864ede0eee172e9d5aaHansong Zhang Log.i(TAG, msg); 556c4fbd756e2645147470c486ae96f2253f5e13a52Jack He } 557d94f6ddab1f088340d197086949409c144ec2b0aJack He } 558d94f6ddab1f088340d197086949409c144ec2b0aJack He 559d94f6ddab1f088340d197086949409c144ec2b0aJack He private static void warnLog(String msg) { 560d94f6ddab1f088340d197086949409c144ec2b0aJack He Log.w(TAG, msg); 561d94f6ddab1f088340d197086949409c144ec2b0aJack He } 562d94f6ddab1f088340d197086949409c144ec2b0aJack He 563d94f6ddab1f088340d197086949409c144ec2b0aJack He private static void errorLog(String msg) { 564d94f6ddab1f088340d197086949409c144ec2b0aJack He Log.e(TAG, msg); 565d94f6ddab1f088340d197086949409c144ec2b0aJack He } 56686c29fe88456bdcfbd4334647b04ef81ff384a06Sanket Agarwal} 567