DeviceProfilesSettings.java revision e79f990490de49b39097433707c2bae6d8238330
1/*
2 * Copyright (C) 2008 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 com.android.settings.R;
20import com.android.settings.SettingsPreferenceFragment;
21import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
22
23import android.bluetooth.BluetoothDevice;
24import android.os.Bundle;
25import android.preference.CheckBoxPreference;
26import android.preference.EditTextPreference;
27import android.preference.Preference;
28import android.preference.PreferenceGroup;
29import android.preference.PreferenceScreen;
30import android.text.TextUtils;
31import android.util.Log;
32import android.view.View;
33
34import java.util.HashMap;
35
36/**
37 * This preference fragment presents the user with all of the profiles
38 * for a particular device, and allows them to be individually connected
39 * (or disconnected).
40 */
41public class DeviceProfilesSettings extends SettingsPreferenceFragment
42        implements CachedBluetoothDevice.Callback, Preference.OnPreferenceChangeListener,
43                View.OnClickListener {
44    private static final String TAG = "DeviceProfilesSettings";
45
46    private static final String KEY_TITLE = "title";
47    private static final String KEY_RENAME_DEVICE = "rename_device";
48    private static final String KEY_PROFILE_CONTAINER = "profile_container";
49    private static final String KEY_UNPAIR = "unpair";
50    private static final String KEY_ALLOW_INCOMING = "allow_incoming";
51
52    private static final String AUTO_CONNECT_KEY_SUFFIX = "X";
53
54    public static final String EXTRA_DEVICE = "device";
55
56    private LocalBluetoothManager mManager;
57    private CachedBluetoothDevice mCachedDevice;
58
59    private PreferenceGroup mProfileContainer;
60    private CheckBoxPreference mAllowIncomingPref;
61    private EditTextPreference mDeviceNamePref;
62    private HashMap<String,CheckBoxPreference> mAutoConnectPrefs
63            = new HashMap<String,CheckBoxPreference>();
64
65    @Override
66    public void onCreate(Bundle savedInstanceState) {
67        super.onCreate(savedInstanceState);
68
69        BluetoothDevice device;
70        if (savedInstanceState != null) {
71            device = savedInstanceState.getParcelable(EXTRA_DEVICE);
72        } else {
73            Bundle args = getArguments();
74            device = args.getParcelable(EXTRA_DEVICE);
75        }
76
77        if (device == null) {
78            Log.w(TAG, "Activity started without a remote Bluetooth device");
79            finish();
80        }
81
82        mManager = LocalBluetoothManager.getInstance(getActivity());
83        mCachedDevice = mManager.getCachedDeviceManager().findDevice(device);
84        if (mCachedDevice == null) {
85            Log.w(TAG, "Device not found, cannot connect to it");
86            finish();
87        }
88
89        addPreferencesFromResource(R.xml.bluetooth_device_advanced);
90        getPreferenceScreen().setOrderingAsAdded(false);
91
92        mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER);
93        mAllowIncomingPref = (CheckBoxPreference) findPreference(KEY_ALLOW_INCOMING);
94        mAllowIncomingPref.setChecked(isIncomingFileTransfersAllowed());
95
96        mDeviceNamePref = (EditTextPreference) findPreference(KEY_RENAME_DEVICE);
97        mDeviceNamePref.setSummary(mCachedDevice.getName());
98        mDeviceNamePref.setText(mCachedDevice.getName());
99
100        // Set the title of the screen
101        findPreference(KEY_TITLE).setTitle(getResources()
102                .getString(R.string.bluetooth_device_advanced_title, mCachedDevice.getName()));
103
104        // Add a preference for each profile
105        addPreferencesForProfiles();
106    }
107
108    @Override
109    public void onSaveInstanceState(Bundle outState) {
110        super.onSaveInstanceState(outState);
111
112        outState.putParcelable(EXTRA_DEVICE, mCachedDevice.getDevice());
113    }
114
115    @Override
116    public void onResume() {
117        super.onResume();
118
119        mManager.setForegroundActivity(getActivity());
120        mCachedDevice.registerCallback(this);
121
122        refresh();
123    }
124
125    @Override
126    public void onPause() {
127        super.onPause();
128
129        mCachedDevice.unregisterCallback(this);
130        mManager.setForegroundActivity(null);
131    }
132
133    private void addPreferencesForProfiles() {
134        for (Profile profile : mCachedDevice.getConnectableProfiles()) {
135            Preference pref = createProfilePreference(profile);
136            mProfileContainer.addPreference(pref);
137        }
138    }
139
140    /**
141     * Creates a checkbox preference for the particular profile. The key will be
142     * the profile's name.
143     *
144     * @param profile The profile for which the preference controls.
145     * @return A preference that allows the user to choose whether this profile
146     *         will be connected to.
147     */
148    private Preference createProfilePreference(Profile profile) {
149        BluetoothProfilePreference pref = new BluetoothProfilePreference(getActivity(), profile);
150        pref.setKey(profile.toString());
151        pref.setTitle(profile.localizedString);
152        pref.setExpanded(false);
153        pref.setPersistent(false);
154        pref.setOrder(getProfilePreferenceIndex(profile));
155        pref.setOnExpandClickListener(this);
156
157        /**
158         * Gray out profile while connecting and disconnecting
159         */
160        pref.setEnabled(!mCachedDevice.isBusy());
161
162        refreshProfilePreference(pref, profile);
163
164        return pref;
165    }
166
167    @Override
168    public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
169        String key = preference.getKey();
170        if (preference instanceof BluetoothProfilePreference) {
171            onProfileClicked(Profile.valueOf(key));
172            return true;
173        } else if (key.equals(KEY_UNPAIR)) {
174            unpairDevice();
175            finish();
176            return true;
177        }
178
179        return false;
180    }
181
182    public boolean onPreferenceChange(Preference preference, Object newValue) {
183        if (preference == mAllowIncomingPref) {
184            setIncomingFileTransfersAllowed(mAllowIncomingPref.isChecked());
185        } else if (preference == mDeviceNamePref) {
186            // TODO: Verify and check for error conditions
187            mCachedDevice.setName(mDeviceNamePref.getText());
188        } else {
189            return false;
190        }
191
192        return true;
193    }
194
195    private void onProfileClicked(Profile profile) {
196        BluetoothDevice device = mCachedDevice.getDevice();
197        LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
198                .getProfileManager(mManager, profile);
199
200        int status = profileManager.getConnectionStatus(device);
201        boolean isConnected =
202                SettingsBtStatus.isConnectionStatusConnected(status);
203
204        // TODO: only change the preference on disconnect if user confirms
205        // TODO: add method to change priority of individual profiles
206        // profileManager.setPreferred(device, !isConnected);
207
208        if (isConnected) {
209            mCachedDevice.askDisconnect(profile);
210        } else {
211            mCachedDevice.connect(profile);
212        }
213    }
214
215    public void onDeviceAttributesChanged(CachedBluetoothDevice cachedDevice) {
216        refresh();
217    }
218
219    private void refresh() {
220        refreshProfiles();
221    }
222
223    private void refreshProfiles() {
224        for (Profile profile : mCachedDevice.getConnectableProfiles()) {
225            Preference profilePref = findPreference(profile.toString());
226            if (profilePref == null) {
227                profilePref = createProfilePreference(profile);
228                mProfileContainer.addPreference(profilePref);
229            } else {
230                refreshProfilePreference(profilePref, profile);
231            }
232        }
233    }
234
235    private void refreshProfilePreference(Preference profilePref, Profile profile) {
236        BluetoothDevice device = mCachedDevice.getDevice();
237        LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
238                .getProfileManager(mManager, profile);
239
240        int connectionStatus = profileManager.getConnectionStatus(device);
241
242        /*
243         * Gray out checkbox while connecting and disconnecting
244         */
245        profilePref.setEnabled(!mCachedDevice.isBusy());
246        profilePref.setSummary(getProfileSummary(profileManager, profile, device,
247                connectionStatus, isDeviceOnline()));
248        // TODO:
249        //profilePref.setChecked(profileManager.isPreferred(device));
250    }
251
252    private Profile getProfileOf(Preference pref) {
253        if (!(pref instanceof CheckBoxPreference)) return null;
254        String key = pref.getKey();
255        if (TextUtils.isEmpty(key)) return null;
256
257        try {
258            return Profile.valueOf(pref.getKey());
259        } catch (IllegalArgumentException e) {
260            return null;
261        }
262    }
263
264    private static int getProfileSummary(LocalBluetoothProfileManager profileManager,
265            Profile profile, BluetoothDevice device, int connectionStatus, boolean onlineMode) {
266        if (!onlineMode || connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED) {
267            return getProfileSummaryForSettingPreference(profile);
268        } else {
269            return profileManager.getSummary(device);
270        }
271    }
272
273    /**
274     * Gets the summary that describes when checked, it will become a preferred profile.
275     *
276     * @param profile The profile to get the summary for.
277     * @return The summary.
278     */
279    private static final int getProfileSummaryForSettingPreference(Profile profile) {
280        switch (profile) {
281            case A2DP:
282                return R.string.bluetooth_a2dp_profile_summary_use_for;
283            case HEADSET:
284                return R.string.bluetooth_headset_profile_summary_use_for;
285            case HID:
286                return R.string.bluetooth_hid_profile_summary_use_for;
287            default:
288                return 0;
289        }
290    }
291
292    public void onClick(View v) {
293        if (v.getTag() instanceof Profile) {
294            Profile prof = (Profile) v.getTag();
295            CheckBoxPreference autoConnectPref = mAutoConnectPrefs.get(prof.toString());
296            if (autoConnectPref == null) {
297                autoConnectPref = new CheckBoxPreference(getActivity());
298                autoConnectPref.setKey(prof.toString() + AUTO_CONNECT_KEY_SUFFIX);
299                autoConnectPref.setTitle(getCheckBoxTitle(prof));
300                autoConnectPref.setOrder(getProfilePreferenceIndex(prof) + 1);
301                autoConnectPref.setChecked(getAutoConnect(prof));
302                mAutoConnectPrefs.put(prof.name(), autoConnectPref);
303            }
304            BluetoothProfilePreference profilePref =
305                    (BluetoothProfilePreference) findPreference(prof.toString());
306            if (profilePref != null) {
307                if (profilePref.isExpanded()) {
308                    mProfileContainer.addPreference(autoConnectPref);
309                } else {
310                    mProfileContainer.removePreference(autoConnectPref);
311                }
312            }
313        }
314    }
315
316    private int getProfilePreferenceIndex(Profile prof) {
317        return mProfileContainer.getOrder() + prof.ordinal() * 10;
318    }
319
320    private void unpairDevice() {
321        mCachedDevice.unpair();
322    }
323
324    private boolean isDeviceOnline() {
325        // TODO: Verify
326        return mCachedDevice.isConnected() || mCachedDevice.isBusy();
327    }
328
329    private void setIncomingFileTransfersAllowed(boolean allow) {
330        // TODO:
331        Log.d(TAG, "Set allow incoming = " + allow);
332    }
333
334    private boolean isIncomingFileTransfersAllowed() {
335        // TODO:
336        return true;
337    }
338
339    private String getCheckBoxTitle(Profile prof) {
340        // TODO: Use resources and base it on profile if necessary
341        return "Auto connect";
342    }
343
344    private boolean getAutoConnect(Profile prof) {
345        // TODO: Get the auto connect toggle state for the profile
346        return true;
347    }
348}
349