| /* | |
| * 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.annotation.FlaggedApi; | |
| import android.annotation.IntDef; | |
| import android.annotation.NonNull; | |
| import android.annotation.Nullable; | |
| import android.annotation.SystemApi; | |
| import android.os.Parcel; | |
| import android.os.Parcelable; | |
| import java.lang.annotation.Retention; | |
| import java.lang.annotation.RetentionPolicy; | |
| import java.time.Instant; | |
| /** | |
| * A log class for OEMs to get log information of NFC events. | |
| * @hide | |
| */ | |
| @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) | |
| @SystemApi | |
| public final class OemLogItems implements Parcelable { | |
| /** | |
| * Used when RF field state is changed. | |
| */ | |
| public static final int LOG_ACTION_RF_FIELD_STATE_CHANGED = 0X01; | |
| /** | |
| * Used when NFC is toggled. Event should be set to {@link LogEvent#EVENT_ENABLE} or | |
| * {@link LogEvent#EVENT_DISABLE} if this action is used. | |
| */ | |
| public static final int LOG_ACTION_NFC_TOGGLE = 0x0201; | |
| /** | |
| * Used when sending host routing status. | |
| */ | |
| public static final int LOG_ACTION_HCE_DATA = 0x0204; | |
| /** | |
| * Used when screen state is changed. | |
| */ | |
| public static final int LOG_ACTION_SCREEN_STATE_CHANGED = 0x0206; | |
| /** | |
| * Used when tag is detected. | |
| */ | |
| public static final int LOG_ACTION_TAG_DETECTED = 0x03; | |
| /** | |
| * @hide | |
| */ | |
| @IntDef(prefix = { "LOG_ACTION_" }, value = { | |
| LOG_ACTION_RF_FIELD_STATE_CHANGED, | |
| LOG_ACTION_NFC_TOGGLE, | |
| LOG_ACTION_HCE_DATA, | |
| LOG_ACTION_SCREEN_STATE_CHANGED, | |
| LOG_ACTION_TAG_DETECTED, | |
| }) | |
| @Retention(RetentionPolicy.SOURCE) | |
| public @interface LogAction {} | |
| /** | |
| * Represents the event is not set. | |
| */ | |
| public static final int EVENT_UNSET = 0; | |
| /** | |
| * Represents nfc enable is called. | |
| */ | |
| public static final int EVENT_ENABLE = 1; | |
| /** | |
| * Represents nfc disable is called. | |
| */ | |
| public static final int EVENT_DISABLE = 2; | |
| /** @hide */ | |
| @IntDef(prefix = { "EVENT_" }, value = { | |
| EVENT_UNSET, | |
| EVENT_ENABLE, | |
| EVENT_DISABLE, | |
| }) | |
| @Retention(RetentionPolicy.SOURCE) | |
| public @interface LogEvent {} | |
| private int mAction; | |
| private int mEvent; | |
| private int mCallingPid; | |
| private byte[] mCommandApdus; | |
| private byte[] mResponseApdus; | |
| private Instant mRfFieldOnTime; | |
| private Tag mTag; | |
| /** @hide */ | |
| public OemLogItems(@LogAction int action, @LogEvent int event, int callingPid, | |
| byte[] commandApdus, byte[] responseApdus, Instant rfFieldOnTime, | |
| Tag tag) { | |
| mAction = action; | |
| mEvent = event; | |
| mTag = tag; | |
| mCallingPid = callingPid; | |
| mCommandApdus = commandApdus; | |
| mResponseApdus = responseApdus; | |
| mRfFieldOnTime = rfFieldOnTime; | |
| } | |
| /** | |
| * Describe the kinds of special objects contained in this Parcelable | |
| * instance's marshaled representation. For example, if the object will | |
| * include a file descriptor in the output of {@link #writeToParcel(Parcel, int)}, | |
| * the return value of this method must include the | |
| * {@link #CONTENTS_FILE_DESCRIPTOR} bit. | |
| * | |
| * @return a bitmask indicating the set of special object types marshaled | |
| * by this Parcelable object instance. | |
| */ | |
| @Override | |
| public int describeContents() { | |
| return 0; | |
| } | |
| /** | |
| * Flatten this object in to a Parcel. | |
| * | |
| * @param dest The Parcel in which the object should be written. | |
| * @param flags Additional flags about how the object should be written. | |
| * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}. | |
| */ | |
| @Override | |
| public void writeToParcel(@NonNull Parcel dest, int flags) { | |
| dest.writeInt(mAction); | |
| dest.writeInt(mEvent); | |
| dest.writeInt(mCallingPid); | |
| dest.writeInt(mCommandApdus.length); | |
| dest.writeByteArray(mCommandApdus); | |
| dest.writeInt(mResponseApdus.length); | |
| dest.writeByteArray(mResponseApdus); | |
| dest.writeBoolean(mRfFieldOnTime != null); | |
| if (mRfFieldOnTime != null) { | |
| dest.writeLong(mRfFieldOnTime.getEpochSecond()); | |
| dest.writeInt(mRfFieldOnTime.getNano()); | |
| } | |
| dest.writeParcelable(mTag, 0); | |
| } | |
| /** @hide */ | |
| public static class Builder { | |
| private final OemLogItems mItem; | |
| public Builder(@LogAction int type) { | |
| mItem = new OemLogItems(type, EVENT_UNSET, 0, new byte[0], new byte[0], null, null); | |
| } | |
| /** Setter of the log action. */ | |
| public OemLogItems.Builder setAction(@LogAction int action) { | |
| mItem.mAction = action; | |
| return this; | |
| } | |
| /** Setter of the log calling event. */ | |
| public OemLogItems.Builder setCallingEvent(@LogEvent int event) { | |
| mItem.mEvent = event; | |
| return this; | |
| } | |
| /** Setter of the log calling Pid. */ | |
| public OemLogItems.Builder setCallingPid(int pid) { | |
| mItem.mCallingPid = pid; | |
| return this; | |
| } | |
| /** Setter of APDU command. */ | |
| public OemLogItems.Builder setApduCommand(byte[] apdus) { | |
| mItem.mCommandApdus = apdus; | |
| return this; | |
| } | |
| /** Setter of RF field on time. */ | |
| public OemLogItems.Builder setRfFieldOnTime(Instant time) { | |
| mItem.mRfFieldOnTime = time; | |
| return this; | |
| } | |
| /** Setter of APDU response. */ | |
| public OemLogItems.Builder setApduResponse(byte[] apdus) { | |
| mItem.mResponseApdus = apdus; | |
| return this; | |
| } | |
| /** Setter of dispatched tag. */ | |
| public OemLogItems.Builder setTag(Tag tag) { | |
| mItem.mTag = tag; | |
| return this; | |
| } | |
| /** Builds an {@link OemLogItems} instance. */ | |
| public OemLogItems build() { | |
| return mItem; | |
| } | |
| } | |
| /** | |
| * Gets the action of this log. | |
| * @return one of {@link LogAction} | |
| */ | |
| @LogAction | |
| public int getAction() { | |
| return mAction; | |
| } | |
| /** | |
| * Gets the event of this log. This will be set to {@link LogEvent#EVENT_ENABLE} or | |
| * {@link LogEvent#EVENT_DISABLE} only when action is set to | |
| * {@link LogAction#LOG_ACTION_NFC_TOGGLE} | |
| * @return one of {@link LogEvent} | |
| */ | |
| @LogEvent | |
| public int getEvent() { | |
| return mEvent; | |
| } | |
| /** | |
| * Gets the calling Pid of this log. This field will be set only when action is set to | |
| * {@link LogAction#LOG_ACTION_NFC_TOGGLE} | |
| * @return calling Pid | |
| */ | |
| public int getCallingPid() { | |
| return mCallingPid; | |
| } | |
| /** | |
| * Gets the command APDUs of this log. This field will be set only when action is set to | |
| * {@link LogAction#LOG_ACTION_HCE_DATA} | |
| * @return a byte array of command APDUs with the same format as | |
| * {@link android.nfc.cardemulation.HostApduService#sendResponseApdu(byte[])} | |
| */ | |
| @Nullable | |
| public byte[] getCommandApdu() { | |
| return mCommandApdus; | |
| } | |
| /** | |
| * Gets the response APDUs of this log. This field will be set only when action is set to | |
| * {@link LogAction#LOG_ACTION_HCE_DATA} | |
| * @return a byte array of response APDUs with the same format as | |
| * {@link android.nfc.cardemulation.HostApduService#sendResponseApdu(byte[])} | |
| */ | |
| @Nullable | |
| public byte[] getResponseApdu() { | |
| return mResponseApdus; | |
| } | |
| /** | |
| * Gets the RF field event time in this log in millisecond. This field will be set only when | |
| * action is set to {@link LogAction#LOG_ACTION_RF_FIELD_STATE_CHANGED} | |
| * @return an {@link Instant} of RF field event time. | |
| */ | |
| @Nullable | |
| public Instant getRfFieldEventTimeMillis() { | |
| return mRfFieldOnTime; | |
| } | |
| /** | |
| * Gets the tag of this log. This field will be set only when action is set to | |
| * {@link LogAction#LOG_ACTION_TAG_DETECTED} | |
| * @return a detected {@link Tag} in {@link #LOG_ACTION_TAG_DETECTED} case. Return | |
| * null otherwise. | |
| */ | |
| @Nullable | |
| public Tag getTag() { | |
| return mTag; | |
| } | |
| private String byteToHex(byte[] bytes) { | |
| char[] HexArray = "0123456789ABCDEF".toCharArray(); | |
| char[] hexChars = new char[bytes.length * 2]; | |
| for (int j = 0; j < bytes.length; j++) { | |
| int v = bytes[j] & 0xFF; | |
| hexChars[j * 2] = HexArray[v >>> 4]; | |
| hexChars[j * 2 + 1] = HexArray[v & 0x0F]; | |
| } | |
| return new String(hexChars); | |
| } | |
| @Override | |
| public String toString() { | |
| return "[mCommandApdus: " | |
| + ((mCommandApdus != null) ? byteToHex(mCommandApdus) : "null") | |
| + "[mResponseApdus: " | |
| + ((mResponseApdus != null) ? byteToHex(mResponseApdus) : "null") | |
| + ", mCallingApi= " + mEvent | |
| + ", mAction= " + mAction | |
| + ", mCallingPId = " + mCallingPid | |
| + ", mRfFieldOnTime= " + mRfFieldOnTime; | |
| } | |
| private OemLogItems(Parcel in) { | |
| this.mAction = in.readInt(); | |
| this.mEvent = in.readInt(); | |
| this.mCallingPid = in.readInt(); | |
| this.mCommandApdus = new byte[in.readInt()]; | |
| in.readByteArray(this.mCommandApdus); | |
| this.mResponseApdus = new byte[in.readInt()]; | |
| in.readByteArray(this.mResponseApdus); | |
| boolean isRfFieldOnTimeSet = in.readBoolean(); | |
| if (isRfFieldOnTimeSet) { | |
| this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt()); | |
| } else { | |
| this.mRfFieldOnTime = null; | |
| } | |
| this.mTag = in.readParcelable(Tag.class.getClassLoader(), Tag.class); | |
| } | |
| public static final @NonNull Parcelable.Creator<OemLogItems> CREATOR = | |
| new Parcelable.Creator<OemLogItems>() { | |
| @Override | |
| public OemLogItems createFromParcel(Parcel in) { | |
| return new OemLogItems(in); | |
| } | |
| @Override | |
| public OemLogItems[] newArray(int size) { | |
| return new OemLogItems[size]; | |
| } | |
| }; | |
| } |