OSDN Git Service

Merge "Stop leaking wakelocks in cryptkeeper."
[android-x86/packages-apps-Settings.git] / src / com / android / settings / bluetooth / BluetoothSettings.java
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.app.ActionBar;
20 import android.app.Activity;
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.BluetoothDevice;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.os.Bundle;
28 import android.preference.Preference;
29 import android.preference.PreferenceActivity;
30 import android.preference.PreferenceCategory;
31 import android.preference.PreferenceGroup;
32 import android.preference.PreferenceScreen;
33 import android.util.Log;
34 import android.view.Gravity;
35 import android.view.LayoutInflater;
36 import android.view.Menu;
37 import android.view.MenuInflater;
38 import android.view.MenuItem;
39 import android.view.View;
40 import android.view.ViewGroup;
41 import android.widget.Switch;
42 import android.widget.TextView;
43
44 import com.android.settings.ProgressCategory;
45 import com.android.settings.R;
46
47 /**
48  * BluetoothSettings is the Settings screen for Bluetooth configuration and
49  * connection management.
50  */
51 public final class BluetoothSettings extends DeviceListPreferenceFragment {
52     private static final String TAG = "BluetoothSettings";
53
54     private static final int MENU_ID_SCAN = Menu.FIRST;
55     private static final int MENU_ID_RENAME_DEVICE = Menu.FIRST + 1;
56     private static final int MENU_ID_VISIBILITY_TIMEOUT = Menu.FIRST + 2;
57     private static final int MENU_ID_SHOW_RECEIVED = Menu.FIRST + 3;
58
59     /* Private intent to show the list of received files */
60     private static final String BTOPP_ACTION_OPEN_RECEIVED_FILES =
61             "android.btopp.intent.action.OPEN_RECEIVED_FILES";
62
63     private BluetoothEnabler mBluetoothEnabler;
64
65     private BluetoothDiscoverableEnabler mDiscoverableEnabler;
66
67     private PreferenceGroup mPairedDevicesCategory;
68
69     private PreferenceGroup mAvailableDevicesCategory;
70     private boolean mAvailableDevicesCategoryIsPresent;
71
72     private TextView mEmptyView;
73
74     private final IntentFilter mIntentFilter;
75
76     // accessed from inner class (not private to avoid thunks)
77     Preference mMyDevicePreference;
78
79     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
80         @Override
81         public void onReceive(Context context, Intent intent) {
82             String action = intent.getAction();
83             if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) {
84                 updateDeviceName();
85             }
86         }
87
88         private void updateDeviceName() {
89             if (mLocalAdapter.isEnabled() && mMyDevicePreference != null) {
90                 mMyDevicePreference.setTitle(mLocalAdapter.getName());
91             }
92         }
93     };
94
95     public BluetoothSettings() {
96         mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
97     }
98
99     @Override
100     public void onActivityCreated(Bundle savedInstanceState) {
101         super.onActivityCreated(savedInstanceState);
102
103         mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
104         getListView().setEmptyView(mEmptyView);
105     }
106
107     @Override
108     void addPreferencesForActivity() {
109         addPreferencesFromResource(R.xml.bluetooth_settings);
110
111         Activity activity = getActivity();
112
113         Switch actionBarSwitch = new Switch(activity);
114
115         if (activity instanceof PreferenceActivity) {
116             PreferenceActivity preferenceActivity = (PreferenceActivity) activity;
117             if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) {
118                 final int padding = activity.getResources().getDimensionPixelSize(
119                         R.dimen.action_bar_switch_padding);
120                 actionBarSwitch.setPadding(0, 0, padding, 0);
121                 activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
122                         ActionBar.DISPLAY_SHOW_CUSTOM);
123                 activity.getActionBar().setCustomView(actionBarSwitch, new ActionBar.LayoutParams(
124                         ActionBar.LayoutParams.WRAP_CONTENT,
125                         ActionBar.LayoutParams.WRAP_CONTENT,
126                         Gravity.CENTER_VERTICAL | Gravity.RIGHT));
127             }
128         }
129
130         mBluetoothEnabler = new BluetoothEnabler(activity, actionBarSwitch);
131
132         setHasOptionsMenu(true);
133     }
134
135     @Override
136     public void onResume() {
137         // resume BluetoothEnabler before calling super.onResume() so we don't get
138         // any onDeviceAdded() callbacks before setting up view in updateContent()
139         mBluetoothEnabler.resume();
140         super.onResume();
141
142         if (mDiscoverableEnabler != null) {
143             mDiscoverableEnabler.resume();
144         }
145         getActivity().registerReceiver(mReceiver, mIntentFilter);
146
147         updateContent(mLocalAdapter.getBluetoothState());
148     }
149
150     @Override
151     public void onPause() {
152         super.onPause();
153         mBluetoothEnabler.pause();
154         getActivity().unregisterReceiver(mReceiver);
155         if (mDiscoverableEnabler != null) {
156             mDiscoverableEnabler.pause();
157         }
158     }
159
160     @Override
161     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
162         boolean bluetoothIsEnabled = mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON;
163         boolean isDiscovering = mLocalAdapter.isDiscovering();
164         int textId = isDiscovering ? R.string.bluetooth_searching_for_devices :
165             R.string.bluetooth_search_for_devices;
166         menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)
167                 .setEnabled(bluetoothIsEnabled && !isDiscovering)
168                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
169         menu.add(Menu.NONE, MENU_ID_RENAME_DEVICE, 0, R.string.bluetooth_rename_device)
170                 .setEnabled(bluetoothIsEnabled)
171                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
172         menu.add(Menu.NONE, MENU_ID_VISIBILITY_TIMEOUT, 0, R.string.bluetooth_visibility_timeout)
173                 .setEnabled(bluetoothIsEnabled)
174                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
175         menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files)
176                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
177     }
178
179     @Override
180     public boolean onOptionsItemSelected(MenuItem item) {
181         switch (item.getItemId()) {
182             case MENU_ID_SCAN:
183                 if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
184                     startScanning();
185                 }
186                 return true;
187
188             case MENU_ID_RENAME_DEVICE:
189                 new BluetoothNameDialogFragment().show(
190                         getFragmentManager(), "rename device");
191                 return true;
192
193             case MENU_ID_VISIBILITY_TIMEOUT:
194                 new BluetoothVisibilityTimeoutFragment().show(
195                         getFragmentManager(), "visibility timeout");
196                 return true;
197
198             case MENU_ID_SHOW_RECEIVED:
199                 Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
200                 getActivity().sendBroadcast(intent);
201                 return true;
202         }
203         return super.onOptionsItemSelected(item);
204     }
205
206     private void startScanning() {
207         if (!mAvailableDevicesCategoryIsPresent) {
208             getPreferenceScreen().addPreference(mAvailableDevicesCategory);
209         }
210         mLocalAdapter.startScanning(true);
211     }
212
213     @Override
214     void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
215         mLocalAdapter.stopScanning();
216         super.onDevicePreferenceClick(btPreference);
217     }
218
219     private void addDeviceCategory(PreferenceGroup preferenceGroup, int titleId,
220             BluetoothDeviceFilter.Filter filter) {
221         preferenceGroup.setTitle(titleId);
222         getPreferenceScreen().addPreference(preferenceGroup);
223         setFilter(filter);
224         setDeviceListGroup(preferenceGroup);
225         addCachedDevices();
226         preferenceGroup.setEnabled(true);
227     }
228
229     private void updateContent(int bluetoothState) {
230         final PreferenceScreen preferenceScreen = getPreferenceScreen();
231         int messageId = 0;
232
233         switch (bluetoothState) {
234             case BluetoothAdapter.STATE_ON:
235                 preferenceScreen.removeAll();
236                 preferenceScreen.setOrderingAsAdded(true);
237
238                 // This device
239                 if (mMyDevicePreference == null) {
240                     mMyDevicePreference = new Preference(getActivity());
241                 }
242                 mMyDevicePreference.setTitle(mLocalAdapter.getName());
243                 if (getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) {
244                     mMyDevicePreference.setIcon(R.drawable.ic_bt_cellphone);    // for phones
245                 } else {
246                     mMyDevicePreference.setIcon(R.drawable.ic_bt_laptop);   // for tablets, etc.
247                 }
248                 mMyDevicePreference.setPersistent(false);
249                 mMyDevicePreference.setEnabled(true);
250                 preferenceScreen.addPreference(mMyDevicePreference);
251
252                 if (mDiscoverableEnabler == null) {
253                     mDiscoverableEnabler = new BluetoothDiscoverableEnabler(getActivity(),
254                             mLocalAdapter, mMyDevicePreference);
255                     mDiscoverableEnabler.resume();
256                     LocalBluetoothManager.getInstance(getActivity()).setDiscoverableEnabler(
257                             mDiscoverableEnabler);
258                 }
259
260                 // Paired devices category
261                 if (mPairedDevicesCategory == null) {
262                     mPairedDevicesCategory = new PreferenceCategory(getActivity());
263                 } else {
264                     mPairedDevicesCategory.removeAll();
265                 }
266                 addDeviceCategory(mPairedDevicesCategory,
267                         R.string.bluetooth_preference_paired_devices,
268                         BluetoothDeviceFilter.BONDED_DEVICE_FILTER);
269                 int numberOfPairedDevices = mPairedDevicesCategory.getPreferenceCount();
270
271                 mDiscoverableEnabler.setNumberOfPairedDevices(numberOfPairedDevices);
272
273                 // Available devices category
274                 if (mAvailableDevicesCategory == null) {
275                     mAvailableDevicesCategory = new ProgressCategory(getActivity(), null);
276                 } else {
277                     mAvailableDevicesCategory.removeAll();
278                 }
279                 addDeviceCategory(mAvailableDevicesCategory,
280                         R.string.bluetooth_preference_found_devices,
281                         BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER);
282                 int numberOfAvailableDevices = mAvailableDevicesCategory.getPreferenceCount();
283                 mAvailableDevicesCategoryIsPresent = true;
284
285                 if (numberOfAvailableDevices == 0) {
286                     preferenceScreen.removePreference(mAvailableDevicesCategory);
287                     mAvailableDevicesCategoryIsPresent = false;
288                 }
289
290                 if (numberOfPairedDevices == 0) {
291                     preferenceScreen.removePreference(mPairedDevicesCategory);
292                     startScanning();
293                 }
294                 getActivity().invalidateOptionsMenu();
295                 return; // not break
296
297             case BluetoothAdapter.STATE_TURNING_OFF:
298                 messageId = R.string.bluetooth_turning_off;
299                 break;
300
301             case BluetoothAdapter.STATE_OFF:
302                 messageId = R.string.bluetooth_empty_list_bluetooth_off;
303                 break;
304
305             case BluetoothAdapter.STATE_TURNING_ON:
306                 messageId = R.string.bluetooth_turning_on;
307                 break;
308         }
309
310         setDeviceListGroup(preferenceScreen);
311         removeAllDevices();
312         mEmptyView.setText(messageId);
313         getActivity().invalidateOptionsMenu();
314     }
315
316     @Override
317     public void onBluetoothStateChanged(int bluetoothState) {
318         super.onBluetoothStateChanged(bluetoothState);
319         updateContent(bluetoothState);
320     }
321
322     @Override
323     public void onScanningStateChanged(boolean started) {
324         super.onScanningStateChanged(started);
325         // Update options' enabled state
326         getActivity().invalidateOptionsMenu();
327     }
328
329     public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
330         setDeviceListGroup(getPreferenceScreen());
331         removeAllDevices();
332         updateContent(mLocalAdapter.getBluetoothState());
333     }
334
335     private final View.OnClickListener mDeviceProfilesListener = new View.OnClickListener() {
336         public void onClick(View v) {
337             // User clicked on advanced options icon for a device in the list
338             if (v.getTag() instanceof CachedBluetoothDevice) {
339                 CachedBluetoothDevice device = (CachedBluetoothDevice) v.getTag();
340
341                 Bundle args = new Bundle(1);
342                 args.putParcelable(DeviceProfilesSettings.EXTRA_DEVICE, device.getDevice());
343
344                 ((PreferenceActivity) getActivity()).startPreferencePanel(
345                         DeviceProfilesSettings.class.getName(), args,
346                         R.string.bluetooth_device_advanced_title, null, null, 0);
347             } else {
348                 Log.w(TAG, "onClick() called for other View: " + v); // TODO remove
349             }
350         }
351     };
352
353     /**
354      * Add a listener, which enables the advanced settings icon.
355      * @param preference the newly added preference
356      */
357     @Override
358     void initDevicePreference(BluetoothDevicePreference preference) {
359         CachedBluetoothDevice cachedDevice = preference.getCachedDevice();
360         if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
361             // Only paired device have an associated advanced settings screen
362             preference.setOnSettingsClickListener(mDeviceProfilesListener);
363         }
364     }
365 }