• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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