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.support.v7.preference.Preference;
23 import android.support.v7.preference.PreferenceCategory;
24 import android.support.v7.preference.PreferenceGroup;
25 import android.util.Log;
26 
27 import com.android.settings.RestrictedSettingsFragment;
28 import com.android.settingslib.bluetooth.BluetoothCallback;
29 import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
30 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
31 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
32 import com.android.settingslib.bluetooth.LocalBluetoothManager;
33 
34 import java.util.Collection;
35 import java.util.WeakHashMap;
36 
37 /**
38  * Parent class for settings fragments that contain a list of Bluetooth
39  * devices.
40  *
41  * @see BluetoothSettings
42  * @see DevicePickerFragment
43  */
44 public abstract class DeviceListPreferenceFragment extends
45         RestrictedSettingsFragment implements BluetoothCallback {
46 
47     private static final String TAG = "DeviceListPreferenceFragment";
48 
49     private static final String KEY_BT_DEVICE_LIST = "bt_device_list";
50     private static final String KEY_BT_SCAN = "bt_scan";
51 
52     private BluetoothDeviceFilter.Filter mFilter;
53 
54     BluetoothDevice mSelectedDevice;
55 
56     LocalBluetoothAdapter mLocalAdapter;
57     LocalBluetoothManager mLocalManager;
58 
59     private PreferenceGroup mDeviceListGroup;
60 
61     final WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference> mDevicePreferenceMap =
62             new WeakHashMap<CachedBluetoothDevice, BluetoothDevicePreference>();
63 
DeviceListPreferenceFragment(String restrictedKey)64     DeviceListPreferenceFragment(String restrictedKey) {
65         super(restrictedKey);
66         mFilter = BluetoothDeviceFilter.ALL_FILTER;
67     }
68 
setFilter(BluetoothDeviceFilter.Filter filter)69     final void setFilter(BluetoothDeviceFilter.Filter filter) {
70         mFilter = filter;
71     }
72 
setFilter(int filterType)73     final void setFilter(int filterType) {
74         mFilter = BluetoothDeviceFilter.getFilter(filterType);
75     }
76 
77     @Override
onCreate(Bundle savedInstanceState)78     public void onCreate(Bundle savedInstanceState) {
79         super.onCreate(savedInstanceState);
80 
81         mLocalManager = Utils.getLocalBtManager(getActivity());
82         if (mLocalManager == null) {
83             Log.e(TAG, "Bluetooth is not supported on this device");
84             return;
85         }
86         mLocalAdapter = mLocalManager.getBluetoothAdapter();
87 
88         addPreferencesForActivity();
89 
90         mDeviceListGroup = (PreferenceCategory) findPreference(KEY_BT_DEVICE_LIST);
91     }
92 
setDeviceListGroup(PreferenceGroup preferenceGroup)93     void setDeviceListGroup(PreferenceGroup preferenceGroup) {
94         mDeviceListGroup = preferenceGroup;
95     }
96 
97     /** Add preferences from the subclass. */
addPreferencesForActivity()98     abstract void addPreferencesForActivity();
99 
100     @Override
onStart()101     public void onStart() {
102         super.onStart();
103         if (mLocalManager == null || isUiRestricted()) return;
104 
105         mLocalManager.setForegroundActivity(getActivity());
106         mLocalManager.getEventManager().registerCallback(this);
107 
108         updateProgressUi(mLocalAdapter.isDiscovering());
109     }
110 
111     @Override
onStop()112     public void onStop() {
113         super.onStop();
114         if (mLocalManager == null || isUiRestricted()) {
115             return;
116         }
117 
118         removeAllDevices();
119         mLocalManager.setForegroundActivity(null);
120         mLocalManager.getEventManager().unregisterCallback(this);
121     }
122 
removeAllDevices()123     void removeAllDevices() {
124         mLocalAdapter.stopScanning();
125         mDevicePreferenceMap.clear();
126         mDeviceListGroup.removeAll();
127     }
128 
addCachedDevices()129     void addCachedDevices() {
130         Collection<CachedBluetoothDevice> cachedDevices =
131                 mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
132         for (CachedBluetoothDevice cachedDevice : cachedDevices) {
133             onDeviceAdded(cachedDevice);
134         }
135     }
136 
137     @Override
onPreferenceTreeClick(Preference preference)138     public boolean onPreferenceTreeClick(Preference preference) {
139         if (KEY_BT_SCAN.equals(preference.getKey())) {
140             mLocalAdapter.startScanning(true);
141             return true;
142         }
143 
144         if (preference instanceof BluetoothDevicePreference) {
145             BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;
146             CachedBluetoothDevice device = btPreference.getCachedDevice();
147             mSelectedDevice = device.getDevice();
148             onDevicePreferenceClick(btPreference);
149             return true;
150         }
151 
152         return super.onPreferenceTreeClick(preference);
153     }
154 
onDevicePreferenceClick(BluetoothDevicePreference btPreference)155     void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
156         btPreference.onClicked();
157     }
158 
onDeviceAdded(CachedBluetoothDevice cachedDevice)159     public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
160         if (mDevicePreferenceMap.get(cachedDevice) != null) {
161             return;
162         }
163 
164         // Prevent updates while the list shows one of the state messages
165         if (mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;
166 
167         if (mFilter.matches(cachedDevice.getDevice())) {
168             createDevicePreference(cachedDevice);
169         }
170     }
171 
createDevicePreference(CachedBluetoothDevice cachedDevice)172     void createDevicePreference(CachedBluetoothDevice cachedDevice) {
173         if (mDeviceListGroup == null) {
174             Log.w(TAG, "Trying to create a device preference before the list group/category "
175                     + "exists!");
176             return;
177         }
178 
179         String key = cachedDevice.getDevice().getAddress();
180         BluetoothDevicePreference preference = (BluetoothDevicePreference) getCachedPreference(key);
181 
182         if (preference == null) {
183             preference = new BluetoothDevicePreference(getPrefContext(), cachedDevice);
184             preference.setKey(key);
185             mDeviceListGroup.addPreference(preference);
186         } else {
187             // Tell the preference it is being re-used in case there is new info in the
188             // cached device.
189             preference.rebind();
190         }
191 
192         initDevicePreference(preference);
193         mDevicePreferenceMap.put(cachedDevice, preference);
194     }
195 
196     /**
197      * Overridden in {@link BluetoothSettings} to add a listener.
198      * @param preference the newly added preference
199      */
initDevicePreference(BluetoothDevicePreference preference)200     void initDevicePreference(BluetoothDevicePreference preference) {
201         // Does nothing by default
202     }
203 
onDeviceDeleted(CachedBluetoothDevice cachedDevice)204     public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
205         BluetoothDevicePreference preference = mDevicePreferenceMap.remove(cachedDevice);
206         if (preference != null) {
207             mDeviceListGroup.removePreference(preference);
208         }
209     }
210 
onScanningStateChanged(boolean started)211     public void onScanningStateChanged(boolean started) {
212         updateProgressUi(started);
213     }
214 
updateProgressUi(boolean start)215     private void updateProgressUi(boolean start) {
216         if (mDeviceListGroup instanceof BluetoothProgressCategory) {
217             ((BluetoothProgressCategory) mDeviceListGroup).setProgress(start);
218         }
219     }
220 
onBluetoothStateChanged(int bluetoothState)221     public void onBluetoothStateChanged(int bluetoothState) {
222         if (bluetoothState == BluetoothAdapter.STATE_OFF) {
223             updateProgressUi(false);
224         }
225     }
226 
onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state)227     public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
228 }
229