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

Commit c5e292c9 authored by George Chang's avatar George Chang Committed by Automerger Merge Worker
Browse files

Merge "Add callbacks to indicate NFC setControllerAlwaysOn state changed" am: cfc798e7

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1657764

Change-Id: Ifa60adda0843a8e6dda1c974d2a4bc354de2df77
parents d7080db9 cfc798e7
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -6728,12 +6728,18 @@ package android.nfc {
    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
    method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnStateCallback(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
    field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
  }
  public static interface NfcAdapter.ControllerAlwaysOnStateCallback {
    method public void onStateChanged(boolean);
  }
  public static interface NfcAdapter.NfcUnlockHandler {
    method public boolean onUnlockAttempted(android.nfc.Tag);
  }
+3 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.nfc.Tag;
import android.nfc.TechListParcel;
import android.nfc.IAppCallback;
import android.nfc.INfcAdapterExtras;
import android.nfc.INfcControllerAlwaysOnStateCallback;
import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
import android.nfc.INfcFCardEmulation;
@@ -75,4 +76,6 @@ interface INfcAdapter
    boolean setControllerAlwaysOn(boolean value);
    boolean isControllerAlwaysOn();
    boolean isControllerAlwaysOnSupported();
    void registerControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
    void unregisterControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
}
+29 −0
Original line number Diff line number Diff line
/*
 * 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.nfc;

/**
 * @hide
 */
oneway interface INfcControllerAlwaysOnStateCallback {
  /**
   * Called whenever the controller always on state changes
   *
   * @param isEnabled true if the state is enabled, false otherwise
   */
  void onControllerAlwaysOnStateChanged(boolean isEnabled);
}
+65 −25
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.nfc;

import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -47,6 +48,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * Represents the local NFC adapter.
@@ -65,6 +67,8 @@ import java.util.List;
public final class NfcAdapter {
    static final String TAG = "NFC";

    private final NfcControllerAlwaysOnStateListener mControllerAlwaysOnStateListener;

    /**
     * Intent to start an activity when a tag with NDEF payload is discovered.
     *
@@ -349,22 +353,6 @@ public final class NfcAdapter {
    public static final String EXTRA_HANDOVER_TRANSFER_STATUS =
            "android.nfc.extra.HANDOVER_TRANSFER_STATUS";

    /** @hide */
    public static final String ACTION_ALWAYS_ON_STATE_CHANGED =
            "android.nfc.action.ALWAYS_ON_STATE_CHANGED";

    /**
     * Used as an int extra field in {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
     * intents to request the current power state. Possible values are:
     * {@link #STATE_OFF},
     * {@link #STATE_TURNING_ON},
     * {@link #STATE_ON},
     * {@link #STATE_TURNING_OFF},
     * @hide
     */
    public static final String EXTRA_ALWAYS_ON_STATE =
            "android.nfc.extra.ALWAYS_ON_STATE";

    /** @hide */
    public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
    /** @hide */
@@ -429,6 +417,22 @@ public final class NfcAdapter {
        public void onTagDiscovered(Tag tag);
    }

    /**
     * A callback to be invoked when NFC controller always on state changes.
     * <p>Register your {@code ControllerAlwaysOnStateCallback} implementation with {@link
     * NfcAdapter#registerControllerAlwaysOnStateCallback} and disable it with {@link
     * NfcAdapter#unregisterControllerAlwaysOnStateCallback}.
     * @see #registerControllerAlwaysOnStateCallback
     * @hide
     */
    @SystemApi
    public interface ControllerAlwaysOnStateCallback {
        /**
         * Called on NFC controller always on state changes
         */
        void onStateChanged(boolean isEnabled);
    }

    /**
     * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
     * to another device.
@@ -744,6 +748,7 @@ public final class NfcAdapter {
        mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
        mTagRemovedListener = null;
        mLock = new Object();
        mControllerAlwaysOnStateListener = new NfcControllerAlwaysOnStateListener(getService());
    }

    /**
@@ -2239,14 +2244,16 @@ public final class NfcAdapter {
    /**
     * Sets NFC controller always on feature.
     * <p>This API is for the NFCC internal state management. It allows to discriminate
     * the controller function from the NFC function by keeping the NFC Controller on without
     * the controller function from the NFC function by keeping the NFC controller on without
     * any NFC RF enabled if necessary.
     * <p>This call is asynchronous. Listen for {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
     * broadcasts to find out when the operation is complete.
     * <p>If this returns true, then either NFCC is already on, or
     * a {@link #ACTION_ALWAYS_ON_STATE_CHANGED} broadcast will be sent to indicate
     * a state transition.
     * If this returns false, then there is some problem that prevents an attempt to turn NFCC on.
     * <p>This call is asynchronous. Register a callback {@link #ControllerAlwaysOnStateCallback}
     * by {@link #registerControllerAlwaysOnStateCallback} to find out when the operation is
     * complete.
     * <p>If this returns true, then either NFCC always on state has been set based on the value,
     * or a {@link ControllerAlwaysOnStateCallback#onStateChanged(boolean)} will be invoked to
     * indicate the state change.
     * If this returns false, then there is some problem that prevents an attempt to turn NFCC
     * always on.
     * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
     * disabled), if false the NFCC will follow completely the Nfc adapter state.
     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
@@ -2284,7 +2291,6 @@ public final class NfcAdapter {
     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
     * @hide
     */

