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

Commit f9bc2d5f authored by Brad Lassey's avatar Brad Lassey Committed by Android (Google) Code Review
Browse files

Merge "Add API for polling loop pattern filters based on developer feedback." into main

parents 748b449d b1917ee5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -10438,6 +10438,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, boolean);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopPatternFilter(@NonNull String, boolean);
    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[]);
    method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream);
@@ -10449,6 +10450,7 @@ package android.nfc.cardemulation {
    method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public android.nfc.cardemulation.AidGroup getDynamicAidGroupForCategory(@NonNull String);
    method @FlaggedApi("android.nfc.enable_nfc_mainline") @Nullable public String getOffHostSecureElement();
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") @NonNull public java.util.List<java.lang.String> getPollingLoopFilters();
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") @NonNull public java.util.List<java.util.regex.Pattern> getPollingLoopPatternFilters();
    method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<java.lang.String> getPrefixAids();
    method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public String getSettingsActivityName();
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean getShouldAutoTransact(@NonNull String);
@@ -10463,6 +10465,7 @@ package android.nfc.cardemulation {
    method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
    method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public boolean removeDynamicAidGroupForCategory(@NonNull String);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void removePollingLoopFilter(@NonNull String);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void removePollingLoopPatternFilter(@NonNull String);
    method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresScreenOn();
    method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock();
    method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement();
+15 −0
Original line number Diff line number Diff line
@@ -4484,6 +4484,21 @@
        <attr name="autoTransact" format="boolean"/>
    </declare-styleable>
    <!-- Specify one or more <code>polling-loop-pattern-filter</code> elements inside a
         <code>host-apdu-service</code> to indicate polling loop frames that
         your service can handle. -->
    <!-- @FlaggedApi("android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP") -->
    <declare-styleable name="PollingLoopPatternFilter">
        <!-- The patter to match polling loop frames to, must to be compatible with
         {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers and
         `.`, `?` and `*` operators. This attribute is mandatory. -->
        <attr name="name" />
        <!-- Whether or not the system should automatically start a transaction when this polling
         loop filter matches. If not set, default value is false. -->
        <!-- @FlaggedApi("android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP") -->
        <attr name="autoTransact" format="boolean"/>
    </declare-styleable>
    <!-- Use <code>host-nfcf-service</code> as the root tag of the XML resource that
         describes an {@link android.nfc.cardemulation.HostNfcFService} service, which
         is referenced from its {@link android.nfc.cardemulation.HostNfcFService#SERVICE_META_DATA}
+3 −0
Original line number Diff line number Diff line
@@ -205,7 +205,10 @@ package android.nfc.cardemulation {
    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, boolean);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
    method public boolean removeAidsForService(android.content.ComponentName, String);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean removePollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String);
    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean removePollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String);
    method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
    method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
    method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setShouldDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean);
+3 −0
Original line number Diff line number Diff line
@@ -33,10 +33,13 @@ interface INfcCardEmulation
    boolean setShouldDefaultToObserveModeForService(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 autoTransact);
    boolean registerPollingLoopPatternFilterForService(int userHandle, in ComponentName service, in String pollingLoopPatternFilter, 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);
    boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
    boolean removePollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter);
    boolean removePollingLoopPatternFilterForService(int userHandle, in ComponentName service, in String pollingLoopPatternFilter);
    List<ApduServiceInfo> getServices(int userHandle, in String category);
    boolean setPreferredService(in ComponentName service);
    boolean unsetPreferredService();
