Home | History | Annotate | Download | only in bluetooth
      1 /*
      2  * Copyright (C) 2011 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.BluetoothClass;
     21 import android.bluetooth.BluetoothDevice;
     22 import android.bluetooth.BluetoothProfile;
     23 import android.content.Context;
     24 import android.content.DialogInterface;
     25 import android.content.res.Resources;
     26 import android.graphics.drawable.Drawable;
     27 import android.support.annotation.DrawableRes;
     28 import android.support.annotation.IdRes;
     29 import android.support.annotation.VisibleForTesting;
     30 import android.util.Pair;
     31 import android.widget.Toast;
     32 
     33 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     34 import com.android.settings.R;
     35 import com.android.settings.overlay.FeatureFactory;
     36 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
     37 import com.android.settingslib.bluetooth.HidProfile;
     38 import com.android.settingslib.bluetooth.LocalBluetoothManager;
     39 import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
     40 import com.android.settingslib.bluetooth.LocalBluetoothProfile;
     41 import com.android.settingslib.bluetooth.Utils.ErrorListener;
     42 import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
     43 
     44 import java.util.List;
     45 
     46 /**
     47  * Utils is a helper class that contains constants for various
     48  * Android resource IDs, debug logging flags, and static methods
     49  * for creating dialogs.
     50  */
     51 public final class Utils {
     52     static final boolean V = com.android.settingslib.bluetooth.Utils.V; // verbose logging
     53     static final boolean D =  com.android.settingslib.bluetooth.Utils.D;  // regular logging
     54 
     55     private Utils() {
     56     }
     57 
     58     public static int getConnectionStateSummary(int connectionState) {
     59         switch (connectionState) {
     60         case BluetoothProfile.STATE_CONNECTED:
     61             return R.string.bluetooth_connected;
     62         case BluetoothProfile.STATE_CONNECTING:
     63             return R.string.bluetooth_connecting;
     64         case BluetoothProfile.STATE_DISCONNECTED:
     65             return R.string.bluetooth_disconnected;
     66         case BluetoothProfile.STATE_DISCONNECTING:
     67             return R.string.bluetooth_disconnecting;
     68         default:
     69             return 0;
     70         }
     71     }
     72 
     73     // Create (or recycle existing) and show disconnect dialog.
     74     static AlertDialog showDisconnectDialog(Context context,
     75             AlertDialog dialog,
     76             DialogInterface.OnClickListener disconnectListener,
     77             CharSequence title, CharSequence message) {
     78         if (dialog == null) {
     79             dialog = new AlertDialog.Builder(context)
     80                     .setPositiveButton(android.R.string.ok, disconnectListener)
     81                     .setNegativeButton(android.R.string.cancel, null)
     82                     .create();
     83         } else {
     84             if (dialog.isShowing()) {
     85                 dialog.dismiss();
     86             }
     87             // use disconnectListener for the correct profile(s)
     88             CharSequence okText = context.getText(android.R.string.ok);
     89             dialog.setButton(DialogInterface.BUTTON_POSITIVE,
     90                     okText, disconnectListener);
     91         }
     92         dialog.setTitle(title);
     93         dialog.setMessage(message);
     94         dialog.show();
     95         return dialog;
     96     }
     97 
     98     // TODO: wire this up to show connection errors...
     99     static void showConnectingError(Context context, String name) {
    100         showConnectingError(context, name, getLocalBtManager(context));
    101     }
    102 
    103     @VisibleForTesting
    104     static void showConnectingError(Context context, String name, LocalBluetoothManager manager) {
    105         FeatureFactory.getFactory(context).getMetricsFeatureProvider().visible(context,
    106             MetricsEvent.VIEW_UNKNOWN, MetricsEvent.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR);
    107         showError(context, name, R.string.bluetooth_connecting_error_message, manager);
    108     }
    109 
    110     static void showError(Context context, String name, int messageResId) {
    111         showError(context, name, messageResId, getLocalBtManager(context));
    112     }
    113 
    114     private static void showError(Context context, String name, int messageResId,
    115             LocalBluetoothManager manager) {
    116         String message = context.getString(messageResId, name);
    117         Context activity = manager.getForegroundActivity();
    118         if (manager.isForegroundActivity()) {
    119             new AlertDialog.Builder(activity)
    120                 .setTitle(R.string.bluetooth_error_title)
    121                 .setMessage(message)
    122                 .setPositiveButton(android.R.string.ok, null)
    123                 .show();
    124         } else {
    125             Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    126         }
    127     }
    128 
    129     public static LocalBluetoothManager getLocalBtManager(Context context) {
    130         return LocalBluetoothManager.getInstance(context, mOnInitCallback);
    131     }
    132 
    133     public static String createRemoteName(Context context, BluetoothDevice device) {
    134         String mRemoteName = device != null ? device.getAliasName() : null;
    135 
    136         if (mRemoteName == null) {
    137             mRemoteName = context.getString(R.string.unknown);
    138         }
    139         return mRemoteName;
    140     }
    141 
    142     private static final ErrorListener mErrorListener = new ErrorListener() {
    143         @Override
    144         public void onShowError(Context context, String name, int messageResId) {
    145             showError(context, name, messageResId);
    146         }
    147     };
    148 
    149     private static final BluetoothManagerCallback mOnInitCallback = new BluetoothManagerCallback() {
    150         @Override
    151         public void onBluetoothManagerInitialized(Context appContext,
    152                 LocalBluetoothManager bluetoothManager) {
    153             com.android.settingslib.bluetooth.Utils.setErrorListener(mErrorListener);
    154         }
    155     };
    156 
    157     static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
    158             CachedBluetoothDevice cachedDevice) {
    159         return getBtClassDrawableWithDescription(context, cachedDevice, 1 /* iconScale */);
    160     }
    161 
    162     static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
    163             CachedBluetoothDevice cachedDevice, float iconScale) {
    164         BluetoothClass btClass = cachedDevice.getBtClass();
    165         final int level = cachedDevice.getBatteryLevel();
    166         if (btClass != null) {
    167             switch (btClass.getMajorDeviceClass()) {
    168                 case BluetoothClass.Device.Major.COMPUTER:
    169                     return new Pair<>(getBluetoothDrawable(context, R.drawable.ic_bt_laptop, level,
    170                             iconScale),
    171                             context.getString(R.string.bluetooth_talkback_computer));
    172 
    173                 case BluetoothClass.Device.Major.PHONE:
    174                     return new Pair<>(
    175                             getBluetoothDrawable(context, R.drawable.ic_bt_cellphone, level,
    176                                     iconScale),
    177                             context.getString(R.string.bluetooth_talkback_phone));
    178 
    179                 case BluetoothClass.Device.Major.PERIPHERAL:
    180                     return new Pair<>(
    181                             getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass),
    182                                     level, iconScale),
    183                             context.getString(R.string.bluetooth_talkback_input_peripheral));
    184 
    185                 case BluetoothClass.Device.Major.IMAGING:
    186                     return new Pair<>(
    187                             getBluetoothDrawable(context, R.drawable.ic_settings_print, level,
    188                                     iconScale),
    189                             context.getString(R.string.bluetooth_talkback_imaging));
    190 
    191                 default:
    192                     // unrecognized device class; continue
    193             }
    194         }
    195 
    196         List<LocalBluetoothProfile> profiles = cachedDevice.getProfiles();
    197         for (LocalBluetoothProfile profile : profiles) {
    198             int resId = profile.getDrawableResource(btClass);
    199             if (resId != 0) {
    200                 return new Pair<>(getBluetoothDrawable(context, resId, level, iconScale), null);
    201             }
    202         }
    203         if (btClass != null) {
    204             if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
    205                 return new Pair<>(
    206                         getBluetoothDrawable(context, R.drawable.ic_bt_headset_hfp, level,
    207                                 iconScale),
    208                         context.getString(R.string.bluetooth_talkback_headset));
    209             }
    210             if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
    211                 return new Pair<>(
    212                         getBluetoothDrawable(context, R.drawable.ic_bt_headphones_a2dp, level,
    213                                 iconScale),
    214                         context.getString(R.string.bluetooth_talkback_headphone));
    215             }
    216         }
    217         return new Pair<>(
    218                 getBluetoothDrawable(context, R.drawable.ic_settings_bluetooth, level, iconScale),
    219                 context.getString(R.string.bluetooth_talkback_bluetooth));
    220     }
    221 
    222     @VisibleForTesting
    223     static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId,
    224             int batteryLevel, float iconScale) {
    225         if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
    226             return BluetoothDeviceLayerDrawable.createLayerDrawable(context, resId, batteryLevel,
    227                     iconScale);
    228         } else if (resId != 0) {
    229             return context.getDrawable(resId);
    230         } else {
    231             return null;
    232         }
    233     }
    234 }
    235