    @SystemApi
    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
    public boolean isControllerAlwaysOn() {
@@ -2313,7 +2319,6 @@ public final class NfcAdapter {
     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
     * @hide
     */

    @SystemApi
    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
    public boolean isControllerAlwaysOnSupported() {
@@ -2337,4 +2342,39 @@ public final class NfcAdapter {
            return false;
        }
    }

    /**
     * Register a {@link ControllerAlwaysOnStateCallback} to listen for NFC controller always on
     * state changes
     * <p>The provided callback will be invoked by the given {@link Executor}.
     *
     * @param executor an {@link Executor} to execute given callback
     * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
    public void registerControllerAlwaysOnStateCallback(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull ControllerAlwaysOnStateCallback callback) {
        mControllerAlwaysOnStateListener.register(executor, callback);
    }

    /**
     * Unregister the specified {@link ControllerAlwaysOnStateCallback}
     * <p>The same {@link ControllerAlwaysOnStateCallback} object used when calling
     * {@link #registerControllerAlwaysOnStateCallback(Executor, ControllerAlwaysOnStateCallback)}
     * must be used.
     *
     * <p>Callbacks are automatically unregistered when application process goes away
     *
     * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
    public void unregisterControllerAlwaysOnStateCallback(
            @NonNull ControllerAlwaysOnStateCallback callback) {
        mControllerAlwaysOnStateListener.unregister(callback);
    }
}
+120 −0
Original line number Diff line number Diff line
/*
 * 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.nfc;

import android.annotation.NonNull;
import android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback;
import android.os.Binder;
import android.os.RemoteException;
import android.util.Log;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;

/**
 * @hide
 */
public class NfcControllerAlwaysOnStateListener extends INfcControllerAlwaysOnStateCallback.Stub {
    private static final String TAG = "NfcControllerAlwaysOnStateListener";

    private final INfcAdapter mAdapter;

    private final Map<ControllerAlwaysOnStateCallback, Executor> mCallbackMap = new HashMap<>();

    private boolean mCurrentState = false;
    private boolean mIsRegistered = false;

    public NfcControllerAlwaysOnStateListener(@NonNull INfcAdapter adapter) {
        mAdapter = adapter;
    }

    /**
     * Register a {@link ControllerAlwaysOnStateCallback} with this
     * {@link NfcControllerAlwaysOnStateListener}
     *
     * @param executor an {@link Executor} to execute given callback
     * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
     */
    public void register(@NonNull Executor executor,
            @NonNull ControllerAlwaysOnStateCallback callback) {
        synchronized (this) {
            if (mCallbackMap.containsKey(callback)) {
                return;
            }

            mCallbackMap.put(callback, executor);
            if (!mIsRegistered) {
                try {
                    mAdapter.registerControllerAlwaysOnStateCallback(this);
                    mIsRegistered = true;
                } catch (RemoteException e) {
                    Log.w(TAG, "Failed to register ControllerAlwaysOnStateListener");
                }
            }
        }
    }

    /**
     * Unregister the specified {@link ControllerAlwaysOnStateCallback}
     *
     * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
     */
    public void unregister(@NonNull ControllerAlwaysOnStateCallback callback) {
        synchronized (this) {
            if (!mCallbackMap.containsKey(callback)) {
                return;
            }

            mCallbackMap.remove(callback);

            if (mCallbackMap.isEmpty() && mIsRegistered) {
                try {
                    mAdapter.unregisterControllerAlwaysOnStateCallback(this);
                } catch (RemoteException e) {
                    Log.w(TAG, "Failed to unregister ControllerAlwaysOnStateListener");
                }
                mIsRegistered = false;
            }
        }
    }

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

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

    @Override
    public void onControllerAlwaysOnStateChanged(boolean isEnabled) {
        synchronized (this) {
            mCurrentState = isEnabled;
            for (ControllerAlwaysOnStateCallback cb : mCallbackMap.keySet()) {
                sendCurrentState(cb);
            }
        }
    }
}
Loading