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 android.bluetooth.BluetoothDevice; 20import android.content.Intent; 21import android.os.Bundle; 22import android.preference.CheckBoxPreference; 23import android.preference.Preference; 24import android.preference.PreferenceActivity; 25import android.preference.PreferenceGroup; 26import android.text.TextUtils; 27import android.util.Log; 28 29import com.android.settings.R; 30import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile; 31 32/** 33 * ConnectSpecificProfilesActivity presents the user with all of the profiles 34 * for a particular device, and allows him to choose which should be connected 35 * (or disconnected). 36 */ 37public class ConnectSpecificProfilesActivity extends PreferenceActivity 38 implements CachedBluetoothDevice.Callback, Preference.OnPreferenceChangeListener { 39 private static final String TAG = "ConnectSpecificProfilesActivity"; 40 41 private static final String KEY_ONLINE_MODE = "online_mode"; 42 private static final String KEY_TITLE = "title"; 43 private static final String KEY_PROFILE_CONTAINER = "profile_container"; 44 45 public static final String EXTRA_DEVICE = "device"; 46 47 private LocalBluetoothManager mManager; 48 private CachedBluetoothDevice mCachedDevice; 49 50 private PreferenceGroup mProfileContainer; 51 private CheckBoxPreference mOnlineModePreference; 52 53 /** 54 * The current mode of this activity and its checkboxes (either online mode 55 * or offline mode). In online mode, user interactions with the profile 56 * checkboxes will also toggle the profile's connectivity. In offline mode, 57 * they will not, and only the preferred state will be saved for the 58 * profile. 59 */ 60 private boolean mOnlineMode; 61 62 @Override 63 protected void onCreate(Bundle savedInstanceState) { 64 super.onCreate(savedInstanceState); 65 66 BluetoothDevice device; 67 if (savedInstanceState != null) { 68 device = savedInstanceState.getParcelable(EXTRA_DEVICE); 69 } else { 70 Intent intent = getIntent(); 71 device = intent.getParcelableExtra(EXTRA_DEVICE); 72 } 73 74 if (device == null) { 75 Log.w(TAG, "Activity started without a remote Bluetooth device"); 76 finish(); 77 } 78 79 mManager = LocalBluetoothManager.getInstance(this); 80 mCachedDevice = mManager.getCachedDeviceManager().findDevice(device); 81 if (mCachedDevice == null) { 82 Log.w(TAG, "Device not found, cannot connect to it"); 83 finish(); 84 } 85 86 addPreferencesFromResource(R.xml.bluetooth_device_advanced); 87 mProfileContainer = (PreferenceGroup) findPreference(KEY_PROFILE_CONTAINER); 88 89 // Set the title of the screen 90 findPreference(KEY_TITLE).setTitle( 91 getString(R.string.bluetooth_device_advanced_title, mCachedDevice.getName())); 92 93 // Listen for check/uncheck of the online mode checkbox 94 mOnlineModePreference = (CheckBoxPreference) findPreference(KEY_ONLINE_MODE); 95 mOnlineModePreference.setOnPreferenceChangeListener(this); 96 97 // Add a preference for each profile 98 addPreferencesForProfiles(); 99 } 100 101 @Override 102 protected void onSaveInstanceState(Bundle outState) { 103 super.onSaveInstanceState(outState); 104 105 outState.putParcelable(EXTRA_DEVICE, mCachedDevice.getDevice()); 106 } 107 108 @Override 109 protected void onResume() { 110 super.onResume(); 111 112 mManager.setForegroundActivity(this); 113 mCachedDevice.registerCallback(this); 114 115 refresh(); 116 } 117 118 @Override 119 protected void onPause() { 120 super.onPause(); 121 122 mCachedDevice.unregisterCallback(this); 123 mManager.setForegroundActivity(null); 124 } 125 126 private void addPreferencesForProfiles() { 127 for (Profile profile : mCachedDevice.getConnectableProfiles()) { 128 Preference pref = createProfilePreference(profile); 129 mProfileContainer.addPreference(pref); 130 } 131 } 132 133 /** 134 * Creates a checkbox preference for the particular profile. The key will be 135 * the profile's name. 136 * 137 * @param profile The profile for which the preference controls. 138 * @return A preference that allows the user to choose whether this profile 139 * will be connected to. 140 */ 141 private CheckBoxPreference createProfilePreference(Profile profile) { 142 CheckBoxPreference pref = new CheckBoxPreference(this); 143 pref.setKey(profile.toString()); 144 pref.setTitle(profile.localizedString); 145 pref.setPersistent(false); 146 pref.setOnPreferenceChangeListener(this); 147 148 LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 149 .getProfileManager(mManager, profile); 150 151 /** 152 * Gray out checkbox while connecting and disconnecting 153 */ 154 pref.setEnabled(!mCachedDevice.isBusy()); 155 156 refreshProfilePreference(pref, profile); 157 158 return pref; 159 } 160 161 public boolean onPreferenceChange(Preference preference, Object newValue) { 162 String key = preference.getKey(); 163 if (TextUtils.isEmpty(key) || newValue == null) return true; 164 165 if (key.equals(KEY_ONLINE_MODE)) { 166 onOnlineModeCheckedStateChanged((Boolean) newValue); 167 168 } else { 169 Profile profile = getProfileOf(preference); 170 if (profile == null) return false; 171 onProfileCheckedStateChanged(profile, (Boolean) newValue); 172 } 173 174 return true; 175 } 176 177 private void onOnlineModeCheckedStateChanged(boolean checked) { 178 setOnlineMode(checked, true); 179 } 180 181 private void onProfileCheckedStateChanged(Profile profile, boolean checked) { 182 LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 183 .getProfileManager(mManager, profile); 184 profileManager.setPreferred(mCachedDevice.getDevice(), checked); 185 if (mOnlineMode) { 186 if (checked) { 187 mCachedDevice.connect(profile); 188 } else { 189 mCachedDevice.disconnect(profile); 190 } 191 } 192 } 193 194 public void onDeviceAttributesChanged(CachedBluetoothDevice cachedDevice) { 195 refresh(); 196 } 197 198 private void refresh() { 199 // We are in 'online mode' if we are connected, connecting, or disconnecting 200 setOnlineMode(mCachedDevice.isConnected() || mCachedDevice.isBusy(), false); 201 refreshProfiles(); 202 } 203 204 /** 205 * Switches between online/offline mode. 206 * 207 * @param onlineMode Whether to be in online mode, or offline mode. 208 * @param takeAction Whether to take action (i.e., connect or disconnect) 209 * based on the new online mode. 210 */ 211 private void setOnlineMode(boolean onlineMode, boolean takeAction) { 212 mOnlineMode = onlineMode; 213 214 if (takeAction) { 215 if (onlineMode) { 216 mCachedDevice.connect(); 217 } else { 218 mCachedDevice.disconnect(); 219 } 220 } 221 222 refreshOnlineModePreference(); 223 } 224 225 private void refreshOnlineModePreference() { 226 mOnlineModePreference.setChecked(mOnlineMode); 227 228 /* Gray out checkbox while connecting and disconnecting */ 229 mOnlineModePreference.setEnabled(!mCachedDevice.isBusy()); 230 231 /** 232 * If the device is online, show status. Otherwise, show a summary that 233 * describes what the checkbox does. 234 */ 235 mOnlineModePreference.setSummary(mOnlineMode ? mCachedDevice.getSummary() 236 : R.string.bluetooth_device_advanced_online_mode_summary); 237 } 238 239 private void refreshProfiles() { 240 for (Profile profile : mCachedDevice.getConnectableProfiles()) { 241 CheckBoxPreference profilePref = 242 (CheckBoxPreference) findPreference(profile.toString()); 243 if (profilePref == null) { 244 profilePref = createProfilePreference(profile); 245 mProfileContainer.addPreference(profilePref); 246 } else { 247 refreshProfilePreference(profilePref, profile); 248 } 249 } 250 } 251 252 private void refreshProfilePreference(CheckBoxPreference profilePref, Profile profile) { 253 BluetoothDevice device = mCachedDevice.getDevice(); 254 LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager 255 .getProfileManager(mManager, profile); 256 257 int connectionStatus = profileManager.getConnectionStatus(device); 258 259 /* 260 * Gray out checkbox while connecting and disconnecting 261 */ 262 profilePref.setEnabled(!mCachedDevice.isBusy()); 263 profilePref.setSummary(getProfileSummary(profileManager, profile, device, 264 connectionStatus, mOnlineMode)); 265 266 profilePref.setChecked(profileManager.isPreferred(device)); 267 } 268 269 private Profile getProfileOf(Preference pref) { 270 if (!(pref instanceof CheckBoxPreference)) return null; 271 String key = pref.getKey(); 272 if (TextUtils.isEmpty(key)) return null; 273 274 try { 275 return Profile.valueOf(pref.getKey()); 276 } catch (IllegalArgumentException e) { 277 return null; 278 } 279 } 280 281 private static int getProfileSummary(LocalBluetoothProfileManager profileManager, 282 Profile profile, BluetoothDevice device, int connectionStatus, boolean onlineMode) { 283 if (!onlineMode || connectionStatus == SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED) { 284 return getProfileSummaryForSettingPreference(profile); 285 } else { 286 return profileManager.getSummary(device); 287 } 288 } 289 290 /** 291 * Gets the summary that describes when checked, it will become a preferred profile. 292 * 293 * @param profile The profile to get the summary for. 294 * @return The summary. 295 */ 296 private static final int getProfileSummaryForSettingPreference(Profile profile) { 297 switch (profile) { 298 case A2DP: 299 return R.string.bluetooth_a2dp_profile_summary_use_for; 300 case HEADSET: 301 return R.string.bluetooth_headset_profile_summary_use_for; 302 default: 303 return 0; 304 } 305 } 306 307} 308