Move existing UWB API classes to UWB apex
Following instructions from go/mainline-java-lib to move the existing UWB API classes to the new apex. Bug: 194906542 Test: Compiles Change-Id: I08801b418c7ba42c76952f5a80745cd0057ca329
This commit is contained in:
@@ -156,6 +156,7 @@ java_library {
|
||||
"framework-sdkextensions.stubs.module_lib",
|
||||
"framework-statsd.stubs.module_lib",
|
||||
"framework-tethering.stubs.module_lib",
|
||||
"framework-uwb.stubs.module_lib",
|
||||
"framework-wifi.stubs.module_lib",
|
||||
],
|
||||
sdk_version: "module_current",
|
||||
@@ -178,6 +179,7 @@ java_library {
|
||||
"framework-sdkextensions.impl",
|
||||
"framework-statsd.impl",
|
||||
"framework-tethering.impl",
|
||||
"framework-uwb.impl",
|
||||
"framework-wifi.impl",
|
||||
"updatable-media",
|
||||
],
|
||||
|
||||
@@ -250,6 +250,7 @@ modules_public_stubs = [
|
||||
"framework-sdkextensions.stubs",
|
||||
"framework-statsd.stubs",
|
||||
"framework-tethering.stubs",
|
||||
"framework-uwb.stubs",
|
||||
"framework-wifi.stubs",
|
||||
"i18n.module.public.api.stubs",
|
||||
]
|
||||
@@ -269,6 +270,7 @@ modules_system_stubs = [
|
||||
"framework-sdkextensions.stubs.system",
|
||||
"framework-statsd.stubs.system",
|
||||
"framework-tethering.stubs.system",
|
||||
"framework-uwb.stubs.system",
|
||||
"framework-wifi.stubs.system",
|
||||
"i18n.module.public.api.stubs", // Only has public stubs
|
||||
]
|
||||
|
||||
@@ -90,6 +90,7 @@ genrule {
|
||||
":framework-sdkextensions{.public.api.txt}",
|
||||
":framework-statsd{.public.api.txt}",
|
||||
":framework-tethering{.public.api.txt}",
|
||||
":framework-uwb{.public.api.txt}",
|
||||
":framework-wifi{.public.api.txt}",
|
||||
":i18n.module.public.api{.public.api.txt}",
|
||||
":non-updatable-current.txt",
|
||||
@@ -149,6 +150,7 @@ genrule {
|
||||
":framework-sdkextensions{.public.stubs.source}",
|
||||
":framework-statsd{.public.stubs.source}",
|
||||
":framework-tethering{.public.stubs.source}",
|
||||
":framework-uwb{.public.stubs.source}",
|
||||
":framework-wifi{.public.stubs.source}",
|
||||
":i18n.module.public.api{.public.stubs.source}",
|
||||
],
|
||||
@@ -175,6 +177,7 @@ genrule {
|
||||
":framework-sdkextensions{.public.removed-api.txt}",
|
||||
":framework-statsd{.public.removed-api.txt}",
|
||||
":framework-tethering{.public.removed-api.txt}",
|
||||
":framework-uwb{.public.removed-api.txt}",
|
||||
":framework-wifi{.public.removed-api.txt}",
|
||||
":i18n.module.public.api{.public.removed-api.txt}",
|
||||
":non-updatable-removed.txt",
|
||||
@@ -215,6 +218,7 @@ genrule {
|
||||
":framework-sdkextensions{.system.api.txt}",
|
||||
":framework-statsd{.system.api.txt}",
|
||||
":framework-tethering{.system.api.txt}",
|
||||
":framework-uwb{.system.api.txt}",
|
||||
":framework-wifi{.system.api.txt}",
|
||||
":non-updatable-system-current.txt",
|
||||
],
|
||||
@@ -273,6 +277,7 @@ genrule {
|
||||
":framework-sdkextensions{.system.removed-api.txt}",
|
||||
":framework-statsd{.system.removed-api.txt}",
|
||||
":framework-tethering{.system.removed-api.txt}",
|
||||
":framework-uwb{.system.removed-api.txt}",
|
||||
":framework-wifi{.system.removed-api.txt}",
|
||||
":non-updatable-system-removed.txt",
|
||||
],
|
||||
@@ -313,6 +318,7 @@ genrule {
|
||||
":framework-sdkextensions{.module-lib.api.txt}",
|
||||
":framework-statsd{.module-lib.api.txt}",
|
||||
":framework-tethering{.module-lib.api.txt}",
|
||||
":framework-uwb{.module-lib.api.txt}",
|
||||
":framework-wifi{.module-lib.api.txt}",
|
||||
":non-updatable-module-lib-current.txt",
|
||||
],
|
||||
@@ -373,6 +379,7 @@ genrule {
|
||||
":framework-sdkextensions{.module-lib.removed-api.txt}",
|
||||
":framework-statsd{.module-lib.removed-api.txt}",
|
||||
":framework-tethering{.module-lib.removed-api.txt}",
|
||||
":framework-uwb{.module-lib.removed-api.txt}",
|
||||
":framework-wifi{.module-lib.removed-api.txt}",
|
||||
":non-updatable-module-lib-removed.txt",
|
||||
],
|
||||
@@ -491,6 +498,7 @@ genrule {
|
||||
":framework-sdkextensions.stubs{.jar}",
|
||||
":framework-statsd.stubs{.jar}",
|
||||
":framework-tethering.stubs{.jar}",
|
||||
":framework-uwb.stubs{.jar}",
|
||||
":framework-wifi.stubs{.jar}",
|
||||
":i18n.module.public.api.stubs{.jar}",
|
||||
],
|
||||
|
||||
@@ -99,6 +99,10 @@ platform_bootclasspath {
|
||||
apex: "com.android.tethering",
|
||||
module: "com.android.tethering-bootclasspath-fragment",
|
||||
},
|
||||
{
|
||||
apex: "com.android.uwb",
|
||||
module: "com.android.uwb-bootclasspath-fragment",
|
||||
},
|
||||
{
|
||||
apex: "com.android.wifi",
|
||||
module: "com.android.wifi-bootclasspath-fragment",
|
||||
|
||||
@@ -14267,148 +14267,6 @@ package android.util {
|
||||
|
||||
}
|
||||
|
||||
package android.uwb {
|
||||
|
||||
public final class AngleMeasurement implements android.os.Parcelable {
|
||||
ctor public AngleMeasurement(@FloatRange(from=-3.141592653589793, to=3.141592653589793) double, @FloatRange(from=0.0, to=3.141592653589793) double, @FloatRange(from=0.0, to=1.0) double);
|
||||
method public int describeContents();
|
||||
method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
|
||||
method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians();
|
||||
method @FloatRange(from=-3.141592653589793, to=3.141592653589793) public double getRadians();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleMeasurement> CREATOR;
|
||||
}
|
||||
|
||||
public final class AngleOfArrivalMeasurement implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @Nullable public android.uwb.AngleMeasurement getAltitude();
|
||||
method @NonNull public android.uwb.AngleMeasurement getAzimuth();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleOfArrivalMeasurement> CREATOR;
|
||||
}
|
||||
|
||||
public static final class AngleOfArrivalMeasurement.Builder {
|
||||
ctor public AngleOfArrivalMeasurement.Builder(@NonNull android.uwb.AngleMeasurement);
|
||||
method @NonNull public android.uwb.AngleOfArrivalMeasurement build();
|
||||
method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAltitude(@NonNull android.uwb.AngleMeasurement);
|
||||
}
|
||||
|
||||
public final class DistanceMeasurement implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
|
||||
method @FloatRange(from=0.0) public double getErrorMeters();
|
||||
method public double getMeters();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.DistanceMeasurement> CREATOR;
|
||||
}
|
||||
|
||||
public static final class DistanceMeasurement.Builder {
|
||||
ctor public DistanceMeasurement.Builder();
|
||||
method @NonNull public android.uwb.DistanceMeasurement build();
|
||||
method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(@FloatRange(from=0.0, to=1.0) double);
|
||||
method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(@FloatRange(from=0.0) double);
|
||||
method @NonNull public android.uwb.DistanceMeasurement.Builder setMeters(double);
|
||||
}
|
||||
|
||||
public final class RangingMeasurement implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @Nullable public android.uwb.AngleOfArrivalMeasurement getAngleOfArrivalMeasurement();
|
||||
method @Nullable public android.uwb.DistanceMeasurement getDistanceMeasurement();
|
||||
method public long getElapsedRealtimeNanos();
|
||||
method @NonNull public android.uwb.UwbAddress getRemoteDeviceAddress();
|
||||
method public int getStatus();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingMeasurement> CREATOR;
|
||||
field public static final int RANGING_STATUS_FAILURE_OUT_OF_RANGE = 1; // 0x1
|
||||
field public static final int RANGING_STATUS_FAILURE_UNKNOWN_ERROR = -1; // 0xffffffff
|
||||
field public static final int RANGING_STATUS_SUCCESS = 0; // 0x0
|
||||
}
|
||||
|
||||
public static final class RangingMeasurement.Builder {
|
||||
ctor public RangingMeasurement.Builder();
|
||||
method @NonNull public android.uwb.RangingMeasurement build();
|
||||
method @NonNull public android.uwb.RangingMeasurement.Builder setAngleOfArrivalMeasurement(@NonNull android.uwb.AngleOfArrivalMeasurement);
|
||||
method @NonNull public android.uwb.RangingMeasurement.Builder setDistanceMeasurement(@NonNull android.uwb.DistanceMeasurement);
|
||||
method @NonNull public android.uwb.RangingMeasurement.Builder setElapsedRealtimeNanos(long);
|
||||
method @NonNull public android.uwb.RangingMeasurement.Builder setRemoteDeviceAddress(@NonNull android.uwb.UwbAddress);
|
||||
method @NonNull public android.uwb.RangingMeasurement.Builder setStatus(int);
|
||||
}
|
||||
|
||||
public final class RangingReport implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public java.util.List<android.uwb.RangingMeasurement> getMeasurements();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingReport> CREATOR;
|
||||
}
|
||||
|
||||
public static final class RangingReport.Builder {
|
||||
ctor public RangingReport.Builder();
|
||||
method @NonNull public android.uwb.RangingReport.Builder addMeasurement(@NonNull android.uwb.RangingMeasurement);
|
||||
method @NonNull public android.uwb.RangingReport.Builder addMeasurements(@NonNull java.util.List<android.uwb.RangingMeasurement>);
|
||||
method @NonNull public android.uwb.RangingReport build();
|
||||
}
|
||||
|
||||
public final class RangingSession implements java.lang.AutoCloseable {
|
||||
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void close();
|
||||
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void reconfigure(@NonNull android.os.PersistableBundle);
|
||||
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void start(@NonNull android.os.PersistableBundle);
|
||||
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void stop();
|
||||
}
|
||||
|
||||
public static interface RangingSession.Callback {
|
||||
method public void onClosed(int, @NonNull android.os.PersistableBundle);
|
||||
method public void onOpenFailed(int, @NonNull android.os.PersistableBundle);
|
||||
method public void onOpened(@NonNull android.uwb.RangingSession);
|
||||
method public void onReconfigureFailed(int, @NonNull android.os.PersistableBundle);
|
||||
method public void onReconfigured(@NonNull android.os.PersistableBundle);
|
||||
method public void onReportReceived(@NonNull android.uwb.RangingReport);
|
||||
method public void onStartFailed(int, @NonNull android.os.PersistableBundle);
|
||||
method public void onStarted(@NonNull android.os.PersistableBundle);
|
||||
method public void onStopFailed(int, @NonNull android.os.PersistableBundle);
|
||||
method public void onStopped(int, @NonNull android.os.PersistableBundle);
|
||||
field public static final int REASON_BAD_PARAMETERS = 3; // 0x3
|
||||
field public static final int REASON_GENERIC_ERROR = 4; // 0x4
|
||||
field public static final int REASON_LOCAL_REQUEST = 1; // 0x1
|
||||
field public static final int REASON_MAX_SESSIONS_REACHED = 5; // 0x5
|
||||
field public static final int REASON_PROTOCOL_SPECIFIC_ERROR = 7; // 0x7
|
||||
field public static final int REASON_REMOTE_REQUEST = 2; // 0x2
|
||||
field public static final int REASON_SYSTEM_POLICY = 6; // 0x6
|
||||
field public static final int REASON_UNKNOWN = 0; // 0x0
|
||||
}
|
||||
|
||||
public final class UwbAddress implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public static android.uwb.UwbAddress fromBytes(@NonNull byte[]);
|
||||
method public int size();
|
||||
method @NonNull public byte[] toBytes();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.UwbAddress> CREATOR;
|
||||
field public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8; // 0x8
|
||||
field public static final int SHORT_ADDRESS_BYTE_LENGTH = 2; // 0x2
|
||||
}
|
||||
|
||||
public final class UwbManager {
|
||||
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos();
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo();
|
||||
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.UWB_PRIVILEGED, android.Manifest.permission.UWB_RANGING}) public android.os.CancellationSignal openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
|
||||
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
|
||||
method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
|
||||
}
|
||||
|
||||
public static interface UwbManager.AdapterStateCallback {
|
||||
method public void onStateChanged(int, int);
|
||||
field public static final int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1; // 0x1
|
||||
field public static final int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4; // 0x4
|
||||
field public static final int STATE_CHANGED_REASON_SESSION_STARTED = 0; // 0x0
|
||||
field public static final int STATE_CHANGED_REASON_SYSTEM_BOOT = 3; // 0x3
|
||||
field public static final int STATE_CHANGED_REASON_SYSTEM_POLICY = 2; // 0x2
|
||||
field public static final int STATE_DISABLED = 0; // 0x0
|
||||
field public static final int STATE_ENABLED_ACTIVE = 2; // 0x2
|
||||
field public static final int STATE_ENABLED_INACTIVE = 1; // 0x1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.view {
|
||||
|
||||
public abstract class Window {
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Backing(type="int")
|
||||
enum AdapterState {
|
||||
/**
|
||||
* The state when UWB is disabled.
|
||||
*/
|
||||
STATE_DISABLED,
|
||||
|
||||
/**
|
||||
* The state when UWB is enabled but has no active sessions.
|
||||
*/
|
||||
STATE_ENABLED_INACTIVE,
|
||||
|
||||
/**
|
||||
* The state when UWB is enabled and has active sessions.
|
||||
*/
|
||||
STATE_ENABLED_ACTIVE,
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Binder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.uwb.UwbManager.AdapterStateCallback;
|
||||
import android.uwb.UwbManager.AdapterStateCallback.State;
|
||||
import android.uwb.UwbManager.AdapterStateCallback.StateChangedReason;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
|
||||
private static final String TAG = "Uwb.StateListener";
|
||||
|
||||
private final IUwbAdapter mAdapter;
|
||||
private boolean mIsRegistered = false;
|
||||
|
||||
private final Map<AdapterStateCallback, Executor> mCallbackMap = new HashMap<>();
|
||||
|
||||
@StateChangedReason
|
||||
private int mAdapterStateChangeReason = AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
|
||||
@State
|
||||
private int mAdapterState = AdapterStateCallback.STATE_DISABLED;
|
||||
|
||||
public AdapterStateListener(@NonNull IUwbAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an {@link AdapterStateCallback} with this {@link AdapterStateListener}
|
||||
*
|
||||
* @param executor an {@link Executor} to execute given callback
|
||||
* @param callback user implementation of the {@link AdapterStateCallback}
|
||||
*/
|
||||
public void register(@NonNull Executor executor, @NonNull AdapterStateCallback callback) {
|
||||
synchronized (this) {
|
||||
if (mCallbackMap.containsKey(callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCallbackMap.put(callback, executor);
|
||||
|
||||
if (!mIsRegistered) {
|
||||
try {
|
||||
mAdapter.registerAdapterStateCallbacks(this);
|
||||
mIsRegistered = true;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to register adapter state callback");
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
} else {
|
||||
sendCurrentState(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister the specified {@link AdapterStateCallback}
|
||||
*
|
||||
* @param callback user implementation of the {@link AdapterStateCallback}
|
||||
*/
|
||||
public void unregister(@NonNull AdapterStateCallback callback) {
|
||||
synchronized (this) {
|
||||
if (!mCallbackMap.containsKey(callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCallbackMap.remove(callback);
|
||||
|
||||
if (mCallbackMap.isEmpty() && mIsRegistered) {
|
||||
try {
|
||||
mAdapter.unregisterAdapterStateCallbacks(this);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to unregister AdapterStateCallback with service");
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
mIsRegistered = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the adapter enabled state
|
||||
*
|
||||
* @param isEnabled value of new adapter state
|
||||
*/
|
||||
public void setEnabled(boolean isEnabled) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
mAdapter.setEnabled(isEnabled);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to set adapter state");
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the adapter enabled state
|
||||
*
|
||||
* @return integer representing adapter enabled state
|
||||
*/
|
||||
public int getAdapterState() {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return mAdapter.getAdapterState();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to get adapter state");
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendCurrentState(@NonNull AdapterStateCallback callback) {
|
||||
synchronized (this) {
|
||||
Executor executor = mCallbackMap.get(callback);
|
||||
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onStateChanged(
|
||||
mAdapterState, mAdapterStateChangeReason));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdapterStateChanged(int state, int reason) {
|
||||
synchronized (this) {
|
||||
@StateChangedReason int localReason =
|
||||
convertToStateChangedReason(reason);
|
||||
@State int localState = convertToState(state);
|
||||
mAdapterStateChangeReason = localReason;
|
||||
mAdapterState = localState;
|
||||
for (AdapterStateCallback cb : mCallbackMap.keySet()) {
|
||||
sendCurrentState(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static @StateChangedReason int convertToStateChangedReason(
|
||||
@StateChangeReason int reason) {
|
||||
switch (reason) {
|
||||
case StateChangeReason.ALL_SESSIONS_CLOSED:
|
||||
return AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED;
|
||||
|
||||
case StateChangeReason.SESSION_STARTED:
|
||||
return AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED;
|
||||
|
||||
case StateChangeReason.SYSTEM_POLICY:
|
||||
return AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY;
|
||||
|
||||
case StateChangeReason.SYSTEM_BOOT:
|
||||
return AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT;
|
||||
|
||||
case StateChangeReason.UNKNOWN:
|
||||
default:
|
||||
return AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private static @State int convertToState(@AdapterState int state) {
|
||||
switch (state) {
|
||||
case AdapterState.STATE_ENABLED_INACTIVE:
|
||||
return AdapterStateCallback.STATE_ENABLED_INACTIVE;
|
||||
|
||||
case AdapterState.STATE_ENABLED_ACTIVE:
|
||||
return AdapterStateCallback.STATE_ENABLED_ACTIVE;
|
||||
|
||||
case AdapterState.STATE_DISABLED:
|
||||
default:
|
||||
return AdapterStateCallback.STATE_DISABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.annotation.FloatRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Angle measurement
|
||||
*
|
||||
* <p>The actual angle is interpreted as:
|
||||
* {@link #getRadians()} +/- {@link #getErrorRadians()} ()} at {@link #getConfidenceLevel()}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class AngleMeasurement implements Parcelable {
|
||||
private final double mRadians;
|
||||
private final double mErrorRadians;
|
||||
private final double mConfidenceLevel;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AngleMeasurement} object
|
||||
*
|
||||
* @param radians the angle in radians
|
||||
* @param errorRadians the error of the angle measurement in radians
|
||||
* @param confidenceLevel confidence level of the angle measurement
|
||||
*
|
||||
* @throws IllegalArgumentException if the radians, errorRadians, or confidenceLevel is out of
|
||||
* allowed range
|
||||
*/
|
||||
public AngleMeasurement(
|
||||
@FloatRange(from = -Math.PI, to = +Math.PI) double radians,
|
||||
@FloatRange(from = 0.0, to = +Math.PI) double errorRadians,
|
||||
@FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
|
||||
if (radians < -Math.PI || radians > Math.PI) {
|
||||
throw new IllegalArgumentException("Invalid radians: " + radians);
|
||||
}
|
||||
mRadians = radians;
|
||||
|
||||
if (errorRadians < 0.0 || errorRadians > Math.PI) {
|
||||
throw new IllegalArgumentException("Invalid error radians: " + errorRadians);
|
||||
}
|
||||
mErrorRadians = errorRadians;
|
||||
|
||||
if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
|
||||
throw new IllegalArgumentException("Invalid confidence level: " + confidenceLevel);
|
||||
}
|
||||
mConfidenceLevel = confidenceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Angle measurement in radians
|
||||
*
|
||||
* @return angle in radians
|
||||
*/
|
||||
@FloatRange(from = -Math.PI, to = +Math.PI)
|
||||
public double getRadians() {
|
||||
return mRadians;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error of angle measurement in radians
|
||||
*
|
||||
* <p>Must be a positive value
|
||||
*
|
||||
* @return angle measurement error in radians
|
||||
*/
|
||||
@FloatRange(from = 0.0, to = +Math.PI)
|
||||
public double getErrorRadians() {
|
||||
return mErrorRadians;
|
||||
}
|
||||
|
||||
/**
|
||||
* Angle measurement confidence level expressed as a value between
|
||||
* 0.0 to 1.0.
|
||||
*
|
||||
* <p>A value of 0.0 indicates there is no confidence in the measurement. A value of 1.0
|
||||
* indicates there is maximum confidence in the measurement.
|
||||
*
|
||||
* @return the confidence level of the angle measurement
|
||||
*/
|
||||
@FloatRange(from = 0.0, to = 1.0)
|
||||
public double getConfidenceLevel() {
|
||||
return mConfidenceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof AngleMeasurement) {
|
||||
AngleMeasurement other = (AngleMeasurement) obj;
|
||||
return mRadians == other.getRadians()
|
||||
&& mErrorRadians == other.getErrorRadians()
|
||||
&& mConfidenceLevel == other.getConfidenceLevel();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mRadians, mErrorRadians, mConfidenceLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeDouble(mRadians);
|
||||
dest.writeDouble(mErrorRadians);
|
||||
dest.writeDouble(mConfidenceLevel);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<AngleMeasurement> CREATOR =
|
||||
new Creator<AngleMeasurement>() {
|
||||
@Override
|
||||
public AngleMeasurement createFromParcel(Parcel in) {
|
||||
return new AngleMeasurement(in.readDouble(), in.readDouble(), in.readDouble());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AngleMeasurement[] newArray(int size) {
|
||||
return new AngleMeasurement[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents an angle of arrival measurement between two devices using Ultra Wideband
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class AngleOfArrivalMeasurement implements Parcelable {
|
||||
private final AngleMeasurement mAzimuthAngleMeasurement;
|
||||
private final AngleMeasurement mAltitudeAngleMeasurement;
|
||||
|
||||
private AngleOfArrivalMeasurement(@NonNull AngleMeasurement azimuthAngleMeasurement,
|
||||
@Nullable AngleMeasurement altitudeAngleMeasurement) {
|
||||
mAzimuthAngleMeasurement = azimuthAngleMeasurement;
|
||||
mAltitudeAngleMeasurement = altitudeAngleMeasurement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Azimuth angle measurement
|
||||
* <p>Azimuth {@link AngleMeasurement} of remote device in horizontal coordinate system, this is
|
||||
* the angle clockwise from the meridian when viewing above the north pole.
|
||||
*
|
||||
* <p>See: https://en.wikipedia.org/wiki/Horizontal_coordinate_system
|
||||
*
|
||||
* <p>On an Android device, azimuth north is defined as the angle perpendicular away from the
|
||||
* back of the device when holding it in portrait mode upright.
|
||||
*
|
||||
* <p>Azimuth angle must be supported when Angle of Arrival is supported
|
||||
*
|
||||
* @return the azimuth {@link AngleMeasurement}
|
||||
*/
|
||||
@NonNull
|
||||
public AngleMeasurement getAzimuth() {
|
||||
return mAzimuthAngleMeasurement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Altitude angle measurement
|
||||
* <p>Altitude {@link AngleMeasurement} of remote device in horizontal coordinate system, this
|
||||
* is the angle above the equator when the north pole is up.
|
||||
*
|
||||
* <p>See: https://en.wikipedia.org/wiki/Horizontal_coordinate_system
|
||||
*
|
||||
* <p>On an Android device, altitude is defined as the angle vertical from ground when holding
|
||||
* the device in portrait mode upright.
|
||||
*
|
||||
* @return altitude {@link AngleMeasurement} or null when this is not available
|
||||
*/
|
||||
@Nullable
|
||||
public AngleMeasurement getAltitude() {
|
||||
return mAltitudeAngleMeasurement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof AngleOfArrivalMeasurement) {
|
||||
AngleOfArrivalMeasurement other = (AngleOfArrivalMeasurement) obj;
|
||||
return mAzimuthAngleMeasurement.equals(other.getAzimuth())
|
||||
&& mAltitudeAngleMeasurement.equals(other.getAltitude());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mAzimuthAngleMeasurement, mAltitudeAngleMeasurement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mAzimuthAngleMeasurement, flags);
|
||||
dest.writeParcelable(mAltitudeAngleMeasurement, flags);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<AngleOfArrivalMeasurement> CREATOR =
|
||||
new Creator<AngleOfArrivalMeasurement>() {
|
||||
@Override
|
||||
public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
|
||||
Builder builder =
|
||||
new Builder(in.readParcelable(AngleMeasurement.class.getClassLoader()));
|
||||
|
||||
builder.setAltitude(in.readParcelable(AngleMeasurement.class.getClassLoader()));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AngleOfArrivalMeasurement[] newArray(int size) {
|
||||
return new AngleOfArrivalMeasurement[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builder class for {@link AngleOfArrivalMeasurement}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private final AngleMeasurement mAzimuthAngleMeasurement;
|
||||
private AngleMeasurement mAltitudeAngleMeasurement = null;
|
||||
|
||||
/**
|
||||
* Constructs an {@link AngleOfArrivalMeasurement} object
|
||||
*
|
||||
* @param azimuthAngle the azimuth angle of the measurement
|
||||
*/
|
||||
public Builder(@NonNull AngleMeasurement azimuthAngle) {
|
||||
mAzimuthAngleMeasurement = azimuthAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the altitude angle
|
||||
*
|
||||
* @param altitudeAngle altitude angle
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setAltitude(@NonNull AngleMeasurement altitudeAngle) {
|
||||
mAltitudeAngleMeasurement = altitudeAngle;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the {@link AngleOfArrivalMeasurement} object
|
||||
*/
|
||||
@NonNull
|
||||
public AngleOfArrivalMeasurement build() {
|
||||
return new AngleOfArrivalMeasurement(mAzimuthAngleMeasurement,
|
||||
mAltitudeAngleMeasurement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.annotation.FloatRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A data point for the distance measurement
|
||||
*
|
||||
* <p>The actual distance is interpreted as:
|
||||
* {@link #getMeters()} +/- {@link #getErrorMeters()} at {@link #getConfidenceLevel()}
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class DistanceMeasurement implements Parcelable {
|
||||
private final double mMeters;
|
||||
private final double mErrorMeters;
|
||||
private final double mConfidenceLevel;
|
||||
|
||||
private DistanceMeasurement(double meters, double errorMeters, double confidenceLevel) {
|
||||
mMeters = meters;
|
||||
mErrorMeters = errorMeters;
|
||||
mConfidenceLevel = confidenceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Distance measurement in meters
|
||||
*
|
||||
* @return distance in meters
|
||||
*/
|
||||
public double getMeters() {
|
||||
return mMeters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error of distance measurement in meters
|
||||
* <p>Must be positive
|
||||
*
|
||||
* @return error of distance measurement in meters
|
||||
*/
|
||||
@FloatRange(from = 0.0)
|
||||
public double getErrorMeters() {
|
||||
return mErrorMeters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Distance measurement confidence level expressed as a value between 0.0 to 1.0.
|
||||
*
|
||||
* <p>A value of 0.0 indicates no confidence in the measurement. A value of 1.0 represents
|
||||
* maximum confidence in the measurement
|
||||
*
|
||||
* @return confidence level
|
||||
*/
|
||||
@FloatRange(from = 0.0, to = 1.0)
|
||||
public double getConfidenceLevel() {
|
||||
return mConfidenceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof DistanceMeasurement) {
|
||||
DistanceMeasurement other = (DistanceMeasurement) obj;
|
||||
return mMeters == other.getMeters()
|
||||
&& mErrorMeters == other.getErrorMeters()
|
||||
&& mConfidenceLevel == other.getConfidenceLevel();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mMeters, mErrorMeters, mConfidenceLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeDouble(mMeters);
|
||||
dest.writeDouble(mErrorMeters);
|
||||
dest.writeDouble(mConfidenceLevel);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<DistanceMeasurement> CREATOR =
|
||||
new Creator<DistanceMeasurement>() {
|
||||
@Override
|
||||
public DistanceMeasurement createFromParcel(Parcel in) {
|
||||
Builder builder = new Builder();
|
||||
builder.setMeters(in.readDouble());
|
||||
builder.setErrorMeters(in.readDouble());
|
||||
builder.setConfidenceLevel(in.readDouble());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistanceMeasurement[] newArray(int size) {
|
||||
return new DistanceMeasurement[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builder to get a {@link DistanceMeasurement} object.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private double mMeters = Double.NaN;
|
||||
private double mErrorMeters = Double.NaN;
|
||||
private double mConfidenceLevel = Double.NaN;
|
||||
|
||||
/**
|
||||
* Set the distance measurement in meters
|
||||
*
|
||||
* @param meters distance in meters
|
||||
* @throws IllegalArgumentException if meters is NaN
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setMeters(double meters) {
|
||||
if (Double.isNaN(meters)) {
|
||||
throw new IllegalArgumentException("meters cannot be NaN");
|
||||
}
|
||||
mMeters = meters;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distance error in meters
|
||||
*
|
||||
* @param errorMeters distance error in meters
|
||||
* @throws IllegalArgumentException if error is negative or NaN
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setErrorMeters(@FloatRange(from = 0.0) double errorMeters) {
|
||||
if (Double.isNaN(errorMeters) || errorMeters < 0.0) {
|
||||
throw new IllegalArgumentException(
|
||||
"errorMeters must be >= 0.0 and not NaN: " + errorMeters);
|
||||
}
|
||||
mErrorMeters = errorMeters;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the confidence level
|
||||
*
|
||||
* @param confidenceLevel the confidence level in the distance measurement
|
||||
* @throws IllegalArgumentException if confidence level is not in the range of [0.0, 1.0]
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setConfidenceLevel(
|
||||
@FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
|
||||
if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
|
||||
throw new IllegalArgumentException(
|
||||
"confidenceLevel must be in the range [0.0, 1.0]: " + confidenceLevel);
|
||||
}
|
||||
mConfidenceLevel = confidenceLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the {@link DistanceMeasurement} object
|
||||
*
|
||||
* @throws IllegalStateException if meters, error, or confidence are not set
|
||||
*/
|
||||
@NonNull
|
||||
public DistanceMeasurement build() {
|
||||
if (Double.isNaN(mMeters)) {
|
||||
throw new IllegalStateException("Meters cannot be NaN");
|
||||
}
|
||||
|
||||
if (Double.isNaN(mErrorMeters)) {
|
||||
throw new IllegalStateException("Error meters cannot be NaN");
|
||||
}
|
||||
|
||||
if (Double.isNaN(mConfidenceLevel)) {
|
||||
throw new IllegalStateException("Confidence level cannot be NaN");
|
||||
}
|
||||
|
||||
return new DistanceMeasurement(mMeters, mErrorMeters, mConfidenceLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.content.AttributionSource;
|
||||
import android.os.PersistableBundle;
|
||||
import android.uwb.IUwbAdapterStateCallbacks;
|
||||
import android.uwb.IUwbRangingCallbacks;
|
||||
import android.uwb.SessionHandle;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
interface IUwbAdapter {
|
||||
/*
|
||||
* Register the callbacks used to notify the framework of events and data
|
||||
*
|
||||
* The provided callback's IUwbAdapterStateCallbacks#onAdapterStateChanged
|
||||
* function must be called immediately following registration with the current
|
||||
* state of the UWB adapter.
|
||||
*
|
||||
* @param callbacks callback to provide range and status updates to the framework
|
||||
*/
|
||||
void registerAdapterStateCallbacks(in IUwbAdapterStateCallbacks adapterStateCallbacks);
|
||||
|
||||
/*
|
||||
* Unregister the callbacks used to notify the framework of events and data
|
||||
*
|
||||
* Calling this function with an unregistered callback is a no-op
|
||||
*
|
||||
* @param callbacks callback to unregister
|
||||
*/
|
||||
void unregisterAdapterStateCallbacks(in IUwbAdapterStateCallbacks callbacks);
|
||||
|
||||
/**
|
||||
* Get the accuracy of the ranging timestamps
|
||||
*
|
||||
* @return accuracy of the ranging timestamps in nanoseconds
|
||||
*/
|
||||
long getTimestampResolutionNanos();
|
||||
|
||||
/**
|
||||
* Provides the capabilities and features of the device
|
||||
*
|
||||
* @return specification specific capabilities and features of the device
|
||||
*/
|
||||
PersistableBundle getSpecificationInfo();
|
||||
|
||||
/**
|
||||
* Request to open a new ranging session
|
||||
*
|
||||
* This function does not start the ranging session, but all necessary
|
||||
* components must be initialized and ready to start a new ranging
|
||||
* session prior to calling IUwbAdapterCallback#onRangingOpened.
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingOpened must be called within
|
||||
* RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being
|
||||
* called if the ranging session is opened successfully.
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingOpenFailed must be called within
|
||||
* RANGING_SESSION_OPEN_THRESHOLD_MS milliseconds of #openRanging being called
|
||||
* if the ranging session fails to be opened.
|
||||
*
|
||||
* If the provided sessionHandle is already open for the calling client, then
|
||||
* #onRangingOpenFailed must be called and the new session must not be opened.
|
||||
*
|
||||
* @param attributionSource AttributionSource to use for permission enforcement.
|
||||
* @param sessionHandle the session handle to open ranging for
|
||||
* @param rangingCallbacks the callbacks used to deliver ranging information
|
||||
* @param parameters the configuration to use for ranging
|
||||
*/
|
||||
void openRanging(in AttributionSource attributionSource,
|
||||
in SessionHandle sessionHandle,
|
||||
in IUwbRangingCallbacks rangingCallbacks,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Request to start ranging
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingStarted must be called within
|
||||
* RANGING_SESSION_START_THRESHOLD_MS milliseconds of #startRanging being
|
||||
* called if the ranging session starts successfully.
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingStartFailed must be called within
|
||||
* RANGING_SESSION_START_THRESHOLD_MS milliseconds of #startRanging being
|
||||
* called if the ranging session fails to be started.
|
||||
*
|
||||
* @param sessionHandle the session handle to start ranging for
|
||||
* @param parameters additional configuration required to start ranging
|
||||
*/
|
||||
void startRanging(in SessionHandle sessionHandle,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Request to reconfigure ranging
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingReconfigured must be called after
|
||||
* successfully reconfiguring the session.
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingReconfigureFailed must be called after
|
||||
* failing to reconfigure the session.
|
||||
*
|
||||
* A session must not be modified by a failed call to #reconfigureRanging.
|
||||
*
|
||||
* @param sessionHandle the session handle to start ranging for
|
||||
* @param parameters the parameters to reconfigure and their new values
|
||||
*/
|
||||
void reconfigureRanging(in SessionHandle sessionHandle,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Request to stop ranging
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingStopped must be called after
|
||||
* successfully stopping the session.
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingStopFailed must be called after failing
|
||||
* to stop the session.
|
||||
*
|
||||
* @param sessionHandle the session handle to stop ranging for
|
||||
*/
|
||||
void stopRanging(in SessionHandle sessionHandle);
|
||||
|
||||
/**
|
||||
* Close ranging for the session associated with the given handle
|
||||
*
|
||||
* Calling with an invalid handle or a handle that has already been closed
|
||||
* is a no-op.
|
||||
*
|
||||
* IUwbAdapterCallbacks#onRangingClosed must be called within
|
||||
* RANGING_SESSION_CLOSE_THRESHOLD_MS of #closeRanging being called.
|
||||
*
|
||||
* @param sessionHandle the session handle to close ranging for
|
||||
*/
|
||||
void closeRanging(in SessionHandle sessionHandle);
|
||||
|
||||
/**
|
||||
* Disables or enables UWB for a user
|
||||
*
|
||||
* The provided callback's IUwbAdapterStateCallbacks#onAdapterStateChanged
|
||||
* function must be called immediately following state change.
|
||||
*
|
||||
* @param enabled value representing intent to disable or enable UWB. If
|
||||
* true, any subsequent calls to #openRanging will be allowed. If false,
|
||||
* all active ranging sessions will be closed and subsequent calls to
|
||||
* #openRanging will be disallowed.
|
||||
*/
|
||||
void setEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Returns the current enabled/disabled UWB state.
|
||||
*
|
||||
* Possible values are:
|
||||
* IUwbAdapterState#STATE_DISABLED
|
||||
* IUwbAdapterState#STATE_ENABLED_ACTIVE
|
||||
* IUwbAdapterState#STATE_ENABLED_INACTIVE
|
||||
*
|
||||
* @return value representing enabled/disabled UWB state.
|
||||
*/
|
||||
int getAdapterState();
|
||||
|
||||
/**
|
||||
* The maximum allowed time to open a ranging session.
|
||||
*/
|
||||
const int RANGING_SESSION_OPEN_THRESHOLD_MS = 3000; // Value TBD
|
||||
|
||||
/**
|
||||
* The maximum allowed time to start a ranging session.
|
||||
*/
|
||||
const int RANGING_SESSION_START_THRESHOLD_MS = 3000; // Value TBD
|
||||
|
||||
/**
|
||||
* The maximum allowed time to notify the framework that a session has been
|
||||
* closed.
|
||||
*/
|
||||
const int RANGING_SESSION_CLOSE_THRESHOLD_MS = 3000; // Value TBD
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.uwb.StateChangeReason;
|
||||
import android.uwb.AdapterState;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
interface IUwbAdapterStateCallbacks {
|
||||
/**
|
||||
* Called whenever the adapter state changes
|
||||
*
|
||||
* @param state UWB state; enabled_active, enabled_inactive, or disabled.
|
||||
* @param reason the reason that the state has changed
|
||||
*/
|
||||
void onAdapterStateChanged(AdapterState state, StateChangeReason reason);
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.os.PersistableBundle;
|
||||
import android.uwb.RangingChangeReason;
|
||||
import android.uwb.RangingReport;
|
||||
import android.uwb.SessionHandle;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IUwbRangingCallbacks {
|
||||
/**
|
||||
* Called when the ranging session has been opened
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
*/
|
||||
void onRangingOpened(in SessionHandle sessionHandle);
|
||||
|
||||
/**
|
||||
* Called when a ranging session fails to start
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
* @param reason the reason the session failed to start
|
||||
* @param parameters protocol specific parameters
|
||||
*/
|
||||
void onRangingOpenFailed(in SessionHandle sessionHandle,
|
||||
RangingChangeReason reason,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Called when ranging has started
|
||||
*
|
||||
* May output parameters generated by the lower layers that must be sent to the
|
||||
* remote device(s). The PersistableBundle must be constructed using the UWB
|
||||
* support library.
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
* @param rangingOutputParameters parameters generated by the lower layer that
|
||||
* should be sent to the remote device.
|
||||
*/
|
||||
void onRangingStarted(in SessionHandle sessionHandle,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Called when a ranging session fails to start
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
* @param reason the reason the session failed to start
|
||||
* @param parameters protocol specific parameters
|
||||
*/
|
||||
void onRangingStartFailed(in SessionHandle sessionHandle,
|
||||
RangingChangeReason reason,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Called when ranging has been reconfigured
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
* @param parameters the updated ranging configuration
|
||||
*/
|
||||
void onRangingReconfigured(in SessionHandle sessionHandle,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Called when a ranging session fails to be reconfigured
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
* @param reason the reason the session failed to reconfigure
|
||||
* @param parameters protocol specific parameters
|
||||
*/
|
||||
void onRangingReconfigureFailed(in SessionHandle sessionHandle,
|
||||
RangingChangeReason reason,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Called when the ranging session has been stopped
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
* @param reason the reason the session was stopped
|
||||
* @param parameters protocol specific parameters
|
||||
*/
|
||||
|
||||
void onRangingStopped(in SessionHandle sessionHandle,
|
||||
RangingChangeReason reason,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Called when a ranging session fails to stop
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
* @param reason the reason the session failed to stop
|
||||
* @param parameters protocol specific parameters
|
||||
*/
|
||||
void onRangingStopFailed(in SessionHandle sessionHandle,
|
||||
RangingChangeReason reason,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Called when a ranging session is closed
|
||||
*
|
||||
* @param sessionHandle the session the callback is being invoked for
|
||||
* @param reason the reason the session was closed
|
||||
* @param parameters protocol specific parameters
|
||||
*/
|
||||
void onRangingClosed(in SessionHandle sessionHandle,
|
||||
RangingChangeReason reason,
|
||||
in PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Provides a new RangingResult to the framework
|
||||
*
|
||||
* The reported timestamp for a ranging measurement must be calculated as the
|
||||
* time which the ranging round that generated this measurement concluded.
|
||||
*
|
||||
* @param sessionHandle an identifier to associate the ranging results with a
|
||||
* session that is active
|
||||
* @param result the ranging report
|
||||
*/
|
||||
void onRangingResult(in SessionHandle sessionHandle, in RangingReport result);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Backing(type="int")
|
||||
enum MeasurementStatus {
|
||||
/**
|
||||
* Ranging was successful
|
||||
*/
|
||||
SUCCESS,
|
||||
|
||||
/**
|
||||
* The remote device is out of range
|
||||
*/
|
||||
FAILURE_OUT_OF_RANGE,
|
||||
|
||||
/**
|
||||
* An unknown failure has occurred.
|
||||
*/
|
||||
FAILURE_UNKNOWN,
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
bstack@google.com
|
||||
eliptus@google.com
|
||||
jsolnit@google.com
|
||||
matbev@google.com
|
||||
siyuanh@google.com
|
||||
zachoverflow@google.com
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Backing(type="int")
|
||||
enum RangingChangeReason {
|
||||
/**
|
||||
* Unknown reason
|
||||
*/
|
||||
UNKNOWN,
|
||||
|
||||
/**
|
||||
* A local API call triggered the change, such as a call to
|
||||
* IUwbAdapter.closeRanging.
|
||||
*/
|
||||
LOCAL_API,
|
||||
|
||||
/**
|
||||
* The maximum number of sessions has been reached. This may be generated for
|
||||
* an active session if a higher priority session begins.
|
||||
*/
|
||||
MAX_SESSIONS_REACHED,
|
||||
|
||||
/**
|
||||
* The system state has changed resulting in the session changing (e.g. the
|
||||
* user disables UWB, or the user's locale changes and an active channel is no
|
||||
* longer permitted to be used).
|
||||
*/
|
||||
SYSTEM_POLICY,
|
||||
|
||||
/**
|
||||
* The remote device has requested to change the session
|
||||
*/
|
||||
REMOTE_REQUEST,
|
||||
|
||||
/**
|
||||
* The session changed for a protocol specific reason
|
||||
*/
|
||||
PROTOCOL_SPECIFIC,
|
||||
|
||||
/**
|
||||
* The provided parameters were invalid
|
||||
*/
|
||||
BAD_PARAMETERS,
|
||||
}
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.AttributionSource;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
|
||||
private static final String TAG = "Uwb.RangingManager";
|
||||
|
||||
private final IUwbAdapter mAdapter;
|
||||
private final Hashtable<SessionHandle, RangingSession> mRangingSessionTable = new Hashtable<>();
|
||||
private int mNextSessionId = 1;
|
||||
|
||||
public RangingManager(IUwbAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a new ranging session
|
||||
*
|
||||
* @param attributionSource Attribution source to use for the enforcement of
|
||||
* {@link android.Manifest.permission#ULTRAWIDEBAND_RANGING} runtime
|
||||
* permission.
|
||||
* @param params the parameters that define the ranging session
|
||||
* @param executor {@link Executor} to run callbacks
|
||||
* @param callbacks {@link RangingSession.Callback} to associate with the {@link RangingSession}
|
||||
* that is being opened.
|
||||
* @return a {@link CancellationSignal} that may be used to cancel the opening of the
|
||||
* {@link RangingSession}.
|
||||
*/
|
||||
public CancellationSignal openSession(@NonNull AttributionSource attributionSource,
|
||||
@NonNull PersistableBundle params,
|
||||
@NonNull Executor executor,
|
||||
@NonNull RangingSession.Callback callbacks) {
|
||||
synchronized (this) {
|
||||
SessionHandle sessionHandle = new SessionHandle(mNextSessionId++);
|
||||
RangingSession session =
|
||||
new RangingSession(executor, callbacks, mAdapter, sessionHandle);
|
||||
mRangingSessionTable.put(sessionHandle, session);
|
||||
try {
|
||||
mAdapter.openRanging(attributionSource, sessionHandle, this, params);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
CancellationSignal cancellationSignal = new CancellationSignal();
|
||||
cancellationSignal.setOnCancelListener(() -> session.close());
|
||||
return cancellationSignal;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSession(SessionHandle sessionHandle) {
|
||||
return mRangingSessionTable.containsKey(sessionHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingOpened(SessionHandle sessionHandle) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG,
|
||||
"onRangingOpened - received unexpected SessionHandle: " + sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingOpened();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingOpenFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
|
||||
PersistableBundle parameters) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG,
|
||||
"onRangingOpenedFailed - received unexpected SessionHandle: "
|
||||
+ sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingOpenFailed(convertToReason(reason), parameters);
|
||||
mRangingSessionTable.remove(sessionHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingReconfigured(SessionHandle sessionHandle, PersistableBundle parameters) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG,
|
||||
"onRangingReconfigured - received unexpected SessionHandle: "
|
||||
+ sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingReconfigured(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingReconfigureFailed(SessionHandle sessionHandle,
|
||||
@RangingChangeReason int reason, PersistableBundle params) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG, "onRangingReconfigureFailed - received unexpected SessionHandle: "
|
||||
+ sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingReconfigureFailed(convertToReason(reason), params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRangingStarted(SessionHandle sessionHandle, PersistableBundle parameters) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG,
|
||||
"onRangingStarted - received unexpected SessionHandle: " + sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingStarted(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingStartFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
|
||||
PersistableBundle params) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG, "onRangingStartFailed - received unexpected SessionHandle: "
|
||||
+ sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingStartFailed(convertToReason(reason), params);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingStopped(SessionHandle sessionHandle, @RangingChangeReason int reason,
|
||||
PersistableBundle params) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG, "onRangingStopped - received unexpected SessionHandle: "
|
||||
+ sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingStopped(convertToReason(reason), params);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingStopFailed(SessionHandle sessionHandle, @RangingChangeReason int reason,
|
||||
PersistableBundle parameters) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG, "onRangingStopFailed - received unexpected SessionHandle: "
|
||||
+ sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingStopFailed(convertToReason(reason), parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingClosed(SessionHandle sessionHandle, @RangingChangeReason int reason,
|
||||
PersistableBundle params) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG, "onRangingClosed - received unexpected SessionHandle: " + sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingClosed(convertToReason(reason), params);
|
||||
mRangingSessionTable.remove(sessionHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRangingResult(SessionHandle sessionHandle, RangingReport result) {
|
||||
synchronized (this) {
|
||||
if (!hasSession(sessionHandle)) {
|
||||
Log.w(TAG, "onRangingResult - received unexpected SessionHandle: " + sessionHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
RangingSession session = mRangingSessionTable.get(sessionHandle);
|
||||
session.onRangingResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
@RangingSession.Callback.Reason
|
||||
private static int convertToReason(@RangingChangeReason int reason) {
|
||||
switch (reason) {
|
||||
case RangingChangeReason.LOCAL_API:
|
||||
return RangingSession.Callback.REASON_LOCAL_REQUEST;
|
||||
|
||||
case RangingChangeReason.MAX_SESSIONS_REACHED:
|
||||
return RangingSession.Callback.REASON_MAX_SESSIONS_REACHED;
|
||||
|
||||
case RangingChangeReason.SYSTEM_POLICY:
|
||||
return RangingSession.Callback.REASON_SYSTEM_POLICY;
|
||||
|
||||
case RangingChangeReason.REMOTE_REQUEST:
|
||||
return RangingSession.Callback.REASON_REMOTE_REQUEST;
|
||||
|
||||
case RangingChangeReason.PROTOCOL_SPECIFIC:
|
||||
return RangingSession.Callback.REASON_PROTOCOL_SPECIFIC_ERROR;
|
||||
|
||||
case RangingChangeReason.BAD_PARAMETERS:
|
||||
return RangingSession.Callback.REASON_BAD_PARAMETERS;
|
||||
|
||||
case RangingChangeReason.UNKNOWN:
|
||||
default:
|
||||
return RangingSession.Callback.REASON_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Representation of a ranging measurement between the local device and a remote device
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class RangingMeasurement implements Parcelable {
|
||||
private final UwbAddress mRemoteDeviceAddress;
|
||||
private final @Status int mStatus;
|
||||
private final long mElapsedRealtimeNanos;
|
||||
private final DistanceMeasurement mDistanceMeasurement;
|
||||
private final AngleOfArrivalMeasurement mAngleOfArrivalMeasurement;
|
||||
|
||||
private RangingMeasurement(@NonNull UwbAddress remoteDeviceAddress, @Status int status,
|
||||
long elapsedRealtimeNanos, @Nullable DistanceMeasurement distanceMeasurement,
|
||||
@Nullable AngleOfArrivalMeasurement angleOfArrivalMeasurement) {
|
||||
mRemoteDeviceAddress = remoteDeviceAddress;
|
||||
mStatus = status;
|
||||
mElapsedRealtimeNanos = elapsedRealtimeNanos;
|
||||
mDistanceMeasurement = distanceMeasurement;
|
||||
mAngleOfArrivalMeasurement = angleOfArrivalMeasurement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remote device's {@link UwbAddress}
|
||||
*
|
||||
* @return the remote device's {@link UwbAddress}
|
||||
*/
|
||||
@NonNull
|
||||
public UwbAddress getRemoteDeviceAddress() {
|
||||
return mRemoteDeviceAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
RANGING_STATUS_SUCCESS,
|
||||
RANGING_STATUS_FAILURE_OUT_OF_RANGE,
|
||||
RANGING_STATUS_FAILURE_UNKNOWN_ERROR})
|
||||
public @interface Status {}
|
||||
|
||||
/**
|
||||
* Ranging attempt was successful for this device
|
||||
*/
|
||||
public static final int RANGING_STATUS_SUCCESS = 0;
|
||||
|
||||
/**
|
||||
* Ranging failed for this device because it is out of range
|
||||
*/
|
||||
public static final int RANGING_STATUS_FAILURE_OUT_OF_RANGE = 1;
|
||||
|
||||
/**
|
||||
* Ranging failed for this device because of unknown error
|
||||
*/
|
||||
public static final int RANGING_STATUS_FAILURE_UNKNOWN_ERROR = -1;
|
||||
|
||||
/**
|
||||
* Get the status of this ranging measurement
|
||||
*
|
||||
* <p>Possible values are
|
||||
* {@link #RANGING_STATUS_SUCCESS},
|
||||
* {@link #RANGING_STATUS_FAILURE_OUT_OF_RANGE},
|
||||
* {@link #RANGING_STATUS_FAILURE_UNKNOWN_ERROR}.
|
||||
*
|
||||
* @return the status of the ranging measurement
|
||||
*/
|
||||
@Status
|
||||
public int getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamp of this ranging measurement in time since boot nanos in the same namespace as
|
||||
* {@link SystemClock#elapsedRealtimeNanos()}
|
||||
*
|
||||
* @return timestamp of ranging measurement in nanoseconds
|
||||
*/
|
||||
@SuppressLint("MethodNameUnits")
|
||||
public long getElapsedRealtimeNanos() {
|
||||
return mElapsedRealtimeNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance measurement
|
||||
*
|
||||
* @return a {@link DistanceMeasurement} or null if {@link #getStatus()} !=
|
||||
* {@link #RANGING_STATUS_SUCCESS}
|
||||
*/
|
||||
@Nullable
|
||||
public DistanceMeasurement getDistanceMeasurement() {
|
||||
return mDistanceMeasurement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the angle of arrival measurement
|
||||
*
|
||||
* @return an {@link AngleOfArrivalMeasurement} or null if {@link #getStatus()} !=
|
||||
* {@link #RANGING_STATUS_SUCCESS}
|
||||
*/
|
||||
@Nullable
|
||||
public AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
|
||||
return mAngleOfArrivalMeasurement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof RangingMeasurement) {
|
||||
RangingMeasurement other = (RangingMeasurement) obj;
|
||||
return mRemoteDeviceAddress.equals(other.getRemoteDeviceAddress())
|
||||
&& mStatus == other.getStatus()
|
||||
&& mElapsedRealtimeNanos == other.getElapsedRealtimeNanos()
|
||||
&& mDistanceMeasurement.equals(other.getDistanceMeasurement())
|
||||
&& mAngleOfArrivalMeasurement.equals(other.getAngleOfArrivalMeasurement());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
|
||||
mDistanceMeasurement, mAngleOfArrivalMeasurement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mRemoteDeviceAddress, flags);
|
||||
dest.writeInt(mStatus);
|
||||
dest.writeLong(mElapsedRealtimeNanos);
|
||||
dest.writeParcelable(mDistanceMeasurement, flags);
|
||||
dest.writeParcelable(mAngleOfArrivalMeasurement, flags);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<RangingMeasurement> CREATOR =
|
||||
new Creator<RangingMeasurement>() {
|
||||
@Override
|
||||
public RangingMeasurement createFromParcel(Parcel in) {
|
||||
Builder builder = new Builder();
|
||||
builder.setRemoteDeviceAddress(
|
||||
in.readParcelable(UwbAddress.class.getClassLoader()));
|
||||
builder.setStatus(in.readInt());
|
||||
builder.setElapsedRealtimeNanos(in.readLong());
|
||||
builder.setDistanceMeasurement(
|
||||
in.readParcelable(DistanceMeasurement.class.getClassLoader()));
|
||||
builder.setAngleOfArrivalMeasurement(
|
||||
in.readParcelable(AngleOfArrivalMeasurement.class.getClassLoader()));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RangingMeasurement[] newArray(int size) {
|
||||
return new RangingMeasurement[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builder for a {@link RangingMeasurement} object.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private UwbAddress mRemoteDeviceAddress = null;
|
||||
private @Status int mStatus = RANGING_STATUS_FAILURE_UNKNOWN_ERROR;
|
||||
private long mElapsedRealtimeNanos = -1L;
|
||||
private DistanceMeasurement mDistanceMeasurement = null;
|
||||
private AngleOfArrivalMeasurement mAngleOfArrivalMeasurement = null;
|
||||
|
||||
/**
|
||||
* Set the remote device address that this measurement is for
|
||||
*
|
||||
* @param remoteDeviceAddress remote device's address
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setRemoteDeviceAddress(@NonNull UwbAddress remoteDeviceAddress) {
|
||||
mRemoteDeviceAddress = remoteDeviceAddress;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status of ranging measurement
|
||||
*
|
||||
* @param status the status of the ranging measurement
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setStatus(@Status int status) {
|
||||
mStatus = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the elapsed realtime in nanoseconds when the ranging measurement occurred
|
||||
*
|
||||
* @param elapsedRealtimeNanos time the ranging measurement occurred
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setElapsedRealtimeNanos(long elapsedRealtimeNanos) {
|
||||
if (elapsedRealtimeNanos < 0) {
|
||||
throw new IllegalArgumentException("elapsedRealtimeNanos must be >= 0");
|
||||
}
|
||||
mElapsedRealtimeNanos = elapsedRealtimeNanos;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link DistanceMeasurement}
|
||||
*
|
||||
* @param distanceMeasurement the distance measurement for this ranging measurement
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDistanceMeasurement(@NonNull DistanceMeasurement distanceMeasurement) {
|
||||
mDistanceMeasurement = distanceMeasurement;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AngleOfArrivalMeasurement}
|
||||
*
|
||||
* @param angleOfArrivalMeasurement the angle of arrival measurement for this ranging
|
||||
* measurement
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setAngleOfArrivalMeasurement(
|
||||
@NonNull AngleOfArrivalMeasurement angleOfArrivalMeasurement) {
|
||||
mAngleOfArrivalMeasurement = angleOfArrivalMeasurement;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the {@link RangingMeasurement} object
|
||||
*
|
||||
* @throws IllegalStateException if a distance or angle of arrival measurement is provided
|
||||
* but the measurement was not successful, if the
|
||||
* elapsedRealtimeNanos of the measurement is invalid, or
|
||||
* if no remote device address is set
|
||||
*/
|
||||
@NonNull
|
||||
public RangingMeasurement build() {
|
||||
if (mStatus != RANGING_STATUS_SUCCESS) {
|
||||
if (mDistanceMeasurement != null) {
|
||||
throw new IllegalStateException(
|
||||
"Distance Measurement must be null if ranging is not successful");
|
||||
}
|
||||
|
||||
if (mAngleOfArrivalMeasurement != null) {
|
||||
throw new IllegalStateException(
|
||||
"Angle of Arrival must be null if ranging is not successful");
|
||||
}
|
||||
}
|
||||
|
||||
if (mRemoteDeviceAddress == null) {
|
||||
throw new IllegalStateException("No remote device address was set");
|
||||
}
|
||||
|
||||
if (mElapsedRealtimeNanos < 0) {
|
||||
throw new IllegalStateException(
|
||||
"elapsedRealtimeNanos must be >=0: " + mElapsedRealtimeNanos);
|
||||
}
|
||||
|
||||
return new RangingMeasurement(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
|
||||
mDistanceMeasurement, mAngleOfArrivalMeasurement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
parcelable RangingReport;
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class contains the UWB ranging data
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class RangingReport implements Parcelable {
|
||||
private final List<RangingMeasurement> mRangingMeasurements;
|
||||
|
||||
private RangingReport(@NonNull List<RangingMeasurement> rangingMeasurements) {
|
||||
mRangingMeasurements = rangingMeasurements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link List} of {@link RangingMeasurement} objects in the last measurement interval
|
||||
* <p>The underlying UWB adapter may choose to do multiple measurements in each ranging
|
||||
* interval.
|
||||
*
|
||||
* <p>The entries in the {@link List} are ordered in ascending order based on
|
||||
* {@link RangingMeasurement#getElapsedRealtimeNanos()}
|
||||
*
|
||||
* @return a {@link List} of {@link RangingMeasurement} objects
|
||||
*/
|
||||
@NonNull
|
||||
public List<RangingMeasurement> getMeasurements() {
|
||||
return mRangingMeasurements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof RangingReport) {
|
||||
RangingReport other = (RangingReport) obj;
|
||||
return mRangingMeasurements.equals(other.getMeasurements());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mRangingMeasurements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeTypedList(mRangingMeasurements);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<RangingReport> CREATOR =
|
||||
new Creator<RangingReport>() {
|
||||
@Override
|
||||
public RangingReport createFromParcel(Parcel in) {
|
||||
Builder builder = new Builder();
|
||||
builder.addMeasurements(in.createTypedArrayList(RangingMeasurement.CREATOR));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RangingReport[] newArray(int size) {
|
||||
return new RangingReport[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builder for {@link RangingReport} object
|
||||
*/
|
||||
public static final class Builder {
|
||||
List<RangingMeasurement> mMeasurements = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add a single {@link RangingMeasurement}
|
||||
*
|
||||
* @param rangingMeasurement a ranging measurement
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addMeasurement(@NonNull RangingMeasurement rangingMeasurement) {
|
||||
mMeasurements.add(rangingMeasurement);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link List} of {@link RangingMeasurement}s
|
||||
*
|
||||
* @param rangingMeasurements {@link List} of {@link RangingMeasurement}s to add
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addMeasurements(@NonNull List<RangingMeasurement> rangingMeasurements) {
|
||||
mMeasurements.addAll(rangingMeasurements);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the {@link RangingReport} object
|
||||
*
|
||||
* @throws IllegalStateException if measurements are not in monotonically increasing order
|
||||
*/
|
||||
@NonNull
|
||||
public RangingReport build() {
|
||||
// Verify that all measurement timestamps are monotonically increasing
|
||||
RangingMeasurement prevMeasurement = null;
|
||||
for (int curIndex = 0; curIndex < mMeasurements.size(); curIndex++) {
|
||||
RangingMeasurement curMeasurement = mMeasurements.get(curIndex);
|
||||
if (prevMeasurement != null
|
||||
&& (prevMeasurement.getElapsedRealtimeNanos()
|
||||
> curMeasurement.getElapsedRealtimeNanos())) {
|
||||
throw new IllegalStateException(
|
||||
"Timestamp (" + curMeasurement.getElapsedRealtimeNanos()
|
||||
+ ") at index " + curIndex + " is less than previous timestamp ("
|
||||
+ prevMeasurement.getElapsedRealtimeNanos() + ")");
|
||||
}
|
||||
prevMeasurement = curMeasurement;
|
||||
}
|
||||
return new RangingReport(mMeasurements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,496 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Binder;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* This class provides a way to control an active UWB ranging session.
|
||||
* <p>It also defines the required {@link RangingSession.Callback} that must be implemented
|
||||
* in order to be notified of UWB ranging results and status events related to the
|
||||
* {@link RangingSession}.
|
||||
*
|
||||
* <p>To get an instance of {@link RangingSession}, first use
|
||||
* {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)} to request to open a
|
||||
* session. Once the session is opened, a {@link RangingSession} object is provided through
|
||||
* {@link RangingSession.Callback#onOpened(RangingSession)}. If opening a session fails, the failure
|
||||
* is reported through {@link RangingSession.Callback#onOpenFailed(int, PersistableBundle)} with the
|
||||
* failure reason.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class RangingSession implements AutoCloseable {
|
||||
private static final String TAG = "Uwb.RangingSession";
|
||||
private final SessionHandle mSessionHandle;
|
||||
private final IUwbAdapter mAdapter;
|
||||
private final Executor mExecutor;
|
||||
private final Callback mCallback;
|
||||
|
||||
private enum State {
|
||||
/**
|
||||
* The state of the {@link RangingSession} until
|
||||
* {@link RangingSession.Callback#onOpened(RangingSession)} is invoked
|
||||
*/
|
||||
INIT,
|
||||
|
||||
/**
|
||||
* The {@link RangingSession} is initialized and ready to begin ranging
|
||||
*/
|
||||
IDLE,
|
||||
|
||||
/**
|
||||
* The {@link RangingSession} is actively ranging
|
||||
*/
|
||||
ACTIVE,
|
||||
|
||||
/**
|
||||
* The {@link RangingSession} is closed and may not be used for ranging.
|
||||
*/
|
||||
CLOSED
|
||||
}
|
||||
|
||||
private State mState = State.INIT;
|
||||
|
||||
/**
|
||||
* Interface for receiving {@link RangingSession} events
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
REASON_UNKNOWN,
|
||||
REASON_LOCAL_REQUEST,
|
||||
REASON_REMOTE_REQUEST,
|
||||
REASON_BAD_PARAMETERS,
|
||||
REASON_GENERIC_ERROR,
|
||||
REASON_MAX_SESSIONS_REACHED,
|
||||
REASON_SYSTEM_POLICY,
|
||||
REASON_PROTOCOL_SPECIFIC_ERROR})
|
||||
@interface Reason {}
|
||||
|
||||
/**
|
||||
* Indicates that the session was closed or failed to open due to an unknown reason
|
||||
*/
|
||||
int REASON_UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* Indicates that the session was closed or failed to open because
|
||||
* {@link AutoCloseable#close()} or {@link RangingSession#close()} was called
|
||||
*/
|
||||
int REASON_LOCAL_REQUEST = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the session was closed or failed to open due to an explicit request from
|
||||
* the remote device.
|
||||
*/
|
||||
int REASON_REMOTE_REQUEST = 2;
|
||||
|
||||
/**
|
||||
* Indicates that the session was closed or failed to open due to erroneous parameters
|
||||
*/
|
||||
int REASON_BAD_PARAMETERS = 3;
|
||||
|
||||
/**
|
||||
* Indicates an error on this device besides the error code already listed
|
||||
*/
|
||||
int REASON_GENERIC_ERROR = 4;
|
||||
|
||||
/**
|
||||
* Indicates that the number of currently open sessions is equal to
|
||||
* {@link UwbManager#getMaxSimultaneousSessions()} and additional sessions may not be
|
||||
* opened.
|
||||
*/
|
||||
int REASON_MAX_SESSIONS_REACHED = 5;
|
||||
|
||||
/**
|
||||
* Indicates that the local system policy caused the change, such
|
||||
* as privacy policy, power management policy, permissions, and more.
|
||||
*/
|
||||
int REASON_SYSTEM_POLICY = 6;
|
||||
|
||||
/**
|
||||
* Indicates a protocol specific error. The associated {@link PersistableBundle} should be
|
||||
* consulted for additional information.
|
||||
*/
|
||||
int REASON_PROTOCOL_SPECIFIC_ERROR = 7;
|
||||
|
||||
/**
|
||||
* Invoked when {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
|
||||
* is successful
|
||||
*
|
||||
* @param session the newly opened {@link RangingSession}
|
||||
*/
|
||||
void onOpened(@NonNull RangingSession session);
|
||||
|
||||
/**
|
||||
* Invoked if {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}}
|
||||
* fails
|
||||
*
|
||||
* @param reason the failure reason
|
||||
* @param params protocol specific parameters
|
||||
*/
|
||||
void onOpenFailed(@Reason int reason, @NonNull PersistableBundle params);
|
||||
|
||||
/**
|
||||
* Invoked when {@link RangingSession#start(PersistableBundle)} is successful
|
||||
* @param sessionInfo session specific parameters from the lower layers
|
||||
*/
|
||||
void onStarted(@NonNull PersistableBundle sessionInfo);
|
||||
|
||||
/**
|
||||
* Invoked when {@link RangingSession#start(PersistableBundle)} fails
|
||||
*
|
||||
* @param reason the failure reason
|
||||
* @param params protocol specific parameters
|
||||
*/
|
||||
void onStartFailed(@Reason int reason, @NonNull PersistableBundle params);
|
||||
|
||||
/**
|
||||
* Invoked when a request to reconfigure the session succeeds
|
||||
*
|
||||
* @param params the updated ranging configuration
|
||||
*/
|
||||
void onReconfigured(@NonNull PersistableBundle params);
|
||||
|
||||
/**
|
||||
* Invoked when a request to reconfigure the session fails
|
||||
*
|
||||
* @param reason reason the session failed to be reconfigured
|
||||
* @param params protocol specific failure reasons
|
||||
*/
|
||||
void onReconfigureFailed(@Reason int reason, @NonNull PersistableBundle params);
|
||||
|
||||
/**
|
||||
* Invoked when a request to stop the session succeeds
|
||||
*
|
||||
* @param reason reason for the session stop
|
||||
* @param parameters protocol specific parameters related to the stop reason
|
||||
*/
|
||||
void onStopped(@Reason int reason, @NonNull PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Invoked when a request to stop the session fails
|
||||
*
|
||||
* @param reason reason the session failed to be stopped
|
||||
* @param params protocol specific failure reasons
|
||||
*/
|
||||
void onStopFailed(@Reason int reason, @NonNull PersistableBundle params);
|
||||
|
||||
/**
|
||||
* Invoked when session is either closed spontaneously, or per user request via
|
||||
* {@link RangingSession#close()} or {@link AutoCloseable#close()}.
|
||||
*
|
||||
* @param reason reason for the session closure
|
||||
* @param parameters protocol specific parameters related to the close reason
|
||||
*/
|
||||
void onClosed(@Reason int reason, @NonNull PersistableBundle parameters);
|
||||
|
||||
/**
|
||||
* Called once per ranging interval even when a ranging measurement fails
|
||||
*
|
||||
* @param rangingReport ranging report for this interval's measurements
|
||||
*/
|
||||
void onReportReceived(@NonNull RangingReport rangingReport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public RangingSession(Executor executor, Callback callback, IUwbAdapter adapter,
|
||||
SessionHandle sessionHandle) {
|
||||
mState = State.INIT;
|
||||
mExecutor = executor;
|
||||
mCallback = callback;
|
||||
mAdapter = adapter;
|
||||
mSessionHandle = sessionHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
return mState == State.IDLE || mState == State.ACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins ranging for the session.
|
||||
*
|
||||
* <p>On successfully starting a ranging session,
|
||||
* {@link RangingSession.Callback#onStarted(PersistableBundle)} is invoked.
|
||||
*
|
||||
* <p>On failure to start the session,
|
||||
* {@link RangingSession.Callback#onStartFailed(int, PersistableBundle)} is invoked.
|
||||
*
|
||||
* @param params configuration parameters for starting the session
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
|
||||
public void start(@NonNull PersistableBundle params) {
|
||||
if (mState != State.IDLE) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
try {
|
||||
mAdapter.startRanging(mSessionHandle, params);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to reconfigure the session with the given parameters
|
||||
* <p>This call may be made when the session is open.
|
||||
*
|
||||
* <p>On successfully reconfiguring the session
|
||||
* {@link RangingSession.Callback#onReconfigured(PersistableBundle)} is invoked.
|
||||
*
|
||||
* <p>On failure to reconfigure the session,
|
||||
* {@link RangingSession.Callback#onReconfigureFailed(int, PersistableBundle)} is invoked.
|
||||
*
|
||||
* @param params the parameters to reconfigure and their new values
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
|
||||
public void reconfigure(@NonNull PersistableBundle params) {
|
||||
if (mState != State.ACTIVE && mState != State.IDLE) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
try {
|
||||
mAdapter.reconfigureRanging(mSessionHandle, params);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops actively ranging
|
||||
*
|
||||
* <p>A session that has been stopped may be resumed by calling
|
||||
* {@link RangingSession#start(PersistableBundle)} without the need to open a new session.
|
||||
*
|
||||
* <p>Stopping a {@link RangingSession} is useful when the lower layers should not discard
|
||||
* the parameters of the session, or when a session needs to be able to be resumed quickly.
|
||||
*
|
||||
* <p>If the {@link RangingSession} is no longer needed, use {@link RangingSession#close()} to
|
||||
* completely close the session and allow lower layers of the stack to perform necessarily
|
||||
* cleanup.
|
||||
*
|
||||
* <p>Stopped sessions may be closed by the system at any time. In such a case,
|
||||
* {@link RangingSession.Callback#onClosed(int, PersistableBundle)} is invoked.
|
||||
*
|
||||
* <p>On failure to stop the session,
|
||||
* {@link RangingSession.Callback#onStopFailed(int, PersistableBundle)} is invoked.
|
||||
*/
|
||||
@RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
|
||||
public void stop() {
|
||||
if (mState != State.ACTIVE) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
try {
|
||||
mAdapter.stopRanging(mSessionHandle);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the ranging session
|
||||
*
|
||||
* <p>After calling this function, in order resume ranging, a new {@link RangingSession} must
|
||||
* be opened by calling
|
||||
* {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}.
|
||||
*
|
||||
* <p>If this session is currently ranging, it will stop and close the session.
|
||||
* <p>If the session is in the process of being opened, it will attempt to stop the session from
|
||||
* being opened.
|
||||
* <p>If the session is already closed, the registered
|
||||
* {@link Callback#onClosed(int, PersistableBundle)} callback will still be invoked.
|
||||
*
|
||||
* <p>{@link Callback#onClosed(int, PersistableBundle)} will be invoked using the same callback
|
||||
* object given to {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
|
||||
* when the {@link RangingSession} was opened. The callback will be invoked after each call to
|
||||
* {@link #close()}, even if the {@link RangingSession} is already closed.
|
||||
*/
|
||||
@Override
|
||||
@RequiresPermission(Manifest.permission.UWB_PRIVILEGED)
|
||||
public void close() {
|
||||
if (mState == State.CLOSED) {
|
||||
mExecutor.execute(() -> mCallback.onClosed(
|
||||
Callback.REASON_LOCAL_REQUEST, new PersistableBundle()));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mAdapter.closeRanging(mSessionHandle);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingOpened() {
|
||||
if (mState == State.CLOSED) {
|
||||
Log.w(TAG, "onRangingOpened invoked for a closed session");
|
||||
return;
|
||||
}
|
||||
|
||||
mState = State.IDLE;
|
||||
executeCallback(() -> mCallback.onOpened(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingOpenFailed(@Callback.Reason int reason,
|
||||
@NonNull PersistableBundle params) {
|
||||
if (mState == State.CLOSED) {
|
||||
Log.w(TAG, "onRangingOpenFailed invoked for a closed session");
|
||||
return;
|
||||
}
|
||||
|
||||
mState = State.CLOSED;
|
||||
executeCallback(() -> mCallback.onOpenFailed(reason, params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingStarted(@NonNull PersistableBundle parameters) {
|
||||
if (mState == State.CLOSED) {
|
||||
Log.w(TAG, "onRangingStarted invoked for a closed session");
|
||||
return;
|
||||
}
|
||||
|
||||
mState = State.ACTIVE;
|
||||
executeCallback(() -> mCallback.onStarted(parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingStartFailed(@Callback.Reason int reason,
|
||||
@NonNull PersistableBundle params) {
|
||||
if (mState == State.CLOSED) {
|
||||
Log.w(TAG, "onRangingStartFailed invoked for a closed session");
|
||||
return;
|
||||
}
|
||||
|
||||
executeCallback(() -> mCallback.onStartFailed(reason, params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingReconfigured(@NonNull PersistableBundle params) {
|
||||
if (mState == State.CLOSED) {
|
||||
Log.w(TAG, "onRangingReconfigured invoked for a closed session");
|
||||
return;
|
||||
}
|
||||
|
||||
executeCallback(() -> mCallback.onReconfigured(params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingReconfigureFailed(@Callback.Reason int reason,
|
||||
@NonNull PersistableBundle params) {
|
||||
if (mState == State.CLOSED) {
|
||||
Log.w(TAG, "onRangingReconfigureFailed invoked for a closed session");
|
||||
return;
|
||||
}
|
||||
|
||||
executeCallback(() -> mCallback.onReconfigureFailed(reason, params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingStopped(@Callback.Reason int reason,
|
||||
@NonNull PersistableBundle params) {
|
||||
if (mState == State.CLOSED) {
|
||||
Log.w(TAG, "onRangingStopped invoked for a closed session");
|
||||
return;
|
||||
}
|
||||
|
||||
mState = State.IDLE;
|
||||
executeCallback(() -> mCallback.onStopped(reason, params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingStopFailed(@Callback.Reason int reason,
|
||||
@NonNull PersistableBundle params) {
|
||||
if (mState == State.CLOSED) {
|
||||
Log.w(TAG, "onRangingStopFailed invoked for a closed session");
|
||||
return;
|
||||
}
|
||||
|
||||
executeCallback(() -> mCallback.onStopFailed(reason, params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingClosed(@Callback.Reason int reason,
|
||||
@NonNull PersistableBundle parameters) {
|
||||
mState = State.CLOSED;
|
||||
executeCallback(() -> mCallback.onClosed(reason, parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void onRangingResult(@NonNull RangingReport report) {
|
||||
if (!isOpen()) {
|
||||
Log.w(TAG, "onRangingResult invoked for non-open session");
|
||||
return;
|
||||
}
|
||||
|
||||
executeCallback(() -> mCallback.onReportReceived(report));
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private void executeCallback(@NonNull Runnable runnable) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(runnable);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
parcelable SessionHandle;
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final class SessionHandle implements Parcelable {
|
||||
private final int mId;
|
||||
|
||||
public SessionHandle(int id) {
|
||||
mId = id;
|
||||
}
|
||||
|
||||
protected SessionHandle(Parcel in) {
|
||||
mId = in.readInt();
|
||||
}
|
||||
|
||||
public static final Creator<SessionHandle> CREATOR = new Creator<SessionHandle>() {
|
||||
@Override
|
||||
public SessionHandle createFromParcel(Parcel in) {
|
||||
return new SessionHandle(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionHandle[] newArray(int size) {
|
||||
return new SessionHandle[size];
|
||||
}
|
||||
};
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof SessionHandle) {
|
||||
SessionHandle other = (SessionHandle) obj;
|
||||
return mId == other.mId;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(mId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SessionHandle [id=" + mId + "]";
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Backing(type="int")
|
||||
enum StateChangeReason {
|
||||
/**
|
||||
* The state changed for an unknown reason
|
||||
*/
|
||||
UNKNOWN,
|
||||
|
||||
/**
|
||||
* The adapter state changed because a session started.
|
||||
*/
|
||||
SESSION_STARTED,
|
||||
|
||||
|
||||
/**
|
||||
* The adapter state changed because all sessions were closed.
|
||||
*/
|
||||
ALL_SESSIONS_CLOSED,
|
||||
|
||||
/**
|
||||
* The adapter state changed because of a device system change.
|
||||
*/
|
||||
SYSTEM_POLICY,
|
||||
|
||||
/**
|
||||
* Used to signal the first adapter state message after boot
|
||||
*/
|
||||
SYSTEM_BOOT,
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "UwbManagerTests"
|
||||
},
|
||||
{
|
||||
"name": "CtsUwbTestCases"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
parcelable UwbAddress;
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A class representing a UWB address
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class UwbAddress implements Parcelable {
|
||||
public static final int SHORT_ADDRESS_BYTE_LENGTH = 2;
|
||||
public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8;
|
||||
|
||||
private final byte[] mAddressBytes;
|
||||
|
||||
private UwbAddress(byte[] address) {
|
||||
mAddressBytes = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link UwbAddress} from a byte array.
|
||||
*
|
||||
* <p>If the provided array is {@link #SHORT_ADDRESS_BYTE_LENGTH} bytes, a short address is
|
||||
* created. If the provided array is {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes, then an
|
||||
* extended address is created.
|
||||
*
|
||||
* @param address a byte array to convert to a {@link UwbAddress}
|
||||
* @return a {@link UwbAddress} created from the input byte array
|
||||
* @throws IllegalArgumentException when the length is not one of
|
||||
* {@link #SHORT_ADDRESS_BYTE_LENGTH} or {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes
|
||||
*/
|
||||
@NonNull
|
||||
public static UwbAddress fromBytes(@NonNull byte[] address) {
|
||||
if (address.length != SHORT_ADDRESS_BYTE_LENGTH
|
||||
&& address.length != EXTENDED_ADDRESS_BYTE_LENGTH) {
|
||||
throw new IllegalArgumentException("Invalid UwbAddress length " + address.length);
|
||||
}
|
||||
return new UwbAddress(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address as a byte array
|
||||
*
|
||||
* @return the byte representation of this {@link UwbAddress}
|
||||
*/
|
||||
@NonNull
|
||||
public byte[] toBytes() {
|
||||
return mAddressBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* The length of the address in bytes
|
||||
* <p>Possible values are {@link #SHORT_ADDRESS_BYTE_LENGTH} and
|
||||
* {@link #EXTENDED_ADDRESS_BYTE_LENGTH}.
|
||||
*/
|
||||
public int size() {
|
||||
return mAddressBytes.length;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("0x");
|
||||
for (byte addressByte : mAddressBytes) {
|
||||
builder.append(String.format("%02X", addressByte));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof UwbAddress) {
|
||||
return Arrays.equals(mAddressBytes, ((UwbAddress) obj).toBytes());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(mAddressBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(mAddressBytes.length);
|
||||
dest.writeByteArray(mAddressBytes);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<UwbAddress> CREATOR =
|
||||
new Creator<UwbAddress>() {
|
||||
@Override
|
||||
public UwbAddress createFromParcel(Parcel in) {
|
||||
byte[] address = new byte[in.readInt()];
|
||||
in.readByteArray(address);
|
||||
return UwbAddress.fromBytes(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UwbAddress[] newArray(int size) {
|
||||
return new UwbAddress[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.IBinder;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* This class provides a way to perform Ultra Wideband (UWB) operations such as querying the
|
||||
* device's capabilities and determining the distance and angle between the local device and a
|
||||
* remote device.
|
||||
*
|
||||
* <p>To get a {@link UwbManager}, call the <code>Context.getSystemService(UwbManager.class)</code>.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@SystemService(Context.UWB_SERVICE)
|
||||
public final class UwbManager {
|
||||
private static final String SERVICE_NAME = Context.UWB_SERVICE;
|
||||
|
||||
private final Context mContext;
|
||||
private final IUwbAdapter mUwbAdapter;
|
||||
private final AdapterStateListener mAdapterStateListener;
|
||||
private final RangingManager mRangingManager;
|
||||
|
||||
/**
|
||||
* Interface for receiving UWB adapter state changes
|
||||
*/
|
||||
public interface AdapterStateCallback {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
STATE_CHANGED_REASON_SESSION_STARTED,
|
||||
STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED,
|
||||
STATE_CHANGED_REASON_SYSTEM_POLICY,
|
||||
STATE_CHANGED_REASON_SYSTEM_BOOT,
|
||||
STATE_CHANGED_REASON_ERROR_UNKNOWN})
|
||||
@interface StateChangedReason {}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
STATE_ENABLED_INACTIVE,
|
||||
STATE_ENABLED_ACTIVE,
|
||||
STATE_DISABLED})
|
||||
@interface State {}
|
||||
|
||||
/**
|
||||
* Indicates that the state change was due to opening of first UWB session
|
||||
*/
|
||||
int STATE_CHANGED_REASON_SESSION_STARTED = 0;
|
||||
|
||||
/**
|
||||
* Indicates that the state change was due to closure of all UWB sessions
|
||||
*/
|
||||
int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the state change was due to changes in system policy
|
||||
*/
|
||||
int STATE_CHANGED_REASON_SYSTEM_POLICY = 2;
|
||||
|
||||
/**
|
||||
* Indicates that the current state is due to a system boot
|
||||
*/
|
||||
int STATE_CHANGED_REASON_SYSTEM_BOOT = 3;
|
||||
|
||||
/**
|
||||
* Indicates that the state change was due to some unknown error
|
||||
*/
|
||||
int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4;
|
||||
|
||||
/**
|
||||
* Indicates that UWB is disabled on device
|
||||
*/
|
||||
int STATE_DISABLED = 0;
|
||||
/**
|
||||
* Indicates that UWB is enabled on device but has no active ranging sessions
|
||||
*/
|
||||
int STATE_ENABLED_INACTIVE = 1;
|
||||
|
||||
/**
|
||||
* Indicates that UWB is enabled and has active ranging session
|
||||
*/
|
||||
int STATE_ENABLED_ACTIVE = 2;
|
||||
|
||||
/**
|
||||
* Invoked when underlying UWB adapter's state is changed
|
||||
* <p>Invoked with the adapter's current state after registering an
|
||||
* {@link AdapterStateCallback} using
|
||||
* {@link UwbManager#registerAdapterStateCallback(Executor, AdapterStateCallback)}.
|
||||
*
|
||||
* <p>Possible reasons for the state to change are
|
||||
* {@link #STATE_CHANGED_REASON_SESSION_STARTED},
|
||||
* {@link #STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED},
|
||||
* {@link #STATE_CHANGED_REASON_SYSTEM_POLICY},
|
||||
* {@link #STATE_CHANGED_REASON_SYSTEM_BOOT},
|
||||
* {@link #STATE_CHANGED_REASON_ERROR_UNKNOWN}.
|
||||
*
|
||||
* <p>Possible values for the UWB state are
|
||||
* {@link #STATE_ENABLED_INACTIVE},
|
||||
* {@link #STATE_ENABLED_ACTIVE},
|
||||
* {@link #STATE_DISABLED}.
|
||||
*
|
||||
* @param state the UWB state; inactive, active or disabled
|
||||
* @param reason the reason for the state change
|
||||
*/
|
||||
void onStateChanged(@State int state, @StateChangedReason int reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use <code>Context.getSystemService(UwbManager.class)</code> to get an instance.
|
||||
*
|
||||
* @param ctx Context of the client.
|
||||
* @param adapter an instance of an {@link android.uwb.IUwbAdapter}
|
||||
*/
|
||||
private UwbManager(@NonNull Context ctx, @NonNull IUwbAdapter adapter) {
|
||||
mContext = ctx;
|
||||
mUwbAdapter = adapter;
|
||||
mAdapterStateListener = new AdapterStateListener(adapter);
|
||||
mRangingManager = new RangingManager(adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static UwbManager getInstance(@NonNull Context ctx) {
|
||||
IBinder b = ServiceManager.getService(SERVICE_NAME);
|
||||
if (b == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
IUwbAdapter adapter = IUwbAdapter.Stub.asInterface(b);
|
||||
if (adapter == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new UwbManager(ctx, adapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an {@link AdapterStateCallback} to listen for UWB adapter state changes
|
||||
* <p>The provided callback will be invoked by the given {@link Executor}.
|
||||
*
|
||||
* <p>When first registering a callback, the callbacks's
|
||||
* {@link AdapterStateCallback#onStateChanged(int, int)} is immediately invoked to indicate
|
||||
* the current state of the underlying UWB adapter with the most recent
|
||||
* {@link AdapterStateCallback.StateChangedReason} that caused the change.
|
||||
*
|
||||
* @param executor an {@link Executor} to execute given callback
|
||||
* @param callback user implementation of the {@link AdapterStateCallback}
|
||||
*/
|
||||
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||||
public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull AdapterStateCallback callback) {
|
||||
mAdapterStateListener.register(executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister the specified {@link AdapterStateCallback}
|
||||
* <p>The same {@link AdapterStateCallback} object used when calling
|
||||
* {@link #registerAdapterStateCallback(Executor, AdapterStateCallback)} must be used.
|
||||
*
|
||||
* <p>Callbacks are automatically unregistered when application process goes away
|
||||
*
|
||||
* @param callback user implementation of the {@link AdapterStateCallback}
|
||||
*/
|
||||
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||||
public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) {
|
||||
mAdapterStateListener.unregister(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link PersistableBundle} with the supported UWB protocols and parameters.
|
||||
* <p>The {@link PersistableBundle} should be parsed using a support library
|
||||
*
|
||||
* <p>Android reserves the '^android.*' namespace</p>
|
||||
*
|
||||
* @return {@link PersistableBundle} of the device's supported UWB protocols and parameters
|
||||
*/
|
||||
@NonNull
|
||||
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||||
public PersistableBundle getSpecificationInfo() {
|
||||
try {
|
||||
return mUwbAdapter.getSpecificationInfo();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timestamp resolution for events in nanoseconds
|
||||
* <p>This value defines the maximum error of all timestamps for events reported to
|
||||
* {@link RangingSession.Callback}.
|
||||
*
|
||||
* @return the timestamp resolution in nanoseconds
|
||||
*/
|
||||
@SuppressLint("MethodNameUnits")
|
||||
@RequiresPermission(permission.UWB_PRIVILEGED)
|
||||
public long elapsedRealtimeResolutionNanos() {
|
||||
try {
|
||||
return mUwbAdapter.getTimestampResolutionNanos();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a {@link RangingSession} with the given parameters
|
||||
* <p>The {@link RangingSession.Callback#onOpened(RangingSession)} function is called with a
|
||||
* {@link RangingSession} object used to control ranging when the session is successfully
|
||||
* opened.
|
||||
*
|
||||
* <p>If a session cannot be opened, then
|
||||
* {@link RangingSession.Callback#onClosed(int, PersistableBundle)} will be invoked with the
|
||||
* appropriate {@link RangingSession.Callback.Reason}.
|
||||
*
|
||||
* <p>An open {@link RangingSession} will be automatically closed if client application process
|
||||
* dies.
|
||||
*
|
||||
* <p>A UWB support library must be used in order to construct the {@code parameter}
|
||||
* {@link PersistableBundle}.
|
||||
*
|
||||
* @param parameters the parameters that define the ranging session
|
||||
* @param executor {@link Executor} to run callbacks
|
||||
* @param callbacks {@link RangingSession.Callback} to associate with the
|
||||
* {@link RangingSession} that is being opened.
|
||||
*
|
||||
* @return an {@link CancellationSignal} that is able to be used to cancel the opening of a
|
||||
* {@link RangingSession} that has been requested through {@link #openRangingSession}
|
||||
* but has not yet been made available by
|
||||
* {@link RangingSession.Callback#onOpened(RangingSession)}.
|
||||
*/
|
||||
@NonNull
|
||||
@RequiresPermission(allOf = {
|
||||
permission.UWB_PRIVILEGED,
|
||||
permission.UWB_RANGING
|
||||
})
|
||||
public CancellationSignal openRangingSession(@NonNull PersistableBundle parameters,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull RangingSession.Callback callbacks) {
|
||||
return mRangingManager.openSession(
|
||||
mContext.getAttributionSource(), parameters, executor, callbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current enabled/disabled state for UWB.
|
||||
*
|
||||
* Possible values are:
|
||||
* AdapterStateCallback#STATE_DISABLED
|
||||
* AdapterStateCallback#STATE_ENABLED_INACTIVE
|
||||
* AdapterStateCallback#STATE_ENABLED_ACTIVE
|
||||
*
|
||||
* @return value representing current enabled/disabled state for UWB.
|
||||
* @hide
|
||||
*/
|
||||
public @AdapterStateCallback.State int getAdapterState() {
|
||||
return mAdapterStateListener.getAdapterState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables or enables UWB for a user
|
||||
*
|
||||
* @param enabled value representing intent to disable or enable UWB. If true any subsequent
|
||||
* calls to IUwbAdapter#openRanging will be allowed. If false, all active ranging sessions will
|
||||
* be closed and subsequent calls to IUwbAdapter#openRanging will be disallowed.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setUwbEnabled(boolean enabled) {
|
||||
mAdapterStateListener.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2020 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "frameworks_base_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["frameworks_base_license"],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "UwbManagerTests",
|
||||
static_libs: [
|
||||
"androidx.test.ext.junit",
|
||||
"androidx.test.rules",
|
||||
"mockito-target-minus-junit4",
|
||||
],
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
],
|
||||
srcs: ["src/**/*.java"],
|
||||
platform_apis: true,
|
||||
certificate: "platform",
|
||||
test_suites: ["device-tests"],
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android.uwb">
|
||||
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<!-- This is a self-instrumenting test package. -->
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="android.uwb"
|
||||
android:label="UWB Manager Tests">
|
||||
</instrumentation>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<configuration description="Config for UWB Manager test cases">
|
||||
<option name="test-suite-tag" value="apct"/>
|
||||
<option name="test-suite-tag" value="apct-instrumentation"/>
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="test-file-name" value="UwbManagerTests.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-suite-tag" value="apct"/>
|
||||
<option name="test-tag" value="UwbManagerTests"/>
|
||||
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="android.uwb" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
|
||||
</test>
|
||||
</configuration>
|
||||
@@ -1 +0,0 @@
|
||||
include /core/java/android/uwb/OWNERS
|
||||
@@ -1,288 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.uwb.UwbManager.AdapterStateCallback;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Test of {@link AdapterStateListener}.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AdapterStateListenerTest {
|
||||
|
||||
IUwbAdapter mUwbAdapter = mock(IUwbAdapter.class);
|
||||
|
||||
Answer mRegisterSuccessAnswer = new Answer() {
|
||||
public Object answer(InvocationOnMock invocation) {
|
||||
Object[] args = invocation.getArguments();
|
||||
IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
|
||||
try {
|
||||
cb.onAdapterStateChanged(AdapterState.STATE_DISABLED, StateChangeReason.UNKNOWN);
|
||||
} catch (RemoteException e) {
|
||||
// Nothing to do
|
||||
}
|
||||
return new Object();
|
||||
}
|
||||
};
|
||||
|
||||
Throwable mThrowRemoteException = new RemoteException("RemoteException");
|
||||
|
||||
private static Executor getExecutor() {
|
||||
return new Executor() {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
command.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void verifyCallbackStateChangedInvoked(
|
||||
AdapterStateCallback callback, int numTimes) {
|
||||
verify(callback, times(numTimes)).onStateChanged(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister_RegisterUnregister() throws RemoteException {
|
||||
doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
|
||||
|
||||
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
|
||||
AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
|
||||
AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
|
||||
|
||||
// Verify that the adapter state listener registered with the UWB Adapter
|
||||
adapterStateListener.register(getExecutor(), callback1);
|
||||
verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
|
||||
verifyCallbackStateChangedInvoked(callback1, 1);
|
||||
verifyCallbackStateChangedInvoked(callback2, 0);
|
||||
|
||||
// Register a second client and no new call to UWB Adapter
|
||||
adapterStateListener.register(getExecutor(), callback2);
|
||||
verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
|
||||
verifyCallbackStateChangedInvoked(callback1, 1);
|
||||
verifyCallbackStateChangedInvoked(callback2, 1);
|
||||
|
||||
// Unregister first callback
|
||||
adapterStateListener.unregister(callback1);
|
||||
verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
|
||||
verify(mUwbAdapter, times(0)).unregisterAdapterStateCallbacks(any());
|
||||
verifyCallbackStateChangedInvoked(callback1, 1);
|
||||
verifyCallbackStateChangedInvoked(callback2, 1);
|
||||
|
||||
// Unregister second callback
|
||||
adapterStateListener.unregister(callback2);
|
||||
verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
|
||||
verify(mUwbAdapter, times(1)).unregisterAdapterStateCallbacks(any());
|
||||
verifyCallbackStateChangedInvoked(callback1, 1);
|
||||
verifyCallbackStateChangedInvoked(callback2, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegister_RegisterSameCallbackTwice() throws RemoteException {
|
||||
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
|
||||
AdapterStateCallback callback = mock(AdapterStateCallback.class);
|
||||
doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback);
|
||||
verifyCallbackStateChangedInvoked(callback, 1);
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback);
|
||||
verifyCallbackStateChangedInvoked(callback, 1);
|
||||
|
||||
// Invoke a state change and ensure the callback is only called once
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
|
||||
StateChangeReason.UNKNOWN);
|
||||
verifyCallbackStateChangedInvoked(callback, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallback_RunViaExecutor_Success() throws RemoteException {
|
||||
// Verify that the callbacks are invoked on the executor when successful
|
||||
doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
|
||||
runViaExecutor();
|
||||
}
|
||||
|
||||
private void runViaExecutor() {
|
||||
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
|
||||
AdapterStateCallback callback = mock(AdapterStateCallback.class);
|
||||
|
||||
Executor executor = mock(Executor.class);
|
||||
|
||||
// Do not run commands received and ensure that the callback is not invoked
|
||||
doAnswer(new ExecutorAnswer(false)).when(executor).execute(any());
|
||||
adapterStateListener.register(executor, callback);
|
||||
verify(executor, times(1)).execute(any());
|
||||
verifyCallbackStateChangedInvoked(callback, 0);
|
||||
|
||||
// Manually invoke the callback and ensure callback is not invoked
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
|
||||
StateChangeReason.UNKNOWN);
|
||||
verify(executor, times(2)).execute(any());
|
||||
verifyCallbackStateChangedInvoked(callback, 0);
|
||||
|
||||
// Run the command that the executor receives
|
||||
doAnswer(new ExecutorAnswer(true)).when(executor).execute(any());
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
|
||||
StateChangeReason.UNKNOWN);
|
||||
verify(executor, times(3)).execute(any());
|
||||
verifyCallbackStateChangedInvoked(callback, 1);
|
||||
}
|
||||
|
||||
class ExecutorAnswer implements Answer {
|
||||
|
||||
final boolean mShouldRun;
|
||||
ExecutorAnswer(boolean shouldRun) {
|
||||
mShouldRun = shouldRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
if (mShouldRun) {
|
||||
((Runnable) invocation.getArgument(0)).run();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotify_AllCallbacksNotified() throws RemoteException {
|
||||
doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
|
||||
|
||||
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
|
||||
List<AdapterStateCallback> callbacks = new ArrayList<>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
AdapterStateCallback callback = mock(AdapterStateCallback.class);
|
||||
adapterStateListener.register(getExecutor(), callback);
|
||||
callbacks.add(callback);
|
||||
}
|
||||
|
||||
// Ensure every callback got the initial state
|
||||
for (AdapterStateCallback callback : callbacks) {
|
||||
verifyCallbackStateChangedInvoked(callback, 1);
|
||||
}
|
||||
|
||||
// Invoke a state change and ensure all callbacks are invoked
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
|
||||
StateChangeReason.ALL_SESSIONS_CLOSED);
|
||||
for (AdapterStateCallback callback : callbacks) {
|
||||
verifyCallbackStateChangedInvoked(callback, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStateChange_CorrectValue() {
|
||||
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
|
||||
|
||||
AdapterStateCallback callback = mock(AdapterStateCallback.class);
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback);
|
||||
|
||||
runStateChangeValue(StateChangeReason.ALL_SESSIONS_CLOSED,
|
||||
AdapterState.STATE_ENABLED_INACTIVE,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED,
|
||||
AdapterStateCallback.STATE_ENABLED_INACTIVE);
|
||||
|
||||
runStateChangeValue(StateChangeReason.SESSION_STARTED, AdapterState.STATE_ENABLED_ACTIVE,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED,
|
||||
AdapterStateCallback.STATE_ENABLED_ACTIVE);
|
||||
|
||||
runStateChangeValue(StateChangeReason.SYSTEM_BOOT, AdapterState.STATE_DISABLED,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT,
|
||||
AdapterStateCallback.STATE_DISABLED);
|
||||
|
||||
runStateChangeValue(StateChangeReason.SYSTEM_POLICY, AdapterState.STATE_DISABLED,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY,
|
||||
AdapterStateCallback.STATE_DISABLED);
|
||||
|
||||
runStateChangeValue(StateChangeReason.UNKNOWN, AdapterState.STATE_DISABLED,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN,
|
||||
AdapterStateCallback.STATE_DISABLED);
|
||||
}
|
||||
|
||||
private void runStateChangeValue(@StateChangeReason int reasonIn, @AdapterState int stateIn,
|
||||
@AdapterStateCallback.StateChangedReason int reasonOut,
|
||||
@AdapterStateCallback.State int stateOut) {
|
||||
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
|
||||
AdapterStateCallback callback = mock(AdapterStateCallback.class);
|
||||
adapterStateListener.register(getExecutor(), callback);
|
||||
|
||||
adapterStateListener.onAdapterStateChanged(stateIn, reasonIn);
|
||||
verify(callback, times(1)).onStateChanged(stateOut, reasonOut);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStateChange_FirstRegisterGetsCorrectState() throws RemoteException {
|
||||
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
|
||||
AdapterStateCallback callback = mock(AdapterStateCallback.class);
|
||||
|
||||
Answer registerAnswer = new Answer() {
|
||||
public Object answer(InvocationOnMock invocation) {
|
||||
Object[] args = invocation.getArguments();
|
||||
IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
|
||||
try {
|
||||
cb.onAdapterStateChanged(AdapterState.STATE_ENABLED_ACTIVE,
|
||||
StateChangeReason.SESSION_STARTED);
|
||||
} catch (RemoteException e) {
|
||||
// Nothing to do
|
||||
}
|
||||
return new Object();
|
||||
}
|
||||
};
|
||||
|
||||
doAnswer(registerAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback);
|
||||
verify(callback).onStateChanged(AdapterStateCallback.STATE_ENABLED_ACTIVE,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStateChange_SecondRegisterGetsCorrectState() {
|
||||
AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
|
||||
AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
|
||||
AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback1);
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_ENABLED_ACTIVE,
|
||||
StateChangeReason.SYSTEM_BOOT);
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback2);
|
||||
verify(callback2).onStateChanged(AdapterStateCallback.STATE_ENABLED_ACTIVE,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT);
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.AttributionSource;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Test of {@link AdapterStateListener}.
|
||||
*/
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class RangingManagerTest {
|
||||
|
||||
private static final Executor EXECUTOR = UwbTestUtils.getExecutor();
|
||||
private static final PersistableBundle PARAMS = new PersistableBundle();
|
||||
private static final @RangingChangeReason int REASON = RangingChangeReason.UNKNOWN;
|
||||
private static final int UID = 343453;
|
||||
private static final String PACKAGE_NAME = "com.uwb.test";
|
||||
private static final AttributionSource ATTRIBUTION_SOURCE =
|
||||
new AttributionSource.Builder(UID).setPackageName(PACKAGE_NAME).build();
|
||||
|
||||
@Test
|
||||
public void testOpenSession_OpenRangingInvoked() throws RemoteException {
|
||||
IUwbAdapter adapter = mock(IUwbAdapter.class);
|
||||
RangingManager rangingManager = new RangingManager(adapter);
|
||||
RangingSession.Callback callback = mock(RangingSession.Callback.class);
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback);
|
||||
verify(adapter, times(1)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRangingOpened_InvalidSessionHandle() throws RemoteException {
|
||||
IUwbAdapter adapter = mock(IUwbAdapter.class);
|
||||
RangingManager rangingManager = new RangingManager(adapter);
|
||||
RangingSession.Callback callback = mock(RangingSession.Callback.class);
|
||||
|
||||
rangingManager.onRangingOpened(new SessionHandle(2));
|
||||
verify(callback, times(0)).onOpened(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRangingOpened_MultipleSessionsRegistered() throws RemoteException {
|
||||
IUwbAdapter adapter = mock(IUwbAdapter.class);
|
||||
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
|
||||
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
|
||||
ArgumentCaptor<SessionHandle> sessionHandleCaptor =
|
||||
ArgumentCaptor.forClass(SessionHandle.class);
|
||||
|
||||
RangingManager rangingManager = new RangingManager(adapter);
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback1);
|
||||
verify(adapter, times(1)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
|
||||
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback2);
|
||||
verify(adapter, times(2)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
|
||||
|
||||
rangingManager.onRangingOpened(sessionHandle1);
|
||||
verify(callback1, times(1)).onOpened(any());
|
||||
verify(callback2, times(0)).onOpened(any());
|
||||
|
||||
rangingManager.onRangingOpened(sessionHandle2);
|
||||
verify(callback1, times(1)).onOpened(any());
|
||||
verify(callback2, times(1)).onOpened(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectCallbackInvoked() throws RemoteException {
|
||||
IUwbAdapter adapter = mock(IUwbAdapter.class);
|
||||
RangingManager rangingManager = new RangingManager(adapter);
|
||||
RangingSession.Callback callback = mock(RangingSession.Callback.class);
|
||||
|
||||
ArgumentCaptor<SessionHandle> sessionHandleCaptor =
|
||||
ArgumentCaptor.forClass(SessionHandle.class);
|
||||
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback);
|
||||
verify(adapter, times(1)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
SessionHandle handle = sessionHandleCaptor.getValue();
|
||||
|
||||
rangingManager.onRangingOpened(handle);
|
||||
verify(callback, times(1)).onOpened(any());
|
||||
|
||||
rangingManager.onRangingStarted(handle, PARAMS);
|
||||
verify(callback, times(1)).onStarted(eq(PARAMS));
|
||||
|
||||
rangingManager.onRangingStartFailed(handle, REASON, PARAMS);
|
||||
verify(callback, times(1)).onStartFailed(eq(REASON), eq(PARAMS));
|
||||
|
||||
RangingReport report = UwbTestUtils.getRangingReports(1);
|
||||
rangingManager.onRangingResult(handle, report);
|
||||
verify(callback, times(1)).onReportReceived(eq(report));
|
||||
|
||||
rangingManager.onRangingReconfigured(handle, PARAMS);
|
||||
verify(callback, times(1)).onReconfigured(eq(PARAMS));
|
||||
|
||||
rangingManager.onRangingReconfigureFailed(handle, REASON, PARAMS);
|
||||
verify(callback, times(1)).onReconfigureFailed(eq(REASON), eq(PARAMS));
|
||||
|
||||
rangingManager.onRangingStopped(handle, REASON, PARAMS);
|
||||
verify(callback, times(1)).onStopped(eq(REASON), eq(PARAMS));
|
||||
|
||||
rangingManager.onRangingStopFailed(handle, REASON, PARAMS);
|
||||
verify(callback, times(1)).onStopFailed(eq(REASON), eq(PARAMS));
|
||||
|
||||
rangingManager.onRangingClosed(handle, REASON, PARAMS);
|
||||
verify(callback, times(1)).onClosed(eq(REASON), eq(PARAMS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRangingClosed_MultipleSessionsRegistered() throws RemoteException {
|
||||
IUwbAdapter adapter = mock(IUwbAdapter.class);
|
||||
// Verify that if multiple sessions are registered, only the session that is
|
||||
// requested to close receives the associated callbacks
|
||||
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
|
||||
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
|
||||
|
||||
RangingManager rangingManager = new RangingManager(adapter);
|
||||
ArgumentCaptor<SessionHandle> sessionHandleCaptor =
|
||||
ArgumentCaptor.forClass(SessionHandle.class);
|
||||
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback1);
|
||||
verify(adapter, times(1)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
|
||||
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback2);
|
||||
verify(adapter, times(2)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
|
||||
|
||||
rangingManager.onRangingClosed(sessionHandle1, REASON, PARAMS);
|
||||
verify(callback1, times(1)).onClosed(anyInt(), any());
|
||||
verify(callback2, times(0)).onClosed(anyInt(), any());
|
||||
|
||||
rangingManager.onRangingClosed(sessionHandle2, REASON, PARAMS);
|
||||
verify(callback1, times(1)).onClosed(anyInt(), any());
|
||||
verify(callback2, times(1)).onClosed(anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnRangingReport_MultipleSessionsRegistered() throws RemoteException {
|
||||
IUwbAdapter adapter = mock(IUwbAdapter.class);
|
||||
RangingSession.Callback callback1 = mock(RangingSession.Callback.class);
|
||||
RangingSession.Callback callback2 = mock(RangingSession.Callback.class);
|
||||
|
||||
ArgumentCaptor<SessionHandle> sessionHandleCaptor =
|
||||
ArgumentCaptor.forClass(SessionHandle.class);
|
||||
|
||||
RangingManager rangingManager = new RangingManager(adapter);
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback1);
|
||||
verify(adapter, times(1)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
SessionHandle sessionHandle1 = sessionHandleCaptor.getValue();
|
||||
|
||||
rangingManager.onRangingStarted(sessionHandle1, PARAMS);
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback2);
|
||||
verify(adapter, times(2)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
SessionHandle sessionHandle2 = sessionHandleCaptor.getValue();
|
||||
rangingManager.onRangingStarted(sessionHandle2, PARAMS);
|
||||
|
||||
rangingManager.onRangingResult(sessionHandle1, UwbTestUtils.getRangingReports(1));
|
||||
verify(callback1, times(1)).onReportReceived(any());
|
||||
verify(callback2, times(0)).onReportReceived(any());
|
||||
|
||||
rangingManager.onRangingResult(sessionHandle2, UwbTestUtils.getRangingReports(1));
|
||||
verify(callback1, times(1)).onReportReceived(any());
|
||||
verify(callback2, times(1)).onReportReceived(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReasons() throws RemoteException {
|
||||
runReason(RangingChangeReason.LOCAL_API,
|
||||
RangingSession.Callback.REASON_LOCAL_REQUEST);
|
||||
|
||||
runReason(RangingChangeReason.MAX_SESSIONS_REACHED,
|
||||
RangingSession.Callback.REASON_MAX_SESSIONS_REACHED);
|
||||
|
||||
runReason(RangingChangeReason.PROTOCOL_SPECIFIC,
|
||||
RangingSession.Callback.REASON_PROTOCOL_SPECIFIC_ERROR);
|
||||
|
||||
runReason(RangingChangeReason.REMOTE_REQUEST,
|
||||
RangingSession.Callback.REASON_REMOTE_REQUEST);
|
||||
|
||||
runReason(RangingChangeReason.SYSTEM_POLICY,
|
||||
RangingSession.Callback.REASON_SYSTEM_POLICY);
|
||||
|
||||
runReason(RangingChangeReason.BAD_PARAMETERS,
|
||||
RangingSession.Callback.REASON_BAD_PARAMETERS);
|
||||
|
||||
runReason(RangingChangeReason.UNKNOWN,
|
||||
RangingSession.Callback.REASON_UNKNOWN);
|
||||
}
|
||||
|
||||
private void runReason(@RangingChangeReason int reasonIn,
|
||||
@RangingSession.Callback.Reason int reasonOut) throws RemoteException {
|
||||
IUwbAdapter adapter = mock(IUwbAdapter.class);
|
||||
RangingManager rangingManager = new RangingManager(adapter);
|
||||
RangingSession.Callback callback = mock(RangingSession.Callback.class);
|
||||
|
||||
ArgumentCaptor<SessionHandle> sessionHandleCaptor =
|
||||
ArgumentCaptor.forClass(SessionHandle.class);
|
||||
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback);
|
||||
verify(adapter, times(1)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
SessionHandle handle = sessionHandleCaptor.getValue();
|
||||
|
||||
rangingManager.onRangingOpenFailed(handle, reasonIn, PARAMS);
|
||||
verify(callback, times(1)).onOpenFailed(eq(reasonOut), eq(PARAMS));
|
||||
|
||||
// Open a new session
|
||||
rangingManager.openSession(ATTRIBUTION_SOURCE, PARAMS, EXECUTOR, callback);
|
||||
verify(adapter, times(2)).openRanging(
|
||||
eq(ATTRIBUTION_SOURCE), sessionHandleCaptor.capture(), any(), any());
|
||||
handle = sessionHandleCaptor.getValue();
|
||||
rangingManager.onRangingOpened(handle);
|
||||
|
||||
rangingManager.onRangingStartFailed(handle, reasonIn, PARAMS);
|
||||
verify(callback, times(1)).onStartFailed(eq(reasonOut), eq(PARAMS));
|
||||
|
||||
rangingManager.onRangingReconfigureFailed(handle, reasonIn, PARAMS);
|
||||
verify(callback, times(1)).onReconfigureFailed(eq(reasonOut), eq(PARAMS));
|
||||
|
||||
rangingManager.onRangingStopFailed(handle, reasonIn, PARAMS);
|
||||
verify(callback, times(1)).onStopFailed(eq(reasonOut), eq(PARAMS));
|
||||
|
||||
rangingManager.onRangingClosed(handle, reasonIn, PARAMS);
|
||||
verify(callback, times(1)).onClosed(eq(reasonOut), eq(PARAMS));
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.uwb;
|
||||
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class UwbTestUtils {
|
||||
private UwbTestUtils() {}
|
||||
|
||||
public static AngleMeasurement getAngleMeasurement() {
|
||||
return new AngleMeasurement(
|
||||
getDoubleInRange(-Math.PI, Math.PI),
|
||||
getDoubleInRange(0, Math.PI),
|
||||
getDoubleInRange(0, 1));
|
||||
}
|
||||
|
||||
public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
|
||||
return new AngleOfArrivalMeasurement.Builder(getAngleMeasurement())
|
||||
.setAltitude(getAngleMeasurement())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static DistanceMeasurement getDistanceMeasurement() {
|
||||
return new DistanceMeasurement.Builder()
|
||||
.setMeters(getDoubleInRange(0, 100))
|
||||
.setErrorMeters(getDoubleInRange(0, 10))
|
||||
.setConfidenceLevel(getDoubleInRange(0, 1))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static RangingMeasurement getRangingMeasurement() {
|
||||
return getRangingMeasurement(getUwbAddress(false));
|
||||
}
|
||||
|
||||
public static RangingMeasurement getRangingMeasurement(UwbAddress address) {
|
||||
return new RangingMeasurement.Builder()
|
||||
.setDistanceMeasurement(getDistanceMeasurement())
|
||||
.setAngleOfArrivalMeasurement(getAngleOfArrivalMeasurement())
|
||||
.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos())
|
||||
.setRemoteDeviceAddress(address != null ? address : getUwbAddress(false))
|
||||
.setStatus(RangingMeasurement.RANGING_STATUS_SUCCESS)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static RangingReport getRangingReports(int numMeasurements) {
|
||||
RangingReport.Builder builder = new RangingReport.Builder();
|
||||
for (int i = 0; i < numMeasurements; i++) {
|
||||
builder.addMeasurement(getRangingMeasurement());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static double getDoubleInRange(double min, double max) {
|
||||
return min + (max - min) * Math.random();
|
||||
}
|
||||
|
||||
public static UwbAddress getUwbAddress(boolean isShortAddress) {
|
||||
byte[] addressBytes = new byte[isShortAddress ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH :
|
||||
UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH];
|
||||
for (int i = 0; i < addressBytes.length; i++) {
|
||||
addressBytes[i] = (byte) getDoubleInRange(1, 255);
|
||||
}
|
||||
return UwbAddress.fromBytes(addressBytes);
|
||||
}
|
||||
|
||||
public static Executor getExecutor() {
|
||||
return new Executor() {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
command.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user