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