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

Commit d469420a authored by Automerger Merge Worker's avatar Automerger Merge Worker Committed by Android (Google) Code Review
Browse files

Merge "Merge "[framework] Add oem log event callback API." into main am:...

Merge "Merge "[framework] Add oem log event callback API." into main am: 44f755b7 am: ce1feb1e" into main
parents f53bf675 09cd047e
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ package android.nfc {
    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 onLogEventNotified(@NonNull android.nfc.OemLogItems);
    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);
@@ -115,6 +116,27 @@ package android.nfc {
    method public int getNfceeId();
  }

  @FlaggedApi("android.nfc.nfc_oem_extension") public final class OemLogItems implements android.os.Parcelable {
    method public int describeContents();
    method public int getAction();
    method public int getCallingPid();
    method @Nullable public byte[] getCommandApdu();
    method public int getEvent();
    method @Nullable public byte[] getResponseApdu();
    method @Nullable public java.time.Instant getRfFieldEventTimeMillis();
    method @Nullable public android.nfc.Tag getTag();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.nfc.OemLogItems> CREATOR;
    field public static final int EVENT_DISABLE = 2; // 0x2
    field public static final int EVENT_ENABLE = 1; // 0x1
    field public static final int EVENT_UNSET = 0; // 0x0
    field public static final int LOG_ACTION_HCE_DATA = 516; // 0x204
    field public static final int LOG_ACTION_NFC_TOGGLE = 513; // 0x201
    field public static final int LOG_ACTION_RF_FIELD_STATE_CHANGED = 1; // 0x1
    field public static final int LOG_ACTION_SCREEN_STATE_CHANGED = 518; // 0x206
    field public static final int LOG_ACTION_TAG_DETECTED = 3; // 0x3
  }

  @FlaggedApi("android.nfc.nfc_oem_extension") public class RoutingStatus {
    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultIsoDepRoute();
    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultOffHostRoute();
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.nfc;
import android.content.ComponentName;
import android.nfc.cardemulation.ApduServiceInfo;
import android.nfc.NdefMessage;
import android.nfc.OemLogItems;
import android.nfc.Tag;
import android.os.ResultReceiver;

@@ -51,4 +52,5 @@ interface INfcOemExtensionCallback {
   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);
   void onLogEventNotified(in OemLogItems item);
}
+12 −0
Original line number Diff line number Diff line
@@ -392,6 +392,12 @@ public final class NfcOemExtension {
         * @param category the category of the service
         */
        void onLaunchHceTapAgainDialog(@NonNull ApduServiceInfo service, @NonNull String category);

        /**
         * Callback when OEM specified log event are notified.
         * @param item the log items that contains log information of NFC event.
         */
        void onLogEventNotified(@NonNull OemLogItems item);
    }


@@ -900,6 +906,12 @@ public final class NfcOemExtension {
                    handleVoid2ArgCallback(service, category, cb::onLaunchHceTapAgainDialog, ex));
        }

        @Override
        public void onLogEventNotified(OemLogItems item) throws RemoteException  {
            mCallbackMap.forEach((cb, ex) ->
                    handleVoidCallback(item, cb::onLogEventNotified, ex));
        }

        private <T> void handleVoidCallback(
                T input, Consumer<T> callbackMethod, Executor executor) {
            synchronized (mLock) {
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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;

parcelable OemLogItems;
 No newline at end of file
+325 −0
Original line number Diff line number Diff line
/*
 * 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.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);
        this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());
        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];
                }
            };

}