BondStateMachine: Allow skipping confirm for some remotes
When pairing two of the Nvidia Shield accessories, a popup would show up
stating that the accessory was an incoming pairing request and needs to
be accepted. The official Nvidia firmware has a whitelist of remotes
that skip this confirmation if pairing request is marked as originating
from the Android device. This change takes a similar approach, but in a
more flexible manner. The main intent is to allow these accessories to
be paired via the pairing intent, which needs to complete with no user
interaction. Previously, the popup would prevent this from succeeding.
Change-Id: Ib5a0226858f5745a20e4cd166500aecdcf1f3354
diff --git a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java
index c6633da..6d64cfd 100644
--- a/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java
+++ b/android/app/src/com/android/bluetooth/btservice/BondStateMachine.java
@@ -32,6 +32,7 @@
import android.os.Message;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Pair;
import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.Utils;
@@ -48,6 +49,7 @@
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -384,7 +386,37 @@
return false;
}
+ // Defining these properly would break current api
+ private static int PERIPHERAL_GAMEPAD = BluetoothClass.Device.Major.PERIPHERAL | 0x08;
+ private static int PERIPHERAL_REMOTE = BluetoothClass.Device.Major.PERIPHERAL | 0x0C;
+
+ private static List<Pair<String, Integer>> accConfirmSkip = new ArrayList<>();
+
+ static {
+ // Jarvis, SHIELD Remote 2015
+ accConfirmSkip.add(new Pair<>("SHIELD Remote", PERIPHERAL_REMOTE));
+ // Thunderstrike, SHIELD Controller 2017
+ accConfirmSkip.add(new Pair<>("NVIDIA Controller v01.04", PERIPHERAL_GAMEPAD));
+ };
+
+ private boolean isSkipConfirmationAccessory(BluetoothDevice device) {
+ for (Pair<String, Integer> entry : accConfirmSkip) {
+ if (device.getName().equals(entry.first)
+ && device.getBluetoothClass().getDeviceClass() == entry.second) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private void sendDisplayPinIntent(byte[] address, Optional<Integer> maybePin, int variant) {
+ BluetoothDevice device = mRemoteDevices.getDevice(address);
+ if (device != null && device.isBondingInitiatedLocally()
+ && isSkipConfirmationAccessory(device)) {
+ device.setPairingConfirmation(true);
+ return;
+ }
Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevices.getDevice(address));
maybePin.ifPresent(pin -> intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin));