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

Commit 39de4cd4 authored by Bob Wang's avatar Bob Wang Committed by Gerrit Code Review
Browse files

Merge "[framework] Add more nfc oem callbacks." into main

parents 13ba8acf 30392b8d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -90,7 +90,11 @@ package android.nfc {
    method public void onEnable(@NonNull java.util.function.Consumer<java.lang.Boolean>);
    method public void onEnableFinished(int);
    method public void onEnableStarted();
    method public void onGetOemAppSearchIntent(@NonNull java.util.List<java.lang.String>, @NonNull java.util.function.Consumer<android.content.Intent>);
    method public void onHceEventReceived(int);
    method public void onLaunchHceAppChooserActivity(@NonNull String, @NonNull java.util.List<android.nfc.cardemulation.ApduServiceInfo>, @NonNull android.content.ComponentName, @NonNull String);
    method public void onLaunchHceTapAgainDialog(@NonNull android.nfc.cardemulation.ApduServiceInfo, @NonNull String);
    method public void onNdefMessage(@NonNull android.nfc.Tag, @NonNull android.nfc.NdefMessage, @NonNull java.util.function.Consumer<java.lang.Boolean>);
    method public void onNdefRead(@NonNull java.util.function.Consumer<java.lang.Boolean>);
    method public void onReaderOptionChanged(boolean);
    method public void onRfDiscoveryStarted(boolean);
+9 −0
Original line number Diff line number Diff line
@@ -15,9 +15,14 @@
 */
package android.nfc;

import android.content.ComponentName;
import android.nfc.cardemulation.ApduServiceInfo;
import android.nfc.NdefMessage;
import android.nfc.Tag;
import android.os.ResultReceiver;

import java.util.List;

/**
 * @hide
 */
@@ -41,4 +46,8 @@ interface INfcOemExtensionCallback {
   void onCardEmulationActivated(boolean isActivated);
   void onRfFieldActivated(boolean isActivated);
   void onRfDiscoveryStarted(boolean isDiscoveryStarted);
   void onGetOemAppSearchIntent(in List<String> firstPackage, in ResultReceiver intentConsumer);
   void onNdefMessage(in Tag tag, in NdefMessage message, in ResultReceiver hasOemExecutableContent);
   void onLaunchHceAppChooserActivity(in String selectedAid, in List<ApduServiceInfo> services, in ComponentName failedComponent, in String category);
   void onLaunchHceTapAgainActivity(in ApduServiceInfo service, in String category);
}
+127 −9
Original line number Diff line number Diff line
@@ -23,8 +23,12 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.nfc.cardemulation.ApduServiceInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.util.Log;
@@ -306,6 +310,60 @@ public final class NfcOemExtension {
        * @param isDiscoveryStarted true, if RF discovery started, else RF state is Idle.
        */
        void onRfDiscoveryStarted(boolean isDiscoveryStarted);

        /**
         * Gets the intent to find the OEM package in the OEM App market. If the consumer returns
         * {@code null} or a timeout occurs, the intent from the first available package will be
         * used instead.
         *
         * @param packages the OEM packages name stored in the tag
         * @param intentConsumer The {@link Consumer} to be completed.
         *                       The {@link Consumer#accept(Object)} should be called with
         *                       the Intent required.
         *
         */
        void onGetOemAppSearchIntent(@NonNull List<String> packages,
                                     @NonNull Consumer<Intent> intentConsumer);

        /**
         * Checks if the NDEF message contains any specific OEM package executable content
         *
         * @param tag        the {@link android.nfc.Tag Tag}
         * @param message NDEF Message to read from tag
         * @param hasOemExecutableContent The {@link Consumer} to be completed. If there is
         *                                OEM package executable content, the
         *                                {@link Consumer#accept(Object)} should be called with
         *                                {@link Boolean#TRUE}, otherwise call with
         *                                {@link Boolean#FALSE}.
         */
        void onNdefMessage(@NonNull Tag tag, @NonNull NdefMessage message,
                           @NonNull Consumer<Boolean> hasOemExecutableContent);

        /**
         * Callback to indicate the app chooser activity should be launched for handling CE
         * transaction. This is invoked for example when there are more than 1 app installed that
         * can handle the HCE transaction. OEMs can launch the Activity based
         * on their requirement.
         *
         * @param selectedAid the selected AID from APDU
         * @param services {@link ApduServiceInfo} of the service triggering the activity
         * @param failedComponent the component failed to be resolved
         * @param category the category of the service
         */
        void onLaunchHceAppChooserActivity(@NonNull String selectedAid,
                                           @NonNull List<ApduServiceInfo> services,
                                           @NonNull ComponentName failedComponent,
                                           @NonNull String category);

        /**
         * Callback to indicate tap again dialog should be launched for handling HCE transaction.
         * This is invoked for example when a CE service needs the device to unlocked before
         * handling the transaction. OEMs can launch the Activity based on their requirement.
         *
         * @param service {@link ApduServiceInfo} of the service triggering the dialog
         * @param category the category of the service
         */
        void onLaunchHceTapAgainDialog(@NonNull ApduServiceInfo service, @NonNull String category);
    }


@@ -562,25 +620,25 @@ public final class NfcOemExtension {
        public void onApplyRouting(ResultReceiver isSkipped) throws RemoteException {
            mCallbackMap.forEach((cb, ex) ->
                    handleVoidCallback(
                        new ReceiverWrapper(isSkipped), cb::onApplyRouting, ex));
                        new ReceiverWrapper<>(isSkipped), cb::onApplyRouting, ex));
        }
        @Override
        public void onNdefRead(ResultReceiver isSkipped) throws RemoteException {
            mCallbackMap.forEach((cb, ex) ->
                    handleVoidCallback(
                        new ReceiverWrapper(isSkipped), cb::onNdefRead, ex));
                        new ReceiverWrapper<>(isSkipped), cb::onNdefRead, ex));
        }
        @Override
        public void onEnable(ResultReceiver isAllowed) throws RemoteException {
            mCallbackMap.forEach((cb, ex) ->
                    handleVoidCallback(
                        new ReceiverWrapper(isAllowed), cb::onEnable, ex));
                        new ReceiverWrapper<>(isAllowed), cb::onEnable, ex));
        }
        @Override
        public void onDisable(ResultReceiver isAllowed) throws RemoteException {
            mCallbackMap.forEach((cb, ex) ->
                    handleVoidCallback(
                        new ReceiverWrapper(isAllowed), cb::onDisable, ex));
                        new ReceiverWrapper<>(isAllowed), cb::onDisable, ex));
        }
        @Override
        public void onBootStarted() throws RemoteException {
@@ -616,7 +674,7 @@ public final class NfcOemExtension {
        public void onTagDispatch(ResultReceiver isSkipped) throws RemoteException {
            mCallbackMap.forEach((cb, ex) ->
                    handleVoidCallback(
                        new ReceiverWrapper(isSkipped), cb::onTagDispatch, ex));
                        new ReceiverWrapper<>(isSkipped), cb::onTagDispatch, ex));
        }
        @Override
        public void onRoutingChanged() throws RemoteException {
@@ -635,6 +693,59 @@ public final class NfcOemExtension {
                    handleVoidCallback(enabled, cb::onReaderOptionChanged, ex));
        }

        @Override
        public void onGetOemAppSearchIntent(List<String> packages, ResultReceiver intentConsumer)
                throws RemoteException {
            mCallbackMap.forEach((cb, ex) ->
                    handleVoid2ArgCallback(packages, new ReceiverWrapper<>(intentConsumer),
                            cb::onGetOemAppSearchIntent, ex));
        }

        @Override
        public void onNdefMessage(Tag tag, NdefMessage message,
                                  ResultReceiver hasOemExecutableContent) throws RemoteException {
            mCallbackMap.forEach((cb, ex) -> {
                synchronized (mLock) {
                    final long identity = Binder.clearCallingIdentity();
                    try {
                        ex.execute(() -> cb.onNdefMessage(
                                tag, message, new ReceiverWrapper<>(hasOemExecutableContent)));
                    } catch (RuntimeException exception) {
                        throw exception;
                    } finally {
                        Binder.restoreCallingIdentity(identity);
                    }
                }
            });
        }

        @Override
        public void onLaunchHceAppChooserActivity(String selectedAid,
                                                  List<ApduServiceInfo> services,
                                                  ComponentName failedComponent, String category)
                throws RemoteException {
            mCallbackMap.forEach((cb, ex) -> {
                synchronized (mLock) {
                    final long identity = Binder.clearCallingIdentity();
                    try {
                        ex.execute(() -> cb.onLaunchHceAppChooserActivity(
                                selectedAid, services, failedComponent, category));
                    } catch (RuntimeException exception) {
                        throw exception;
                    } finally {
                        Binder.restoreCallingIdentity(identity);
                    }
                }
            });
        }

        @Override
        public void onLaunchHceTapAgainActivity(ApduServiceInfo service, String category)
                throws RemoteException {
            mCallbackMap.forEach((cb, ex) ->
                    handleVoid2ArgCallback(service, category, cb::onLaunchHceTapAgainDialog, ex));
        }

        private <T> void handleVoidCallback(
                T input, Consumer<T> callbackMethod, Executor executor) {
            synchronized (mLock) {
@@ -718,7 +829,7 @@ public final class NfcOemExtension {
        }
    }

    private class ReceiverWrapper implements Consumer<Boolean> {
    private class ReceiverWrapper<T> implements Consumer<T> {
        private final ResultReceiver mResultReceiver;

        ReceiverWrapper(ResultReceiver resultReceiver) {
@@ -726,12 +837,19 @@ public final class NfcOemExtension {
        }

        @Override
        public void accept(Boolean result) {
            mResultReceiver.send(result ? 1 : 0, null);
        public void accept(T result) {
            if (result instanceof Boolean) {
                mResultReceiver.send((Boolean) result ? 1 : 0, null);
            } else if (result instanceof Intent) {
                Bundle bundle = new Bundle();
                bundle.putParcelable("intent", (Intent) result);
                mResultReceiver.send(0, bundle);
            }

        }

        @Override
        public Consumer<Boolean> andThen(Consumer<? super Boolean> after) {
        public Consumer<T> andThen(Consumer<? super T> after) {
            return Consumer.super.andThen(after);
        }
    }