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 android.annotation.WorkerThread; 20 import android.bluetooth.BluetoothDevice; 21 22 import androidx.annotation.Nullable; 23 import androidx.core.util.Consumer; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.server.nearby.common.bluetooth.BluetoothException; 27 28 import java.security.GeneralSecurityException; 29 import java.util.Arrays; 30 import java.util.List; 31 import java.util.Objects; 32 import java.util.concurrent.ExecutionException; 33 import java.util.concurrent.TimeoutException; 34 35 /** Abstract class for pairing or connecting via FastPair. */ 36 public abstract class FastPairConnection { 37 @Nullable protected OnPairedCallback mPairedCallback; 38 @Nullable protected OnGetBluetoothAddressCallback mOnGetBluetoothAddressCallback; 39 @Nullable protected PasskeyConfirmationHandler mPasskeyConfirmationHandler; 40 @Nullable protected FastPairSignalChecker mFastPairSignalChecker; 41 @Nullable protected Consumer<Integer> mRescueFromError; 42 @Nullable protected Runnable mPrepareCreateBondCallback; 43 protected boolean mPasskeyIsGotten; 44 45 /** Sets a callback to be invoked once the device is paired. */ setOnPairedCallback(OnPairedCallback callback)46 public void setOnPairedCallback(OnPairedCallback callback) { 47 this.mPairedCallback = callback; 48 } 49 50 /** Sets a callback to be invoked while the target bluetooth address is decided. */ setOnGetBluetoothAddressCallback(OnGetBluetoothAddressCallback callback)51 public void setOnGetBluetoothAddressCallback(OnGetBluetoothAddressCallback callback) { 52 this.mOnGetBluetoothAddressCallback = callback; 53 } 54 55 /** Sets a callback to be invoked while handling the passkey confirmation. */ setPasskeyConfirmationHandler( PasskeyConfirmationHandler passkeyConfirmationHandler)56 public void setPasskeyConfirmationHandler( 57 PasskeyConfirmationHandler passkeyConfirmationHandler) { 58 this.mPasskeyConfirmationHandler = passkeyConfirmationHandler; 59 } 60 setFastPairSignalChecker(FastPairSignalChecker fastPairSignalChecker)61 public void setFastPairSignalChecker(FastPairSignalChecker fastPairSignalChecker) { 62 this.mFastPairSignalChecker = fastPairSignalChecker; 63 } 64 setRescueFromError(Consumer<Integer> rescueFromError)65 public void setRescueFromError(Consumer<Integer> rescueFromError) { 66 this.mRescueFromError = rescueFromError; 67 } 68 setPrepareCreateBondCallback(Runnable runnable)69 public void setPrepareCreateBondCallback(Runnable runnable) { 70 this.mPrepareCreateBondCallback = runnable; 71 } 72 73 @VisibleForTesting 74 @Nullable getPrepareCreateBondCallback()75 public Runnable getPrepareCreateBondCallback() { 76 return mPrepareCreateBondCallback; 77 } 78 79 /** 80 * Sets the fast pair history for identifying whether or not the provider has paired with the 81 * primary account on other phones before. 82 */ 83 @WorkerThread setFastPairHistory(List<FastPairHistoryItem> fastPairHistoryItem)84 public abstract void setFastPairHistory(List<FastPairHistoryItem> fastPairHistoryItem); 85 86 /** Sets the device name to the Provider. */ setProviderDeviceName(String deviceName)87 public abstract void setProviderDeviceName(String deviceName); 88 89 /** Gets the device name from the Provider. */ 90 @Nullable getProviderDeviceName()91 public abstract String getProviderDeviceName(); 92 93 /** 94 * Gets the existing account key of the Provider. 95 * 96 * @return the existing account key if the Provider has paired with the account, null otherwise 97 */ 98 @WorkerThread 99 @Nullable getExistingAccountKey()100 public abstract byte[] getExistingAccountKey(); 101 102 /** 103 * Pairs with Provider. Synchronous: Blocks until paired and connected. Throws on any error. 104 * 105 * @return the secret key for the user's account, if written 106 */ 107 @WorkerThread 108 @Nullable pair()109 public abstract SharedSecret pair() 110 throws BluetoothException, InterruptedException, TimeoutException, ExecutionException, 111 PairingException, ReflectionException; 112 113 /** 114 * Pairs with Provider. Synchronous: Blocks until paired and connected. Throws on any error. 115 * 116 * @param key can be in two different formats. If it is 16 bytes long, then it is an AES account 117 * key. Otherwise, it's a public key generated by {@link EllipticCurveDiffieHellmanExchange}. 118 * See go/fast-pair-2-spec for how each of these keys are used. 119 * @return the secret key for the user's account, if written 120 */ 121 @WorkerThread 122 @Nullable pair(@ullable byte[] key)123 public abstract SharedSecret pair(@Nullable byte[] key) 124 throws BluetoothException, InterruptedException, TimeoutException, ExecutionException, 125 PairingException, GeneralSecurityException, ReflectionException; 126 127 /** Unpairs with Provider. Synchronous: Blocks until unpaired. Throws on any error. */ 128 @WorkerThread unpair(BluetoothDevice device)129 public abstract void unpair(BluetoothDevice device) 130 throws InterruptedException, TimeoutException, ExecutionException, PairingException, 131 ReflectionException; 132 133 /** Gets the public address of the Provider. */ 134 @Nullable getPublicAddress()135 public abstract String getPublicAddress(); 136 137 138 /** Callback for getting notifications when pairing has completed. */ 139 public interface OnPairedCallback { 140 /** Called when the device at address has finished pairing. */ onPaired(String address)141 void onPaired(String address); 142 } 143 144 /** Callback for getting bluetooth address Bisto oobe need this information */ 145 public interface OnGetBluetoothAddressCallback { 146 /** Called when the device has received bluetooth address. */ onGetBluetoothAddress(String address)147 void onGetBluetoothAddress(String address); 148 } 149 150 /** Holds the exchanged secret key and the public mac address of the device. */ 151 public static class SharedSecret { 152 private final byte[] mKey; 153 private final String mAddress; SharedSecret(byte[] key, String address)154 private SharedSecret(byte[] key, String address) { 155 mKey = key; 156 mAddress = address; 157 } 158 159 /** Creates Shared Secret. */ create(byte[] key, String address)160 public static SharedSecret create(byte[] key, String address) { 161 return new SharedSecret(key, address); 162 } 163 164 /** Gets Shared Secret Key. */ getKey()165 public byte[] getKey() { 166 return mKey; 167 } 168 169 /** Gets Shared Secret Address. */ getAddress()170 public String getAddress() { 171 return mAddress; 172 } 173 174 @Override toString()175 public String toString() { 176 return "SharedSecret{" 177 + "key=" + Arrays.toString(mKey) + ", " 178 + "address=" + mAddress 179 + "}"; 180 } 181 182 @Override equals(@ullable Object o)183 public boolean equals(@Nullable Object o) { 184 if (o == this) { 185 return true; 186 } 187 if (o instanceof SharedSecret) { 188 SharedSecret that = (SharedSecret) o; 189 return Arrays.equals(this.mKey, that.getKey()) 190 && this.mAddress.equals(that.getAddress()); 191 } 192 return false; 193 } 194 195 @Override hashCode()196 public int hashCode() { 197 return Objects.hash(Arrays.hashCode(mKey), mAddress); 198 } 199 } 200 201 /** Invokes if gotten the passkey. */ setPasskeyIsGotten()202 public void setPasskeyIsGotten() { 203 mPasskeyIsGotten = true; 204 } 205 206 /** Returns the value of passkeyIsGotten. */ getPasskeyIsGotten()207 public boolean getPasskeyIsGotten() { 208 return mPasskeyIsGotten; 209 } 210 211 /** Interface to get latest address of ModelId. */ 212 public interface FastPairSignalChecker { 213 /** Gets address of ModelId. */ getValidAddressForModelId(String currentDevice)214 String getValidAddressForModelId(String currentDevice); 215 } 216 } 217