Home | History | Annotate | Download | only in bluetooth
      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 android.app.AlertDialog;
     20 import android.bluetooth.BluetoothDevice;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.res.Resources;
     24 import android.graphics.drawable.Drawable;
     25 import android.os.UserManager;
     26 import android.support.v7.preference.Preference;
     27 import android.support.v7.preference.PreferenceViewHolder;
     28 import android.text.Html;
     29 import android.text.TextUtils;
     30 import android.util.Pair;
     31 import android.util.TypedValue;
     32 import android.widget.ImageView;
     33 
     34 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     35 import com.android.settings.R;
     36 import com.android.settings.core.instrumentation.MetricsFeatureProvider;
     37 import com.android.settings.overlay.FeatureFactory;
     38 import com.android.settings.widget.GearPreference;
     39 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
     40 
     41 import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
     42 
     43 /**
     44  * BluetoothDevicePreference is the preference type used to display each remote
     45  * Bluetooth device in the Bluetooth Settings screen.
     46  */
     47 public final class BluetoothDevicePreference extends GearPreference implements
     48         CachedBluetoothDevice.Callback {
     49     private static final String TAG = "BluetoothDevicePref";
     50 
     51     private static int sDimAlpha = Integer.MIN_VALUE;
     52 
     53     private final CachedBluetoothDevice mCachedDevice;
     54     private final UserManager mUserManager;
     55 
     56     private AlertDialog mDisconnectDialog;
     57     private String contentDescription = null;
     58     private DeviceListPreferenceFragment mDeviceListPreferenceFragment;
     59     /* Talk-back descriptions for various BT icons */
     60     Resources mResources;
     61 
     62     public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice,
     63             DeviceListPreferenceFragment deviceListPreferenceFragment) {
     64         super(context, null);
     65         mResources = getContext().getResources();
     66         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
     67         mDeviceListPreferenceFragment = deviceListPreferenceFragment;
     68 
     69         if (sDimAlpha == Integer.MIN_VALUE) {
     70             TypedValue outValue = new TypedValue();
     71             context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
     72             sDimAlpha = (int) (outValue.getFloat() * 255);
     73         }
     74 
     75         mCachedDevice = cachedDevice;
     76         mCachedDevice.registerCallback(this);
     77 
     78         onDeviceAttributesChanged();
     79     }
     80 
     81     void rebind() {
     82         notifyChanged();
     83     }
     84 
     85     @Override
     86     protected boolean shouldHideSecondTarget() {
     87         return mCachedDevice == null
     88                 || mCachedDevice.getBondState() != BluetoothDevice.BOND_BONDED
     89                 || mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH);
     90     }
     91 
     92     @Override
     93     protected int getSecondTargetResId() {
     94         return R.layout.preference_widget_gear;
     95     }
     96 
     97     CachedBluetoothDevice getCachedDevice() {
     98         return mCachedDevice;
     99     }
    100 
    101     @Override
    102     protected void onPrepareForRemoval() {
    103         super.onPrepareForRemoval();
    104         mCachedDevice.unregisterCallback(this);
    105         if (mDisconnectDialog != null) {
    106             mDisconnectDialog.dismiss();
    107             mDisconnectDialog = null;
    108         }
    109     }
    110 
    111     public CachedBluetoothDevice getBluetoothDevice() {
    112         return mCachedDevice;
    113     }
    114 
    115     public void onDeviceAttributesChanged() {
    116         /*
    117          * The preference framework takes care of making sure the value has
    118          * changed before proceeding. It will also call notifyChanged() if
    119          * any preference info has changed from the previous value.
    120          */
    121         setTitle(mCachedDevice.getName());
    122         // Null check is done at the framework
    123         setSummary(mCachedDevice.getConnectionSummary());
    124 
    125         final Pair<Drawable, String> pair = Utils.getBtClassDrawableWithDescription(getContext(),
    126                 mCachedDevice);
    127         if (pair.first != null) {
    128             setIcon(pair.first);
    129             contentDescription = pair.second;
    130         }
    131 
    132         // Used to gray out the item
    133         setEnabled(!mCachedDevice.isBusy());
    134 
    135         // Device is only visible in the UI if it has a valid name besides MAC address or when user
    136         // allows showing devices without user-friendly name in developer settings
    137         setVisible(mDeviceListPreferenceFragment.shouldShowDevicesWithoutNames()
    138                 || mCachedDevice.hasHumanReadableName());
    139 
    140         // This could affect ordering, so notify that
    141         notifyHierarchyChanged();
    142     }
    143 
    144     @Override
    145     public void onBindViewHolder(PreferenceViewHolder view) {
    146         // Disable this view if the bluetooth enable/disable preference view is off
    147         if (null != findPreferenceInHierarchy("bt_checkbox")) {
    148             setDependency("bt_checkbox");
    149         }
    150 
    151         if (mCachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
    152             ImageView deviceDetails = (ImageView) view.findViewById(R.id.settings_button);
    153 
    154             if (deviceDetails != null) {
    155                 deviceDetails.setOnClickListener(this);
    156             }
    157         }
    158         final ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
    159         if (imageView != null) {
    160             imageView.setContentDescription(contentDescription);
    161         }
    162         super.onBindViewHolder(view);
    163     }
    164 
    165     @Override
    166     public boolean equals(Object o) {
    167         if ((o == null) || !(o instanceof BluetoothDevicePreference)) {
    168             return false;
    169         }
    170         return mCachedDevice.equals(
    171                 ((BluetoothDevicePreference) o).mCachedDevice);
    172     }
    173 
    174     @Override
    175     public int hashCode() {
    176         return mCachedDevice.hashCode();
    177     }
    178 
    179     @Override
    180     public int compareTo(Preference another) {
    181         if (!(another instanceof BluetoothDevicePreference)) {
    182             // Rely on default sort
    183             return super.compareTo(another);
    184         }
    185 
    186         return mCachedDevice
    187                 .compareTo(((BluetoothDevicePreference) another).mCachedDevice);
    188     }
    189 
    190     void onClicked() {
    191         Context context = getContext();
    192         int bondState = mCachedDevice.getBondState();
    193 
    194         final MetricsFeatureProvider metricsFeatureProvider =
    195                 FeatureFactory.getFactory(context).getMetricsFeatureProvider();
    196 
    197         if (mCachedDevice.isConnected()) {
    198             metricsFeatureProvider.action(context,
    199                     MetricsEvent.ACTION_SETTINGS_BLUETOOTH_DISCONNECT);
    200             askDisconnect();
    201         } else if (bondState == BluetoothDevice.BOND_BONDED) {
    202             metricsFeatureProvider.action(context,
    203                     MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT);
    204             mCachedDevice.connect(true);
    205         } else if (bondState == BluetoothDevice.BOND_NONE) {
    206             metricsFeatureProvider.action(context,
    207                     MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR);
    208             if (!mCachedDevice.hasHumanReadableName()) {
    209                 metricsFeatureProvider.action(context,
    210                         MetricsEvent.ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES);
    211             }
    212             pair();
    213         }
    214     }
    215 
    216     // Show disconnect confirmation dialog for a device.
    217     private void askDisconnect() {
    218         Context context = getContext();
    219         String name = mCachedDevice.getName();
    220         if (TextUtils.isEmpty(name)) {
    221             name = context.getString(R.string.bluetooth_device);
    222         }
    223         String message = context.getString(R.string.bluetooth_disconnect_all_profiles, name);
    224         String title = context.getString(R.string.bluetooth_disconnect_title);
    225 
    226         DialogInterface.OnClickListener disconnectListener = new DialogInterface.OnClickListener() {
    227             public void onClick(DialogInterface dialog, int which) {
    228                 mCachedDevice.disconnect();
    229             }
    230         };
    231 
    232         mDisconnectDialog = Utils.showDisconnectDialog(context,
    233                 mDisconnectDialog, disconnectListener, title, Html.fromHtml(message));
    234     }
    235 
    236     private void pair() {
    237         if (!mCachedDevice.startPairing()) {
    238             Utils.showError(getContext(), mCachedDevice.getName(),
    239                     R.string.bluetooth_pairing_error_message);
    240         }
    241     }
    242 
    243 }
    244