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

Commit e2c184c3 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "nfc(api) APIs added for sending Vendor specific commands" into main am: 7f0c8fef

parents 771b0b47 7f0c8fef
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -14,12 +14,20 @@ package android.nfc {
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
    method @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerNfcVendorNciCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.NfcVendorNciCallback);
    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
    method @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int sendVendorNciMessage(int, @IntRange(from=0, to=15) int, @IntRange(from=0) int, @NonNull byte[]);
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
    method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean);
    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
    method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
    method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterNfcVendorNciCallback(@NonNull android.nfc.NfcAdapter.NfcVendorNciCallback);
    field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int MESSAGE_TYPE_COMMAND = 1; // 0x1
    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3; // 0x3
    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED = 2; // 0x2
    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_REJECTED = 1; // 0x1
    field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_SUCCESS = 0; // 0x0
    field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
    field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
    field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe
@@ -33,6 +41,11 @@ package android.nfc {
    method public boolean onUnlockAttempted(android.nfc.Tag);
  }

  @FlaggedApi("android.nfc.nfc_vendor_cmd") public static interface NfcAdapter.NfcVendorNciCallback {
    method @FlaggedApi("android.nfc.nfc_vendor_cmd") public void onVendorNciNotification(@IntRange(from=9, to=15) int, int, @NonNull byte[]);
    method @FlaggedApi("android.nfc.nfc_vendor_cmd") public void onVendorNciResponse(@IntRange(from=0, to=15) int, int, @NonNull byte[]);
  }

}

