1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.settings.bluetooth;
17 
18 import android.app.settings.SettingsEnums;
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothDevice;
21 import android.content.Context;
22 import android.util.Log;
23 
24 import androidx.annotation.VisibleForTesting;
25 import androidx.preference.Preference;
26 
27 import com.android.settings.connecteddevice.DevicePreferenceCallback;
28 import com.android.settingslib.bluetooth.BluetoothUtils;
29 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
30 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
31 import com.android.settingslib.flags.Flags;
32 
33 import java.util.ArrayList;
34 import java.util.List;
35 
36 /**
37  * Maintain and update saved bluetooth devices(bonded but not connected)
38  */
39 public class SavedBluetoothDeviceUpdater extends BluetoothDeviceUpdater
40         implements Preference.OnPreferenceClickListener {
41 
42     private static final String TAG = "SavedBluetoothDeviceUpdater";
43 
44     private static final String PREF_KEY = "saved_bt";
45 
46     private final boolean mShowConnectedDevice;
47 
48     @VisibleForTesting
49     BluetoothAdapter mBluetoothAdapter;
50 
SavedBluetoothDeviceUpdater(Context context, DevicePreferenceCallback devicePreferenceCallback, boolean showConnectedDevice, int metricsCategory)51     public SavedBluetoothDeviceUpdater(Context context,
52             DevicePreferenceCallback devicePreferenceCallback, boolean showConnectedDevice,
53             int metricsCategory) {
54         super(context, devicePreferenceCallback, metricsCategory);
55         mShowConnectedDevice = showConnectedDevice;
56         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
57     }
58 
59     @Override
forceUpdate()60     public void forceUpdate() {
61         if (mBluetoothAdapter.isEnabled()) {
62             final CachedBluetoothDeviceManager cachedManager =
63                     mLocalManager.getCachedDeviceManager();
64             final List<BluetoothDevice> bluetoothDevices =
65                     mBluetoothAdapter.getMostRecentlyConnectedDevices();
66             removePreferenceIfNecessary(bluetoothDevices, cachedManager);
67             for (BluetoothDevice device : bluetoothDevices) {
68                 final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device);
69                 if (cachedDevice != null && !cachedManager.isSubDevice(device)) {
70                     update(cachedDevice);
71                 }
72             }
73         } else {
74             removeAllDevicesFromPreference();
75         }
76     }
77 
removePreferenceIfNecessary(List<BluetoothDevice> bluetoothDevices, CachedBluetoothDeviceManager cachedManager)78     private void removePreferenceIfNecessary(List<BluetoothDevice> bluetoothDevices,
79             CachedBluetoothDeviceManager cachedManager) {
80         for (BluetoothDevice device : new ArrayList<>(mPreferenceMap.keySet())) {
81             if (!bluetoothDevices.contains(device)) {
82                 final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device);
83                 if (cachedDevice != null) {
84                     removePreference(cachedDevice);
85                 }
86             }
87         }
88     }
89 
90     @Override
update(CachedBluetoothDevice cachedDevice)91     public void update(CachedBluetoothDevice cachedDevice) {
92         if (isFilterMatched(cachedDevice)) {
93             // Add the preference if it is new one
94             addPreference(cachedDevice, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
95         } else {
96             removePreference(cachedDevice);
97         }
98         Log.d(TAG, "Map : " + mPreferenceMap);
99     }
100 
101     @Override
isFilterMatched(CachedBluetoothDevice cachedDevice)102     public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
103         final BluetoothDevice device = cachedDevice.getDevice();
104         boolean isExclusivelyManaged = BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
105                 cachedDevice.getDevice());
106         Log.d(TAG, "isFilterMatched() device name : " + cachedDevice.getName()
107                 + ", is connected : " + device.isConnected() + ", is profile connected : "
108                 + cachedDevice.isConnected() + ", is exclusively managed : "
109                 + isExclusivelyManaged);
110         if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
111             return device.getBondState() == BluetoothDevice.BOND_BONDED
112                     && (mShowConnectedDevice || (!device.isConnected()
113                     && isDeviceInCachedDevicesList(cachedDevice)))
114                     && !isExclusivelyManaged;
115         } else {
116             return device.getBondState() == BluetoothDevice.BOND_BONDED
117                     && (mShowConnectedDevice || (!device.isConnected()
118                     && isDeviceInCachedDevicesList(cachedDevice)));
119         }
120     }
121 
122     @Override
onPreferenceClick(Preference preference)123     public boolean onPreferenceClick(Preference preference) {
124         mMetricsFeatureProvider.logClickedPreference(preference, mMetricsCategory);
125         final CachedBluetoothDevice device = ((BluetoothDevicePreference) preference)
126                 .getBluetoothDevice();
127         if (device.isConnected()) {
128             return device.setActive();
129         }
130         mMetricsFeatureProvider.action(mPrefContext,
131                 SettingsEnums.ACTION_SETTINGS_BLUETOOTH_CONNECT);
132         device.connect();
133         return true;
134     }
135 
136     @Override
getPreferenceKey()137     protected String getPreferenceKey() {
138         return PREF_KEY;
139     }
140 
141     @Override
getLogTag()142     protected String getLogTag() {
143         return TAG;
144     }
145 }
146