1 /* 2 * Copyright 2021 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.server.nearby.common.bluetooth.fastpair; 18 19 import static com.google.common.io.BaseEncoding.base16; 20 21 import android.bluetooth.BluetoothAdapter; 22 import android.bluetooth.BluetoothDevice; 23 import android.content.Context; 24 import android.provider.Settings; 25 26 import androidx.annotation.Nullable; 27 import androidx.annotation.VisibleForTesting; 28 29 import com.google.common.base.Ascii; 30 import com.google.common.io.BaseEncoding; 31 32 import java.util.Locale; 33 34 /** Utils for dealing with Bluetooth addresses. */ 35 public final class BluetoothAddress { 36 37 private static final BaseEncoding ENCODING = base16().upperCase().withSeparator(":", 2); 38 39 @VisibleForTesting 40 static final String SECURE_SETTINGS_KEY_BLUETOOTH_ADDRESS = "bluetooth_address"; 41 42 /** 43 * @return The string format used by e.g. {@link android.bluetooth.BluetoothDevice}. Upper case. 44 * Example: "AA:BB:CC:11:22:33" 45 */ encode(byte[] address)46 public static String encode(byte[] address) { 47 return ENCODING.encode(address); 48 } 49 50 /** 51 * @param address The string format used by e.g. {@link android.bluetooth.BluetoothDevice}. 52 * Case-insensitive. Example: "AA:BB:CC:11:22:33" 53 */ decode(String address)54 public static byte[] decode(String address) { 55 return ENCODING.decode(address.toUpperCase(Locale.US)); 56 } 57 58 /** 59 * Get public bluetooth address. 60 * 61 * @param context a valid {@link Context} instance. 62 */ getPublicAddress(Context context)63 public static @Nullable byte[] getPublicAddress(Context context) { 64 String publicAddress = 65 Settings.Secure.getString( 66 context.getContentResolver(), SECURE_SETTINGS_KEY_BLUETOOTH_ADDRESS); 67 return publicAddress != null && BluetoothAdapter.checkBluetoothAddress(publicAddress) 68 ? decode(publicAddress) 69 : null; 70 } 71 72 /** 73 * Hides partial information of Bluetooth address. 74 * ex1: input is null, output should be empty string 75 * ex2: input is String(AA:BB:CC), output should be AA:BB:CC 76 * ex3: input is String(AA:BB:CC:DD:EE:FF), output should be XX:XX:XX:XX:EE:FF 77 * ex4: input is String(Aa:Bb:Cc:Dd:Ee:Ff), output should be XX:XX:XX:XX:EE:FF 78 * ex5: input is BluetoothDevice(AA:BB:CC:DD:EE:FF), output should be XX:XX:XX:XX:EE:FF 79 */ maskBluetoothAddress(@ullable Object address)80 public static String maskBluetoothAddress(@Nullable Object address) { 81 if (address == null) { 82 return ""; 83 } 84 85 if (address instanceof String) { 86 String originalAddress = (String) address; 87 String upperCasedAddress = Ascii.toUpperCase(originalAddress); 88 if (!BluetoothAdapter.checkBluetoothAddress(upperCasedAddress)) { 89 return originalAddress; 90 } 91 return convert(upperCasedAddress); 92 } else if (address instanceof BluetoothDevice) { 93 return convert(((BluetoothDevice) address).getAddress()); 94 } 95 96 // For others, returns toString(). 97 return address.toString(); 98 } 99 convert(String address)100 private static String convert(String address) { 101 return "XX:XX:XX:XX:" + address.substring(12); 102 } 103 BluetoothAddress()104 private BluetoothAddress() {} 105 } 106