1 /*
2  * Copyright (C) 2019 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.car.developeroptions.bluetooth;
18 
19 import android.app.settings.SettingsEnums;
20 import android.bluetooth.BluetoothDevice;
21 import android.bluetooth.BluetoothProfile;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.provider.Settings;
25 import android.util.Log;
26 import android.widget.Toast;
27 
28 import androidx.annotation.VisibleForTesting;
29 import androidx.appcompat.app.AlertDialog;
30 
31 import com.android.car.developeroptions.R;
32 import com.android.car.developeroptions.overlay.FeatureFactory;
33 import com.android.settingslib.bluetooth.BluetoothUtils;
34 import com.android.settingslib.bluetooth.BluetoothUtils.ErrorListener;
35 import com.android.settingslib.bluetooth.LocalBluetoothManager;
36 import com.android.settingslib.bluetooth.LocalBluetoothManager.BluetoothManagerCallback;
37 
38 /**
39  * Utils is a helper class that contains constants for various
40  * Android resource IDs, debug logging flags, and static methods
41  * for creating dialogs.
42  */
43 public final class Utils {
44 
45     private static final String TAG = "BluetoothUtils";
46 
47     static final boolean V = BluetoothUtils.V; // verbose logging
48     static final boolean D =  BluetoothUtils.D;  // regular logging
49 
50     public static final int META_INT_ERROR = -1;
51 
Utils()52     private Utils() {
53     }
54 
getConnectionStateSummary(int connectionState)55     public static int getConnectionStateSummary(int connectionState) {
56         switch (connectionState) {
57             case BluetoothProfile.STATE_CONNECTED:
58                 return R.string.bluetooth_connected;
59             case BluetoothProfile.STATE_CONNECTING:
60                 return R.string.bluetooth_connecting;
61             case BluetoothProfile.STATE_DISCONNECTED:
62                 return R.string.bluetooth_disconnected;
63             case BluetoothProfile.STATE_DISCONNECTING:
64                 return R.string.bluetooth_disconnecting;
65             default:
66                 return 0;
67         }
68     }
69 
70     // Create (or recycle existing) and show disconnect dialog.
showDisconnectDialog(Context context, AlertDialog dialog, DialogInterface.OnClickListener disconnectListener, CharSequence title, CharSequence message)71     static AlertDialog showDisconnectDialog(Context context,
72             AlertDialog dialog,
73             DialogInterface.OnClickListener disconnectListener,
74             CharSequence title, CharSequence message) {
75         if (dialog == null) {
76             dialog = new AlertDialog.Builder(context)
77                     .setPositiveButton(android.R.string.ok, disconnectListener)
78                     .setNegativeButton(android.R.string.cancel, null)
79                     .create();
80         } else {
81             if (dialog.isShowing()) {
82                 dialog.dismiss();
83             }
84             // use disconnectListener for the correct profile(s)
85             CharSequence okText = context.getText(android.R.string.ok);
86             dialog.setButton(DialogInterface.BUTTON_POSITIVE,
87                     okText, disconnectListener);
88         }
89         dialog.setTitle(title);
90         dialog.setMessage(message);
91         dialog.show();
92         return dialog;
93     }
94 
95     @VisibleForTesting
showConnectingError(Context context, String name, LocalBluetoothManager manager)96     static void showConnectingError(Context context, String name, LocalBluetoothManager manager) {
97         FeatureFactory.getFactory(context).getMetricsFeatureProvider().visible(context,
98                 SettingsEnums.PAGE_UNKNOWN, SettingsEnums.ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR,
99                 0);
100         showError(context, name, R.string.bluetooth_connecting_error_message, manager);
101     }
102 
showError(Context context, String name, int messageResId)103     static void showError(Context context, String name, int messageResId) {
104         showError(context, name, messageResId, getLocalBtManager(context));
105     }
106 
showError(Context context, String name, int messageResId, LocalBluetoothManager manager)107     private static void showError(Context context, String name, int messageResId,
108             LocalBluetoothManager manager) {
109         String message = context.getString(messageResId, name);
110         Context activity = manager.getForegroundActivity();
111         if (manager.isForegroundActivity()) {
112             try {
113                 new AlertDialog.Builder(activity)
114                         .setTitle(R.string.bluetooth_error_title)
115                         .setMessage(message)
116                         .setPositiveButton(android.R.string.ok, null)
117                         .show();
118             } catch (Exception e) {
119                 Log.e(TAG, "Cannot show error dialog.", e);
120             }
121         } else {
122             Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
123         }
124     }
125 
getLocalBtManager(Context context)126     public static LocalBluetoothManager getLocalBtManager(Context context) {
127         return LocalBluetoothManager.getInstance(context, mOnInitCallback);
128     }
129 
createRemoteName(Context context, BluetoothDevice device)130     public static String createRemoteName(Context context, BluetoothDevice device) {
131         String mRemoteName = device != null ? device.getAlias() : null;
132 
133         if (mRemoteName == null) {
134             mRemoteName = context.getString(R.string.unknown);
135         }
136         return mRemoteName;
137     }
138 
139     private static final ErrorListener mErrorListener = new ErrorListener() {
140         @Override
141         public void onShowError(Context context, String name, int messageResId) {
142             showError(context, name, messageResId);
143         }
144     };
145 
146     private static final BluetoothManagerCallback mOnInitCallback = new BluetoothManagerCallback() {
147         @Override
148         public void onBluetoothManagerInitialized(Context appContext,
149                 LocalBluetoothManager bluetoothManager) {
150             BluetoothUtils.setErrorListener(mErrorListener);
151         }
152     };
153 
isBluetoothScanningEnabled(Context context)154     public static boolean isBluetoothScanningEnabled(Context context) {
155         return Settings.Global.getInt(context.getContentResolver(),
156                 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
157     }
158 
getBooleanMetaData(BluetoothDevice bluetoothDevice, int key)159     public static boolean getBooleanMetaData(BluetoothDevice bluetoothDevice, int key) {
160         if (bluetoothDevice == null) {
161             return false;
162         }
163 
164         return Boolean.parseBoolean("false");
165     }
166 
getStringMetaData(BluetoothDevice bluetoothDevice, int key)167     public static String getStringMetaData(BluetoothDevice bluetoothDevice, int key) {
168         if (bluetoothDevice == null) {
169             return null;
170         }
171         return "";
172     }
173 
getIntMetaData(BluetoothDevice bluetoothDevice, int key)174     public static int getIntMetaData(BluetoothDevice bluetoothDevice, int key) {
175         if (bluetoothDevice == null) {
176             return META_INT_ERROR;
177         }
178         try {
179             return Integer.parseInt("");
180         } catch (NumberFormatException e) {
181             return META_INT_ERROR;
182         }
183     }
184 }
185