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 Utils()55 private Utils() { 56 } 57 getConnectionStateSummary(int connectionState)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. showDisconnectDialog(Context context, AlertDialog dialog, DialogInterface.OnClickListener disconnectListener, CharSequence title, CharSequence message)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... showConnectingError(Context context, String name)99 static void showConnectingError(Context context, String name) { 100 showConnectingError(context, name, getLocalBtManager(context)); 101 } 102 103 @VisibleForTesting showConnectingError(Context context, String name, LocalBluetoothManager manager)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 showError(Context context, String name, int messageResId)110 static void showError(Context context, String name, int messageResId) { 111 showError(context, name, messageResId, getLocalBtManager(context)); 112 } 113 showError(Context context, String name, int messageResId, LocalBluetoothManager manager)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 getLocalBtManager(Context context)129 public static LocalBluetoothManager getLocalBtManager(Context context) { 130 return LocalBluetoothManager.getInstance(context, mOnInitCallback); 131 } 132 createRemoteName(Context context, BluetoothDevice device)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 getBtClassDrawableWithDescription(Context context, CachedBluetoothDevice cachedDevice)157 static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context, 158 CachedBluetoothDevice cachedDevice) { 159 return getBtClassDrawableWithDescription(context, cachedDevice, 1 /* iconScale */); 160 } 161 getBtClassDrawableWithDescription(Context context, CachedBluetoothDevice cachedDevice, float iconScale)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 getBluetoothDrawable(Context context, @DrawableRes int resId, int batteryLevel, float iconScale)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