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         showError(context, name, R.string.bluetooth_connecting_error_message, manager);
100     }
101 
showError(Context context, String name, int messageResId)102     static void showError(Context context, String name, int messageResId) {
103         showError(context, name, messageResId, getLocalBtManager(context));
104     }
105 
showError(Context context, String name, int messageResId, LocalBluetoothManager manager)106     private static void showError(Context context, String name, int messageResId,
107             LocalBluetoothManager manager) {
108         String message = context.getString(messageResId, name);
109         Context activity = manager.getForegroundActivity();
110         if (manager.isForegroundActivity()) {
111             try {
112                 new AlertDialog.Builder(activity)
113                         .setTitle(R.string.bluetooth_error_title)
114                         .setMessage(message)
115                         .setPositiveButton(android.R.string.ok, null)
116                         .show();
117             } catch (Exception e) {
118                 Log.e(TAG, "Cannot show error dialog.", e);
119             }
120         } else {
121             Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
122         }
123     }
124 
getLocalBtManager(Context context)125     public static LocalBluetoothManager getLocalBtManager(Context context) {
126         return LocalBluetoothManager.getInstance(context, mOnInitCallback);
127     }
128 
createRemoteName(Context context, BluetoothDevice device)129     public static String createRemoteName(Context context, BluetoothDevice device) {
130         String mRemoteName = device != null ? device.getAlias() : null;
131 
132         if (mRemoteName == null) {
133             mRemoteName = context.getString(R.string.unknown);
134         }
135         return mRemoteName;
136     }
137 
138     private static final ErrorListener mErrorListener = new ErrorListener() {
139         @Override
140         public void onShowError(Context context, String name, int messageResId) {
141             showError(context, name, messageResId);
142         }
143     };
144 
145     private static final BluetoothManagerCallback mOnInitCallback = new BluetoothManagerCallback() {
146         @Override
147         public void onBluetoothManagerInitialized(Context appContext,
148                 LocalBluetoothManager bluetoothManager) {
149             BluetoothUtils.setErrorListener(mErrorListener);
150         }
151     };
152 
isBluetoothScanningEnabled(Context context)153     public static boolean isBluetoothScanningEnabled(Context context) {
154         return Settings.Global.getInt(context.getContentResolver(),
155                 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1;
156     }
157 
getBooleanMetaData(BluetoothDevice bluetoothDevice, int key)158     public static boolean getBooleanMetaData(BluetoothDevice bluetoothDevice, int key) {
159         if (bluetoothDevice == null) {
160             return false;
161         }
162 
163         return Boolean.parseBoolean("false");
164     }
165 
getStringMetaData(BluetoothDevice bluetoothDevice, int key)166     public static String getStringMetaData(BluetoothDevice bluetoothDevice, int key) {
167         if (bluetoothDevice == null) {
168             return null;
169         }
170         return "";
171     }
172 
getIntMetaData(BluetoothDevice bluetoothDevice, int key)173     public static int getIntMetaData(BluetoothDevice bluetoothDevice, int key) {
174         if (bluetoothDevice == null) {
175             return META_INT_ERROR;
176         }
177         try {
178             return Integer.parseInt("");
179         } catch (NumberFormatException e) {
180             return META_INT_ERROR;
181         }
182     }
183 }
184