• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.bluetooth;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothDevice;
21 import android.os.Bundle;
22 import android.os.SystemProperties;
23 import android.support.annotation.VisibleForTesting;
24 import android.support.v7.preference.Preference;
25 import android.support.v7.preference.PreferenceCategory;
26 import android.support.v7.preference.PreferenceGroup;
27 import android.text.BidiFormatter;
28 import android.util.Log;
29 
30 import com.android.settings.R;
31 import com.android.settings.dashboard.RestrictedDashboardFragment;
32 import com.android.settingslib.bluetooth.BluetoothCallback;
33 import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
34 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
35 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
36 import com.android.settingslib.bluetooth.LocalBluetoothManager;
37 
38 import java.util.Collection;
39 import java.util.WeakHashMap;
40 
41 /**
42  * Parent class for settings fragments that contain a list of Bluetooth
43  * devices.
44  *
45  * @see DevicePickerFragment
46  */
47 // TODO: Refactor this fragment
48 public abstract class DeviceListPreferenceFragment extends
49         RestrictedDashboardFragment implements BluetoothCallback {
50 
51     private static final String TAG = "DeviceListPreferenceFragment";
52 
53     private static final String KEY_BT_SCAN = "bt_scan";
54 
55     // Copied from BluetoothDeviceNoNamePreferenceController.java
56     private static final String BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY =
57             "persist.bluetooth.showdeviceswithoutnames";
58 
59     private BluetoothDeviceFilter.Filter mFilter;
60 
61     @VisibleForTesting
62     boolean mScanEnabled;
63 
64     BluetoothDevice mSelectedDevice;
65 
66     LocalBluetoothAdapter mLocalAdapter;
67     LocalBluetoothManager mLocalManager;
68 
69     @VisibleForTesting
70     PreferenceGroup mDeviceListGroup;
71 
72     final WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
73             new WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference>();
74 
75     boolean mShowDevicesWithoutNames;
76 
DeviceListPreferenceFragment(String restrictedKey)77     DeviceListPreferenceFragment(String restrictedKey) {
78         super(restrictedKey);
79         mFilter = BluetoothDeviceFilter.ALL_FILTER;
80     }
81 
setFilter(BluetoothDeviceFilter.Filter filter)82     final void setFilter(BluetoothDeviceFilter.Filter filter) {
83         mFilter = filter;
84     }
85 
setFilter(int filterType)86     final void setFilter(int filterType) {
87         mFilter = BluetoothDeviceFilter.getFilter(filterType);
88     }
89 
90     @Override
onCreate(Bundle savedInstanceState)91     public void onCreate(Bundle savedInstanceState) {
92         super.onCreate(savedInstanceState);
93 
94         mLocalManager = Utils.getLocalBtManager(getActivity());
95         if (mLocalManager == null) {
96             Log.e(TAG, "Bluetooth is not supported on this device");
97             return;
98         }
99         mLocalAdapter = mLocalManager.getBluetoothAdapter();
100         mShowDevicesWithoutNames = SystemProperties.getBoolean(
101                 BLUETOOTH_SHOW_DEVICES_WITHOUT_NAMES_PROPERTY, false);
102 
103         initPreferencesFromPreferenceScreen();
104 
105         mDeviceListGroup = (PreferenceCategory) findPreference(getDeviceListKey());
106     }
107 
108     /** find and update preference that already existed in preference screen */
initPreferencesFromPreferenceScreen()109     abstract void initPreferencesFromPreferenceScreen();
110 
111     @Override
onStart()112     public void onStart() {
113         super.onStart();
114         if (mLocalManager == null || isUiRestricted()) return;
115 
116         mLocalManager.setForegroundActivity(getActivity());
117         mLocalManager.getEventManager().registerCallback(this);
118     }
119 
120     @Override
onStop()121     public void onStop() {
122         super.onStop();
123         if (mLocalManager == null || isUiRestricted()) {
124             return;
125         }
126 
127         removeAllDevices();
128         mLocalManager.setForegroundActivity(null);
129         mLocalManager.getEventManager().unregisterCallback(this);
130     }
131 
removeAllDevices()132     void removeAllDevices() {
133         mDevicePreferenceMap.clear();
134         mDeviceListGroup.removeAll();
135     }
136 
addCachedDevices()137     void addCachedDevices() {
138         Collection<CachedBluetoothDevice> cachedDevices =
139                 mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
140         for (CachedBluetoothDevice cachedDevice : cachedDevices) {
141             onDeviceAdded(cachedDevice);
142         }
143     }
144 
145     @Override
onPreferenceTreeClick(Preference preference)146     public boolean onPreferenceTreeClick(Preference preference) {
147         if (KEY_BT_SCAN.equals(preference.getKey())) {
148             mLocalAdapter.startScanning(true);
149             return true;
150         }
151 
152         if (preference instanceof BluetoothDevicePreference) {
153             BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;
154             CachedBluetoothDevice device = btPreference.getCachedDevice();
155             mSelectedDevice = device.getDevice();
156             onDevicePreferenceClick(btPreference);
157             return true;
158         }
159 
160         return super.onPreferenceTreeClick(preference);
161     }
162 
onDevicePreferenceClick(BluetoothDevicePreference btPreference)163     void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
164         btPreference.onClicked();
165     }
166 
167     @Override
onDeviceAdded(CachedBluetoothDevice cachedDevice)168     public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
169         if (mDevicePreferenceMap.get(cachedDevice) != null) {
170             return;
171         }
172 
173         // Prevent updates while the list shows one of the state messages
174         if (mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;
175 
176         if (mFilter.matches(cachedDevice.getDevice())) {
177             createDevicePreference(cachedDevice);
178         }
179     }
180 
createDevicePreference(CachedBluetoothDevice cachedDevice)181     void createDevicePreference(CachedBluetoothDevice cachedDevice) {
182         if (mDeviceListGroup == null) {
183             Log.w(TAG, "Trying to create a device preference before the list group/category "
184                     + "exists!");
185             return;
186         }
187 
188         String key = cachedDevice.getDevice().getAddress();
189         BluetoothDevicePreference preference = (BluetoothDevicePreference) getCachedPreference(key);
190 
191         if (preference == null) {
192             preference = new BluetoothDevicePreference(getPrefContext(), cachedDevice,
193                     mShowDevicesWithoutNames);
194             preference.setKey(key);
195             mDeviceListGroup.addPreference(preference);
196         } else {
197             // Tell the preference it is being re-used in case there is new info in the
198             // cached device.
199             preference.rebind();
200         }
201 
202         initDevicePreference(preference);
203         mDevicePreferenceMap.put(cachedDevice, preference);
204     }
205 
initDevicePreference(BluetoothDevicePreference preference)206     void initDevicePreference(BluetoothDevicePreference preference) {
207         // Does nothing by default
208     }
209 
210     @VisibleForTesting
updateFooterPreference(Preference myDevicePreference)211     void updateFooterPreference(Preference myDevicePreference) {
212         final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
213 
214         myDevicePreference.setTitle(getString(
215                 R.string.bluetooth_footer_mac_message,
216                 bidiFormatter.unicodeWrap(mLocalAdapter.getAddress())));
217     }
218 
219     @Override
onDeviceDeleted(CachedBluetoothDevice cachedDevice)220     public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
221         BluetoothDevicePreference preference = mDevicePreferenceMap.remove(cachedDevice);
222         if (preference != null) {
223             mDeviceListGroup.removePreference(preference);
224         }
225     }
226 
227     @VisibleForTesting
enableScanning()228     void enableScanning() {
229         // LocalBluetoothAdapter already handles repeated scan requests
230         mLocalAdapter.startScanning(true);
231         mScanEnabled = true;
232     }
233 
234     @VisibleForTesting
disableScanning()235     void disableScanning() {
236         mLocalAdapter.stopScanning();
237         mScanEnabled = false;
238     }
239 
240     @Override
onScanningStateChanged(boolean started)241     public void onScanningStateChanged(boolean started) {
242         if (!started && mScanEnabled) {
243             mLocalAdapter.startScanning(true);
244         }
245     }
246 
247     @Override
onBluetoothStateChanged(int bluetoothState)248     public void onBluetoothStateChanged(int bluetoothState) {}
249 
250     /**
251      * Add bluetooth device preferences to {@code preferenceGroup} which satisfy the {@code filter}
252      *
253      * This method will also (1) set the title for {@code preferenceGroup} and (2) change the
254      * default preferenceGroup and filter
255      * @param preferenceGroup
256      * @param titleId
257      * @param filter
258      * @param addCachedDevices
259      */
addDeviceCategory(PreferenceGroup preferenceGroup, int titleId, BluetoothDeviceFilter.Filter filter, boolean addCachedDevices)260     public void addDeviceCategory(PreferenceGroup preferenceGroup, int titleId,
261             BluetoothDeviceFilter.Filter filter, boolean addCachedDevices) {
262         cacheRemoveAllPrefs(preferenceGroup);
263         preferenceGroup.setTitle(titleId);
264         mDeviceListGroup = preferenceGroup;
265         setFilter(filter);
266         if (addCachedDevices) {
267             addCachedDevices();
268         }
269         preferenceGroup.setEnabled(true);
270         removeCachedPrefs(preferenceGroup);
271     }
272 
onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state)273     public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
274 
275     @Override
onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile)276     public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { }
277 
278     @Override
onAudioModeChanged()279     public void onAudioModeChanged() { }
280 
281     /**
282      * Return the key of the {@link PreferenceGroup} that contains the bluetooth devices
283      */
getDeviceListKey()284     public abstract String getDeviceListKey();
285 
shouldShowDevicesWithoutNames()286     public boolean shouldShowDevicesWithoutNames() {
287         return mShowDevicesWithoutNames;
288     }
289 }
290