1 /* 2 * Copyright (C) 2022 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 android.companion; 18 19 import android.bluetooth.BluetoothDevice; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 23 import androidx.annotation.NonNull; 24 import androidx.annotation.Nullable; 25 26 /** 27 * Container for device info from an association that is not self-managed. 28 * Device can be one of three types: 29 * 30 * <ul> 31 * <li>for classic Bluetooth - {@link android.bluetooth.BluetoothDevice}</li> 32 * <li>for Bluetooth LE - {@link android.bluetooth.le.ScanResult}</li> 33 * <li>for WiFi - {@link android.net.wifi.ScanResult}</li> 34 * </ul> 35 */ 36 public final class AssociatedDevice implements Parcelable { 37 private static final int CLASSIC_BLUETOOTH = 0; 38 private static final int BLUETOOTH_LE = 1; 39 private static final int WIFI = 2; 40 41 @NonNull private final Parcelable mDevice; 42 43 /** @hide */ AssociatedDevice(@onNull Parcelable device)44 public AssociatedDevice(@NonNull Parcelable device) { 45 mDevice = device; 46 } 47 AssociatedDevice(Parcel in)48 private AssociatedDevice(Parcel in) { 49 Creator<? extends Parcelable> creator = getDeviceCreator(in.readInt()); 50 mDevice = creator.createFromParcel(in); 51 } 52 53 /** 54 * Return bluetooth device info. Null if associated device is not a bluetooth device. 55 * @return Remote bluetooth device details containing MAC address. 56 */ 57 @Nullable getBluetoothDevice()58 public BluetoothDevice getBluetoothDevice() { 59 if (mDevice instanceof BluetoothDevice) { 60 return (BluetoothDevice) mDevice; 61 } 62 return null; 63 } 64 65 /** 66 * Return bluetooth LE device info. Null if associated device is not a BLE device. 67 * @return BLE scan result containing details of detected BLE device. 68 */ 69 @Nullable getBleDevice()70 public android.bluetooth.le.ScanResult getBleDevice() { 71 if (mDevice instanceof android.bluetooth.le.ScanResult) { 72 return (android.bluetooth.le.ScanResult) mDevice; 73 } 74 return null; 75 } 76 77 /** 78 * Return Wi-Fi device info. Null if associated device is not a Wi-Fi device. 79 * @return Wi-Fi scan result containing details of detected access point. 80 */ 81 @Nullable getWifiDevice()82 public android.net.wifi.ScanResult getWifiDevice() { 83 if (mDevice instanceof android.net.wifi.ScanResult) { 84 return (android.net.wifi.ScanResult) mDevice; 85 } 86 return null; 87 } 88 89 @Override writeToParcel(@onNull Parcel dest, int flags)90 public void writeToParcel(@NonNull Parcel dest, int flags) { 91 // Parcel device type with int for efficiency 92 dest.writeInt(getDeviceType()); 93 mDevice.writeToParcel(dest, flags); 94 } 95 96 @Override describeContents()97 public int describeContents() { 98 return 0; 99 } 100 getDeviceType()101 private int getDeviceType() { 102 if (mDevice instanceof android.bluetooth.BluetoothDevice) return CLASSIC_BLUETOOTH; 103 if (mDevice instanceof android.bluetooth.le.ScanResult) return BLUETOOTH_LE; 104 if (mDevice instanceof android.net.wifi.ScanResult) return WIFI; 105 throw new UnsupportedOperationException("Unsupported device type."); 106 } 107 getDeviceCreator(int deviceType)108 private static Creator<? extends Parcelable> getDeviceCreator(int deviceType) { 109 switch (deviceType) { 110 case CLASSIC_BLUETOOTH: return android.bluetooth.BluetoothDevice.CREATOR; 111 case BLUETOOTH_LE: return android.bluetooth.le.ScanResult.CREATOR; 112 case WIFI: return android.net.wifi.ScanResult.CREATOR; 113 default: throw new UnsupportedOperationException("Unsupported device type."); 114 } 115 } 116 117 @NonNull 118 public static final Parcelable.Creator<AssociatedDevice> CREATOR = 119 new Parcelable.Creator<AssociatedDevice>() { 120 @Override 121 public AssociatedDevice[] newArray(int size) { 122 return new AssociatedDevice[size]; 123 } 124 125 @Override 126 public AssociatedDevice createFromParcel(@NonNull Parcel in) { 127 return new AssociatedDevice(in); 128 } 129 }; 130 131 @Override toString()132 public String toString() { 133 return "AssociatedDevice { " 134 + "device = " + mDevice 135 + " }"; 136 } 137 138 @Override equals(@ullable Object o)139 public boolean equals(@Nullable Object o) { 140 if (this == o) return true; 141 if (o == null || getClass() != o.getClass()) return false; 142 AssociatedDevice that = (AssociatedDevice) o; 143 if (getDeviceType() != that.getDeviceType()) return false; 144 145 // TODO(b/31972115): Take out this whole part ¯\_(ツ)_/¯ 146 if (mDevice instanceof android.bluetooth.le.ScanResult 147 || mDevice instanceof android.net.wifi.ScanResult) { 148 return mDevice.toString().equals(that.mDevice.toString()); 149 } 150 151 return java.util.Objects.equals(mDevice, that.mDevice); 152 } 153 154 @Override hashCode()155 public int hashCode() { 156 return java.util.Objects.hash(mDevice); 157 } 158 } 159