Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93964f8f authored by Brian Stack's avatar Brian Stack
Browse files

Implement UWB AdapterStateListener

The AdapterStateListener registers with the underlying UWB Service for
UWB Adapter state changes and notifies registered client callbacks.

Bug: 170323306
Test: atest UwbManagerTests
Change-Id: Ie8ba8208909652b98ee2df15e08433627542f28b
parent 8cc2de8c
Loading
Loading
Loading
Loading
+149 −0
Original line number Diff line number Diff line
/*
 * 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.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;
    private boolean mAdapterEnabledState = false;

    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");
                    executor.execute(() -> callback.onStateChanged(false,
                            AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN));
                }
            } 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");
                }
                mIsRegistered = false;
            }
        }
    }

    private void sendCurrentState(@NonNull AdapterStateCallback callback) {
        synchronized (this) {
            Executor executor = mCallbackMap.get(callback);

            final long identity = Binder.clearCallingIdentity();
            try {
                executor.execute(() -> callback.onStateChanged(
                        mAdapterEnabledState, mAdapterStateChangeReason));
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

    @Override
    public void onAdapterStateChanged(boolean isEnabled, int reason) {
        synchronized (this) {
            @StateChangedReason int localReason =
                    convertToStateChangedReason(reason);
            mAdapterEnabledState = isEnabled;
            mAdapterStateChangeReason = localReason;
            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;
        }
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -41,5 +41,10 @@ enum StateChangeReason {
   * The adapter state changed because of a device system change.
   */
  SYSTEM_POLICY,

  /**
   * Used to signal the first adapter state message after boot
   */
   SYSTEM_BOOT,
}
+9 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.uwb;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
@@ -48,6 +49,8 @@ public final class UwbManager {
    private IUwbAdapter mUwbAdapter;
    private static final String SERVICE_NAME = "uwb";

    private AdapterStateListener mAdapterStateListener;

    /**
     * Interface for receiving UWB adapter state changes
     */
@@ -112,6 +115,7 @@ public final class UwbManager {
     */
    private UwbManager(IUwbAdapter adapter) {
        mUwbAdapter = adapter;
        mAdapterStateListener = new AdapterStateListener(adapter);
    }

    /**
@@ -143,8 +147,9 @@ public final class UwbManager {
     * @param executor an {@link Executor} to execute given callback
     * @param callback user implementation of the {@link AdapterStateCallback}
     */
    public void registerAdapterStateCallback(Executor executor, AdapterStateCallback callback) {
        throw new UnsupportedOperationException();
    public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor,
            @NonNull AdapterStateCallback callback) {
        mAdapterStateListener.register(executor, callback);
    }

    /**
@@ -156,8 +161,8 @@ public final class UwbManager {
     *
     * @param callback user implementation of the {@link AdapterStateCallback}
     */
    public void unregisterAdapterStateCallback(AdapterStateCallback callback) {
        throw new UnsupportedOperationException();
    public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) {
        mAdapterStateListener.unregister(callback);
    }

    /**