Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +69 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; Loading @@ -24,6 +25,7 @@ import android.util.Pair; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import androidx.core.graphics.drawable.IconCompat; Loading @@ -31,9 +33,12 @@ import com.android.settingslib.R; import com.android.settingslib.widget.AdaptiveIcon; import com.android.settingslib.widget.AdaptiveOutlineDrawable; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; Loading @@ -47,6 +52,8 @@ public class BluetoothUtils { public static final String BT_ADVANCED_HEADER_ENABLED = "bt_advanced_header_enabled"; private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25; private static final String KEY_HEARABLE_CONTROL_SLICE = "HEARABLE_CONTROL_SLICE_WITH_WIDTH"; private static final Set<String> EXCLUSIVE_MANAGERS = ImmutableSet.of( "com.google.android.gms.dck"); private static ErrorListener sErrorListener; Loading Loading @@ -647,4 +654,66 @@ public class BluetoothUtils { private static String generateExpressionWithTag(String tag, String value) { return getTagStart(tag) + value + getTagEnd(tag); } /** * Returns the BluetoothDevice's exclusive manager * ({@link BluetoothDevice.METADATA_EXCLUSIVE_MANAGER} in metadata) if it exists and is in the * given set, otherwise null. */ @Nullable private static String getAllowedExclusiveManager(BluetoothDevice bluetoothDevice) { byte[] exclusiveManagerNameBytes = bluetoothDevice.getMetadata( BluetoothDevice.METADATA_EXCLUSIVE_MANAGER); if (exclusiveManagerNameBytes == null) { Log.d(TAG, "Bluetooth device " + bluetoothDevice.getName() + " doesn't have exclusive manager"); return null; } String exclusiveManagerName = new String(exclusiveManagerNameBytes); return getExclusiveManagers().contains(exclusiveManagerName) ? exclusiveManagerName : null; } /** * Checks if given package is installed */ private static boolean isPackageInstalled(Context context, String packageName) { PackageManager packageManager = context.getPackageManager(); try { packageManager.getPackageInfo(packageName, 0); return true; } catch (PackageManager.NameNotFoundException e) { Log.d(TAG, "Package " + packageName + " is not installed"); } return false; } /** * A BluetoothDevice is exclusively managed if * 1) it has field {@link BluetoothDevice.METADATA_EXCLUSIVE_MANAGER} in metadata. * 2) the exclusive manager app name is in the allowlist. * 3) the exclusive manager app is installed. */ public static boolean isExclusivelyManagedBluetoothDevice(@NonNull Context context, @NonNull BluetoothDevice bluetoothDevice) { String exclusiveManagerName = getAllowedExclusiveManager(bluetoothDevice); if (exclusiveManagerName == null) { return false; } if (!isPackageInstalled(context, exclusiveManagerName)) { return false; } else { Log.d(TAG, "Found exclusively managed app " + exclusiveManagerName); return true; } } /** * Return the allowlist for exclusive manager names. */ @NonNull public static Set<String> getExclusiveManagers() { return EXCLUSIVE_MANAGERS; } } packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java +58 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -24,6 +26,8 @@ import static org.mockito.Mockito.when; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; Loading @@ -49,6 +53,8 @@ public class BluetoothUtilsTest { private BluetoothDevice mBluetoothDevice; @Mock private AudioManager mAudioManager; @Mock private PackageManager mPackageManager; private Context mContext; private static final String STRING_METADATA = "string_metadata"; Loading @@ -59,6 +65,7 @@ public class BluetoothUtilsTest { private static final String CONTROL_METADATA = "<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" + STRING_METADATA + "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>"; private static final String FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name"; @Before public void setUp() { Loading Loading @@ -372,4 +379,55 @@ public class BluetoothUtilsTest { assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager)).isEqualTo(false); } @Test public void isExclusivelyManagedBluetoothDevice_isNotExclusivelyManaged_returnFalse() { when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( null); assertThat(BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, mBluetoothDevice)).isEqualTo(false); } @Test public void isExclusivelyManagedBluetoothDevice_isNotInAllowList_returnFalse() { when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( FAKE_EXCLUSIVE_MANAGER_NAME.getBytes()); assertThat(BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, mBluetoothDevice)).isEqualTo(false); } @Test public void isExclusivelyManagedBluetoothDevice_packageNotInstalled_returnFalse() throws Exception { final String exclusiveManagerName = BluetoothUtils.getExclusiveManagers().stream().findAny().orElse( FAKE_EXCLUSIVE_MANAGER_NAME); when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( exclusiveManagerName.getBytes()); when(mContext.getPackageManager()).thenReturn(mPackageManager); doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo( exclusiveManagerName, 0); assertThat(BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, mBluetoothDevice)).isEqualTo(false); } @Test public void isExclusivelyManagedBluetoothDevice_isExclusivelyManaged_returnTrue() throws Exception { final String exclusiveManagerName = BluetoothUtils.getExclusiveManagers().stream().findAny().orElse( FAKE_EXCLUSIVE_MANAGER_NAME); when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( exclusiveManagerName.getBytes()); when(mContext.getPackageManager()).thenReturn(mPackageManager); doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0); assertThat(BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, mBluetoothDevice)).isEqualTo(true); } } Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +69 −0 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; Loading @@ -24,6 +25,7 @@ import android.util.Pair; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import androidx.core.graphics.drawable.IconCompat; Loading @@ -31,9 +33,12 @@ import com.android.settingslib.R; import com.android.settingslib.widget.AdaptiveIcon; import com.android.settingslib.widget.AdaptiveOutlineDrawable; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; Loading @@ -47,6 +52,8 @@ public class BluetoothUtils { public static final String BT_ADVANCED_HEADER_ENABLED = "bt_advanced_header_enabled"; private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25; private static final String KEY_HEARABLE_CONTROL_SLICE = "HEARABLE_CONTROL_SLICE_WITH_WIDTH"; private static final Set<String> EXCLUSIVE_MANAGERS = ImmutableSet.of( "com.google.android.gms.dck"); private static ErrorListener sErrorListener; Loading Loading @@ -647,4 +654,66 @@ public class BluetoothUtils { private static String generateExpressionWithTag(String tag, String value) { return getTagStart(tag) + value + getTagEnd(tag); } /** * Returns the BluetoothDevice's exclusive manager * ({@link BluetoothDevice.METADATA_EXCLUSIVE_MANAGER} in metadata) if it exists and is in the * given set, otherwise null. */ @Nullable private static String getAllowedExclusiveManager(BluetoothDevice bluetoothDevice) { byte[] exclusiveManagerNameBytes = bluetoothDevice.getMetadata( BluetoothDevice.METADATA_EXCLUSIVE_MANAGER); if (exclusiveManagerNameBytes == null) { Log.d(TAG, "Bluetooth device " + bluetoothDevice.getName() + " doesn't have exclusive manager"); return null; } String exclusiveManagerName = new String(exclusiveManagerNameBytes); return getExclusiveManagers().contains(exclusiveManagerName) ? exclusiveManagerName : null; } /** * Checks if given package is installed */ private static boolean isPackageInstalled(Context context, String packageName) { PackageManager packageManager = context.getPackageManager(); try { packageManager.getPackageInfo(packageName, 0); return true; } catch (PackageManager.NameNotFoundException e) { Log.d(TAG, "Package " + packageName + " is not installed"); } return false; } /** * A BluetoothDevice is exclusively managed if * 1) it has field {@link BluetoothDevice.METADATA_EXCLUSIVE_MANAGER} in metadata. * 2) the exclusive manager app name is in the allowlist. * 3) the exclusive manager app is installed. */ public static boolean isExclusivelyManagedBluetoothDevice(@NonNull Context context, @NonNull BluetoothDevice bluetoothDevice) { String exclusiveManagerName = getAllowedExclusiveManager(bluetoothDevice); if (exclusiveManagerName == null) { return false; } if (!isPackageInstalled(context, exclusiveManagerName)) { return false; } else { Log.d(TAG, "Found exclusively managed app " + exclusiveManagerName); return true; } } /** * Return the allowlist for exclusive manager names. */ @NonNull public static Set<String> getExclusiveManagers() { return EXCLUSIVE_MANAGERS; } }
packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java +58 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.settingslib.bluetooth; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -24,6 +26,8 @@ import static org.mockito.Mockito.when; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; Loading @@ -49,6 +53,8 @@ public class BluetoothUtilsTest { private BluetoothDevice mBluetoothDevice; @Mock private AudioManager mAudioManager; @Mock private PackageManager mPackageManager; private Context mContext; private static final String STRING_METADATA = "string_metadata"; Loading @@ -59,6 +65,7 @@ public class BluetoothUtilsTest { private static final String CONTROL_METADATA = "<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" + STRING_METADATA + "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>"; private static final String FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name"; @Before public void setUp() { Loading Loading @@ -372,4 +379,55 @@ public class BluetoothUtilsTest { assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager)).isEqualTo(false); } @Test public void isExclusivelyManagedBluetoothDevice_isNotExclusivelyManaged_returnFalse() { when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( null); assertThat(BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, mBluetoothDevice)).isEqualTo(false); } @Test public void isExclusivelyManagedBluetoothDevice_isNotInAllowList_returnFalse() { when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( FAKE_EXCLUSIVE_MANAGER_NAME.getBytes()); assertThat(BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, mBluetoothDevice)).isEqualTo(false); } @Test public void isExclusivelyManagedBluetoothDevice_packageNotInstalled_returnFalse() throws Exception { final String exclusiveManagerName = BluetoothUtils.getExclusiveManagers().stream().findAny().orElse( FAKE_EXCLUSIVE_MANAGER_NAME); when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( exclusiveManagerName.getBytes()); when(mContext.getPackageManager()).thenReturn(mPackageManager); doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo( exclusiveManagerName, 0); assertThat(BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, mBluetoothDevice)).isEqualTo(false); } @Test public void isExclusivelyManagedBluetoothDevice_isExclusivelyManaged_returnTrue() throws Exception { final String exclusiveManagerName = BluetoothUtils.getExclusiveManagers().stream().findAny().orElse( FAKE_EXCLUSIVE_MANAGER_NAME); when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn( exclusiveManagerName.getBytes()); when(mContext.getPackageManager()).thenReturn(mPackageManager); doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0); assertThat(BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext, mBluetoothDevice)).isEqualTo(true); } }