+76 −5
Original line number Diff line number Diff line
@@ -108,6 +108,8 @@ public final class ApduServiceInfo implements Parcelable {

    private final Map<String, Boolean> mAutoTransact;

    private final Map<Pattern, Boolean> mAutoTransactPatterns;

    /**
     * Whether this service should only be started when the device is unlocked.
     */
@@ -179,7 +181,7 @@ public final class ApduServiceInfo implements Parcelable {
        this(info, onHost, description, staticAidGroups, dynamicAidGroups,
                requiresUnlock, requiresScreenOn, bannerResource, uid,
                settingsActivityName, offHost, staticOffHost, isEnabled,
                new HashMap<String, Boolean>());
                new HashMap<String, Boolean>(), new HashMap<Pattern, Boolean>());
    }

    /**
@@ -189,12 +191,13 @@ public final class ApduServiceInfo implements Parcelable {
            List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
            boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid,
            String settingsActivityName, String offHost, String staticOffHost, boolean isEnabled,
            HashMap<String, Boolean> autoTransact) {
            Map<String, Boolean> autoTransact, Map<Pattern, Boolean> autoTransactPatterns) {
        this.mService = info;
        this.mDescription = description;
        this.mStaticAidGroups = new HashMap<String, AidGroup>();
        this.mDynamicAidGroups = new HashMap<String, AidGroup>();
        this.mAutoTransact = autoTransact;
        this.mAutoTransactPatterns = autoTransactPatterns;
        this.mOffHostName = offHost;
        this.mStaticOffHostName = staticOffHost;
        this.mOnHost = onHost;
@@ -314,6 +317,7 @@ public final class ApduServiceInfo implements Parcelable {
            mStaticAidGroups = new HashMap<String, AidGroup>();
            mDynamicAidGroups = new HashMap<String, AidGroup>();
            mAutoTransact = new HashMap<String, Boolean>();
            mAutoTransactPatterns = new HashMap<Pattern, Boolean>();
            mOnHost = onHost;

            final int depth = parser.getDepth();
@@ -408,6 +412,18 @@ public final class ApduServiceInfo implements Parcelable {
                            false);
                    mAutoTransact.put(plf, autoTransact);
                    a.recycle();
                } else if (eventType == XmlPullParser.START_TAG
                        && "polling-loop-pattern-filter".equals(tagName) && currentGroup == null) {
                    final TypedArray a = res.obtainAttributes(attrs,
                            com.android.internal.R.styleable.PollingLoopPatternFilter);
                    String plf = a.getString(
                            com.android.internal.R.styleable.PollingLoopPatternFilter_name)
                                    .toUpperCase(Locale.ROOT);
                    boolean autoTransact = a.getBoolean(
                            com.android.internal.R.styleable.PollingLoopFilter_autoTransact,
                            false);
                    mAutoTransactPatterns.put(Pattern.compile(plf), autoTransact);
                    a.recycle();
                }
            }
        } catch (NameNotFoundException e) {
@@ -481,7 +497,30 @@ public final class ApduServiceInfo implements Parcelable {
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    public boolean getShouldAutoTransact(@NonNull String plf) {
        return mAutoTransact.getOrDefault(plf.toUpperCase(Locale.ROOT), false);
        if (mAutoTransact.getOrDefault(plf.toUpperCase(Locale.ROOT), false)) {
            return true;
        }
        List<Pattern> patternMatches = mAutoTransactPatterns.keySet().stream()
                .filter(p -> p.matcher(plf).matches()).toList();
        if (patternMatches == null || patternMatches.size() == 0) {
            return false;
        }
        for (Pattern patternMatch : patternMatches) {
            if (mAutoTransactPatterns.get(patternMatch)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns the current polling loop pattern filters for this service.
     * @return List of polling loop pattern filters.
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    @NonNull
    public List<Pattern> getPollingLoopPatternFilters() {
        return new ArrayList<>(mAutoTransactPatterns.keySet());
    }

    /**
@@ -683,7 +722,7 @@ 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
     * 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
     * @param pollingLoopFilter the polling loop filter to add, must be a valid hexadecimal string
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    public void addPollingLoopFilter(@NonNull String pollingLoopFilter,
@@ -702,6 +741,31 @@ public final class ApduServiceInfo implements Parcelable {
        mAutoTransact.remove(pollingLoopFilter.toUpperCase(Locale.ROOT));
    }

    /**
     * Add a Polling Loop Pattern Filter. Custom NFC polling frames that match this filter will be
     * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this
     * multiple times will cause the value to be overwritten each time.
     * @param pollingLoopPatternFilter the polling loop pattern filter to add, must be a valid
     *                                regex to match a hexadecimal string
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    public void addPollingLoopPatternFilter(@NonNull String pollingLoopPatternFilter,
            boolean autoTransact) {
        mAutoTransactPatterns.put(Pattern.compile(pollingLoopPatternFilter), autoTransact);

    }

    /**
     * Remove a Polling Loop Pattern Filter. Custom NFC polling frames that match this filter will
     * no longer be delivered to {@link HostApduService#processPollingFrames(List)}.
     * @param pollingLoopPatternFilter this polling loop filter to add.
     */
    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
    public void removePollingLoopPatternFilter(@NonNull String pollingLoopPatternFilter) {
        mAutoTransactPatterns.remove(
                Pattern.compile(pollingLoopPatternFilter.toUpperCase(Locale.ROOT)));
    }

    /**
     * Sets the off host Secure Element.
     * @param  offHost  Secure Element to set. Only accept strings with prefix SIM or prefix eSE.
@@ -856,6 +920,8 @@ public final class ApduServiceInfo implements Parcelable {
        dest.writeInt(mCategoryOtherServiceEnabled ? 1 : 0);
        dest.writeInt(mAutoTransact.size());
        dest.writeMap(mAutoTransact);
        dest.writeInt(mAutoTransactPatterns.size());
        dest.writeMap(mAutoTransactPatterns);
    };

    @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@@ -889,10 +955,15 @@ public final class ApduServiceInfo implements Parcelable {
                            new HashMap<String, Boolean>(autoTransactSize);
                    source.readMap(autoTransact, getClass().getClassLoader(),
                            String.class, Boolean.class);
                    int autoTransactPatternSize = source.readInt();
                    HashMap<Pattern, Boolean> autoTransactPatterns =
                            new HashMap<Pattern, Boolean>(autoTransactSize);
                    source.readMap(autoTransactPatterns, getClass().getClassLoader(),
                            Pattern.class, Boolean.class);
                    return new ApduServiceInfo(info, onHost, description, staticAidGroups,
                            dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid,
                            settingsActivityName, offHostName, staticOffHostName,
                            isEnabled, autoTransact);
                            isEnabled, autoTransact, autoTransactPatterns);
                }

                @Override
Loading