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

Commit ec6ff848 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes from topics "dynamic_autotransct", "throw_for_invalid_plf" into main

* changes:
  Update javadoc to make it clear that polling loop filter needs at least one byte and the implementation to throw if the filter isn't valid.
  Add boolean autoTransact flag to registerPollingLoopForService()
parents 1d41776d c44d59d7
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -10421,8 +10421,7 @@ package android.nfc.cardemulation {
  @FlaggedApi("android.nfc.enable_nfc_mainline") public final class ApduServiceInfo implements android.os.Parcelable {
    ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilterToAutoTransact(@NonNull String);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String, boolean);
    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean defaultToObserveMode();
    method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
    method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
+1 −1
Original line number Diff line number Diff line
@@ -204,7 +204,7 @@ package android.nfc.cardemulation {
    method public boolean isDefaultServiceForAid(android.content.ComponentName, String);
    method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
    method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
    method public boolean removeAidsForService(android.content.ComponentName, String);
    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean);
    method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ interface INfcCardEmulation
    boolean setDefaultForNextTap(int userHandle, in ComponentName service);
    boolean setDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable);
    boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
    boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter);
    boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter, boolean autoTransact);
    boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
    boolean unsetOffHostForService(int userHandle, in ComponentName service);
    AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
+5 −21
Original line number Diff line number Diff line
@@ -681,33 +681,17 @@ public final class ApduServiceInfo implements Parcelable {

    /**
     * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will be
     * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this or
     * {@link  ApduServiceInfo#addPollingLoopFilterToAutoTransact(String)} multiple times will
     * cause the value to be overwritten each time.
     * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this
     * multiple times will cause the value to be overwritten each time.
     * @param pollingLoopFilter the polling loop filter to add, must be a  valide hexadecimal string
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    public void addPollingLoopFilter(@NonNull String pollingLoopFilter) {
        mAutoTransact.put(pollingLoopFilter.toUpperCase(Locale.ROOT), false);
    public void addPollingLoopFilter(@NonNull String pollingLoopFilter,
            boolean autoTransact) {
        mAutoTransact.put(pollingLoopFilter, autoTransact);

    }

    /**
     * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will cause the
     * device to exit observe mode, just as if
     * {@link android.nfc.NfcAdapter#setObserveModeEnabled(boolean)} had been called with true,
     * allowing transactions to proceed. The matching frame will also be delivered to
     * {@link HostApduService#processPollingFrames(List)}. Adding a key with this or
     * {@link  ApduServiceInfo#addPollingLoopFilter(String)} multiple times will
     * cause the value to be overwritten each time.
     *
     * @param pollingLoopFilter the polling loop filter to add, must be a  valide hexadecimal string
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    public void addPollingLoopFilterToAutoTransact(@NonNull String pollingLoopFilter) {
        mAutoTransact.put(pollingLoopFilter.toUpperCase(Locale.ROOT), true);
    }

    /**
     * Remove a Polling Loop Filter. Custom NFC polling frames that match this filter will no
     * longer be delivered to {@link HostApduService#processPollingFrames(List)}.
+23 −16
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.provider.Settings.SettingNotFoundException;
import android.util.Log;

import java.util.HashMap;
import java.util.HexFormat;
import java.util.List;
import java.util.regex.Pattern;

@@ -59,7 +60,6 @@ import java.util.regex.Pattern;
 */
public final class CardEmulation {
    private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?");
    private static final Pattern PLF_PATTERN = Pattern.compile("[0-9A-Fa-f]{1,32}");

    static final String TAG = "CardEmulation";

@@ -360,21 +360,28 @@ public final class CardEmulation {
    }

    /**
     * Register a polling loop filter (PLF) for a HostApduService. The PLF can be sequence of an
     * even number of hexadecimal numbers (0-9, A-F or a-f). When non-standard polling loop frame
     * matches this sequence exactly, it may be delivered to
     * {@link HostApduService#processPollingFrames(List)}  if this service is currently
     * preferred or there are no other services registered for this filter.
     * Register a polling loop filter (PLF) for a HostApduService and indicate whether it should
     * auto-transact or not.  The PLF can be sequence of an
     * even number of at least 2 hexadecimal numbers (0-9, A-F or a-f), representing a series of
     * bytes. When non-standard polling loop frame matches this sequence exactly, it may be
     * delivered to {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to
     * true, then observe mode will also be disabled.  if this service is currently preferred or
     * there are no other services registered for this filter.
     * @param service The HostApduService to register the filter for
     * @param pollingLoopFilter The filter to register
     * @param autoTransact true to have the NFC stack automatically disable observe mode and allow
     *         transactions to proceed when this filter matches, false otherwise
     * @return true if the filter was registered, false otherwise
     * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    public boolean registerPollingLoopFilterForService(@NonNull ComponentName service,
            @NonNull String pollingLoopFilter) {
            @NonNull String pollingLoopFilter, boolean autoTransact) {
        pollingLoopFilter = validatePollingLoopFilter(pollingLoopFilter);

        try {
            return sService.registerPollingLoopFilterForService(mContext.getUser().getIdentifier(),
                    service, pollingLoopFilter);
                    service, pollingLoopFilter, autoTransact);
        } catch (RemoteException e) {
            // Try one more time
            recoverService();
@@ -384,7 +391,8 @@ public final class CardEmulation {
            }
            try {
                return sService.registerPollingLoopFilterForService(
                        mContext.getUser().getIdentifier(), service, pollingLoopFilter);
                        mContext.getUser().getIdentifier(), service,
                        pollingLoopFilter, autoTransact);
            } catch (RemoteException ee) {
                Log.e(TAG, "Failed to reach CardEmulationService.");
                return false;
@@ -979,15 +987,14 @@ public final class CardEmulation {
     * @hide
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    public static boolean isValidPollingLoopFilter(@NonNull String pollingLoopFilter) {
    public static @NonNull String validatePollingLoopFilter(@NonNull String pollingLoopFilter) {
        // Verify hex characters
        if (!PLF_PATTERN.matcher(pollingLoopFilter).matches()) {
            Log.e(TAG, "Polling Loop Filter " + pollingLoopFilter
                    + " is not a valid Polling Loop Filter.");
            return false;
        byte[] plfBytes = HexFormat.of().parseHex(pollingLoopFilter);
        if (plfBytes.length == 0) {
            throw new IllegalArgumentException(
                "Polling loop filter must contain at least one byte.");
        }

        return true;
        return HexFormat.of().withUpperCase().formatHex(plfBytes);
    }

    /**