Use IntDef for polling frame types

Bug: b/321800939
Test: tested with CTS
Change-Id: I8d8e3dc41e80f09d6107aa5c7883f569fae9fad8
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 0383276..e244520 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -232,12 +232,6 @@
     method public final void sendResponseApdu(byte[]);
     field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
     field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_A = 65; // 0x0041 'A'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_B = 66; // 0x0042 'B'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_F = 70; // 0x0046 'F'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_OFF = 88; // 0x0058 'X'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_ON = 79; // 0x004f 'O'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x0055 'U'
     field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
     field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
   }
@@ -271,14 +265,20 @@
   }
 
   @FlaggedApi("android.nfc.nfc_read_polling_loop") public final class PollingFrame implements android.os.Parcelable {
-    ctor public PollingFrame(char, @Nullable byte[], int, int);
+    ctor public PollingFrame(int, @Nullable byte[], int, int);
     method public int describeContents();
     method @NonNull public byte[] getData();
     method public int getGain();
     method public int getTimestamp();
-    method public char getType();
+    method public int getType();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.PollingFrame> CREATOR;
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_A = 65; // 0x41
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_B = 66; // 0x42
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_F = 70; // 0x46
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_OFF = 88; // 0x58
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_ON = 79; // 0x4f
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x55
   }
 
 }
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 313e6d2..e5752d1 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -38,7 +38,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
-import android.nfc.cardemulation.HostApduService;
 import android.nfc.cardemulation.PollingFrame;
 import android.nfc.tech.MifareClassic;
 import android.nfc.tech.Ndef;
