diff options
| author | 2021-04-21 23:50:23 +0000 | |
|---|---|---|
| committer | 2021-04-21 23:50:23 +0000 | |
| commit | ca5c906ab58488995ebb59a4df1b3d0473643e35 (patch) | |
| tree | 367da708ee6e6a4f30ab9efaf784aff6f8de295c | |
| parent | eb52e08c30b04a28f97497b71ef8eb42c3dc773d (diff) | |
| parent | 17b112aef8051a899c21f99102b10fc00774a654 (diff) | |
Merge "UWB: Add setUwbEnabled System API." am: 17b112aef8
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1683089
Change-Id: Icb9adae4bd40e937dc0ff702da04f8ecbdd77f1d
| -rw-r--r-- | core/api/system-current.txt | 5 | ||||
| -rw-r--r-- | core/java/android/uwb/AdapterState.aidl | 38 | ||||
| -rw-r--r-- | core/java/android/uwb/AdapterStateListener.java | 63 | ||||
| -rw-r--r-- | core/java/android/uwb/IUwbAdapter.aidl | 13 | ||||
| -rw-r--r-- | core/java/android/uwb/IUwbAdapterStateCallbacks.aidl | 13 | ||||
| -rw-r--r-- | core/java/android/uwb/UwbManager.java | 48 | ||||
| -rw-r--r-- | core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java | 63 |
7 files changed, 201 insertions, 42 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index e376fb82f498..2e4043654d44 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -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 } } diff --git a/core/java/android/uwb/AdapterState.aidl b/core/java/android/uwb/AdapterState.aidl new file mode 100644 index 000000000000..991f64a0c0ae --- /dev/null +++ b/core/java/android/uwb/AdapterState.aidl @@ -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, +}
\ No newline at end of file diff --git a/core/java/android/uwb/AdapterStateListener.java b/core/java/android/uwb/AdapterStateListener.java index 8875af385238..b9900951591f 100644 --- a/core/java/android/uwb/AdapterStateListener.java +++ b/core/java/android/uwb/AdapterStateListener.java @@ -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; + } + } } diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl index 30da248e9e87..5804d04bdba7 100644 --- a/core/java/android/uwb/IUwbAdapter.aidl +++ b/core/java/android/uwb/IUwbAdapter.aidl @@ -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. */ diff --git a/core/java/android/uwb/IUwbAdapterStateCallbacks.aidl b/core/java/android/uwb/IUwbAdapterStateCallbacks.aidl index d928eabae465..d3b34c632bcc 100644 --- a/core/java/android/uwb/IUwbAdapterStateCallbacks.aidl +++ b/core/java/android/uwb/IUwbAdapterStateCallbacks.aidl @@ -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); }
\ No newline at end of file diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java index 844bbbe7970b..9116c49d0764 100644 --- a/core/java/android/uwb/UwbManager.java +++ b/core/java/android/uwb/UwbManager.java @@ -70,6 +70,16 @@ public final class UwbManager { @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; @@ -95,22 +105,41 @@ 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); + } } diff --git a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java index ce67ef7868e8..bdaf63021503 100644 --- a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java +++ b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java @@ -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); } } |