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

Commit 6be655c7 authored by Jeff Hamilton's avatar Jeff Hamilton
Browse files

Rough first pass at the NFC technology API.

Change-Id: I903ad6bc124bf9a65af788dae45f55d58704ef7b
parent 4934d336
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -119,7 +119,6 @@ LOCAL_SRC_FILES += \
	core/java/android/nfc/ILlcpConnectionlessSocket.aidl \
	core/java/android/nfc/ILlcpServiceSocket.aidl \
	core/java/android/nfc/ILlcpSocket.aidl \
	core/java/android/nfc/INdefTag.aidl \
	core/java/android/nfc/INfcAdapter.aidl \
	core/java/android/nfc/INfcTag.aidl \
	core/java/android/nfc/IP2pInitiator.aidl \
@@ -252,7 +251,6 @@ aidl_files := \
	frameworks/base/core/java/android/nfc/NdefMessage.aidl \
	frameworks/base/core/java/android/nfc/NdefRecord.aidl \
	frameworks/base/core/java/android/nfc/Tag.aidl \
	frameworks/base/core/java/android/nfc/NdefTag.aidl \
	frameworks/base/core/java/android/os/Bundle.aidl \
	frameworks/base/core/java/android/os/DropBoxManager.aidl \
	frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
+1 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/com/trustedlogic)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/trustedlogic)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/com/trustedlogic)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/INdefTag.java)

# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ interface INfcTag
{
    int close(int nativeHandle);
    int connect(int nativeHandle);
    String getType(int nativeHandle);
    int[] getTechList(int nativeHandle);
    byte[] getUid(int nativeHandle);
    boolean isNdef(int nativeHandle);
    boolean isPresent(int nativeHandle);
+0 −245
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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.os.Parcel;
import android.os.Parcelable;

/**
 * Represents a discovered tag that contains {@link NdefMessage}s (or a tag that can store them).
 * In practice, a tag is a thing that an NFC-enabled device can communicate with. This
 * class is a representation of such a tag and can contain the NDEF messages shared by the tag.
 * <p>An NDEF tag can contain zero or more NDEF messages (represented by {@link NdefMessage}
 * objects) in addition to the basic tag properties of UID and Type.
 * <p>
 * {@link NdefTag}s that have been initialized will usually contain a single {@link NdefMessage}
 * (and that Message can contain multiple {@link NdefRecord}s). However it
 * is possible for {@link NdefTag}s to contain multiple {@link NdefMessage}s.
 * <p>{@link NfcAdapter#createNdefTagConnection createNdefTagConnection()} can be used to modify the
 * contents of some tags.
 * <p>This is an immutable data class. All properties are set at Tag discovery
 * time and calls on this class will retrieve those read-only properties, and
 * not cause any further RF activity or block. Note however that arrays passed to and
 * returned by this class are *not* cloned, so be careful not to modify them.
 * @hide
 */
public class NdefTag extends Tag implements Parcelable {
    /**
     * Target for NFC Forum Type 1 compliant tag.
     * <p>This is based on Jewel/Topaz technology
     */
    public static final String TARGET_TYPE_1 = "type_1";

    /**
     * Target for NFC Forum Type 2 compliant tag.
     * <p>This is based on Mifare Ultralight technology.
     */
    public static final String TARGET_TYPE_2 = "type_2";

    /**
     * Target for NFC Forum Type 3 compliant tag.
     * <p>This is based on Felica technology.
     */
    public static final String TARGET_TYPE_3 = "type_3";

    /**
     * Target for NFC Forum Type 4 compliant tag.
     * <p>This is based on Mifare Desfire technology.
     */
    public static final String TARGET_TYPE_4 = "type_4";

    /**
     * Target for NFC Forum Enabled: Mifare Classic tag.
     * <p>This is not strictly a NFC Forum tag type, but is a common
     * NDEF message container.
     */
    public static final String TARGET_MIFARE_CLASSIC = "type_mifare_classic";

    /**
     * Any other target.
     */
    public static final String TARGET_OTHER = "other";

    private final String[] mNdefTargets;
    private final NdefMessage[][] mMessages;  // one NdefMessage[] per NDEF target
    private NdefMessage[] mFlatMessages;  // collapsed mMessages, built lazily, protected by (this)

    /**
     * Hidden constructor to be used by NFC service only.
     * @hide
     */
    public NdefTag(byte[] id, String[] rawTargets, byte[] pollBytes, byte[] activationBytes,
            int serviceHandle, String[] ndefTargets, NdefMessage[][] messages) {
        super(id, true, rawTargets, pollBytes, activationBytes, serviceHandle);
        if (ndefTargets == null || messages == null) {
            throw new IllegalArgumentException("ndefTargets or messages cannot be null");
        }
        if (ndefTargets.length != messages.length){
            throw new IllegalArgumentException("ndefTargets and messages arrays must match");
        }
        for (NdefMessage[] ms : messages) {
            if (ms == null) {
                throw new IllegalArgumentException("messages elements cannot be null");
            }
        }
        mNdefTargets = ndefTargets;
        mMessages = messages;
    }

    /**
     * Construct a mock NdefTag.
     * <p>This is an application constructed tag, so NfcAdapter methods on this
     * Tag such as {@link NfcAdapter#createRawTagConnection} will fail with
     * {@link IllegalArgumentException} since it does not represent a physical Tag.
     * <p>This constructor might be useful for mock testing.
     * @param id The tag identifier, can be null
     * @param rawTargets must not be null
     * @param pollBytes can be null
     * @param activationBytes can be null
     * @param ndefTargets NDEF target array, such as {TARGET_TYPE_2}, cannot be null
     * @param messages messages, one array per NDEF target, cannot be null
     * @return freshly constructed NdefTag
     */
    public static NdefTag createMockNdefTag(byte[] id, String[] rawTargets, byte[] pollBytes,
            byte[] activationBytes, String[] ndefTargets, NdefMessage[][] messages) {
        // set serviceHandle to 0 to indicate mock tag
        return new NdefTag(id, rawTargets, pollBytes, activationBytes, 0, ndefTargets, messages);
    }

    /**
     * Get all NDEF Messages.
     * <p>
     * This retrieves the NDEF Messages that were found on the Tag at discovery
     * time. It does not cause any further RF activity, and does not block.
     * <p>
     * Most tags only contain a single NDEF message.
     *
     * @return NDEF Messages found at Tag discovery
     */
    public NdefMessage[] getNdefMessages() {
        // common-case optimization
        if (mMessages.length == 1) {
            return mMessages[0];
        }

        // return cached flat array
        synchronized(this) {
            if (mFlatMessages != null) {
                return mFlatMessages;
            }
            // not cached - build a flat array
            int sz = 0;
            for (NdefMessage[] ms : mMessages) {
                sz += ms.length;
            }
            mFlatMessages = new NdefMessage[sz];
            int i = 0;
            for (NdefMessage[] ms : mMessages) {
                System.arraycopy(ms, 0, mFlatMessages, i, ms.length);
                i += ms.length;
            }
            return mFlatMessages;
        }
    }

    /**
     * Get only the NDEF Messages from a single NDEF target on a tag.
     * <p>
     * This retrieves the NDEF Messages that were found on the Tag at discovery
     * time. It does not cause any further RF activity, and does not block.
     * <p>
     * Most tags only contain a single NDEF message.
     *
     * @param target one of targets strings provided by getNdefTargets()
     * @return NDEF Messages found at Tag discovery
     */
    public NdefMessage[] getNdefMessages(String target) {
        for (int i=0; i<mNdefTargets.length; i++) {
            if (target.equals(mNdefTargets[i])) {
                return mMessages[i];
            }
        }
        throw new IllegalArgumentException("target (" + target + ") not found");
    }

    /**
     * Return the NDEF targets on this Tag that support NDEF messages.
     *
     * @return
     */
    public String[] getNdefTargets() {
        return mNdefTargets;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        // Tag fields
        dest.writeInt(mIsNdef ? 1 : 0);
        writeBytesWithNull(dest, mId);
        dest.writeInt(mRawTargets.length);
        dest.writeStringArray(mRawTargets);
        writeBytesWithNull(dest, mPollBytes);
        writeBytesWithNull(dest, mActivationBytes);
        dest.writeInt(mServiceHandle);

        // NdefTag fields
        dest.writeInt(mNdefTargets.length);
        dest.writeStringArray(mNdefTargets);
        dest.writeInt(mMessages.length);
        for (NdefMessage[] ms : mMessages) {
            dest.writeInt(ms.length);
            dest.writeTypedArray(ms, flags);
        }
    }

    public static final Parcelable.Creator<NdefTag> CREATOR =
            new Parcelable.Creator<NdefTag>() {
        public NdefTag createFromParcel(Parcel in) {
            boolean isNdef = (in.readInt() == 1);
            if (!isNdef) {
                throw new IllegalArgumentException("Creating NdefTag from Tag parcel");
            }

            // Tag fields
            byte[] id = readBytesWithNull(in);
            String[] rawTargets = new String[in.readInt()];
            in.readStringArray(rawTargets);
            byte[] pollBytes = readBytesWithNull(in);
            byte[] activationBytes = readBytesWithNull(in);
            int serviceHandle = in.readInt();

            // NdefTag fields
            String[] ndefTargets = new String[in.readInt()];
            in.readStringArray(ndefTargets);
            NdefMessage[][] messages = new NdefMessage[in.readInt()][];
            for (int i=0; i<messages.length; i++) {
                messages[i] = new NdefMessage[in.readInt()];
                in.readTypedArray(messages[i], NdefMessage.CREATOR);
            }
            return new NdefTag(id, rawTargets, pollBytes, activationBytes, serviceHandle,
                    ndefTargets, messages);
        }
        public NdefTag[] newArray(int size) {
            return new NdefTag[size];
        }
    };
}
 No newline at end of file
+19 −74
Original line number Diff line number Diff line
@@ -11,15 +11,11 @@

package android.nfc;

import java.lang.UnsupportedOperationException;

import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.ActivityThread;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.nfc.INfcAdapter;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -39,6 +35,12 @@ public final class NfcAdapter {
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";

    /**
     * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED
     * @hide
     */
    public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST";

    /**
     * Mandatory Tag extra for the ACTION_TAG intents.
     * @hide
@@ -169,6 +171,14 @@ public final class NfcAdapter {
        mService = service;
    }

    /**
     * Returns the binder interface to the service.
     * @hide
     */
    public INfcAdapter getService() {
        return mService;
    }
    
    /**
     * Helper to check if this device has FEATURE_NFC, but without using
     * a context.
@@ -230,8 +240,11 @@ public final class NfcAdapter {
        }
    }

    /** NFC service dead - attempt best effort recovery */
    /*package*/ void attemptDeadServiceRecovery(Exception e) {
    /**
     * NFC service dead - attempt best effort recovery
     * @hide
     */
    public void attemptDeadServiceRecovery(Exception e) {
        Log.e(TAG, "NFC service dead - attempting to recover", e);
        INfcAdapter service = getServiceInterface();
        if (service == null) {
@@ -341,72 +354,4 @@ public final class NfcAdapter {
            return null;
        }
    }

    /**
     * Create a raw tag connection to the default Target
     * <p>Requires {@link android.Manifest.permission#NFC} permission.
     * @hide
     */
    public RawTagConnection createRawTagConnection(Tag tag) {
        if (tag.mServiceHandle == 0) {
            throw new IllegalArgumentException("mock tag cannot be used for connections");
        }
        try {
            return new RawTagConnection(this, tag);
        } catch (RemoteException e) {
            attemptDeadServiceRecovery(e);
            return null;
        }
    }

    /**
     * Create a raw tag connection to the specified Target
     * <p>Requires {@link android.Manifest.permission#NFC} permission.
     * @hide
     */
    public RawTagConnection createRawTagConnection(Tag tag, String target) {
        if (tag.mServiceHandle == 0) {
            throw new IllegalArgumentException("mock tag cannot be used for connections");
        }
        try {
            return new RawTagConnection(this, tag, target);
        } catch (RemoteException e) {
            attemptDeadServiceRecovery(e);
            return null;
        }
    }

    /**
     * Create an NDEF tag connection to the default Target
     * <p>Requires {@link android.Manifest.permission#NFC} permission.
     * @hide
     */
    public NdefTagConnection createNdefTagConnection(NdefTag tag) {
        if (tag.mServiceHandle == 0) {
            throw new IllegalArgumentException("mock tag cannot be used for connections");
        }
        try {
            return new NdefTagConnection(this, tag);
        } catch (RemoteException e) {
            attemptDeadServiceRecovery(e);
            return null;
        }
    }

    /**
     * Create an NDEF tag connection to the specified Target
     * <p>Requires {@link android.Manifest.permission#NFC} permission.
     * @hide
     */
    public NdefTagConnection createNdefTagConnection(NdefTag tag, String target) {
        if (tag.mServiceHandle == 0) {
            throw new IllegalArgumentException("mock tag cannot be used for connections");
        }
        try {
            return new NdefTagConnection(this, tag, target);
        } catch (RemoteException e) {
            attemptDeadServiceRecovery(e);
            return null;
        }
    }
}
Loading