@@ -2802,11 +2801,7 @@
     @TestApi
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public void notifyPollingLoop(@NonNull PollingFrame pollingFrame) {
-        Bundle frame = new Bundle();
-        frame.putChar(HostApduService.KEY_POLLING_LOOP_TYPE, pollingFrame.getType());
-        frame.putByte(HostApduService.KEY_POLLING_LOOP_GAIN, (byte) pollingFrame.getGain());
-        frame.putByteArray(HostApduService.KEY_POLLING_LOOP_DATA, pollingFrame.getData());
-        frame.putInt(HostApduService.KEY_POLLING_LOOP_TIMESTAMP, pollingFrame.getTimestamp());
+        Bundle frame = pollingFrame.toBundle();
         try {
             if (sService == null) {
                 attemptDeadServiceRecovery(null);
diff --git a/nfc/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java
index a71764d..61037a2 100644
--- a/nfc/java/android/nfc/cardemulation/HostApduService.java
+++ b/nfc/java/android/nfc/cardemulation/HostApduService.java
@@ -244,90 +244,6 @@
     public static final String KEY_DATA = "data";
 
     /**
-     * KEY_POLLING_LOOP_TYPE is the Bundle key for the type of
-     * polling loop frame in the Bundle included in MSG_POLLING_LOOP.
-     *
-     * @hide
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE";
-
-    /**
-     * POLLING_LOOP_TYPE_A is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop is for NFC-A.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_A = 'A';
-
-    /**
-     * POLLING_LOOP_TYPE_B is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop is for NFC-B.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_B = 'B';
-
-    /**
-     * POLLING_LOOP_TYPE_F is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop is for NFC-F.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_F = 'F';
-
-    /**
-     * POLLING_LOOP_TYPE_ON is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop turns on.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_ON = 'O';
-
-    /**
-     * POLLING_LOOP_TYPE_OFF is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop turns off.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_OFF = 'X';
-
-    /**
-     * POLLING_LOOP_TYPE_UNKNOWN is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop frame isn't recognized.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_UNKNOWN = 'U';
-
-    /**
-     * KEY_POLLING_LOOP_DATA is the Bundle key for the raw data of captured from
-     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
-     *
-     * @hide
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA";
-
-    /**
-     * KEY_POLLING_LOOP_GAIN is the Bundle key for the field strength of
-     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
-     *
-     * @hide
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN";
-
-    /**
-     * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for the timestamp of
-     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
-     *
-     * @hide
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP";
-
-    /**
      * @hide
      */
     public static final String KEY_POLLING_LOOP_FRAMES_BUNDLE =
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.java b/nfc/java/android/nfc/cardemulation/PollingFrame.java
index 2e7c77c..51e168d 100644
--- a/nfc/java/android/nfc/cardemulation/PollingFrame.java
+++ b/nfc/java/android/nfc/cardemulation/PollingFrame.java
@@ -17,6 +17,7 @@
 package android.nfc.cardemulation;
 
 import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
@@ -24,6 +25,10 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
 /**
  * Polling Frames represent data about individual frames of an NFC polling loop. These frames will
  * be deliverd to subclasses of {@link HostApduService} that have registered filters with
@@ -33,14 +38,109 @@
  */
 @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
 public final class PollingFrame implements Parcelable{
-    private char mType;
-    private byte[] mData;
-    private int mGain;
-    private int mTimestamp;
+
+    /**
+     * @hide
+     */
+    @IntDef(prefix = { "POLLING_LOOP_TYPE_"}, value = { POLLING_LOOP_TYPE_A, POLLING_LOOP_TYPE_B,
+            POLLING_LOOP_TYPE_F, POLLING_LOOP_TYPE_OFF, POLLING_LOOP_TYPE_ON })
+    @Retention(RetentionPolicy.SOURCE)
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public @interface PollingFrameType {}
+
+    /**
+     * POLLING_LOOP_TYPE_A is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop is for NFC-A.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_A = 'A';
+
+    /**
+     * POLLING_LOOP_TYPE_B is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop is for NFC-B.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_B = 'B';
+
+    /**
+     * POLLING_LOOP_TYPE_F is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop is for NFC-F.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_F = 'F';
+
+    /**
+     * POLLING_LOOP_TYPE_ON is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop turns on.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_ON = 'O';
+
+    /**
+     * POLLING_LOOP_TYPE_OFF is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop turns off.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_OFF = 'X';
+
+    /**
+     * POLLING_LOOP_TYPE_UNKNOWN is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop frame isn't recognized.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_UNKNOWN = 'U';
+
+    /**
+     * KEY_POLLING_LOOP_TYPE is the Bundle key for the type of
+     * polling loop frame in the Bundle included in MSG_POLLING_LOOP.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE";
+
+    /**
+     * KEY_POLLING_LOOP_DATA is the Bundle key for the raw data of captured from
+     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA";
+
+    /**
+     * KEY_POLLING_LOOP_GAIN is the Bundle key for the field strength of
+     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN";
+
+    /**
+     * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for the timestamp of
+     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP";
+
+
+    @PollingFrameType
+    private final int mType;
+    private final byte[] mData;
+    private final int mGain;
+    private final int mTimestamp;
 
     public static final @NonNull Parcelable.Creator<PollingFrame> CREATOR =
-            new Parcelable.Creator<PollingFrame>() {
-
+            new Parcelable.Creator<>() {
                 @Override
                 public PollingFrame createFromParcel(Parcel source) {
                     return new PollingFrame(source.readBundle());
@@ -48,47 +148,38 @@
 
                 @Override
                 public PollingFrame[] newArray(int size) {
-                    return new PollingFrame[0];
+                    return new PollingFrame[size];
                 }
             };
 
     PollingFrame(Bundle frame) {
-        mType = frame.getChar(HostApduService.KEY_POLLING_LOOP_TYPE);
-        mData = frame.getByteArray(HostApduService.KEY_POLLING_LOOP_DATA);
-        if (mData == null) {
-            mData = new byte[0];
-        }
-        mGain = frame.getByte(HostApduService.KEY_POLLING_LOOP_GAIN);
-        mTimestamp = frame.getInt(HostApduService.KEY_POLLING_LOOP_TIMESTAMP);
+        mType = frame.getInt(KEY_POLLING_LOOP_TYPE);
+        byte[] data = frame.getByteArray(KEY_POLLING_LOOP_DATA);
+        mData = (data == null) ? new byte[0] : data;
+        mGain = frame.getByte(KEY_POLLING_LOOP_GAIN);
+        mTimestamp = frame.getInt(KEY_POLLING_LOOP_TIMESTAMP);
     }
 
-    public PollingFrame(char type, @Nullable byte[] data, int gain, int timestamp) {
+    public PollingFrame(@PollingFrameType int type, @Nullable byte[] data,
+            int gain, int timestamp) {
         mType = type;
         mData = data == null ? new byte[0] : data;
         mGain = gain;
         mTimestamp = timestamp;
     }
 
-    private PollingFrame(Parcel source) {
-        mType = (char) source.readInt();
-        source.readByteArray(mData);
-        mGain = source.readInt();
-        mTimestamp = source.readInt();
-    }
-
     /**
      * Returns the type of frame for this polling loop frame.
-     *
      * The possible return values are:
      * <ul>
-     *   <li>{@link HostApduService#POLLING_LOOP_TYPE_ON}</li>
-     *   <li>{@link HostApduService#POLLING_LOOP_TYPE_OFF}</li>
-     *   <li>{@link HostApduService#POLLING_LOOP_TYPE_A}</li>
-     *   <li>{@link HostApduService#POLLING_LOOP_TYPE_B}</li>
-     *   <li>{@link HostApduService#POLLING_LOOP_TYPE_F}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_ON}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_OFF}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_A}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_B}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_F}</li>
      * </ul>
      */
-    public char getType() {
+    public @PollingFrameType int getType() {
         return mType;
     }
 
@@ -134,10 +225,10 @@
      */
     public Bundle toBundle() {
         Bundle frame = new Bundle();
-        frame.putInt(HostApduService.KEY_POLLING_LOOP_TYPE, getType());
-        frame.putByte(HostApduService.KEY_POLLING_LOOP_GAIN, (byte) getGain());
-        frame.putByteArray(HostApduService.KEY_POLLING_LOOP_DATA, getData());
-        frame.putInt(HostApduService.KEY_POLLING_LOOP_TIMESTAMP, getTimestamp());
+        frame.putInt(KEY_POLLING_LOOP_TYPE, getType());
+        frame.putByte(KEY_POLLING_LOOP_GAIN, (byte) getGain());
+        frame.putByteArray(KEY_POLLING_LOOP_DATA, getData());
+        frame.putInt(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp());
         return frame;
     }
 }