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