nfc(api): Add OEM extension surface
This is added as a separate class to avoid cluttering the public NFC
API surface.
Bug: 330376108
Test: Compiles
Merged-In: Ia74d9e25b69fe3550b167ec83896c01a1fc569b9
Change-Id: Ia74d9e25b69fe3550b167ec83896c01a1fc569b9
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index ece8851..79373a5 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -9,6 +9,7 @@
method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState();
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public android.nfc.NfcOemExtension getNfcOemExtension();
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
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();
@@ -46,6 +47,16 @@
method @FlaggedApi("android.nfc.nfc_vendor_cmd") public void onVendorNciResponse(@IntRange(from=0, to=15) int, int, @NonNull byte[]);
}
+ @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
+ }
+
+ public static interface NfcOemExtension.Callback {
+ method public void onTagConnected(boolean, @NonNull android.nfc.Tag);
+ }
+
}
package android.nfc.cardemulation {
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 8fea5af..bde63c3 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -28,6 +28,7 @@
import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
import android.nfc.INfcFCardEmulation;
+import android.nfc.INfcOemExtensionCallback;
import android.nfc.INfcUnlockHandler;
import android.nfc.ITagRemovedCallback;
import android.nfc.INfcDta;
@@ -91,4 +92,7 @@
int sendVendorNciMessage(int mt, int gid, int oid, in byte[] payload);
void registerVendorExtensionCallback(in INfcVendorNciCallback callbacks);
void unregisterVendorExtensionCallback(in INfcVendorNciCallback callbacks);
+ void registerOemExtensionCallback(INfcOemExtensionCallback callbacks);
+ void unregisterOemExtensionCallback(INfcOemExtensionCallback callbacks);
+ void clearPreference();
}
diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
new file mode 100644
index 0000000..6c9096d
--- /dev/null
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 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.nfc.Tag;
+
+/**
+ * @hide
+ */
+interface INfcOemExtensionCallback {
+ void onTagConnected(boolean connected, in Tag tag);
+}
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 40bbe74..7e0a111 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -556,6 +556,7 @@
final Context mContext;
final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
final Object mLock;
+ final NfcOemExtension mNfcOemExtension;
ITagRemovedCallback mTagRemovedListener; // protected by mLock
@@ -864,6 +865,7 @@
mLock = new Object();
mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService());
mNfcVendorNciCallbackListener = new NfcVendorNciCallbackListener(getService());
+ mNfcOemExtension = new NfcOemExtension(mContext, this);
}
/**
@@ -2919,4 +2921,19 @@
void onVendorNciNotification(
@IntRange(from = 9, to = 15) int gid, int oid, @NonNull byte[] payload);
}
+
+ /**
+ * Returns an instance of {@link NfcOemExtension} associated with {@link NfcAdapter} instance.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @NonNull public NfcOemExtension getNfcOemExtension() {
+ synchronized (sLock) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
+ return mNfcOemExtension;
+ }
}
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
new file mode 100644
index 0000000..1eff58c
--- /dev/null
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -0,0 +1,160 @@
+/*
+ * 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.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Used for OEM extension APIs.
+ * This class holds all the APIs and callbacks defined for OEMs/vendors to extend the NFC stack
+ * for their proprietary features.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class NfcOemExtension {
+ private static final String TAG = "NfcOemExtension";
+ private static final int OEM_EXTENSION_RESPONSE_THRESHOLD_MS = 2000;
+ private final NfcAdapter mAdapter;
+ private final NfcOemExtensionCallback mOemNfcExtensionCallback;
+ private final Context mContext;
+ private Executor mExecutor = null;
+ private Callback mCallback = null;
+ private final Object mLock = new Object();
+
+ /**
+ * Interface for Oem extensions for NFC.
+ */
+ public interface Callback {
+ /**
+ * Notify Oem to tag is connected or not
+ * ex - if tag is connected notify cover and Nfctest app if app is in testing mode
+ *
+ * @param connected status of the tag true if tag is connected otherwise false
+ * @param tag Tag details
+ */
+ void onTagConnected(boolean connected, @NonNull Tag tag);
+ }
+
+
+ /**
+ * Constructor to be used only by {@link NfcAdapter}.
+ * @hide
+ */
+ public NfcOemExtension(@NonNull Context context, @NonNull NfcAdapter adapter) {
+ mContext = context;
+ mAdapter = adapter;
+ mOemNfcExtensionCallback = new NfcOemExtensionCallback();
+ }
+
+ /**
+ * Register an {@link Callback} to listen for UWB oem extension callbacks
+ * <p>The provided callback will be invoked by the given {@link Executor}.
+ *
+ * @param executor an {@link Executor} to execute given callback
+ * @param callback oem implementation of {@link Callback}
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Callback callback) {
+ synchronized (mLock) {
+ if (mCallback != null) {
+ Log.e(TAG, "Callback already registered. Unregister existing callback before"
+ + "registering");
+ throw new IllegalArgumentException();
+ }
+ try {
+ NfcAdapter.sService.registerOemExtensionCallback(mOemNfcExtensionCallback);
+ mCallback = callback;
+ mExecutor = executor;
+ } catch (RemoteException e) {
+ mAdapter.attemptDeadServiceRecovery(e);
+ }
+ }
+ }
+
+ /**
+ * Unregister the specified {@link Callback}
+ *
+ * <p>The same {@link Callback} object used when calling
+ * {@link #registerCallback(Executor, Callback)} must be used.
+ *
+ * <p>Callbacks are automatically unregistered when an application process goes away
+ *
+ * @param callback oem implementation of {@link Callback}
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public void unregisterCallback(@NonNull Callback callback) {
+ synchronized (mLock) {
+ if (mCallback == null || mCallback != callback) {
+ Log.e(TAG, "Callback not registered");
+ throw new IllegalArgumentException();
+ }
+ try {
+ NfcAdapter.sService.unregisterOemExtensionCallback(mOemNfcExtensionCallback);
+ mCallback = null;
+ mExecutor = null;
+ } catch (RemoteException e) {
+ mAdapter.attemptDeadServiceRecovery(e);
+ }
+ }
+ }
+
+ /**
+ * Clear NfcService preference, interface method to clear NFC preference values on OEM specific
+ * events. For ex: on soft reset, Nfc default values needs to be overridden by OEM defaults.
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public void clearPreference() {
+ try {
+ NfcAdapter.sService.clearPreference();
+ } catch (RemoteException e) {
+ mAdapter.attemptDeadServiceRecovery(e);
+ }
+ }
+
+ private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
+ @Override
+ public void onTagConnected(boolean connected, Tag tag) throws RemoteException {
+ synchronized (mLock) {
+ if (mCallback == null || mExecutor == null) {
+ return;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onTagConnected(connected, tag));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+ }
+}
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 44924ae..5879595 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -76,3 +76,11 @@
description: "Enable NFC vendor command support"
bug: "289879306"
}
+
+flag {
+ name: "nfc_oem_extension"
+ is_exported: true
+ namespace: "nfc"
+ description: "Enable NFC OEM extension support"
+ bug: "331206243"
+}