• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.tv.settings.accessories;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothClass;
21 import android.bluetooth.BluetoothDevice;
22 import android.content.Context;
23 import android.text.Html;
24 import android.util.Log;
25 
26 import androidx.annotation.Nullable;
27 
28 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
29 import com.android.settingslib.bluetooth.LocalBluetoothManager;
30 import com.android.tv.settings.R;
31 
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.concurrent.ExecutionException;
36 import java.util.concurrent.FutureTask;
37 
38 /** Provide utilities for Remote & Accessories. */
39 final class AccessoryUtils {
40 
41     public static final String TAG = "AccessoryUtils";
42 
43     private static final int MINOR_MASK = 0b11111100;
44     // Includes any generic keyboards or pointers, and any joystick, game pad, or remote subtypes.
45     private static final int MINOR_REMOTE_MASK = 0b11001100;
46     private static List<String> sKnownDeviceLabels = null;
47 
48     /** This allows OEM to easily override the main Service if desired. */
getBluetoothDeviceServiceClass()49     public static Class getBluetoothDeviceServiceClass() {
50         return BluetoothDevicesService.class;
51     }
52 
getLocalBluetoothManager(Context context)53     public static LocalBluetoothManager getLocalBluetoothManager(Context context) {
54         final FutureTask<LocalBluetoothManager> localBluetoothManagerFutureTask =
55                 new FutureTask<>(
56                         // Avoid StrictMode ThreadPolicy violation
57                         () -> LocalBluetoothManager.getInstance(
58                                 context, (c, bluetoothManager) -> {
59                                 })
60                 );
61         try {
62             localBluetoothManagerFutureTask.run();
63             return localBluetoothManagerFutureTask.get();
64         } catch (InterruptedException | ExecutionException e) {
65             Log.w(TAG, "Error getting LocalBluetoothManager.", e);
66             return null;
67         }
68     }
69 
getCachedBluetoothDevice( Context context, BluetoothDevice device)70     public static CachedBluetoothDevice getCachedBluetoothDevice(
71             Context context, BluetoothDevice device) {
72         LocalBluetoothManager localBluetoothManager = getLocalBluetoothManager(context);
73         if (localBluetoothManager != null) {
74             return localBluetoothManager.getCachedDeviceManager().findDevice(device);
75         }
76         return null;
77     }
78 
getDefaultBluetoothAdapter()79     public static BluetoothAdapter getDefaultBluetoothAdapter() {
80         final FutureTask<BluetoothAdapter> defaultBluetoothAdapterFutureTask =
81                 new FutureTask<>(
82                         // Avoid StrictMode ThreadPolicy violation
83                         BluetoothAdapter::getDefaultAdapter);
84         try {
85             defaultBluetoothAdapterFutureTask.run();
86             return defaultBluetoothAdapterFutureTask.get();
87         } catch (InterruptedException | ExecutionException e) {
88             Log.w(TAG, "Error getting default BluetoothAdapter.", e);
89             return null;
90         }
91     }
92 
getLocalName(BluetoothDevice device)93     public static String getLocalName(BluetoothDevice device) {
94         if (device == null) {
95             return null;
96         }
97         return device.getAlias();
98     }
99 
isBluetoothEnabled()100     public static boolean isBluetoothEnabled() {
101         return getDefaultBluetoothAdapter() != null && getDefaultBluetoothAdapter().isEnabled();
102     }
103 
isConnected(BluetoothDevice device)104     public static boolean isConnected(BluetoothDevice device) {
105         if (device == null) {
106             return false;
107         }
108         return device.getBondState() == BluetoothDevice.BOND_BONDED && device.isConnected();
109     }
110 
isBonded(BluetoothDevice device)111     public static boolean isBonded(BluetoothDevice device) {
112         if (device == null) {
113             return false;
114         }
115         return device.getBondState() == BluetoothDevice.BOND_BONDED && !device.isConnected();
116     }
117 
isRemoteClass(BluetoothDevice device)118     public static boolean isRemoteClass(BluetoothDevice device) {
119         if (device == null || device.getBluetoothClass() == null) {
120             return false;
121         }
122         int major = device.getBluetoothClass().getMajorDeviceClass();
123         int minor = device.getBluetoothClass().getDeviceClass() & MINOR_MASK;
124         return BluetoothClass.Device.Major.PERIPHERAL == major
125                 && (minor & ~MINOR_REMOTE_MASK) == 0;
126     }
127 
128     // For partner, this will be used to identify official device to omit it in the generic
129     // accessories section since the device's settings will be displayed in partner-implemented
130     // Slice.
isKnownDevice(Context context, BluetoothDevice device)131     public static boolean isKnownDevice(Context context, BluetoothDevice device) {
132         if (device == null || device.getName() == null) {
133             return false;
134         }
135         if (sKnownDeviceLabels == null) {
136             if (context == null) {
137                 return false;
138             } else {
139                 sKnownDeviceLabels =
140                         Collections.unmodifiableList(
141                                 Arrays.asList(context.getResources().getStringArray(
142                                         R.array.known_bluetooth_device_labels)));
143                 // For backward compatibility, the customization name used to be known_remote_labels
144                 if (sKnownDeviceLabels.isEmpty()) {
145                     sKnownDeviceLabels = Collections.unmodifiableList(
146                             Arrays.asList(
147                                 context.getResources().getStringArray(
148                                     R.array.known_remote_labels)));
149                 }
150             }
151         }
152 
153         final String name = device.getName().toLowerCase();
154         for (String knownLabel : sKnownDeviceLabels) {
155             if (name.contains(knownLabel.toLowerCase())) {
156                 return true;
157             }
158         }
159         return false;
160     }
161 
162     @Nullable
getHtmlEscapedDeviceName(@ullable BluetoothDevice bluetoothDevice)163     static String getHtmlEscapedDeviceName(@Nullable BluetoothDevice bluetoothDevice) {
164         if (bluetoothDevice == null || bluetoothDevice.getName() == null) {
165             return null;
166         }
167         return Html.escapeHtml(bluetoothDevice.getName());
168     }
169 
AccessoryUtils()170     private AccessoryUtils() {
171         // do not allow instantiation
172     }
173 }
174