Merge "UWB: Add setUwbEnabled System API."
This commit is contained in:
@@ -12606,12 +12606,15 @@ package android.uwb {
|
||||
}
|
||||
|
||||
public static interface UwbManager.AdapterStateCallback {
|
||||
method public void onStateChanged(boolean, int);
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
38
core/java/android/uwb/AdapterState.aidl
Normal file
38
core/java/android/uwb/AdapterState.aidl
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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,
|
||||
}
|
||||
@@ -21,6 +21,7 @@ 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;
|
||||
@@ -40,7 +41,8 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
|
||||
|
||||
@StateChangedReason
|
||||
private int mAdapterStateChangeReason = AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
|
||||
private boolean mAdapterEnabledState = false;
|
||||
@State
|
||||
private int mAdapterState = AdapterStateCallback.STATE_DISABLED;
|
||||
|
||||
public AdapterStateListener(@NonNull IUwbAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
@@ -66,7 +68,7 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
|
||||
mIsRegistered = true;
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to register adapter state callback");
|
||||
executor.execute(() -> callback.onStateChanged(false,
|
||||
executor.execute(() -> callback.onStateChanged(mAdapterState,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN));
|
||||
}
|
||||
} else {
|
||||
@@ -99,6 +101,42 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the adapter enabled state
|
||||
*
|
||||
* @param isEnabled value of new adapter state
|
||||
*/
|
||||
public void setEnabled(boolean isEnabled) {
|
||||
synchronized (this) {
|
||||
if (!mIsRegistered) {
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
mAdapter.setEnabled(isEnabled);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed to set adapter state");
|
||||
sendErrorState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendErrorState() {
|
||||
synchronized (this) {
|
||||
for (AdapterStateCallback callback: mCallbackMap.keySet()) {
|
||||
Executor executor = mCallbackMap.get(callback);
|
||||
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onStateChanged(
|
||||
mAdapterState, mAdapterStateChangeReason));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendCurrentState(@NonNull AdapterStateCallback callback) {
|
||||
synchronized (this) {
|
||||
Executor executor = mCallbackMap.get(callback);
|
||||
@@ -106,7 +144,7 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> callback.onStateChanged(
|
||||
mAdapterEnabledState, mAdapterStateChangeReason));
|
||||
mAdapterState, mAdapterStateChangeReason));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
@@ -114,12 +152,13 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdapterStateChanged(boolean isEnabled, int reason) {
|
||||
public void onAdapterStateChanged(int state, int reason) {
|
||||
synchronized (this) {
|
||||
@StateChangedReason int localReason =
|
||||
convertToStateChangedReason(reason);
|
||||
mAdapterEnabledState = isEnabled;
|
||||
@State int localState = convertToState(state);
|
||||
mAdapterStateChangeReason = localReason;
|
||||
mAdapterState = localState;
|
||||
for (AdapterStateCallback cb : mCallbackMap.keySet()) {
|
||||
sendCurrentState(cb);
|
||||
}
|
||||
@@ -146,4 +185,18 @@ public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +145,19 @@ interface IUwbAdapter {
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* The maximum allowed time to open a ranging session.
|
||||
*/
|
||||
|
||||
@@ -17,16 +17,17 @@
|
||||
package android.uwb;
|
||||
|
||||
import android.uwb.StateChangeReason;
|
||||
import android.uwb.AdapterState;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
interface IUwbAdapterStateCallbacks {
|
||||
/**
|
||||
* Called whenever the adapter state changes
|
||||
*
|
||||
* @param isEnabled true if the adapter is enabled, false otherwise
|
||||
* @param reason the reason that the state has changed
|
||||
*/
|
||||
void onAdapterStateChanged(boolean isEnabled, StateChangeReason reason);
|
||||
* 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);
|
||||
}
|
||||
@@ -69,6 +69,16 @@ public final class UwbManager {
|
||||
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
|
||||
*/
|
||||
@@ -94,23 +104,42 @@ public final class UwbManager {
|
||||
*/
|
||||
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 values for the state to change are
|
||||
* <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}.
|
||||
*
|
||||
* @param isEnabled true when UWB adapter is enabled, false when it is disabled
|
||||
* <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(boolean isEnabled, @StateChangedReason int reason);
|
||||
void onStateChanged(@State int state, @StateChangedReason int reason);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,4 +270,17 @@ public final class UwbManager {
|
||||
@NonNull RangingSession.Callback callbacks) {
|
||||
return mRangingManager.openSession(parameters, executor, callbacks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package android.uwb;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
@@ -55,7 +54,7 @@ public class AdapterStateListenerTest {
|
||||
Object[] args = invocation.getArguments();
|
||||
IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
|
||||
try {
|
||||
cb.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
|
||||
cb.onAdapterStateChanged(AdapterState.STATE_DISABLED, StateChangeReason.UNKNOWN);
|
||||
} catch (RemoteException e) {
|
||||
// Nothing to do
|
||||
}
|
||||
@@ -76,7 +75,7 @@ public class AdapterStateListenerTest {
|
||||
|
||||
private static void verifyCallbackStateChangedInvoked(
|
||||
AdapterStateCallback callback, int numTimes) {
|
||||
verify(callback, times(numTimes)).onStateChanged(anyBoolean(), anyInt());
|
||||
verify(callback, times(numTimes)).onStateChanged(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -151,7 +150,8 @@ public class AdapterStateListenerTest {
|
||||
verifyCallbackStateChangedInvoked(callback, 1);
|
||||
|
||||
// Invoke a state change and ensure the callback is only called once
|
||||
adapterStateListener.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
|
||||
StateChangeReason.UNKNOWN);
|
||||
verifyCallbackStateChangedInvoked(callback, 2);
|
||||
}
|
||||
|
||||
@@ -182,13 +182,15 @@ public class AdapterStateListenerTest {
|
||||
verifyCallbackStateChangedInvoked(callback, 0);
|
||||
|
||||
// Manually invoke the callback and ensure callback is not invoked
|
||||
adapterStateListener.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
|
||||
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(false, StateChangeReason.UNKNOWN);
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
|
||||
StateChangeReason.UNKNOWN);
|
||||
verify(executor, times(3)).execute(any());
|
||||
verifyCallbackStateChangedInvoked(callback, 1);
|
||||
}
|
||||
@@ -227,7 +229,8 @@ public class AdapterStateListenerTest {
|
||||
}
|
||||
|
||||
// Invoke a state change and ensure all callbacks are invoked
|
||||
adapterStateListener.onAdapterStateChanged(true, StateChangeReason.ALL_SESSIONS_CLOSED);
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_DISABLED,
|
||||
StateChangeReason.ALL_SESSIONS_CLOSED);
|
||||
for (AdapterStateCallback callback : callbacks) {
|
||||
verifyCallbackStateChangedInvoked(callback, 2);
|
||||
}
|
||||
@@ -242,32 +245,36 @@ public class AdapterStateListenerTest {
|
||||
adapterStateListener.register(getExecutor(), callback);
|
||||
|
||||
runStateChangeValue(StateChangeReason.ALL_SESSIONS_CLOSED,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED);
|
||||
AdapterState.STATE_ENABLED_INACTIVE,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED,
|
||||
AdapterStateCallback.STATE_ENABLED_INACTIVE);
|
||||
|
||||
runStateChangeValue(StateChangeReason.SESSION_STARTED,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED);
|
||||
runStateChangeValue(StateChangeReason.SESSION_STARTED, AdapterState.STATE_ENABLED_ACTIVE,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED,
|
||||
AdapterStateCallback.STATE_ENABLED_ACTIVE);
|
||||
|
||||
runStateChangeValue(StateChangeReason.SYSTEM_BOOT,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT);
|
||||
runStateChangeValue(StateChangeReason.SYSTEM_BOOT, AdapterState.STATE_DISABLED,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT,
|
||||
AdapterStateCallback.STATE_DISABLED);
|
||||
|
||||
runStateChangeValue(StateChangeReason.SYSTEM_POLICY,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY);
|
||||
runStateChangeValue(StateChangeReason.SYSTEM_POLICY, AdapterState.STATE_DISABLED,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY,
|
||||
AdapterStateCallback.STATE_DISABLED);
|
||||
|
||||
runStateChangeValue(StateChangeReason.UNKNOWN,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN);
|
||||
runStateChangeValue(StateChangeReason.UNKNOWN, AdapterState.STATE_DISABLED,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN,
|
||||
AdapterStateCallback.STATE_DISABLED);
|
||||
}
|
||||
|
||||
private void runStateChangeValue(@StateChangeReason int reasonIn,
|
||||
@AdapterStateCallback.StateChangedReason int reasonOut) {
|
||||
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(false, reasonIn);
|
||||
verify(callback, times(1)).onStateChanged(false, reasonOut);
|
||||
|
||||
adapterStateListener.onAdapterStateChanged(true, reasonIn);
|
||||
verify(callback, times(1)).onStateChanged(true, reasonOut);
|
||||
adapterStateListener.onAdapterStateChanged(stateIn, reasonIn);
|
||||
verify(callback, times(1)).onStateChanged(stateOut, reasonOut);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -280,7 +287,8 @@ public class AdapterStateListenerTest {
|
||||
Object[] args = invocation.getArguments();
|
||||
IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
|
||||
try {
|
||||
cb.onAdapterStateChanged(true, StateChangeReason.SESSION_STARTED);
|
||||
cb.onAdapterStateChanged(AdapterState.STATE_ENABLED_ACTIVE,
|
||||
StateChangeReason.SESSION_STARTED);
|
||||
} catch (RemoteException e) {
|
||||
// Nothing to do
|
||||
}
|
||||
@@ -291,7 +299,7 @@ public class AdapterStateListenerTest {
|
||||
doAnswer(registerAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback);
|
||||
verify(callback).onStateChanged(true,
|
||||
verify(callback).onStateChanged(AdapterStateCallback.STATE_ENABLED_ACTIVE,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED);
|
||||
}
|
||||
|
||||
@@ -302,10 +310,11 @@ public class AdapterStateListenerTest {
|
||||
AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback1);
|
||||
adapterStateListener.onAdapterStateChanged(true, StateChangeReason.SYSTEM_BOOT);
|
||||
adapterStateListener.onAdapterStateChanged(AdapterState.STATE_ENABLED_ACTIVE,
|
||||
StateChangeReason.SYSTEM_BOOT);
|
||||
|
||||
adapterStateListener.register(getExecutor(), callback2);
|
||||
verify(callback2).onStateChanged(true,
|
||||
verify(callback2).onStateChanged(AdapterStateCallback.STATE_ENABLED_ACTIVE,
|
||||
AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user