Unbind from service on app killed and dedup association requests
1. Listen to calling package binder death stopping the scanning on that.
2. Don't restart scanning when a request with the same values was made.
Bug: 30932767
Test: 1.:
- Using a test app start scanning and kill the app.
- In debug mode ensure that DeviceDiscoveryService#stopScan gets triggered
2.:
- Start scanning and rotate the device while device chooser is visible
- Ensure no visible loss of state is happening
Change-Id: If126a2c963da90172a956fbd88e6b3dcd7ac8b01
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 124749a..f719749 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -93,6 +93,7 @@
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Build;
+import android.os.Debug;
import android.os.DropBoxManager;
import android.os.HardwarePropertiesManager;
import android.os.IBatteryPropertiesRegistrar;
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index bb844a3..919f4ba 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* A request for the user to select a companion device to associate with.
@@ -69,6 +70,20 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ AssociationRequest that = (AssociationRequest) o;
+ return mSingleDevice == that.mSingleDevice &&
+ Objects.equals(mDeviceFilters, that.mDeviceFilters);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSingleDevice, mDeviceFilters);
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (mSingleDevice ? 1 : 0));
dest.writeParcelableList(mDeviceFilters, flags);
diff --git a/core/java/android/companion/BluetoothDeviceFilter.java b/core/java/android/companion/BluetoothDeviceFilter.java
index 1d8df7f..84e1536 100644
--- a/core/java/android/companion/BluetoothDeviceFilter.java
+++ b/core/java/android/companion/BluetoothDeviceFilter.java
@@ -35,6 +35,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.regex.Pattern;
/**
@@ -123,6 +124,22 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BluetoothDeviceFilter that = (BluetoothDeviceFilter) o;
+ return Objects.equals(mNamePattern, that.mNamePattern) &&
+ Objects.equals(mAddress, that.mAddress) &&
+ Objects.equals(mServiceUuids, that.mServiceUuids) &&
+ Objects.equals(mServiceUuidMasks, that.mServiceUuidMasks);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNamePattern, mAddress, mServiceUuids, mServiceUuidMasks);
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java
index e057fbc..0444775 100644
--- a/core/java/android/companion/BluetoothLEDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.java
@@ -36,6 +36,8 @@
import com.android.internal.util.ObjectUtils;
import com.android.internal.util.Preconditions;
+import java.util.Arrays;
+import java.util.Objects;
import java.util.regex.Pattern;
/**
@@ -160,9 +162,39 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BluetoothLEDeviceFilter that = (BluetoothLEDeviceFilter) o;
+ return mRenameBytesFrom == that.mRenameBytesFrom &&
+ mRenameBytesTo == that.mRenameBytesTo &&
+ mRenameBytesReverseOrder == that.mRenameBytesReverseOrder &&
+ Objects.equals(mNamePattern, that.mNamePattern) &&
+ Objects.equals(mScanFilter, that.mScanFilter) &&
+ Arrays.equals(mRawDataFilter, that.mRawDataFilter) &&
+ Arrays.equals(mRawDataFilterMask, that.mRawDataFilterMask) &&
+ Objects.equals(mRenamePrefix, that.mRenamePrefix) &&
+ Objects.equals(mRenameSuffix, that.mRenameSuffix);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNamePattern, mScanFilter, mRawDataFilter, mRawDataFilterMask,
+ mRenamePrefix, mRenameSuffix, mRenameBytesFrom, mRenameBytesTo,
+ mRenameBytesReverseOrder);
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(patternToString(getNamePattern()));
dest.writeParcelable(mScanFilter, flags);
+ dest.writeByteArray(mRawDataFilter);
+ dest.writeByteArray(mRawDataFilterMask);
+ dest.writeString(mRenamePrefix);
+ dest.writeString(mRenameSuffix);
+ dest.writeInt(mRenameBytesFrom);
+ dest.writeInt(mRenameBytesTo);
+ dest.writeBoolean(mRenameBytesReverseOrder);
}
@Override
@@ -174,13 +206,23 @@
= new Creator<BluetoothLEDeviceFilter>() {
@Override
public BluetoothLEDeviceFilter createFromParcel(Parcel in) {
- return new BluetoothLEDeviceFilter.Builder()
+ Builder builder = new Builder()
.setNamePattern(patternFromString(in.readString()))
- .setScanFilter(in.readParcelable(null))
- .setRawDataFilter(in.readBlob(), in.readBlob())
- .setRename(in.readString(), in.readString(),
- in.readInt(), in.readInt(), in.readBoolean())
- .build();
+ .setScanFilter(in.readParcelable(null));
+ byte[] rawDataFilter = in.createByteArray();
+ byte[] rawDataFilterMask = in.createByteArray();
+ if (rawDataFilter != null) {
+ builder.setRawDataFilter(rawDataFilter, rawDataFilterMask);
+ }
+ String renamePrefix = in.readString();
+ String suffix = in.readString();
+ int bytesFrom = in.readInt();
+ int bytesTo = in.readInt();
+ boolean bytesReverseOrder = in.readBoolean();
+ if (renamePrefix != null) {
+ builder.setRename(renamePrefix, suffix, bytesFrom, bytesTo, bytesReverseOrder);
+ }
+ return builder.build();
}
@Override
@@ -240,12 +282,14 @@
*/
@NonNull
public Builder setRawDataFilter(@NonNull byte[] rawDataFilter,
- @NonNull byte[] rawDataFilterMask) {
+ @Nullable byte[] rawDataFilterMask) {
checkNotUsed();
- checkArgument(rawDataFilter.length == rawDataFilterMask.length,
+ Preconditions.checkNotNull(rawDataFilter);
+ checkArgument(rawDataFilterMask == null ||
+ rawDataFilter.length == rawDataFilterMask.length,
"Mask and filter should be the same length");
- mRawDataFilter = Preconditions.checkNotNull(rawDataFilter);
- mRawDataFilterMask = Preconditions.checkNotNull(rawDataFilterMask);
+ mRawDataFilter = rawDataFilter;
+ mRawDataFilterMask = rawDataFilterMask;
return this;
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index ecdc0ce..0d8e365 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -17,6 +17,8 @@
package android.companion;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -24,7 +26,6 @@
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Handler;
-import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
@@ -43,7 +44,7 @@
*/
public final class CompanionDeviceManager {
- private static final boolean DEBUG = false; //TODO
+ private static final boolean DEBUG = false;
private static final String LOG_TAG = "CompanionDeviceManager";
/**
@@ -129,10 +130,9 @@
if (!checkFeaturePresent()) {
return;
}
-
- final Handler finalHandler = handler != null
- ? handler
- : new Handler(Looper.getMainLooper());
+ checkNotNull(request, "Request cannot be null");
+ checkNotNull(callback, "Callback cannot be null");
+ final Handler finalHandler = Handler.mainIfNull(handler);
try {
mService.associate(
request,
diff --git a/core/java/android/companion/WifiDeviceFilter.java b/core/java/android/companion/WifiDeviceFilter.java
index 1ab9ce1..b6e704c 100644
--- a/core/java/android/companion/WifiDeviceFilter.java
+++ b/core/java/android/companion/WifiDeviceFilter.java
@@ -29,6 +29,7 @@
import android.os.Parcel;
import android.provider.OneTimeUseBuilder;
+import java.util.Objects;
import java.util.regex.Pattern;
/**
@@ -75,6 +76,19 @@
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ WifiDeviceFilter that = (WifiDeviceFilter) o;
+ return Objects.equals(mNamePattern, that.mNamePattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNamePattern);
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(patternToString(getNamePattern()));
}
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 3c7c962..8678d95 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.Log;
import android.util.Printer;
@@ -69,6 +71,7 @@
*/
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
+ private static Handler MAIN_THREAD_HANDLER = null;
/**
* Callback interface you can use when instantiating a Handler to avoid
@@ -231,6 +234,21 @@
mAsynchronous = async;
}
+ /** @hide */
+ @NonNull
+ public static Handler getMain() {
+ if (MAIN_THREAD_HANDLER == null) {
+ MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
+ }
+ return MAIN_THREAD_HANDLER;
+ }
+
+ /** @hide */
+ @NonNull
+ public static Handler mainIfNull(@Nullable Handler handler) {
+ return handler == null ? getMain() : handler;
+ }
+
/** {@hide} */
public String getTraceName(Message message) {
final StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java
index 87231e1..44019c32 100644
--- a/core/java/android/util/ExceptionUtils.java
+++ b/core/java/android/util/ExceptionUtils.java
@@ -17,6 +17,7 @@
package android.util;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.ParcelableException;
import com.android.internal.util.Preconditions;
@@ -55,10 +56,26 @@
return getCompleteMessage(null, t);
}
+ public static <E extends Throwable> void propagateIfInstanceOf(
+ @Nullable Throwable t, Class<E> c) throws E {
+ if (t != null && c.isInstance(t)) {
+ throw c.cast(t);
+ }
+ }
+
+ /**
+ * @param <E> a checked exception that is ok to throw without wrapping
+ */
+ public static <E extends Exception> RuntimeException propagate(@NonNull Throwable t, Class<E> c)
+ throws E {
+ propagateIfInstanceOf(t, c);
+ return propagate(t);
+ }
+
public static RuntimeException propagate(@NonNull Throwable t) {
Preconditions.checkNotNull(t);
- if (t instanceof Error) throw (Error)t;
- if (t instanceof RuntimeException) throw (RuntimeException)t;
+ propagateIfInstanceOf(t, Error.class);
+ propagateIfInstanceOf(t, RuntimeException.class);
throw new RuntimeException(t);
}
}