package android.nfc.cardemulation {
+4 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.nfc.TechListParcel;
import android.nfc.IAppCallback;
import android.nfc.INfcAdapterExtras;
import android.nfc.INfcControllerAlwaysOnListener;
import android.nfc.INfcVendorNciCallback;
import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
import android.nfc.INfcFCardEmulation;
@@ -87,4 +88,7 @@ interface INfcAdapter
    boolean isObserveModeSupported();
    boolean setObserveMode(boolean enabled);
    void updateDiscoveryTechnology(IBinder b, int pollFlags, int listenFlags);
    int sendVendorNciMessage(int mt, int gid, int oid, in byte[] payload);
    void registerVendorExtensionCallback(in INfcVendorNciCallback callbacks);
    void unregisterVendorExtensionCallback(in INfcVendorNciCallback callbacks);
}
+24 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 INfcVendorNciCallback {
    void onVendorResponseReceived(int gid, int oid, in byte[] payload);
    void onVendorNotificationReceived(int gid, int oid, in byte[] payload);
}
+162 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.nfc;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -75,6 +76,7 @@ public final class NfcAdapter {
    static final String TAG = "NFC";

    private final NfcControllerAlwaysOnListener mControllerAlwaysOnListener;
    private final NfcVendorNciCallbackListener mNfcVendorNciCallbackListener;

    /**
     * Intent to start an activity when a tag with NDEF payload is discovered.
@@ -861,6 +863,7 @@ public final class NfcAdapter {
        mTagRemovedListener = null;
        mLock = new Object();
        mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService());
        mNfcVendorNciCallbackListener = new NfcVendorNciCallbackListener(getService());
    }

    /**
@@ -2757,4 +2760,163 @@ public final class NfcAdapter {
            return false;
        }
    }

    /**
     * Vendor NCI command success.
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
    public static final int SEND_VENDOR_NCI_STATUS_SUCCESS = 0;
    /**
     * Vendor NCI command rejected.
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
    public static final int SEND_VENDOR_NCI_STATUS_REJECTED = 1;
    /**
     * Vendor NCI command corrupted.
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
    public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED  = 2;
    /**
     * Vendor NCI command failed with unknown reason.
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
    public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3;

    /**
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(value = {
            SEND_VENDOR_NCI_STATUS_SUCCESS,
            SEND_VENDOR_NCI_STATUS_REJECTED,
            SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED,
            SEND_VENDOR_NCI_STATUS_FAILED,
    })
    @interface SendVendorNciStatus {}

    /**
     * Message Type for NCI Command.
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
    public static final int MESSAGE_TYPE_COMMAND = 1;

    /**
     * @hide
     */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(value = {
            MESSAGE_TYPE_COMMAND,
    })
    @interface MessageType {}

    /**
     * Send Vendor specific Nci Messages with custom message type.
     *
     * The format of the NCI messages are defined in the NCI specification. The platform is
     * responsible for fragmenting the payload if necessary.
     *
     * Note that mt (message type) is added at the beginning of method parameters as it is more
     * distinctive than other parameters and was requested from vendor.
     *
     * @param mt message Type of the command
     * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
     *            the NCI specification
     * @param oid opcode ID of the command. This is left to the OEM / vendor to decide
     * @param payload containing vendor Nci message payload
     * @return message send status
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
    public @SendVendorNciStatus int sendVendorNciMessage(@MessageType int mt,
            @IntRange(from = 0, to = 15) int gid, @IntRange(from = 0) int oid,
            @NonNull byte[] payload) {
        Objects.requireNonNull(payload, "Payload must not be null");
        try {
            return sService.sendVendorNciMessage(mt, gid, oid, payload);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Register an {@link NfcVendorNciCallback} to listen for Nfc vendor responses and notifications
     * <p>The provided callback will be invoked by the given {@link Executor}.
     *
     * <p>When first registering a callback, the callbacks's
     * {@link NfcVendorNciCallback#onVendorNciCallBack(byte[])} is immediately invoked to
     * notify the vendor notification.
     *
     * @param executor an {@link Executor} to execute given callback
     * @param callback user implementation of the {@link NfcVendorNciCallback}
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
    public void registerNfcVendorNciCallback(@NonNull @CallbackExecutor Executor executor,
            @NonNull NfcVendorNciCallback callback) {
        mNfcVendorNciCallbackListener.register(executor, callback);
    }

    /**
     * Unregister the specified {@link NfcVendorNciCallback}
     *
     * <p>The same {@link NfcVendorNciCallback} object used when calling
     * {@link #registerNfcVendorNciCallback(Executor, NfcVendorNciCallback)} must be used.
     *
     * <p>Callbacks are automatically unregistered when application process goes away
     *
     * @param callback user implementation of the {@link NfcVendorNciCallback}
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
    public void unregisterNfcVendorNciCallback(@NonNull NfcVendorNciCallback callback) {
        mNfcVendorNciCallbackListener.unregister(callback);
    }

    /**
     * Interface for receiving vendor NCI responses and notifications.
     * @hide
     */
    @SystemApi
    @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
    public interface NfcVendorNciCallback {
        /**
         * Invoked when a vendor specific NCI response is received.
         *
         * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
         *            the NCI specification.
         * @param oid opcode ID of the command. This is left to the OEM / vendor to decide.
         * @param payload containing vendor Nci message payload.
         */
        @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
        void onVendorNciResponse(
                @IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload);

        /**
         * Invoked when a vendor specific NCI notification is received.
         *
         * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
         *            the NCI specification.
         * @param oid opcode ID of the command. This is left to the OEM / vendor to decide.
         * @param payload containing vendor Nci message payload.
         */
        @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
        void onVendorNciNotification(
                @IntRange(from = 9, to = 15) int gid, int oid, @NonNull byte[] payload);
    }
}
+115 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.NfcVendorNciCallback;
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 final class NfcVendorNciCallbackListener extends INfcVendorNciCallback.Stub {
    private static final String TAG = "Nfc.NfcVendorNciCallbacks";
    private final INfcAdapter mAdapter;
    private boolean mIsRegistered = false;
    private final Map<NfcVendorNciCallback, Executor> mCallbackMap = new HashMap<>();

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

    public void register(@NonNull Executor executor, @NonNull NfcVendorNciCallback callback) {
        synchronized (this) {
            if (mCallbackMap.containsKey(callback)) {
                return;
            }
            mCallbackMap.put(callback, executor);
            if (!mIsRegistered) {
                try {
                    mAdapter.registerVendorExtensionCallback(this);
                    mIsRegistered = true;
                } catch (RemoteException e) {
                    Log.w(TAG, "Failed to register adapter state callback");
                    mCallbackMap.remove(callback);
                    throw e.rethrowFromSystemServer();
                }
            }
        }
    }

    public void unregister(@NonNull NfcVendorNciCallback callback) {
        synchronized (this) {
            if (!mCallbackMap.containsKey(callback) || !mIsRegistered) {
                return;
            }
            if (mCallbackMap.size() == 1) {
                try {
                    mAdapter.unregisterVendorExtensionCallback(this);
                    mIsRegistered = false;
                    mCallbackMap.remove(callback);
                } catch (RemoteException e) {
                    Log.w(TAG, "Failed to unregister AdapterStateCallback with service");
                    throw e.rethrowFromSystemServer();
                }
            } else {
                mCallbackMap.remove(callback);
            }
        }
    }

    @Override
    public void onVendorResponseReceived(int gid, int oid, @NonNull byte[] payload)
            throws RemoteException {
        synchronized (this) {
            final long identity = Binder.clearCallingIdentity();
            try {
                for (NfcVendorNciCallback callback : mCallbackMap.keySet()) {
                    Executor executor = mCallbackMap.get(callback);
                    executor.execute(() -> callback.onVendorNciResponse(gid, oid, payload));
                }
            } catch (RuntimeException ex) {
                throw ex;
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

    @Override
    public void onVendorNotificationReceived(int gid, int oid, @NonNull byte[] payload)
            throws RemoteException {
        synchronized (this) {
            final long identity = Binder.clearCallingIdentity();
            try {
                for (NfcVendorNciCallback callback : mCallbackMap.keySet()) {
                    Executor executor = mCallbackMap.get(callback);
                    executor.execute(() -> callback.onVendorNciNotification(gid, oid, payload));
                }
            } catch (RuntimeException ex) {
                throw ex;
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }
}
Loading