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 17 package com.android.settings.bluetooth; 18 19 import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH; 20 21 import android.app.AlertDialog; 22 import android.bluetooth.BluetoothClass; 23 import android.bluetooth.BluetoothDevice; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.os.UserManager; 27 import android.preference.Preference; 28 import android.text.Html; 29 import android.text.TextUtils; 30 import android.util.Log; 31 import android.util.TypedValue; 32 import android.view.View; 33 import android.view.View.OnClickListener; 34 import android.widget.ImageView; 35 36 import com.android.settings.R; 37 import com.android.settings.search.Index; 38 import com.android.settings.search.SearchIndexableRaw; 39 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 40 import com.android.settingslib.bluetooth.HidProfile; 41 import com.android.settingslib.bluetooth.LocalBluetoothProfile; 42 43 import java.util.List; 44 45 /** 46 * BluetoothDevicePreference is the preference type used to display each remote 47 * Bluetooth device in the Bluetooth Settings screen. 48 */ 49 public final class BluetoothDevicePreference extends Preference implements 50 CachedBluetoothDevice.Callback, OnClickListener { 51 private static final String TAG = "BluetoothDevicePreference"; 52 53 private static int sDimAlpha = Integer.MIN_VALUE; 54 55 private final CachedBluetoothDevice mCachedDevice; 56 57 private OnClickListener mOnSettingsClickListener; 58 59 private AlertDialog mDisconnectDialog; 60 BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice)61 public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice) { 62 super(context); 63 64 if (sDimAlpha == Integer.MIN_VALUE) { 65 TypedValue outValue = new TypedValue(); 66 context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true); 67 sDimAlpha = (int) (outValue.getFloat() * 255); 68 } 69 70 mCachedDevice = cachedDevice; 71 72 setLayoutResource(R.layout.preference_bt_icon); 73 74 if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) { 75 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 76 if (! um.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)) { 77 setWidgetLayoutResource(R.layout.preference_bluetooth); 78 } 79 } 80 81 mCachedDevice.registerCallback(this); 82 83 onDeviceAttributesChanged(); 84 } 85 getCachedDevice()86 CachedBluetoothDevice getCachedDevice() { 87 return mCachedDevice; 88 } 89 setOnSettingsClickListener(OnClickListener listener)90 public void setOnSettingsClickListener(OnClickListener listener) { 91 mOnSettingsClickListener = listener; 92 } 93 94 @Override onPrepareForRemoval()95 protected void onPrepareForRemoval() { 96 super.onPrepareForRemoval(); 97 mCachedDevice.unregisterCallback(this); 98 if (mDisconnectDialog != null) { 99 mDisconnectDialog.dismiss(); 100 mDisconnectDialog = null; 101 } 102 } 103 onDeviceAttributesChanged()104 public void onDeviceAttributesChanged() { 105 /* 106 * The preference framework takes care of making sure the value has 107 * changed before proceeding. It will also call notifyChanged() if 108 * any preference info has changed from the previous value. 109 */ 110 setTitle(mCachedDevice.getName()); 111 112 int summaryResId = mCachedDevice.getConnectionSummary(); 113 if (summaryResId != 0) { 114 setSummary(summaryResId); 115 } else { 116 setSummary(null); // empty summary for unpaired devices 117 } 118 119 int iconResId = getBtClassDrawable(); 120 if (iconResId != 0) { 121 setIcon(iconResId); 122 } 123 124 // Used to gray out the item 125 setEnabled(!mCachedDevice.isBusy()); 126 127 // This could affect ordering, so notify that 128 notifyHierarchyChanged(); 129 } 130 131 @Override onBindView(View view)132 protected void onBindView(View view) { 133 // Disable this view if the bluetooth enable/disable preference view is off 134 if (null != findPreferenceInHierarchy("bt_checkbox")) { 135 setDependency("bt_checkbox"); 136 } 137 138 if (mCachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) { 139 ImageView deviceDetails = (ImageView) view.findViewById(R.id.deviceDetails); 140 141 if (deviceDetails != null) { 142 deviceDetails.setOnClickListener(this); 143 deviceDetails.setTag(mCachedDevice); 144 } 145 } 146 147 super.onBindView(view); 148 } 149 onClick(View v)150 public void onClick(View v) { 151 // Should never be null by construction 152 if (mOnSettingsClickListener != null) { 153 mOnSettingsClickListener.onClick(v); 154 } 155 } 156 157 @Override equals(Object o)158 public boolean equals(Object o) { 159 if ((o == null) || !(o instanceof BluetoothDevicePreference)) { 160 return false; 161 } 162 return mCachedDevice.equals( 163 ((BluetoothDevicePreference) o).mCachedDevice); 164 } 165 166 @Override hashCode()167 public int hashCode() { 168 return mCachedDevice.hashCode(); 169 } 170 171 @Override compareTo(Preference another)172 public int compareTo(Preference another) { 173 if (!(another instanceof BluetoothDevicePreference)) { 174 // Rely on default sort 175 return super.compareTo(another); 176 } 177 178 return mCachedDevice 179 .compareTo(((BluetoothDevicePreference) another).mCachedDevice); 180 } 181 onClicked()182 void onClicked() { 183 int bondState = mCachedDevice.getBondState(); 184 185 if (mCachedDevice.isConnected()) { 186 askDisconnect(); 187 } else if (bondState == BluetoothDevice.BOND_BONDED) { 188 mCachedDevice.connect(true); 189 } else if (bondState == BluetoothDevice.BOND_NONE) { 190 pair(); 191 } 192 } 193 194 // Show disconnect confirmation dialog for a device. askDisconnect()195 private void askDisconnect() { 196 Context context = getContext(); 197 String name = mCachedDevice.getName(); 198 if (TextUtils.isEmpty(name)) { 199 name = context.getString(R.string.bluetooth_device); 200 } 201 String message = context.getString(R.string.bluetooth_disconnect_all_profiles, name); 202 String title = context.getString(R.string.bluetooth_disconnect_title); 203 204 DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() { 205 public void onClick(DialogInterface dialog, int which) { 206 mCachedDevice.disconnect(); 207 } 208 }; 209 210 mDisconnectDialog = Utils.showDisconnectDialog(context, 211 mDisconnectDialog, disconnectListener, title, Html.fromHtml(message)); 212 } 213 pair()214 private void pair() { 215 if (!mCachedDevice.startPairing()) { 216 Utils.showError(getContext(), mCachedDevice.getName(), 217 R.string.bluetooth_pairing_error_message); 218 } else { 219 final Context context = getContext(); 220 221 SearchIndexableRaw data = new SearchIndexableRaw(context); 222 data.className = BluetoothSettings.class.getName(); 223 data.title = mCachedDevice.getName(); 224 data.screenTitle = context.getResources().getString(R.string.bluetooth_settings); 225 data.iconResId = R.drawable.ic_settings_bluetooth; 226 data.enabled = true; 227 228 Index.getInstance(context).updateFromSearchIndexableData(data); 229 } 230 } 231 getBtClassDrawable()232 private int getBtClassDrawable() { 233 BluetoothClass btClass = mCachedDevice.getBtClass(); 234 if (btClass != null) { 235 switch (btClass.getMajorDeviceClass()) { 236 case BluetoothClass.Device.Major.COMPUTER: 237 return R.drawable.ic_bt_laptop; 238 239 case BluetoothClass.Device.Major.PHONE: 240 return R.drawable.ic_bt_cellphone; 241 242 case BluetoothClass.Device.Major.PERIPHERAL: 243 return HidProfile.getHidClassDrawable(btClass); 244 245 case BluetoothClass.Device.Major.IMAGING: 246 return R.drawable.ic_bt_imaging; 247 248 default: 249 // unrecognized device class; continue 250 } 251 } else { 252 Log.w(TAG, "mBtClass is null"); 253 } 254 255 List<LocalBluetoothProfile> profiles = mCachedDevice.getProfiles(); 256 for (LocalBluetoothProfile profile : profiles) { 257 int resId = profile.getDrawableResource(btClass); 258 if (resId != 0) { 259 return resId; 260 } 261 } 262 if (btClass != null) { 263 if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) { 264 return R.drawable.ic_bt_headphones_a2dp; 265 266 } 267 if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { 268 return R.drawable.ic_bt_headset_hfp; 269 } 270 } 271 return R.drawable.ic_settings_bluetooth; 272 } 273 } 274