summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/Activity.java12
-rw-r--r--core/java/android/app/ActivityThread.java36
-rw-r--r--core/java/android/app/Instrumentation.java1
-rw-r--r--core/java/android/app/OnActivityPausedListener.java31
-rw-r--r--core/java/android/content/ContentResolver.java4
-rw-r--r--core/java/android/hardware/SensorManager.java29
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl9
-rw-r--r--core/java/android/nfc/INfcTag.aidl6
-rw-r--r--core/java/android/nfc/NfcAdapter.java188
-rwxr-xr-xcore/java/android/nfc/NfcSecureElement.java2
-rw-r--r--core/java/android/nfc/Tag.java176
-rw-r--r--core/java/android/nfc/TagLostException.java29
-rw-r--r--core/java/android/nfc/TechListParcel.aidl19
-rw-r--r--core/java/android/nfc/TechListParcel.java66
-rw-r--r--core/java/android/nfc/TransceiveResult.aidl19
-rw-r--r--core/java/android/nfc/TransceiveResult.java90
-rw-r--r--core/java/android/nfc/tech/BasicTagTechnology.java160
-rw-r--r--core/java/android/nfc/tech/IsoDep.java132
-rw-r--r--core/java/android/nfc/tech/MifareClassic.java432
-rw-r--r--core/java/android/nfc/tech/MifareUltralight.java (renamed from core/java/android/nfc/technology/MifareUltralight.java)105
-rw-r--r--core/java/android/nfc/tech/Ndef.java (renamed from core/java/android/nfc/technology/Ndef.java)134
-rw-r--r--core/java/android/nfc/tech/NdefFormatable.java (renamed from core/java/android/nfc/technology/NdefFormatable.java)46
-rw-r--r--core/java/android/nfc/tech/NfcA.java (renamed from core/java/android/nfc/technology/NfcA.java)43
-rw-r--r--core/java/android/nfc/tech/NfcB.java (renamed from core/java/android/nfc/technology/NfcB.java)43
-rw-r--r--core/java/android/nfc/tech/NfcF.java (renamed from core/java/android/nfc/technology/NfcF.java)44
-rw-r--r--core/java/android/nfc/tech/NfcV.java (renamed from core/java/android/nfc/technology/NfcV.java)46
-rw-r--r--core/java/android/nfc/tech/TagTechnology.java139
-rw-r--r--core/java/android/nfc/technology/BasicTagTechnology.java254
-rw-r--r--core/java/android/nfc/technology/IsoDep.java67
-rw-r--r--core/java/android/nfc/technology/MifareClassic.java404
-rw-r--r--core/java/android/nfc/technology/TagTechnology.java94
-rw-r--r--core/java/android/nfc/technology/package.html5
-rw-r--r--core/java/android/os/Message.java25
-rw-r--r--core/java/android/os/storage/IObbActionListener.java2
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java7
-rwxr-xr-xcore/java/android/speech/tts/TextToSpeech.java23
-rw-r--r--core/java/android/view/LayoutInflater.java2
-rw-r--r--core/java/android/view/WindowManager.java8
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java17
-rw-r--r--core/java/com/android/internal/nfc/LlcpSocket.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java2
-rw-r--r--core/java/com/android/internal/widget/DigitalClock.java108
-rw-r--r--core/tests/coretests/src/android/content/ContentResolverTest.java41
44 files changed, 1948 insertions, 1156 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 055984f..804aeaa 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -655,7 +655,7 @@ public class Activity extends ContextThemeWrapper
boolean mCalled;
boolean mCheckedForLoaderManager;
boolean mLoadersStarted;
- private boolean mResumed;
+ /*package*/ boolean mResumed;
private boolean mStopped;
boolean mFinished;
boolean mStartedActivity;
@@ -4363,9 +4363,8 @@ public class Activity extends ContextThemeWrapper
mLastNonConfigurationInstances = null;
- // First call onResume() -before- setting mResumed, so we don't
- // send out any status bar / menu notifications the client makes.
mCalled = false;
+ // mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
if (!mCalled) {
throw new SuperNotCalledException(
@@ -4374,7 +4373,6 @@ public class Activity extends ContextThemeWrapper
}
// Now really resume, and install the current status bar and menu.
- mResumed = true;
mCalled = false;
mFragments.dispatchResume();
@@ -4399,6 +4397,7 @@ public class Activity extends ContextThemeWrapper
"Activity " + mComponent.toShortString() +
" did not call through to super.onPause()");
}
+ mResumed = false;
}
final void performUserLeaving() {
@@ -4461,7 +4460,10 @@ public class Activity extends ContextThemeWrapper
}
}
- final boolean isResumed() {
+ /**
+ * @hide
+ */
+ public final boolean isResumed() {
return mResumed;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 960b943..8f9a76b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -193,6 +193,9 @@ public final class ActivityThread {
final HashMap<IBinder, ProviderClientRecord> mLocalProviders
= new HashMap<IBinder, ProviderClientRecord>();
+ final HashMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
+ = new HashMap<Activity, ArrayList<OnActivityPausedListener>>();
+
final GcIdler mGcIdler = new GcIdler();
boolean mGcIdlerScheduled = false;
@@ -1514,6 +1517,28 @@ public final class ActivityThread {
}
}
+ public void registerOnActivityPausedListener(Activity activity,
+ OnActivityPausedListener listener) {
+ synchronized (mOnPauseListeners) {
+ ArrayList<OnActivityPausedListener> list = mOnPauseListeners.get(activity);
+ if (list == null) {
+ list = new ArrayList<OnActivityPausedListener>();
+ mOnPauseListeners.put(activity, list);
+ }
+ list.add(listener);
+ }
+ }
+
+ public void unregisterOnActivityPausedListener(Activity activity,
+ OnActivityPausedListener listener) {
+ synchronized (mOnPauseListeners) {
+ ArrayList<OnActivityPausedListener> list = mOnPauseListeners.get(activity);
+ if (list != null) {
+ list.remove(listener);
+ }
+ }
+ }
+
public final ActivityInfo resolveActivityInfo(Intent intent) {
ActivityInfo aInfo = intent.resolveActivityInfo(
mInitialApplication.getPackageManager(), PackageManager.GET_SHARED_LIBRARY_FILES);
@@ -2454,6 +2479,17 @@ public final class ActivityThread {
}
}
r.paused = true;
+
+ // Notify any outstanding on paused listeners
+ ArrayList<OnActivityPausedListener> listeners;
+ synchronized (mOnPauseListeners) {
+ listeners = mOnPauseListeners.remove(r.activity);
+ }
+ int size = (listeners != null ? listeners.size() : 0);
+ for (int i = 0; i < size; i++) {
+ listeners.get(i).onPaused(r.activity);
+ }
+
return state;
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index ad811d8..cd278be 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1149,6 +1149,7 @@ public class Instrumentation {
* @param activity The activity being resumed.
*/
public void callActivityOnResume(Activity activity) {
+ activity.mResumed = true;
activity.onResume();
if (mActivityMonitors != null) {
diff --git a/core/java/android/app/OnActivityPausedListener.java b/core/java/android/app/OnActivityPausedListener.java
new file mode 100644
index 0000000..379f133
--- /dev/null
+++ b/core/java/android/app/OnActivityPausedListener.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * 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.app;
+
+/**
+ * A listener that is called when an Activity is paused. Since this is tracked client side
+ * it should not be trusted to represent the exact current state, but can be used as a hint
+ * for cleanup.
+ *
+ * @hide
+ */
+public interface OnActivityPausedListener {
+ /**
+ * Called when the given activity is paused.
+ */
+ public void onPaused(Activity activity);
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index da518c2..2d03e7c 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1579,9 +1579,11 @@ public abstract class ContentResolver {
@Override
protected void finalize() throws Throwable {
+ // TODO: integrate CloseGuard support.
try {
if(!mCloseFlag) {
- ContentResolver.this.releaseProvider(mContentProvider);
+ Log.w(TAG, "Cursor finalized without prior close()");
+ close();
}
} finally {
super.finalize();
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 4a75514..f079e42 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -25,6 +25,7 @@ import android.os.ServiceManager;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.view.IRotationWatcher;
import android.view.IWindowManager;
import android.view.Surface;
@@ -489,6 +490,8 @@ public class SensorManager
private final Handler mHandler;
private SensorEvent mValuesPool;
public SparseBooleanArray mSensors = new SparseBooleanArray();
+ public SparseBooleanArray mFirstEvent = new SparseBooleanArray();
+ public SparseIntArray mSensorAccuracies = new SparseIntArray();
ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
mSensorEventListener = listener;
@@ -499,10 +502,30 @@ public class SensorManager
mHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
- SensorEvent t = (SensorEvent)msg.obj;
- if (t.accuracy >= 0) {
- mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
+ final SensorEvent t = (SensorEvent)msg.obj;
+ final int handle = t.sensor.getHandle();
+
+ switch (t.sensor.getType()) {
+ // Only report accuracy for sensors that support it.
+ case Sensor.TYPE_MAGNETIC_FIELD:
+ case Sensor.TYPE_ORIENTATION:
+ // call onAccuracyChanged() only if the value changes
+ final int accuracy = mSensorAccuracies.get(handle);
+ if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
+ mSensorAccuracies.put(handle, t.accuracy);
+ mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
+ }
+ break;
+ default:
+ // For other sensors, just report the accuracy once
+ if (mFirstEvent.get(handle) == false) {
+ mFirstEvent.put(handle, true);
+ mSensorEventListener.onAccuracyChanged(
+ t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
+ }
+ break;
}
+
mSensorEventListener.onSensorChanged(t);
returnToPool(t);
}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index a663fb8..d439a48 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -16,8 +16,12 @@
package android.nfc;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.Tag;
+import android.nfc.TechListParcel;
import android.nfc.ILlcpSocket;
import android.nfc.ILlcpServiceSocket;
import android.nfc.ILlcpConnectionlessSocket;
@@ -44,6 +48,11 @@ interface INfcAdapter
NdefMessage localGet();
void localSet(in NdefMessage message);
void openTagConnection(in Tag tag);
+ void enableForegroundDispatch(in ComponentName activity, in PendingIntent intent,
+ in IntentFilter[] filters, in TechListParcel techLists);
+ void disableForegroundDispatch(in ComponentName activity);
+ void enableForegroundNdefPush(in ComponentName activity, in NdefMessage msg);
+ void disableForegroundNdefPush(in ComponentName activity);
// Non-public methods
// TODO: check and complete
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index 5d222d9..57dc38c 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -17,6 +17,7 @@
package android.nfc;
import android.nfc.NdefMessage;
+import android.nfc.TransceiveResult;
/**
* @hide
@@ -30,7 +31,7 @@ interface INfcTag
byte[] getUid(int nativeHandle);
boolean isNdef(int nativeHandle);
boolean isPresent(int nativeHandle);
- byte[] transceive(int nativeHandle, in byte[] data, boolean raw);
+ TransceiveResult transceive(int nativeHandle, in byte[] data, boolean raw);
int getLastError(int nativeHandle);
@@ -39,4 +40,7 @@ interface INfcTag
int ndefMakeReadOnly(int nativeHandle);
boolean ndefIsWritable(int nativeHandle);
int formatNdef(int nativeHandle, in byte[] key);
+
+ void setIsoDepTimeout(int timeout);
+ void resetIsoDepTimeout();
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 758c8a0..4808032 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -18,11 +18,16 @@ package android.nfc;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Activity;
import android.app.ActivityThread;
+import android.app.OnActivityPausedListener;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.os.IBinder;
+import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -43,7 +48,6 @@ public final class NfcAdapter {
*
* If any activities respond to this intent neither
* {@link #ACTION_TECHNOLOGY_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
- * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
@@ -51,13 +55,12 @@ public final class NfcAdapter {
/**
* Intent to started when a tag is discovered. The data URI is formated as
* {@code vnd.android.nfc://tag/} with the path having a directory entry for each technology
- * in the {@link Tag#getTechnologyList()} is ascending order.
+ * in the {@link Tag#getTechList()} is sorted ascending order.
*
* This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before
* {@link #ACTION_TAG_DISCOVERED}
*
* If any activities respond to this intent {@link #ACTION_TAG_DISCOVERED} will not be started.
- * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_TECHNOLOGY_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
@@ -76,7 +79,6 @@ public final class NfcAdapter {
/**
* Mandatory Tag extra for the ACTION_TAG intents.
- * @hide
*/
public static final String EXTRA_TAG = "android.nfc.extra.TAG";
@@ -102,6 +104,20 @@ public final class NfcAdapter {
"android.nfc.action.TRANSACTION_DETECTED";
/**
+ * Broadcast Action: an RF field ON has been detected.
+ * @hide
+ */
+ public static final String ACTION_RF_FIELD_ON_DETECTED =
+ "android.nfc.action.RF_FIELD_ON_DETECTED";
+
+ /**
+ * Broadcast Action: an RF Field OFF has been detected.
+ * @hide
+ */
+ public static final String ACTION_RF_FIELD_OFF_DETECTED =
+ "android.nfc.action.RF_FIELD_OFF_DETECTED";
+
+ /**
* Broadcast Action: an adapter's state changed between enabled and disabled.
*
* The new value is stored in the extra EXTRA_NEW_BOOLEAN_STATE and just contains
@@ -197,8 +213,7 @@ public final class NfcAdapter {
// attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
// recovery
private static INfcAdapter sService;
-
- private final Context mContext;
+ private static INfcTag sTagService;
/**
* Helper to check if this device has FEATURE_NFC, but without using
@@ -235,6 +250,12 @@ public final class NfcAdapter {
Log.e(TAG, "could not retrieve NFC service");
return null;
}
+ try {
+ sTagService = sService.getNfcTagInterface();
+ } catch (RemoteException e) {
+ Log.e(TAG, "could not retrieve NFC Tag service");
+ return null;
+ }
}
return sService;
}
@@ -289,7 +310,6 @@ public final class NfcAdapter {
if (setupService() == null) {
throw new UnsupportedOperationException();
}
- mContext = context;
}
/**
@@ -297,10 +317,20 @@ public final class NfcAdapter {
* @hide
*/
public INfcAdapter getService() {
+ isEnabled(); // NOP call to recover sService if it is stale
return sService;
}
/**
+ * Returns the binder interface to the tag service.
+ * @hide
+ */
+ public INfcTag getTagService() {
+ isEnabled(); // NOP call to recover sTagService if it is stale
+ return sTagService;
+ }
+
+ /**
* NFC service dead - attempt best effort recovery
* @hide
*/
@@ -309,11 +339,21 @@ public final class NfcAdapter {
INfcAdapter service = getServiceInterface();
if (service == null) {
Log.e(TAG, "could not retrieve NFC service during service recovery");
+ // nothing more can be done now, sService is still stale, we'll hit
+ // this recovery path again later
return;
}
- /* assigning to sService is not thread-safe, but this is best-effort code
- * and on a well-behaved system should never happen */
+ // assigning to sService is not thread-safe, but this is best-effort code
+ // and on a well-behaved system should never happen
sService = service;
+ try {
+ sTagService = service.getNfcTagInterface();
+ } catch (RemoteException ee) {
+ Log.e(TAG, "could not retrieve NFC tag service during service recovery");
+ // nothing more can be done now, sService is still stale, we'll hit
+ // this recovery path again later
+ }
+
return;
}
@@ -374,6 +414,136 @@ public final class NfcAdapter {
}
/**
+ * Enables foreground dispatching to the given Activity. This will force all NFC Intents that
+ * match the given filters to be delivered to the activity bypassing the standard dispatch
+ * mechanism. If no IntentFilters are given all the PendingIntent will be invoked for every
+ * dispatch Intent.
+ *
+ * This method must be called from the main thread.
+ *
+ * @param activity the Activity to dispatch to
+ * @param intent the PendingIntent to start for the dispatch
+ * @param filters the IntentFilters to override dispatching for, or null to always dispatch
+ * @throws IllegalStateException
+ */
+ public void enableForegroundDispatch(Activity activity, PendingIntent intent,
+ IntentFilter[] filters, String[][] techLists) {
+ if (activity == null || intent == null) {
+ throw new NullPointerException();
+ }
+ if (!activity.isResumed()) {
+ throw new IllegalStateException("Foregorund dispatching can only be enabled " +
+ "when your activity is resumed");
+ }
+ try {
+ TechListParcel parcel = null;
+ if (techLists != null && techLists.length > 0) {
+ parcel = new TechListParcel(techLists);
+ }
+ ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
+ mForegroundDispatchListener);
+ sService.enableForegroundDispatch(activity.getComponentName(), intent, filters,
+ parcel);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ }
+ }
+
+ /**
+ * Disables foreground activity dispatching setup with
+ * {@link #enableForegroundDispatch}.
+ *
+ * <p>This must be called before the Activity returns from
+ * it's <code>onPause()</code> or this method will throw an IllegalStateException.
+ *
+ * <p>This method must be called from the main thread.
+ */
+ public void disableForegroundDispatch(Activity activity) {
+ ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
+ mForegroundDispatchListener);
+ disableForegroundDispatchInternal(activity, false);
+ }
+
+ OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() {
+ @Override
+ public void onPaused(Activity activity) {
+ disableForegroundDispatchInternal(activity, true);
+ }
+ };
+
+ void disableForegroundDispatchInternal(Activity activity, boolean force) {
+ try {
+ sService.disableForegroundDispatch(activity.getComponentName());
+ if (!force && !activity.isResumed()) {
+ throw new IllegalStateException("You must disable forgeground dispatching " +
+ "while your activity is still resumed");
+ }
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ }
+ }
+
+ /**
+ * Enable NDEF message push over P2P while this Activity is in the foreground. For this to
+ * function properly the other NFC device being scanned must support the "com.android.npp"
+ * NDEF push protocol.
+ *
+ * <p><em>NOTE</em> While foreground NDEF push is active standard tag dispatch is disabled.
+ * Only the foreground activity may receive tag discovered dispatches via
+ * {@link #enableForegroundDispatch}.
+ */
+ public void enableForegroundNdefPush(Activity activity, NdefMessage msg) {
+ if (activity == null || msg == null) {
+ throw new NullPointerException();
+ }
+ if (!activity.isResumed()) {
+ throw new IllegalStateException("Foregorund NDEF push can only be enabled " +
+ "when your activity is resumed");
+ }
+ try {
+ ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
+ mForegroundNdefPushListener);
+ sService.enableForegroundNdefPush(activity.getComponentName(), msg);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ }
+ }
+
+ /**
+ * Disables foreground NDEF push setup with
+ * {@link #enableForegroundNdefPush}.
+ *
+ * <p>This must be called before the Activity returns from
+ * it's <code>onPause()</code> or this method will throw an IllegalStateException.
+ *
+ * <p>This method must be called from the main thread.
+ */
+ public void disableForegroundNdefPush(Activity activity) {
+ ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
+ mForegroundNdefPushListener);
+ disableForegroundNdefPushInternal(activity, false);
+ }
+
+ OnActivityPausedListener mForegroundNdefPushListener = new OnActivityPausedListener() {
+ @Override
+ public void onPaused(Activity activity) {
+ disableForegroundNdefPushInternal(activity, true);
+ }
+ };
+
+ void disableForegroundNdefPushInternal(Activity activity, boolean force) {
+ try {
+ sService.disableForegroundNdefPush(activity.getComponentName());
+ if (!force && !activity.isResumed()) {
+ throw new IllegalStateException("You must disable forgeground NDEF push " +
+ "while your activity is still resumed");
+ }
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ }
+ }
+
+ /**
* Set the NDEF Message that this NFC adapter should appear as to Tag
* readers.
* <p>
diff --git a/core/java/android/nfc/NfcSecureElement.java b/core/java/android/nfc/NfcSecureElement.java
index 5f4c066..ea2846e 100755
--- a/core/java/android/nfc/NfcSecureElement.java
+++ b/core/java/android/nfc/NfcSecureElement.java
@@ -16,7 +16,7 @@
package android.nfc;
-import android.nfc.technology.TagTechnology;
+import android.nfc.tech.TagTechnology;
import android.os.RemoteException;
import android.util.Log;
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 7404950..aae75c9 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -16,36 +16,35 @@
package android.nfc;
-import android.nfc.technology.IsoDep;
-import android.nfc.technology.MifareClassic;
-import android.nfc.technology.MifareUltralight;
-import android.nfc.technology.NfcV;
-import android.nfc.technology.Ndef;
-import android.nfc.technology.NdefFormatable;
-import android.nfc.technology.NfcA;
-import android.nfc.technology.NfcB;
-import android.nfc.technology.NfcF;
-import android.nfc.technology.TagTechnology;
+import android.nfc.tech.IsoDep;
+import android.nfc.tech.MifareClassic;
+import android.nfc.tech.MifareUltralight;
+import android.nfc.tech.Ndef;
+import android.nfc.tech.NdefFormatable;
+import android.nfc.tech.NfcA;
+import android.nfc.tech.NfcB;
+import android.nfc.tech.NfcF;
+import android.nfc.tech.NfcV;
+import android.nfc.tech.TagTechnology;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
import java.util.Arrays;
/**
* Represents a (generic) discovered tag.
* <p>
- * A tag is a passive NFC element, such as NFC Forum Tag's, Mifare class Tags,
- * Sony Felica Tags.
+ * A tag is a passive NFC element, such as NFC Forum Tag's, MIFARE class Tags,
+ * Sony FeliCa Tags, etc.
* <p>
* Tag's have a type and usually have a UID.
* <p>
* {@link Tag} objects are passed to applications via the {@link NfcAdapter#EXTRA_TAG} extra
* in {@link NfcAdapter#ACTION_TAG_DISCOVERED} intents. A {@link Tag} object is immutable
* and represents the state of the tag at the time of discovery. It can be
- * directly queried for its UID and Type, or used to create a {@link TagTechnology}
- * (with {@link Tag#getTechnology(int)}).
+ * directly queried for its UID and Type, or used to create a {@link TagTechnology} using the
+ * static <code>get()</code> methods on the varios tech classes.
* <p>
* A {@link Tag} can be used to create a {@link TagTechnology} only while the tag is in
* range. If it is removed and then returned to range, then the most recent
@@ -55,13 +54,14 @@ import java.util.Arrays;
* 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 Tag implements Parcelable {
/*package*/ final byte[] mId;
/*package*/ final int[] mTechList;
+ /*package*/ final String[] mTechStringList;
/*package*/ final Bundle[] mTechExtras;
/*package*/ final int mServiceHandle; // for use by NFC service, 0 indicates a mock
+ /*package*/ final INfcTag mTagService;
/*package*/ int mConnectedTechnology;
@@ -69,24 +69,26 @@ public class Tag implements Parcelable {
* Hidden constructor to be used by NFC service and internal classes.
* @hide
*/
- public Tag(byte[] id, int[] techList, Bundle[] techListExtras, int serviceHandle) {
+ public Tag(byte[] id, int[] techList, Bundle[] techListExtras, int serviceHandle,
+ INfcTag tagService) {
if (techList == null) {
throw new IllegalArgumentException("rawTargets cannot be null");
}
mId = id;
mTechList = Arrays.copyOf(techList, techList.length);
+ mTechStringList = generateTechStringList(techList);
// Ensure mTechExtras is as long as mTechList
mTechExtras = Arrays.copyOf(techListExtras, techList.length);
mServiceHandle = serviceHandle;
+ mTagService = tagService;
mConnectedTechnology = -1;
}
/**
* Construct a mock Tag.
- * <p>This is an application constructed tag, so NfcAdapter methods on this
- * Tag such as {@link #getTechnology} may fail with
- * {@link IllegalArgumentException} since it does not represent a physical Tag.
+ * <p>This is an application constructed tag, so NfcAdapter methods on this Tag may 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 techList must not be null
@@ -94,7 +96,46 @@ public class Tag implements Parcelable {
*/
public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras) {
// set serviceHandle to 0 to indicate mock tag
- return new Tag(id, techList, techListExtras, 0);
+ return new Tag(id, techList, techListExtras, 0, null);
+ }
+
+ private String[] generateTechStringList(int[] techList) {
+ final int size = techList.length;
+ String[] strings = new String[size];
+ for (int i = 0; i < size; i++) {
+ switch (techList[i]) {
+ case TagTechnology.ISO_DEP:
+ strings[i] = IsoDep.class.getName();
+ break;
+ case TagTechnology.MIFARE_CLASSIC:
+ strings[i] = MifareClassic.class.getName();
+ break;
+ case TagTechnology.MIFARE_ULTRALIGHT:
+ strings[i] = MifareUltralight.class.getName();
+ break;
+ case TagTechnology.NDEF:
+ strings[i] = Ndef.class.getName();
+ break;
+ case TagTechnology.NDEF_FORMATABLE:
+ strings[i] = NdefFormatable.class.getName();
+ break;
+ case TagTechnology.NFC_A:
+ strings[i] = NfcA.class.getName();
+ break;
+ case TagTechnology.NFC_B:
+ strings[i] = NfcB.class.getName();
+ break;
+ case TagTechnology.NFC_F:
+ strings[i] = NfcF.class.getName();
+ break;
+ case TagTechnology.NFC_V:
+ strings[i] = NfcV.class.getName();
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown tech type " + techList[i]);
+ }
+ }
+ return strings;
}
/**
@@ -119,19 +160,24 @@ public class Tag implements Parcelable {
* Returns technologies present in the tag that this implementation understands,
* or a zero length array if there are no supported technologies on this tag.
*
- * The elements of the list are guaranteed be one of the constants defined in
- * {@link TagTechnology}.
+ * The elements of the list are the names of the classes implementing the technology.
*
* The ordering of the returned array is undefined and should not be relied upon.
*/
- public int[] getTechnologyList() {
- return Arrays.copyOf(mTechList, mTechList.length);
+ public String[] getTechList() {
+ return mTechStringList;
}
- /**
- * Returns the technology, or null if not present
- */
- public TagTechnology getTechnology(NfcAdapter adapter, int tech) {
+ /** @hide */
+ public boolean hasTech(int techType) {
+ for (int tech : mTechList) {
+ if (tech == techType) return true;
+ }
+ return false;
+ }
+
+ /** @hide */
+ public Bundle getTechExtras(int tech) {
int pos = -1;
for (int idx = 0; idx < mTechList.length; idx++) {
if (mTechList[idx] == tech) {
@@ -143,44 +189,12 @@ public class Tag implements Parcelable {
return null;
}
- Bundle extras = mTechExtras[pos];
- try {
- switch (tech) {
- case TagTechnology.NFC_A: {
- return new NfcA(adapter, this, extras);
- }
- case TagTechnology.NFC_B: {
- return new NfcB(adapter, this, extras);
- }
- case TagTechnology.ISO_DEP: {
- return new IsoDep(adapter, this, extras);
- }
- case TagTechnology.NFC_V: {
- return new NfcV(adapter, this, extras);
- }
- case TagTechnology.NDEF: {
- return new Ndef(adapter, this, tech, extras);
- }
- case TagTechnology.NDEF_FORMATABLE: {
- return new NdefFormatable(adapter, this, tech, extras);
- }
- case TagTechnology.NFC_F: {
- return new NfcF(adapter, this, extras);
- }
- case TagTechnology.MIFARE_CLASSIC: {
- return new MifareClassic(adapter, this, extras);
- }
- case TagTechnology.MIFARE_ULTRALIGHT: {
- return new MifareUltralight(adapter, this, extras);
- }
+ return mTechExtras[pos];
+ }
- default: {
- throw new UnsupportedOperationException("Tech " + tech + " not supported");
- }
- }
- } catch (RemoteException e) {
- return null;
- }
+ /** @hide */
+ public INfcTag getTagService() {
+ return mTagService;
}
@Override
@@ -222,25 +236,41 @@ public class Tag implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
+ // Null mTagService means this is a mock tag
+ int isMock = (mTagService == null)?1:0;
+
writeBytesWithNull(dest, mId);
dest.writeInt(mTechList.length);
dest.writeIntArray(mTechList);
dest.writeTypedArray(mTechExtras, 0);
dest.writeInt(mServiceHandle);
+ dest.writeInt(isMock);
+ if (isMock == 0) {
+ dest.writeStrongBinder(mTagService.asBinder());
+ }
}
public static final Parcelable.Creator<Tag> CREATOR =
new Parcelable.Creator<Tag>() {
@Override
public Tag createFromParcel(Parcel in) {
+ INfcTag tagService;
+
// Tag fields
byte[] id = Tag.readBytesWithNull(in);
int[] techList = new int[in.readInt()];
in.readIntArray(techList);
Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR);
int serviceHandle = in.readInt();
+ int isMock = in.readInt();
+ if (isMock == 0) {
+ tagService = INfcTag.Stub.asInterface(in.readStrongBinder());
+ }
+ else {
+ tagService = null;
+ }
- return new Tag(id, techList, techExtras, serviceHandle);
+ return new Tag(id, techList, techExtras, serviceHandle, tagService);
}
@Override
@@ -249,7 +279,9 @@ public class Tag implements Parcelable {
}
};
- /*
+ /**
+ * For internal use only.
+ *
* @hide
*/
public synchronized void setConnectedTechnology(int technology) {
@@ -260,14 +292,18 @@ public class Tag implements Parcelable {
}
}
- /*
+ /**
+ * For internal use only.
+ *
* @hide
*/
public int getConnectedTechnology() {
return mConnectedTechnology;
}
- /*
+ /**
+ * For internal use only.
+ *
* @hide
*/
public void setTechnologyDisconnected() {
diff --git a/core/java/android/nfc/TagLostException.java b/core/java/android/nfc/TagLostException.java
new file mode 100644
index 0000000..1981d7c
--- /dev/null
+++ b/core/java/android/nfc/TagLostException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011, 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 java.io.IOException;
+
+public class TagLostException extends IOException {
+ public TagLostException() {
+ super();
+ }
+
+ public TagLostException(String message) {
+ super(message);
+ }
+}
diff --git a/core/java/android/nfc/TechListParcel.aidl b/core/java/android/nfc/TechListParcel.aidl
new file mode 100644
index 0000000..92e646f
--- /dev/null
+++ b/core/java/android/nfc/TechListParcel.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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 TechListParcel; \ No newline at end of file
diff --git a/core/java/android/nfc/TechListParcel.java b/core/java/android/nfc/TechListParcel.java
new file mode 100644
index 0000000..396f0f1
--- /dev/null
+++ b/core/java/android/nfc/TechListParcel.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 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;
+
+/** @hide */
+public class TechListParcel implements Parcelable {
+
+ private String[][] mTechLists;
+
+ public TechListParcel(String[]... strings) {
+ mTechLists = strings;
+ }
+
+ public String[][] getTechLists() {
+ return mTechLists;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ int count = mTechLists.length;
+ dest.writeInt(count);
+ for (int i = 0; i < count; i++) {
+ String[] techList = mTechLists[i];
+ dest.writeStringArray(techList);
+ }
+ }
+
+ public static final Creator<TechListParcel> CREATOR = new Creator<TechListParcel>() {
+ @Override
+ public TechListParcel createFromParcel(Parcel source) {
+ int count = source.readInt();
+ String[][] techLists = new String[count][];
+ for (int i = 0; i < count; i++) {
+ techLists[i] = source.readStringArray();
+ }
+ return new TechListParcel(techLists);
+ }
+
+ @Override
+ public TechListParcel[] newArray(int size) {
+ return new TechListParcel[size];
+ }
+ };
+}
diff --git a/core/java/android/nfc/TransceiveResult.aidl b/core/java/android/nfc/TransceiveResult.aidl
new file mode 100644
index 0000000..98f92ee
--- /dev/null
+++ b/core/java/android/nfc/TransceiveResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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 TransceiveResult;
diff --git a/core/java/android/nfc/TransceiveResult.java b/core/java/android/nfc/TransceiveResult.java
new file mode 100644
index 0000000..16244b8
--- /dev/null
+++ b/core/java/android/nfc/TransceiveResult.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011, 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;
+
+/**
+ * Class used to pipe transceive result from the NFC service.
+ *
+ * @hide
+ */
+public final class TransceiveResult implements Parcelable {
+ private final boolean mTagLost;
+ private final boolean mSuccess;
+ private final byte[] mResponseData;
+
+ public TransceiveResult(final boolean success, final boolean tagIsLost,
+ final byte[] data) {
+ mSuccess = success;
+ mTagLost = tagIsLost;
+ mResponseData = data;
+ }
+
+ public boolean isSuccessful() {
+ return mSuccess;
+ }
+
+ public boolean isTagLost() {
+ return mTagLost;
+ }
+
+ public byte[] getResponseData() {
+ return mResponseData;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSuccess ? 1 : 0);
+ dest.writeInt(mTagLost ? 1 : 0);
+ if (mSuccess) {
+ dest.writeInt(mResponseData.length);
+ dest.writeByteArray(mResponseData);
+ }
+ }
+
+ public static final Parcelable.Creator<TransceiveResult> CREATOR =
+ new Parcelable.Creator<TransceiveResult>() {
+ @Override
+ public TransceiveResult createFromParcel(Parcel in) {
+ boolean success = (in.readInt() == 1) ? true : false;
+ boolean tagLost = (in.readInt() == 1) ? true : false;
+ byte[] responseData;
+
+ if (success) {
+ int responseLength = in.readInt();
+ responseData = new byte[responseLength];
+ in.readByteArray(responseData);
+ } else {
+ responseData = null;
+ }
+ return new TransceiveResult(success, tagLost, responseData);
+ }
+
+ @Override
+ public TransceiveResult[] newArray(int size) {
+ return new TransceiveResult[size];
+ }
+ };
+
+}
diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/core/java/android/nfc/tech/BasicTagTechnology.java
new file mode 100644
index 0000000..e635f21
--- /dev/null
+++ b/core/java/android/nfc/tech/BasicTagTechnology.java
@@ -0,0 +1,160 @@
+/*
+ * 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.tech;
+
+import android.nfc.ErrorCodes;
+import android.nfc.Tag;
+import android.nfc.TagLostException;
+import android.nfc.TransceiveResult;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * A base class for tag technologies that are built on top of transceive().
+ */
+/* package */ abstract class BasicTagTechnology implements TagTechnology {
+ private static final String TAG = "NFC";
+
+ /*package*/ final Tag mTag;
+ /*package*/ boolean mIsConnected;
+ /*package*/ int mSelectedTechnology;
+
+ BasicTagTechnology(Tag tag, int tech) throws RemoteException {
+ mTag = tag;
+ mSelectedTechnology = tech;
+ }
+
+ @Override
+ public Tag getTag() {
+ return mTag;
+ }
+
+ /** Internal helper to throw IllegalStateException if the technology isn't connected */
+ void checkConnected() {
+ if ((mTag.getConnectedTechnology() != mSelectedTechnology) ||
+ (mTag.getConnectedTechnology() == -1)) {
+ throw new IllegalStateException("Call connect() first!");
+ }
+ }
+
+ /**
+ * Helper to indicate if {@link #connect} has succeeded.
+ * <p>
+ * Does not cause RF activity, and does not block.
+ * @return true if {@link #connect} has completed successfully and the {@link Tag} is believed
+ * to be within range. Applications must still handle {@link java.io.IOException}
+ * while using methods that require a connection in case the connection is lost after this
+ * method returns.
+ */
+ public boolean isConnected() {
+ if (!mIsConnected) {
+ return false;
+ }
+
+ try {
+ return mTag.getTagService().isPresent(mTag.getServiceHandle());
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ return false;
+ }
+ }
+
+ @Override
+ public void connect() throws IOException {
+ try {
+ int errorCode = mTag.getTagService().connect(mTag.getServiceHandle(),
+ mSelectedTechnology);
+
+ if (errorCode == ErrorCodes.SUCCESS) {
+ // Store this in the tag object
+ mTag.setConnectedTechnology(mSelectedTechnology);
+ mIsConnected = true;
+ } else {
+ throw new IOException();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ throw new IOException("NFC service died");
+ }
+ }
+
+ @Override
+ public void reconnect() throws IOException {
+ if (!mIsConnected) {
+ throw new IllegalStateException("Technology not connected yet");
+ }
+
+ try {
+ int errorCode = mTag.getTagService().reconnect(mTag.getServiceHandle());
+
+ if (errorCode != ErrorCodes.SUCCESS) {
+ mIsConnected = false;
+ mTag.setTechnologyDisconnected();
+ throw new IOException();
+ }
+ } catch (RemoteException e) {
+ mIsConnected = false;
+ mTag.setTechnologyDisconnected();
+ Log.e(TAG, "NFC service dead", e);
+ throw new IOException("NFC service died");
+ }
+ }
+
+ @Override
+ public void close() {
+ try {
+ /* Note that we don't want to physically disconnect the tag,
+ * but just reconnect to it to reset its state
+ */
+ mTag.getTagService().reconnect(mTag.getServiceHandle());
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ } finally {
+ mIsConnected = false;
+ mTag.setTechnologyDisconnected();
+ }
+ }
+
+ /** Internal transceive */
+ /*package*/ byte[] transceive(byte[] data, boolean raw) throws IOException {
+ checkConnected();
+
+ try {
+ TransceiveResult result = mTag.getTagService().transceive(mTag.getServiceHandle(),
+ data, raw);
+ if (result == null) {
+ throw new IOException("transceive failed");
+ } else {
+ if (result.isSuccessful()) {
+ return result.getResponseData();
+ } else {
+ if (result.isTagLost()) {
+ throw new TagLostException("Tag was lost.");
+ }
+ else {
+ throw new IOException("transceive failed");
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ throw new IOException("NFC service died");
+ }
+ }
+}
diff --git a/core/java/android/nfc/tech/IsoDep.java b/core/java/android/nfc/tech/IsoDep.java
new file mode 100644
index 0000000..f6d141a
--- /dev/null
+++ b/core/java/android/nfc/tech/IsoDep.java
@@ -0,0 +1,132 @@
+/*
+ * 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.tech;
+
+import android.nfc.Tag;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * A low-level connection to a {@link Tag} using the ISO-DEP technology, also known as
+ * ISO1443-4.
+ *
+ * <p>You can acquire this kind of connection with {@link #get}.
+ * Use this class to send and receive data with {@link #transceive transceive()}.
+ *
+ * <p>Applications must implement their own protocol stack on top of
+ * {@link #transceive transceive()}.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * Use of this class requires the {@link android.Manifest.permission#NFC}
+ * permission.
+ */
+public final class IsoDep extends BasicTagTechnology {
+ private static final String TAG = "NFC";
+
+ /** @hide */
+ public static final String EXTRA_HI_LAYER_RESP = "hiresp";
+ /** @hide */
+ public static final String EXTRA_HIST_BYTES = "histbytes";
+
+ private byte[] mHiLayerResponse = null;
+ private byte[] mHistBytes = null;
+
+ /**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static IsoDep get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.ISO_DEP)) return null;
+ try {
+ return new IsoDep(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public IsoDep(Tag tag)
+ throws RemoteException {
+ super(tag, TagTechnology.ISO_DEP);
+ Bundle extras = tag.getTechExtras(TagTechnology.ISO_DEP);
+ if (extras != null) {
+ mHiLayerResponse = extras.getByteArray(EXTRA_HI_LAYER_RESP);
+ mHistBytes = extras.getByteArray(EXTRA_HIST_BYTES);
+ }
+ }
+
+ /**
+ * Sets the timeout of an IsoDep transceive transaction in milliseconds.
+ * If the transaction has not completed before the timeout,
+ * any ongoing {@link #transceive} operation will be
+ * aborted and the connection to the tag is lost. This setting is applied
+ * only to the {@link Tag} object linked to this technology and will be
+ * reset when {@link IsoDep#close} is called.
+ * The default transaction timeout is 300 milliseconds.
+ */
+ public void setTimeout(int timeout) {
+ try {
+ mTag.getTagService().setIsoDepTimeout(timeout);
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ }
+ }
+
+ @Override
+ public void close() {
+ try {
+ mTag.getTagService().resetIsoDepTimeout();
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ }
+ super.close();
+ }
+
+ /**
+ * Return the historical bytes if the tag is using {@link NfcA}, null otherwise.
+ */
+ public byte[] getHistoricalBytes() {
+ return mHistBytes;
+ }
+
+ /**
+ * Return the hi layer response bytes if the tag is using {@link NfcB}, null otherwise.
+ */
+ public byte[] getHiLayerResponse() {
+ return mHiLayerResponse;
+ }
+
+ /**
+ * Send data to a tag and receive the response.
+ * <p>
+ * This method will block until the response is received. It can be canceled
+ * with {@link #close}.
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.
+ *
+ * @param data bytes to send
+ * @return bytes received in response
+ * @throws IOException if the target is lost or connection closed
+ */
+ public byte[] transceive(byte[] data) throws IOException {
+ return transceive(data, true);
+ }
+}
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
new file mode 100644
index 0000000..34fd7cf
--- /dev/null
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -0,0 +1,432 @@
+/*
+ * 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.tech;
+
+import android.nfc.Tag;
+import android.nfc.TagLostException;
+import android.os.RemoteException;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Technology class representing MIFARE Classic tags (also known as MIFARE Standard).
+ *
+ * <p>Support for this technology type is optional. If the NFC stack doesn't support this technology
+ * MIFARE Classic tags will still be scanned, but will only show the NfcA technology.
+ *
+ * <p>MIFARE Classic tags have sectors that each contain blocks. The block size is constant at
+ * 16 bytes, but the number of sectors and the sector size varies by product. MIFARE has encryption
+ * built in and each sector has two keys associated with it, as well as ACLs to determine what
+ * level acess each key grants. Before operating on a sector you must call either
+ * {@link #authenticateSectorWithKeyA(int, byte[])} or
+ * {@link #authenticateSectorWithKeyB(int, byte[])} to gain authorization for your request.
+ */
+public final class MifareClassic extends BasicTagTechnology {
+ /**
+ * The well-known default MIFARE read key. All keys are set to this at the factory.
+ * Using this key will effectively make the payload in the sector public.
+ */
+ public static final byte[] KEY_DEFAULT =
+ {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
+ /**
+ * The well-known, default MIFARE Application Directory read key.
+ */
+ public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY =
+ {(byte)0xA0,(byte)0xA1,(byte)0xA2,(byte)0xA3,(byte)0xA4,(byte)0xA5};
+ /**
+ * The well-known, default read key for NDEF data on a MIFARE Classic
+ */
+ public static final byte[] KEY_NFC_FORUM =
+ {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7};
+
+ /** A MIFARE Classic tag */
+ public static final int TYPE_CLASSIC = 0;
+ /** A MIFARE Plus tag */
+ public static final int TYPE_PLUS = 1;
+ /** A MIFARE Pro tag */
+ public static final int TYPE_PRO = 2;
+ /** A Mifare Classic compatible card that does not match the other types */
+ public static final int TYPE_OTHER = -1;
+
+ /** The tag contains 16 sectors, each holding 4 blocks. */
+ public static final int SIZE_1K = 1024;
+ /** The tag contains 32 sectors, each holding 4 blocks. */
+ public static final int SIZE_2K = 2048;
+ /**
+ * The tag contains 40 sectors. The first 32 sectors contain 4 blocks and the last 8 sectors
+ * contain 16 blocks.
+ */
+ public static final int SIZE_4K = 4096;
+ /** The tag contains 5 sectors, each holding 4 blocks. */
+ public static final int SIZE_MINI = 320;
+
+ /** Size of a Mifare Classic block (in bytes) */
+ public static final int BLOCK_SIZE = 16;
+
+ private static final int MAX_BLOCK_COUNT = 256;
+ private static final int MAX_SECTOR_COUNT = 40;
+
+ private boolean mIsEmulated;
+ private int mType;
+ private int mSize;
+
+ /**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static MifareClassic get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.MIFARE_CLASSIC)) return null;
+ try {
+ return new MifareClassic(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public MifareClassic(Tag tag) throws RemoteException {
+ super(tag, TagTechnology.MIFARE_CLASSIC);
+
+ NfcA a = NfcA.get(tag); // Mifare Classic is always based on NFC a
+
+ mIsEmulated = false;
+
+ switch (a.getSak()) {
+ case 0x08:
+ mType = TYPE_CLASSIC;
+ mSize = SIZE_1K;
+ break;
+ case 0x09:
+ mType = TYPE_CLASSIC;
+ mSize = SIZE_MINI;
+ break;
+ case 0x10:
+ mType = TYPE_PLUS;
+ mSize = SIZE_2K;
+ // SecLevel = SL2
+ break;
+ case 0x11:
+ mType = TYPE_PLUS;
+ mSize = SIZE_4K;
+ // Seclevel = SL2
+ break;
+ case 0x18:
+ mType = TYPE_CLASSIC;
+ mSize = SIZE_4K;
+ break;
+ case 0x28:
+ mType = TYPE_CLASSIC;
+ mSize = SIZE_1K;
+ mIsEmulated = true;
+ break;
+ case 0x38:
+ mType = TYPE_CLASSIC;
+ mSize = SIZE_4K;
+ mIsEmulated = true;
+ break;
+ case 0x88:
+ mType = TYPE_CLASSIC;
+ mSize = SIZE_1K;
+ // NXP-tag: false
+ break;
+ case 0x98:
+ case 0xB8:
+ mType = TYPE_PRO;
+ mSize = SIZE_4K;
+ break;
+ default:
+ // Stack incorrectly reported a MifareClassic. We cannot handle this
+ // gracefully - we have no idea of the memory layout. Bail.
+ throw new RuntimeException(
+ "Tag incorrectly enumerated as Mifare Classic, SAK = " + a.getSak());
+ }
+ }
+
+ /** Returns the type of the tag, determined at discovery time */
+ public int getType() {
+ return mType;
+ }
+
+ /** Returns the size of the tag in bytes, determined at discovery time */
+ public int getSize() {
+ return mSize;
+ }
+
+ /** Returns true if the tag is emulated, determined at discovery time.
+ * These are actually smart-cards that emulate a Mifare Classic interface.
+ * They can be treated identically to a Mifare Classic tag.
+ * @hide
+ */
+ public boolean isEmulated() {
+ return mIsEmulated;
+ }
+
+ /** Returns the number of sectors on this tag, determined at discovery time */
+ public int getSectorCount() {
+ switch (mSize) {
+ case SIZE_1K:
+ return 16;
+ case SIZE_2K:
+ return 32;
+ case SIZE_4K:
+ return 40;
+ case SIZE_MINI:
+ return 5;
+ default:
+ return 0;
+ }
+ }
+
+ /** Returns the total block count, determined at discovery time */
+ public int getBlockCount() {
+ return mSize / BLOCK_SIZE;
+ }
+
+ /** Returns the block count for the given sector, determined at discovery time */
+ public int getBlockCountInSector(int sectorIndex) {
+ validateSector(sectorIndex);
+
+ if (sectorIndex < 32) {
+ return 4;
+ } else {
+ return 16;
+ }
+ }
+
+ /** Return the sector index of a given block */
+ public int blockToSector(int blockIndex) {
+ validateBlock(blockIndex);
+
+ if (blockIndex < 32 * 4) {
+ return blockIndex / 4;
+ } else {
+ return 32 + (blockIndex - 32 * 4) / 16;
+ }
+ }
+
+ /** Return the first block of a given sector */
+ public int sectorToBlock(int sectorIndex) {
+ if (sectorIndex < 32) {
+ return sectorIndex * 4;
+ } else {
+ return 32 * 4 + (sectorIndex - 32) * 16;
+ }
+ }
+
+ // Methods that require connect()
+ /**
+ * Authenticate a sector.
+ * <p>Every sector has an A and B key with different access privileges,
+ * this method attempts to authenticate against the A key.
+ * <p>This requires a that the tag be connected.
+ */
+ public boolean authenticateSectorWithKeyA(int sectorIndex, byte[] key) throws IOException {
+ return authenticate(sectorIndex, key, true);
+ }
+
+ /**
+ * Authenticate a sector.
+ * <p>Every sector has an A and B key with different access privileges,
+ * this method attempts to authenticate against the B key.
+ * <p>This requires a that the tag be connected.
+ */
+ public boolean authenticateSectorWithKeyB(int sectorIndex, byte[] key) throws IOException {
+ return authenticate(sectorIndex, key, false);
+ }
+
+ private boolean authenticate(int sector, byte[] key, boolean keyA) throws IOException {
+ validateSector(sector);
+ checkConnected();
+
+ byte[] cmd = new byte[12];
+
+ // First byte is the command
+ if (keyA) {
+ cmd[0] = 0x60; // phHal_eMifareAuthentA
+ } else {
+ cmd[0] = 0x61; // phHal_eMifareAuthentB
+ }
+
+ // Second byte is block address
+ // Authenticate command takes a block address. Authenticating a block
+ // of a sector will authenticate the entire sector.
+ cmd[1] = (byte) sectorToBlock(sector);
+
+ // Next 4 bytes are last 4 bytes of UID
+ byte[] uid = getTag().getId();
+ System.arraycopy(uid, uid.length - 4, cmd, 2, 4);
+
+ // Next 6 bytes are key
+ System.arraycopy(key, 0, cmd, 6, 6);
+
+ try {
+ if (transceive(cmd, false) != null) {
+ return true;
+ }
+ } catch (TagLostException e) {
+ throw e;
+ } catch (IOException e) {
+ // No need to deal with, will return false anyway
+ }
+ return false;
+ }
+
+ /**
+ * Read 16-byte block.
+ * <p>This requires a that the tag be connected.
+ * @throws IOException
+ */
+ public byte[] readBlock(int blockIndex) throws IOException {
+ validateBlock(blockIndex);
+ checkConnected();
+
+ byte[] cmd = { 0x30, (byte) blockIndex };
+ return transceive(cmd, false);
+ }
+
+ /**
+ * Write 16-byte block.
+ * <p>This requires a that the tag be connected.
+ * @throws IOException
+ */
+ public void writeBlock(int blockIndex, byte[] data) throws IOException {
+ validateBlock(blockIndex);
+ checkConnected();
+ if (data.length != 16) {
+ throw new IllegalArgumentException("must write 16-bytes");
+ }
+
+ byte[] cmd = new byte[data.length + 2];
+ cmd[0] = (byte) 0xA0; // MF write command
+ cmd[1] = (byte) blockIndex;
+ System.arraycopy(data, 0, cmd, 2, data.length);
+
+ transceive(cmd, false);
+ }
+
+ /**
+ * Increment a value block, and store the result in temporary memory.
+ * @param blockIndex
+ * @throws IOException
+ */
+ public void increment(int blockIndex, int value) throws IOException {
+ validateBlock(blockIndex);
+ validateValueOperand(value);
+ checkConnected();
+
+ ByteBuffer cmd = ByteBuffer.allocate(6);
+ cmd.order(ByteOrder.LITTLE_ENDIAN);
+ cmd.put( (byte) 0xC1 );
+ cmd.put( (byte) blockIndex );
+ cmd.putInt(value);
+
+ transceive(cmd.array(), false);
+ }
+
+ /**
+ * Decrement a value block, and store the result in temporary memory.
+ * @param blockIndex
+ * @throws IOException
+ */
+ public void decrement(int blockIndex, int value) throws IOException {
+ validateBlock(blockIndex);
+ validateValueOperand(value);
+ checkConnected();
+
+ ByteBuffer cmd = ByteBuffer.allocate(6);
+ cmd.order(ByteOrder.LITTLE_ENDIAN);
+ cmd.put( (byte) 0xC0 );
+ cmd.put( (byte) blockIndex );
+ cmd.putInt(value);
+
+ transceive(cmd.array(), false);
+ }
+
+ private void validateValueOperand(int value) {
+ if (value < 0) {
+ throw new IllegalArgumentException("value operand negative");
+ }
+ }
+
+ /**
+ * Copy from temporary memory to value block.
+ * @param blockIndex
+ * @throws IOException
+ */
+ public void transfer(int blockIndex) throws IOException {
+ validateBlock(blockIndex);
+ checkConnected();
+
+ byte[] cmd = { (byte) 0xB0, (byte) blockIndex };
+
+ transceive(cmd, false);
+ }
+
+ /**
+ * Copy from value block to temporary memory.
+ * @param blockIndex
+ * @throws IOException
+ */
+ public void restore(int blockIndex) throws IOException {
+ validateBlock(blockIndex);
+ checkConnected();
+
+ byte[] cmd = { (byte) 0xC2, (byte) blockIndex };
+
+ transceive(cmd, false);
+ }
+
+ /**
+ * Send raw NfcA data to a tag and receive the response.
+ * <p>
+ * This method will block until the response is received. It can be canceled
+ * with {@link #close}.
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.
+ * <p>This requires a that the tag be connected.
+ *
+ * @param data bytes to send
+ * @return bytes received in response
+ * @throws IOException if the target is lost or connection closed
+ */
+ public byte[] transceive(byte[] data) throws IOException {
+ return transceive(data, true);
+ }
+
+ private void validateSector(int sector) {
+ // Do not be too strict on upper bounds checking, since some cards
+ // have more addressable memory than they report. For example,
+ // Mifare Plus 2k cards will appear as Mifare Classic 1k cards when in
+ // Mifare Classic compatibility mode.
+ // Note that issuing a command to an out-of-bounds block is safe - the
+ // tag should report error causing IOException. This validation is a
+ // helper to guard against obvious programming mistakes.
+ if (sector < 0 || sector >= MAX_SECTOR_COUNT) {
+ throw new IndexOutOfBoundsException("sector out of bounds: " + sector);
+ }
+ }
+
+ private void validateBlock(int block) {
+ // Just looking for obvious out of bounds...
+ if (block < 0 || block >= MAX_BLOCK_COUNT) {
+ throw new IndexOutOfBoundsException("block out of bounds: " + block);
+ }
+ }
+}
diff --git a/core/java/android/nfc/technology/MifareUltralight.java b/core/java/android/nfc/tech/MifareUltralight.java
index 7103b4d..f096298 100644
--- a/core/java/android/nfc/technology/MifareUltralight.java
+++ b/core/java/android/nfc/tech/MifareUltralight.java
@@ -14,120 +14,117 @@
* limitations under the License.
*/
-package android.nfc.technology;
+package android.nfc.tech;
-import java.io.IOException;
-
-import android.nfc.NfcAdapter;
import android.nfc.Tag;
-import android.os.Bundle;
import android.os.RemoteException;
+import java.io.IOException;
+
/**
- * Concrete class for TagTechnology.MIFARE_ULTRALIGHT
+ * Technology class representing MIFARE Ultralight and MIFARE Ultralight C tags.
*
- * Mifare classic has n sectors, with varying sizes, although
- * they are at least the same pattern for any one mifare classic
- * product. Each sector has two keys. Authentication with the correct
- * key is needed before access to any sector.
+ * <p>Support for this technology type is optional. If the NFC stack doesn't support this technology
+ * MIFARE Ultralight class tags will still be scanned, but will only show the NfcA technology.
*
- * Each sector has k blocks.
- * Block size is constant across the whole mifare classic family.
+ * <p>MIFARE Ultralight class tags have a series of 4 bytes pages that can be individually written
+ * and read in chunks of 4 for a total read of 16 bytes.
*/
public final class MifareUltralight extends BasicTagTechnology {
+ /** A MIFARE Ultralight tag */
public static final int TYPE_ULTRALIGHT = 1;
+ /** A MIFARE Ultralight C tag */
public static final int TYPE_ULTRALIGHT_C = 2;
+ /** The tag type is unknown */
public static final int TYPE_UNKNOWN = 10;
private static final int NXP_MANUFACTURER_ID = 0x04;
private int mType;
- public MifareUltralight(NfcAdapter adapter, Tag tag, Bundle extras) throws RemoteException {
- super(adapter, tag, TagTechnology.MIFARE_ULTRALIGHT);
+ /**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static MifareUltralight get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) return null;
+ try {
+ return new MifareUltralight(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public MifareUltralight(Tag tag) throws RemoteException {
+ super(tag, TagTechnology.MIFARE_ULTRALIGHT);
// Check if this could actually be a Mifare
- NfcA a = (NfcA) tag.getTechnology(adapter, TagTechnology.NFC_A);
+ NfcA a = NfcA.get(tag);
mType = TYPE_UNKNOWN;
- if( a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID ) {
+ if (a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID) {
// could be UL or UL-C
mType = TYPE_ULTRALIGHT;
}
}
+ /** Returns the type of the tag */
public int getType() {
return mType;
}
// Methods that require connect()
/**
+ * Reads a single 16 byte block from the given page offset.
+ *
+ * <p>This requires a that the tag be connected.
+ *
* @throws IOException
*/
- public byte[] readBlock(int block) throws IOException {
+ public byte[] readBlock(int page) throws IOException {
checkConnected();
- byte[] blockread_cmd = { 0x30, (byte)block }; // phHal_eMifareRead
- return transceive(blockread_cmd);
+ byte[] blockread_cmd = { 0x30, (byte) page}; // phHal_eMifareRead
+ return transceive(blockread_cmd, false);
}
/**
+ * Writes a 4 byte page to the tag.
+ *
+ * <p>This requires a that the tag be connected.
+ *
+ * @param page The offset of the page to write
+ * @param data The data to write
* @throws IOException
*/
- public byte[] readOTP() throws IOException {
- checkConnected();
-
- return readBlock(3); // OTP is at page 3
- }
-
- public void writePage(int block, byte[] data) throws IOException {
+ public void writePage(int page, byte[] data) throws IOException {
checkConnected();
byte[] pagewrite_cmd = new byte[data.length + 2];
pagewrite_cmd[0] = (byte) 0xA2;
- pagewrite_cmd[1] = (byte) block;
+ pagewrite_cmd[1] = (byte) page;
System.arraycopy(data, 0, pagewrite_cmd, 2, data.length);
- transceive(pagewrite_cmd);
- }
-
- public void writeBlock(int block, byte[] data) throws IOException {
- checkConnected();
-
- byte[] blockwrite_cmd = new byte[data.length + 2];
- blockwrite_cmd[0] = (byte) 0xA0;
- blockwrite_cmd[1] = (byte) block;
- System.arraycopy(data, 0, blockwrite_cmd, 2, data.length);
-
- transceive(blockwrite_cmd);
+ transceive(pagewrite_cmd, false);
}
/**
- * Send data to a tag and receive the response.
+ * Send raw NfcA data to a tag and receive the response.
* <p>
* This method will block until the response is received. It can be canceled
* with {@link #close}.
* <p>Requires {@link android.Manifest.permission#NFC} permission.
+ * <p>This requires a that the tag be connected.
*
* @param data bytes to send
* @return bytes received in response
* @throws IOException if the target is lost or connection closed
*/
- @Override
public byte[] transceive(byte[] data) throws IOException {
- checkConnected();
-
- try {
- byte[] response = mTagService.transceive(mTag.getServiceHandle(), data, false);
- if (response == null) {
- throw new IOException("transceive failed");
- }
- return response;
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- throw new IOException("NFC service died");
- }
+ return transceive(data, true);
}
-
}
diff --git a/core/java/android/nfc/technology/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index 05872fe..c6804f9 100644
--- a/core/java/android/nfc/technology/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -14,30 +14,34 @@
* limitations under the License.
*/
-package android.nfc.technology;
+package android.nfc.tech;
import android.nfc.ErrorCodes;
import android.nfc.FormatException;
+import android.nfc.INfcTag;
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.RemoteException;
+import android.util.Log;
import java.io.IOException;
/**
* A high-level connection to a {@link Tag} using one of the NFC type 1, 2, 3, or 4 technologies
* to interact with NDEF data. MiFare Classic cards that present NDEF data may also be used
- * via this class. To determine the exact technology being used call {@link #getTechnologyId()}
+ * via this class. To determine the exact technology being used call {@link #getType()}
*
- * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}.
+ * <p>You can acquire this kind of connection with {@link #get}.
*
* <p class="note"><strong>Note:</strong>
* Use of this class requires the {@link android.Manifest.permission#NFC}
* permission.
*/
public final class Ndef extends BasicTagTechnology {
+ private static final String TAG = "NFC";
+
/** @hide */
public static final int NDEF_MODE_READ_ONLY = 1;
/** @hide */
@@ -57,14 +61,12 @@ public final class Ndef extends BasicTagTechnology {
/** @hide */
public static final String EXTRA_NDEF_TYPE = "ndeftype";
- //TODO: consider removing OTHER entirely - and not allowing Ndef to
- // enumerate for tag types outside of (NFC Forum 1-4, MifareClassic)
public static final int OTHER = -1;
public static final int NFC_FORUM_TYPE_1 = 1;
public static final int NFC_FORUM_TYPE_2 = 2;
public static final int NFC_FORUM_TYPE_3 = 3;
public static final int NFC_FORUM_TYPE_4 = 4;
- public static final int MIFARE_CLASSIC = 105;
+ public static final int MIFARE_CLASSIC = 101;
private final int mMaxNdefSize;
private final int mCardState;
@@ -72,11 +74,27 @@ public final class Ndef extends BasicTagTechnology {
private final int mNdefType;
/**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static Ndef get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.NDEF)) return null;
+ try {
+ return new Ndef(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Internal constructor, to be used by NfcAdapter
* @hide
*/
- public Ndef(NfcAdapter adapter, Tag tag, int tech, Bundle extras) throws RemoteException {
- super(adapter, tag, tech);
+ public Ndef(Tag tag) throws RemoteException {
+ super(tag, TagTechnology.NDEF);
+ Bundle extras = tag.getTechExtras(TagTechnology.NDEF);
if (extras != null) {
mMaxNdefSize = extras.getInt(EXTRA_NDEF_MAXLENGTH);
mCardState = extras.getInt(EXTRA_NDEF_CARDSTATE);
@@ -97,15 +115,6 @@ public final class Ndef extends BasicTagTechnology {
}
/**
- * Get optional extra NDEF messages.
- * Some tags may contain extra NDEF messages, but not all
- * implementations will be able to read them.
- */
- public NdefMessage[] getExtraNdefMessage() throws IOException, FormatException {
- throw new UnsupportedOperationException();
- }
-
- /**
* Get NDEF tag type.
* <p>Returns one of {@link #NFC_FORUM_TYPE_1}, {@link #NFC_FORUM_TYPE_2},
* {@link #NFC_FORUM_TYPE_3}, {@link #NFC_FORUM_TYPE_4},
@@ -148,11 +157,12 @@ public final class Ndef extends BasicTagTechnology {
checkConnected();
try {
+ INfcTag tagService = mTag.getTagService();
int serviceHandle = mTag.getServiceHandle();
- if (mTagService.isNdef(serviceHandle)) {
- NdefMessage msg = mTagService.ndefRead(serviceHandle);
+ if (tagService.isNdef(serviceHandle)) {
+ NdefMessage msg = tagService.ndefRead(serviceHandle);
if (msg == null) {
- int errorCode = mTagService.getLastError(serviceHandle);
+ int errorCode = tagService.getLastError(serviceHandle);
switch (errorCode) {
case ErrorCodes.ERROR_IO:
throw new IOException();
@@ -168,7 +178,7 @@ public final class Ndef extends BasicTagTechnology {
return null;
}
} catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
+ Log.e(TAG, "NFC service dead", e);
return null;
}
}
@@ -181,9 +191,10 @@ public final class Ndef extends BasicTagTechnology {
checkConnected();
try {
+ INfcTag tagService = mTag.getTagService();
int serviceHandle = mTag.getServiceHandle();
- if (mTagService.isNdef(serviceHandle)) {
- int errorCode = mTagService.ndefWrite(serviceHandle, msg);
+ if (tagService.isNdef(serviceHandle)) {
+ int errorCode = tagService.ndefWrite(serviceHandle, msg);
switch (errorCode) {
case ErrorCodes.SUCCESS:
break;
@@ -200,67 +211,54 @@ public final class Ndef extends BasicTagTechnology {
throw new IOException("Tag is not ndef");
}
} catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
+ Log.e(TAG, "NFC service dead", e);
}
}
/**
- * Attempt to write extra NDEF messages.
- * Implementations may be able to write extra NDEF
- * message after the first primary message, but it is not
- * guaranteed. Even if it can be written, other implementations
- * may not be able to read NDEF messages after the primary message.
- * It is recommended to use additional NDEF records instead.
- *
- * @throws IOException
+ * Indicates whether a tag can be made read-only with
+ * {@link #makeReadonly()}
*/
- public void writeExtraNdefMessage(int i, NdefMessage msg) throws IOException, FormatException {
- checkConnected();
-
- throw new UnsupportedOperationException();
+ public boolean canMakeReadonly() {
+ if (mNdefType == NFC_FORUM_TYPE_1 || mNdefType == NFC_FORUM_TYPE_2) {
+ return true;
+ } else {
+ return false;
+ }
}
/**
- * Set the CC field to indicate this tag is read-only
+ * Sets the CC field to indicate this tag is read-only
+ * and permanently sets the lock bits to prevent any further NDEF
+ * modifications.
+ * This is a one-way process and can not be reverted!
* @throws IOException
*/
public boolean makeReadonly() throws IOException {
checkConnected();
try {
- int errorCode = mTagService.ndefMakeReadOnly(mTag.getServiceHandle());
- switch (errorCode) {
- case ErrorCodes.SUCCESS:
- return true;
- case ErrorCodes.ERROR_IO:
- throw new IOException();
- case ErrorCodes.ERROR_INVALID_PARAM:
- return false;
- default:
- // Should not happen
- throw new IOException();
- }
+ INfcTag tagService = mTag.getTagService();
+ if (tagService.isNdef(mTag.getServiceHandle())) {
+ int errorCode = tagService.ndefMakeReadOnly(mTag.getServiceHandle());
+ switch (errorCode) {
+ case ErrorCodes.SUCCESS:
+ return true;
+ case ErrorCodes.ERROR_IO:
+ throw new IOException();
+ case ErrorCodes.ERROR_INVALID_PARAM:
+ return false;
+ default:
+ // Should not happen
+ throw new IOException();
+ }
+ }
+ else {
+ throw new IOException("Tag is not ndef");
+ }
} catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
+ Log.e(TAG, "NFC service dead", e);
return false;
}
}
-
- /**
- * Attempt to use tag specific technology to really make
- * the tag read-only
- * For NFC Forum Type 1 and 2 only.
- */
- public void makeLowLevelReadonly() {
- checkConnected();
-
- throw new UnsupportedOperationException();
- }
-
- @Override
- public byte[] transceive(byte[] data) {
- checkConnected();
-
- throw new UnsupportedOperationException();
- }
}
diff --git a/core/java/android/nfc/technology/NdefFormatable.java b/core/java/android/nfc/tech/NdefFormatable.java
index 222c558..2919c43 100644
--- a/core/java/android/nfc/technology/NdefFormatable.java
+++ b/core/java/android/nfc/tech/NdefFormatable.java
@@ -14,34 +14,52 @@
* limitations under the License.
*/
-package android.nfc.technology;
+package android.nfc.tech;
import android.nfc.ErrorCodes;
import android.nfc.FormatException;
+import android.nfc.INfcTag;
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
-import android.os.Bundle;
import android.os.RemoteException;
+import android.util.Log;
import java.io.IOException;
/**
* An interface to a {@link Tag} allowing to format the tag as NDEF.
*
- * <p>You can acquire this kind of interface with {@link Tag#getTechnology(int)}.
+ * <p>You can acquire this kind of connection with {@link #get}.
*
* <p class="note"><strong>Note:</strong>
* Use of this class requires the {@link android.Manifest.permission#NFC}
* permission.
*/
public final class NdefFormatable extends BasicTagTechnology {
+ private static final String TAG = "NFC";
+
+ /**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static NdefFormatable get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null;
+ try {
+ return new NdefFormatable(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
/**
* Internal constructor, to be used by NfcAdapter
* @hide
*/
- public NdefFormatable(NfcAdapter adapter, Tag tag, int tech, Bundle extras) throws RemoteException {
- super(adapter, tag, tech);
+ public NdefFormatable(Tag tag) throws RemoteException {
+ super(tag, TagTechnology.NDEF_FORMATABLE);
}
/**
@@ -52,10 +70,9 @@ public final class NdefFormatable extends BasicTagTechnology {
checkConnected();
try {
- byte[] DEFAULT_KEY = {(byte)0xFF,(byte)0xFF,(byte)0xFF,
- (byte)0xFF,(byte)0xFF,(byte)0xFF};
int serviceHandle = mTag.getServiceHandle();
- int errorCode = mTagService.formatNdef(serviceHandle, DEFAULT_KEY);
+ INfcTag tagService = mTag.getTagService();
+ int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT);
switch (errorCode) {
case ErrorCodes.SUCCESS:
break;
@@ -68,8 +85,8 @@ public final class NdefFormatable extends BasicTagTechnology {
throw new IOException();
}
// Now check and see if the format worked
- if (mTagService.isNdef(serviceHandle)) {
- errorCode = mTagService.ndefWrite(serviceHandle, firstMessage);
+ if (tagService.isNdef(serviceHandle)) {
+ errorCode = tagService.ndefWrite(serviceHandle, firstMessage);
switch (errorCode) {
case ErrorCodes.SUCCESS:
break;
@@ -85,14 +102,7 @@ public final class NdefFormatable extends BasicTagTechnology {
throw new IOException();
}
} catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
+ Log.e(TAG, "NFC service dead", e);
}
}
-
- @Override
- public byte[] transceive(byte[] data) {
- checkConnected();
-
- throw new UnsupportedOperationException();
- }
}
diff --git a/core/java/android/nfc/technology/NfcA.java b/core/java/android/nfc/tech/NfcA.java
index ef46762..24badc4 100644
--- a/core/java/android/nfc/technology/NfcA.java
+++ b/core/java/android/nfc/tech/NfcA.java
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-package android.nfc.technology;
+package android.nfc.tech;
-import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.RemoteException;
+import java.io.IOException;
+
/**
* A low-level connection to a {@link Tag} using the NFC-A technology, also known as
* ISO1443-3A.
*
- * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}.
+ * <p>You can acquire this kind of connection with {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}.
*
* <p>Applications must implement their own protocol stack on top of
@@ -44,8 +45,25 @@ public final class NfcA extends BasicTagTechnology {
private short mSak;
private byte[] mAtqa;
- public NfcA(NfcAdapter adapter, Tag tag, Bundle extras) throws RemoteException {
- super(adapter, tag, TagTechnology.NFC_A);
+ /**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static NfcA get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.NFC_A)) return null;
+ try {
+ return new NfcA(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public NfcA(Tag tag) throws RemoteException {
+ super(tag, TagTechnology.NFC_A);
+ Bundle extras = tag.getTechExtras(TagTechnology.NFC_A);
mSak = extras.getShort(EXTRA_SAK);
mAtqa = extras.getByteArray(EXTRA_ATQA);
}
@@ -63,4 +81,19 @@ public final class NfcA extends BasicTagTechnology {
public short getSak() {
return mSak;
}
+
+ /**
+ * Send data to a tag and receive the response.
+ * <p>
+ * This method will block until the response is received. It can be canceled
+ * with {@link #close}.
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.
+ *
+ * @param data bytes to send
+ * @return bytes received in response
+ * @throws IOException if the target is lost or connection closed
+ */
+ public byte[] transceive(byte[] data) throws IOException {
+ return transceive(data, true);
+ }
}
diff --git a/core/java/android/nfc/technology/NfcB.java b/core/java/android/nfc/tech/NfcB.java
index 267c94d..abeef32 100644
--- a/core/java/android/nfc/technology/NfcB.java
+++ b/core/java/android/nfc/tech/NfcB.java
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-package android.nfc.technology;
+package android.nfc.tech;
-import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.RemoteException;
+import java.io.IOException;
+
/**
* A low-level connection to a {@link Tag} using the NFC-B technology, also known as
* ISO1443-3B.
*
- * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}.
+ * <p>You can acquire this kind of connection with {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}.
*
* <p>Applications must implement their own protocol stack on top of
@@ -44,9 +45,25 @@ public final class NfcB extends BasicTagTechnology {
private byte[] mAppData;
private byte[] mProtInfo;
- public NfcB(NfcAdapter adapter, Tag tag, Bundle extras)
- throws RemoteException {
- super(adapter, tag, TagTechnology.NFC_B);
+ /**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static NfcB get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.NFC_B)) return null;
+ try {
+ return new NfcB(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public NfcB(Tag tag) throws RemoteException {
+ super(tag, TagTechnology.NFC_B);
+ Bundle extras = tag.getTechExtras(TagTechnology.NFC_B);
mAppData = extras.getByteArray(EXTRA_APPDATA);
mProtInfo = extras.getByteArray(EXTRA_PROTINFO);
}
@@ -67,4 +84,18 @@ public final class NfcB extends BasicTagTechnology {
return mProtInfo;
}
+ /**
+ * Send data to a tag and receive the response.
+ * <p>
+ * This method will block until the response is received. It can be canceled
+ * with {@link #close}.
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.
+ *
+ * @param data bytes to send
+ * @return bytes received in response
+ * @throws IOException if the target is lost or connection closed
+ */
+ public byte[] transceive(byte[] data) throws IOException {
+ return transceive(data, true);
+ }
}
diff --git a/core/java/android/nfc/technology/NfcF.java b/core/java/android/nfc/tech/NfcF.java
index 6741ac8..f617739 100644
--- a/core/java/android/nfc/technology/NfcF.java
+++ b/core/java/android/nfc/tech/NfcF.java
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-package android.nfc.technology;
+package android.nfc.tech;
-import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.RemoteException;
+import java.io.IOException;
+
/**
* A low-level connection to a {@link Tag} using the NFC-F technology, also known as
* JIS6319-4.
*
- * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}.
+ * <p>You can acquire this kind of connection with {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}.
*
* <p>Applications must implement their own protocol stack on top of
@@ -44,9 +45,25 @@ public final class NfcF extends BasicTagTechnology {
private byte[] mSystemCode = null;
private byte[] mManufacturer = null;
- public NfcF(NfcAdapter adapter, Tag tag, Bundle extras)
- throws RemoteException {
- super(adapter, tag, TagTechnology.NFC_F);
+ /**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static NfcF get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.NFC_F)) return null;
+ try {
+ return new NfcF(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public NfcF(Tag tag) throws RemoteException {
+ super(tag, TagTechnology.NFC_F);
+ Bundle extras = tag.getTechExtras(TagTechnology.NFC_F);
if (extras != null) {
mSystemCode = extras.getByteArray(EXTRA_SC);
mManufacturer = extras.getByteArray(EXTRA_PMM);
@@ -60,4 +77,19 @@ public final class NfcF extends BasicTagTechnology {
public byte[] getManufacturer() {
return mManufacturer;
}
+
+ /**
+ * Send data to a tag and receive the response.
+ * <p>
+ * This method will block until the response is received. It can be canceled
+ * with {@link #close}.
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.
+ *
+ * @param data bytes to send
+ * @return bytes received in response
+ * @throws IOException if the target is lost or connection closed
+ */
+ public byte[] transceive(byte[] data) throws IOException {
+ return transceive(data, true);
+ }
}
diff --git a/core/java/android/nfc/technology/NfcV.java b/core/java/android/nfc/tech/NfcV.java
index 460de6a..8e1f066 100644
--- a/core/java/android/nfc/technology/NfcV.java
+++ b/core/java/android/nfc/tech/NfcV.java
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-package android.nfc.technology;
+package android.nfc.tech;
-import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.os.Bundle;
import android.os.RemoteException;
+import java.io.IOException;
+
/**
- * A low-level connection to a {@link Tag} using the NFC-V technology, also known as
+ * A low-level connection to a {@link Tag} using NFC vicinity technology, also known as
* ISO15693.
*
- * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}.
+ * <p>You can acquire this kind of connection with {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}.
*
* <p>Applications must implement their own protocol stack on top of
@@ -45,9 +46,25 @@ public final class NfcV extends BasicTagTechnology {
private byte mRespFlags;
private byte mDsfId;
- public NfcV(NfcAdapter adapter, Tag tag, Bundle extras)
- throws RemoteException {
- super(adapter, tag, TagTechnology.NFC_V);
+ /**
+ * Returns an instance of this tech for the given tag. If the tag doesn't support
+ * this tech type null is returned.
+ *
+ * @param tag The tag to get the tech from
+ */
+ public static NfcV get(Tag tag) {
+ if (!tag.hasTech(TagTechnology.NFC_V)) return null;
+ try {
+ return new NfcV(tag);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public NfcV(Tag tag) throws RemoteException {
+ super(tag, TagTechnology.NFC_V);
+ Bundle extras = tag.getTechExtras(TagTechnology.NFC_V);
mRespFlags = extras.getByte(EXTRA_RESP_FLAGS);
mDsfId = extras.getByte(EXTRA_DSFID);
}
@@ -59,4 +76,19 @@ public final class NfcV extends BasicTagTechnology {
public byte getDsfId() {
return mDsfId;
}
+
+ /**
+ * Send data to a tag and receive the response.
+ * <p>
+ * This method will block until the response is received. It can be canceled
+ * with {@link #close}.
+ * <p>Requires {@link android.Manifest.permission#NFC} permission.
+ *
+ * @param data bytes to send
+ * @return bytes received in response
+ * @throws IOException if the target is lost or connection closed
+ */
+ public byte[] transceive(byte[] data) throws IOException {
+ return transceive(data, true);
+ }
}
diff --git a/core/java/android/nfc/tech/TagTechnology.java b/core/java/android/nfc/tech/TagTechnology.java
new file mode 100644
index 0000000..aebb3e8
--- /dev/null
+++ b/core/java/android/nfc/tech/TagTechnology.java
@@ -0,0 +1,139 @@
+/*
+ * 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.tech;
+
+import android.nfc.Tag;
+
+import java.io.IOException;
+
+public interface TagTechnology {
+ /**
+ * This technology is an instance of {@link NfcA}.
+ * <p>Support for this technology type is mandatory.
+ * @hide
+ */
+ public static final int NFC_A = 1;
+
+ /**
+ * This technology is an instance of {@link NfcB}.
+ * <p>Support for this technology type is mandatory.
+ * @hide
+ */
+ public static final int NFC_B = 2;
+
+ /**
+ * This technology is an instance of {@link IsoDep}.
+ * <p>Support for this technology type is mandatory.
+ * @hide
+ */
+ public static final int ISO_DEP = 3;
+
+ /**
+ * This technology is an instance of {@link NfcF}.
+ * <p>Support for this technology type is mandatory.
+ * @hide
+ */
+ public static final int NFC_F = 4;
+
+ /**
+ * This technology is an instance of {@link NfcV}.
+ * <p>Support for this technology type is mandatory.
+ * @hide
+ */
+ public static final int NFC_V = 5;
+
+ /**
+ * This technology is an instance of {@link Ndef}.
+ * <p>Support for this technology type is mandatory.
+ * @hide
+ */
+ public static final int NDEF = 6;
+
+ /**
+ * This technology is an instance of {@link NdefFormatable}.
+ * <p>Support for this technology type is mandatory.
+ * @hide
+ */
+ public static final int NDEF_FORMATABLE = 7;
+
+ /**
+ * This technology is an instance of {@link MifareClassic}.
+ * <p>Support for this technology type is optional. If a stack doesn't support this technology
+ * type tags using it must still be discovered and present the lower level radio interface
+ * technologies in use.
+ * @hide
+ */
+ public static final int MIFARE_CLASSIC = 8;
+
+ /**
+ * This technology is an instance of {@link MifareUltralight}.
+ * <p>Support for this technology type is optional. If a stack doesn't support this technology
+ * type tags using it must still be discovered and present the lower level radio interface
+ * technologies in use.
+ * @hide
+ */
+ public static final int MIFARE_ULTRALIGHT = 9;
+
+ /**
+ * Get the {@link Tag} object this technology came from.
+ */
+ public Tag getTag();
+
+ /**
+ * Opens a connection to the {@link Tag} enabling interactive commands. The command set
+ * varies by the technology type.
+ *
+ * <p>This method blocks until the connection has been established.
+ *
+ * <p>A call to {@link #close} from another thread will cancel a blocked call and cause an
+ * IOException to be thrown on the thread that is blocked.
+ *
+ * @see #reconnect()
+ * @see #close()
+ * @throws IOException if the target is lost, or connect canceled
+ */
+ public void connect() throws IOException;
+
+ /**
+ * Re-connect to the {@link Tag} associated with this connection. Reconnecting to a tag can be
+ * used to reset the state of the tag itself.
+ *
+ * <p>This method blocks until the connection is re-established.
+ *
+ * <p>A call to {@link #close} from another thread will cancel a blocked call and cause an
+ * IOException to be thrown on the thread that is blocked.
+ *
+ * @see #connect()
+ * @see #close()
+ * @throws IOException
+ */
+ public void reconnect() throws IOException;
+
+ /**
+ * Closes the connection to the {@link Tag}. This call is non-blocking and causes all blocking
+ * operations such as {@link #connect} to be canceled and immediately throw
+ * {@link java.io.IOException} on the thread that is blocked.
+ *
+ * <p>
+ * Once this method is called, this object cannot be re-used and should be discarded. Further
+ * calls to {@link #connect} will fail.
+ *
+ * @see #connect()
+ * @see #reconnect()
+ */
+ public void close();
+}
diff --git a/core/java/android/nfc/technology/BasicTagTechnology.java b/core/java/android/nfc/technology/BasicTagTechnology.java
deleted file mode 100644
index 553f6ec..0000000
--- a/core/java/android/nfc/technology/BasicTagTechnology.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * 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.technology;
-
-import java.io.IOException;
-
-import android.nfc.INfcAdapter;
-import android.nfc.INfcTag;
-import android.nfc.NfcAdapter;
-import android.nfc.Tag;
-import android.nfc.ErrorCodes;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * A base class for tag technologies that are built on top of transceive().
- */
-/* package */ abstract class BasicTagTechnology implements TagTechnology {
-
- /*package*/ final Tag mTag;
- /*package*/ boolean mIsConnected;
- /*package*/ int mSelectedTechnology;
- private final NfcAdapter mAdapter;
-
- // Following fields are final after construction, except for
- // during attemptDeadServiceRecovery() when NFC crashes.
- // Not locked - we accept a best effort attempt when NFC crashes.
- /*package*/ INfcAdapter mService;
- /*package*/ INfcTag mTagService;
-
- private static final String TAG = "NFC";
-
- /**
- * @hide
- */
- public BasicTagTechnology(NfcAdapter adapter, Tag tag, int tech) throws RemoteException {
- int[] techList = tag.getTechnologyList();
- int i;
-
- // Check target validity
- for (i = 0; i < techList.length; i++) {
- if (tech == techList[i]) {
- break;
- }
- }
- if (i >= techList.length) {
- // Technology not found
- throw new IllegalArgumentException("Technology " + tech + " not present on tag " + tag);
- }
-
- mAdapter = adapter;
- mService = mAdapter.getService();
- try {
- mTagService = mService.getNfcTagInterface();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- }
- mTag = tag;
- mSelectedTechnology = tech;
- }
-
- /**
- * @hide
- */
- public BasicTagTechnology(NfcAdapter adapter, Tag tag) throws RemoteException {
- this(adapter, tag, tag.getTechnologyList()[0]);
- }
-
- /** NFC service dead - attempt best effort recovery */
- /*package*/ void attemptDeadServiceRecovery(Exception e) {
- mAdapter.attemptDeadServiceRecovery(e);
- /* assigning to mService is not thread-safe, but this is best-effort code
- * and on a well-behaved system should never happen */
- mService = mAdapter.getService();
- try {
- mTagService = mService.getNfcTagInterface();
- } catch (RemoteException e2) {
- Log.e(TAG, "second RemoteException trying to recover from dead NFC service", e2);
- }
- }
-
- /**
- * Get the {@link Tag} this connection is associated with.
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- */
- @Override
- public Tag getTag() {
- return mTag;
- }
-
- public void checkConnected() {
- if ((mTag.getConnectedTechnology() != getTechnologyId()) ||
- (mTag.getConnectedTechnology() == -1)) {
- throw new IllegalStateException("Call connect() first!");
- }
- }
-
- /**
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- */
- @Override
- public int getTechnologyId() {
- return mSelectedTechnology;
- }
-
- /**
- * Helper to indicate if {@link #transceive transceive()} calls might succeed.
- * <p>
- * Does not cause RF activity, and does not block.
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- * @return true if {@link #connect} has completed successfully and the {@link Tag} is believed
- * to be within range. Applications must still handle {@link java.io.IOException}
- * while using {@link #transceive transceive()}, in case connection is lost after this method
- * returns true.
- */
- public boolean isConnected() {
- if (!mIsConnected) {
- return false;
- }
-
- try {
- return mTagService.isPresent(mTag.getServiceHandle());
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- return false;
- }
- }
-
- /**
- * Connect to the {@link Tag} associated with this connection.
- * <p>
- * This method blocks until the connection is established.
- * <p>
- * {@link #close} can be called from another thread to cancel this connection
- * attempt.
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- * @throws IOException if the target is lost, or connect canceled
- */
- @Override
- public void connect() throws IOException {
- try {
- int errorCode = mTagService.connect(mTag.getServiceHandle(), getTechnologyId());
-
- if (errorCode == ErrorCodes.SUCCESS) {
- // Store this in the tag object
- mTag.setConnectedTechnology(getTechnologyId());
- mIsConnected = true;
- } else {
- throw new IOException();
- }
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- throw new IOException("NFC service died");
- }
- }
-
- /**
- * Re-connect to the {@link Tag} associated with this connection.
- * <p>
- * Reconnecting to a tag can be used to reset the state of the tag itself.
- * This method blocks until the connection is re-established.
- * <p>
- * {@link #close} can be called from another thread to cancel this connection
- * attempt.
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- * @throws IOException if the target is lost, or connect canceled
- */
- @Override
- public void reconnect() throws IOException {
- if (!mIsConnected) {
- throw new IllegalStateException("Technology not connected yet");
- } else {
- try {
- int errorCode = mTagService.reconnect(mTag.getServiceHandle());
-
- if (errorCode != ErrorCodes.SUCCESS) {
- mIsConnected = false;
- mTag.setTechnologyDisconnected();
- throw new IOException();
- }
- } catch (RemoteException e) {
- mIsConnected = false;
- mTag.setTechnologyDisconnected();
- attemptDeadServiceRecovery(e);
- throw new IOException("NFC service died");
- }
- }
- }
-
- /**
- * Close this connection.
- * <p>
- * Causes blocking operations such as {@link #transceive transceive()} or {@link #connect} to
- * be canceled and immediately throw {@link java.io.IOException}.
- * <p>
- * Once this method is called, this object cannot be re-used and should be discarded. Further
- * calls to {@link #transceive transceive()} or {@link #connect} will fail.
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- */
- @Override
- public void close() {
- try {
- /* Note that we don't want to physically disconnect the tag,
- * but just reconnect to it to reset its state
- */
- mTagService.reconnect(mTag.getServiceHandle());
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- } finally {
- mIsConnected = false;
- mTag.setTechnologyDisconnected();
- }
- }
-
- /**
- * Send data to a tag and receive the response.
- * <p>
- * This method will block until the response is received. It can be canceled
- * with {@link #close}.
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- *
- * @param data bytes to send
- * @return bytes received in response
- * @throws IOException if the target is lost or connection closed
- */
- public byte[] transceive(byte[] data) throws IOException {
- checkConnected();
-
- try {
- byte[] response = mTagService.transceive(mTag.getServiceHandle(), data, true);
- if (response == null) {
- throw new IOException("transceive failed");
- }
- return response;
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- throw new IOException("NFC service died");
- }
- }
-}
diff --git a/core/java/android/nfc/technology/IsoDep.java b/core/java/android/nfc/technology/IsoDep.java
deleted file mode 100644
index 32a7542..0000000
--- a/core/java/android/nfc/technology/IsoDep.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.technology;
-
-import android.nfc.NfcAdapter;
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import java.io.IOException;
-
-/**
- * A low-level connection to a {@link Tag} using the ISO-DEP technology, also known as
- * ISO1443-4.
- *
- * <p>You can acquire this kind of connection with {@link Tag#getTechnology(int)}.
- * Use this class to send and receive data with {@link #transceive transceive()}.
- *
- * <p>Applications must implement their own protocol stack on top of
- * {@link #transceive transceive()}.
- *
- * <p class="note"><strong>Note:</strong>
- * Use of this class requires the {@link android.Manifest.permission#NFC}
- * permission.
- */
-public final class IsoDep extends BasicTagTechnology {
- /** @hide */
- public static final String EXTRA_HI_LAYER_RESP = "hiresp";
- /** @hide */
- public static final String EXTRA_HIST_BYTES = "histbytes";
-
- private byte[] mHiLayerResponse = null;
- private byte[] mHistBytes = null;
-
- public IsoDep(NfcAdapter adapter, Tag tag, Bundle extras)
- throws RemoteException {
- super(adapter, tag, TagTechnology.ISO_DEP);
- if (extras != null) {
- mHiLayerResponse = extras.getByteArray(EXTRA_HI_LAYER_RESP);
- mHistBytes = extras.getByteArray(EXTRA_HIST_BYTES);
- }
- }
-
- /**
- * 3A only
- */
- public byte[] getHistoricalBytes() { return mHistBytes; }
-
- /**
- * 3B only
- */
- public byte[] getHiLayerResponse() { return mHiLayerResponse; }
-}
diff --git a/core/java/android/nfc/technology/MifareClassic.java b/core/java/android/nfc/technology/MifareClassic.java
deleted file mode 100644
index 799f0a7..0000000
--- a/core/java/android/nfc/technology/MifareClassic.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * 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.technology;
-
-import android.nfc.NfcAdapter;
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import java.io.IOException;
-
-/**
- * Concrete class for TagTechnology.MIFARE_CLASSIC
- *
- * Mifare classic has n sectors, with varying sizes, although
- * they are at least the same pattern for any one mifare classic
- * product. Each sector has two keys. Authentication with the correct
- * key is needed before access to any sector.
- *
- * Each sector has k blocks.
- * Block size is constant across the whole mifare classic family.
- */
-public final class MifareClassic extends BasicTagTechnology {
- /**
- * The well-known, default MIFARE read key.
- * Use this key to effectively make the payload in this sector
- * public.
- */
- public static final byte[] KEY_DEFAULT =
- {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
- /**
- * The well-known, default Mifare Application Directory read key.
- */
- public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY =
- {(byte)0xA0,(byte)0xA1,(byte)0xA2,(byte)0xA3,(byte)0xA4,(byte)0xA5};
- /**
- * The well-known, default read key for NDEF data on a Mifare Classic
- */
- public static final byte[] KEY_NFC_FORUM =
- {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7};
-
- public static final int TYPE_CLASSIC = 0;
- public static final int TYPE_PLUS = 1;
- public static final int TYPE_PRO = 2;
- public static final int TYPE_DESFIRE = 3;
- public static final int TYPE_ULTRALIGHT = 4;
- public static final int TYPE_UNKNOWN = 5;
-
- public static final int SIZE_1K = 1024;
- public static final int SIZE_2K = 2048;
- public static final int SIZE_4K = 4096;
- public static final int SIZE_MINI = 320;
- public static final int SIZE_UNKNOWN = 0;
-
- private boolean mIsEmulated;
- private int mType;
- private int mSize;
-
- public MifareClassic(NfcAdapter adapter, Tag tag, Bundle extras) throws RemoteException {
- super(adapter, tag, TagTechnology.MIFARE_CLASSIC);
-
- // Check if this could actually be a Mifare
- NfcA a = (NfcA) tag.getTechnology(adapter, TagTechnology.NFC_A);
- //short[] ATQA = getATQA(tag);
-
- mIsEmulated = false;
- mType = TYPE_UNKNOWN;
- mSize = SIZE_UNKNOWN;
-
- switch (a.getSak()) {
- case 0x00:
- // could be UL or UL-C
- mType = TYPE_ULTRALIGHT;
- break;
- case 0x08:
- // Type == classic
- // Size = 1K
- mType = TYPE_CLASSIC;
- mSize = SIZE_1K;
- break;
- case 0x09:
- // Type == classic mini
- // Size == ?
- mType = TYPE_CLASSIC;
- mSize = SIZE_MINI;
- break;
- case 0x10:
- // Type == MF+
- // Size == 2K
- // SecLevel = SL2
- mType = TYPE_PLUS;
- mSize = SIZE_2K;
- break;
- case 0x11:
- // Type == MF+
- // Size == 4K
- // Seclevel = SL2
- mType = TYPE_PLUS;
- mSize = SIZE_4K;
- break;
- case 0x18:
- // Type == classic
- // Size == 4k
- mType = TYPE_CLASSIC;
- mSize = SIZE_4K;
- break;
- case 0x20:
- // TODO this really should be a short, not byte
- if (a.getAtqa()[0] == 0x03) {
- // Type == DESFIRE
- mType = TYPE_DESFIRE;
- } else {
- // Type == MF+
- // SL = SL3
- mType = TYPE_PLUS;
- mSize = SIZE_UNKNOWN;
- }
- break;
- case 0x28:
- // Type == MF Classic
- // Size == 1K
- // Emulated == true
- mType = TYPE_CLASSIC;
- mSize = SIZE_1K;
- mIsEmulated = true;
- break;
- case 0x38:
- // Type == MF Classic
- // Size == 4K
- // Emulated == true
- mType = TYPE_CLASSIC;
- mSize = SIZE_4K;
- mIsEmulated = true;
- break;
- case 0x88:
- // Type == MF Classic
- // Size == 1K
- // NXP-tag: false
- mType = TYPE_CLASSIC;
- mSize = SIZE_1K;
- break;
- case 0x98:
- case 0xB8:
- // Type == MF Pro
- // Size == 4K
- mType = TYPE_PRO;
- mSize = SIZE_4K;
- break;
- default:
- // Unknown mifare
- mType = TYPE_UNKNOWN;
- mSize = SIZE_UNKNOWN;
- break;
- }
- }
-
- // Immutable data known at discovery time
- public int getSize() {
- return mSize;
- }
-
- public int getType() {
- return mType;
- }
-
- public boolean isEmulated() {
- return mIsEmulated;
- }
-
- public int getSectorCount() {
- switch (mSize) {
- case SIZE_1K: {
- return 16;
- }
- case SIZE_2K: {
- return 32;
- }
- case SIZE_4K: {
- return 40;
- }
- case SIZE_MINI: {
- return 5;
- }
- default: {
- return 0;
- }
- }
- }
-
- public int getSectorSize(int sector) {
- return getBlockCount(sector) * 16;
- }
-
- public int getTotalBlockCount() {
- int totalBlocks = 0;
- for (int sec = 0; sec < getSectorCount(); sec++) {
- totalBlocks += getSectorSize(sec);
- }
-
- return totalBlocks;
- }
-
- public int getBlockCount(int sector) {
- if (sector >= getSectorCount()) {
- throw new IllegalArgumentException("this card only has " + getSectorCount() +
- " sectors");
- }
-
- if (sector <= 32) {
- return 4;
- } else {
- return 16;
- }
- }
-
- private byte firstBlockInSector(int sector) {
- if (sector < 32) {
- return (byte) ((sector * 4) & 0xff);
- } else {
- return (byte) ((32 * 4 + ((sector - 32) * 16)) & 0xff);
- }
- }
-
- // Methods that require connect()
- /**
- * Authenticate for a given block.
- * Note that this will authenticate the entire sector the block belongs to.
- */
- public boolean authenticateBlock(int block, byte[] key, boolean keyA) {
- checkConnected();
-
- byte[] cmd = new byte[12];
-
- // First byte is the command
- if (keyA) {
- cmd[0] = 0x60; // phHal_eMifareAuthentA
- } else {
- cmd[0] = 0x61; // phHal_eMifareAuthentB
- }
-
- // Second byte is block address
- cmd[1] = (byte) block;
-
- // Next 4 bytes are last 4 bytes of UID
- byte[] uid = getTag().getId();
- System.arraycopy(uid, uid.length - 4, cmd, 2, 4);
-
- // Next 6 bytes are key
- System.arraycopy(key, 0, cmd, 6, 6);
-
- try {
- if ((transceive(cmd) != null)) {
- return true;
- }
- } catch (IOException e) {
- // No need to deal with, will return false anyway
- }
- return false;
- }
-
- /**
- * Authenticate for a given sector.
- */
- public boolean authenticateSector(int sector, byte[] key, boolean keyA) {
- checkConnected();
-
- byte addr = (byte) ((firstBlockInSector(sector)) & 0xff);
-
- // Note that authenticating a block of a sector, will authenticate
- // the entire sector.
- return authenticateBlock(addr, key, keyA);
- }
-
- /**
- * Sector indexing starts at 0.
- * Block indexing starts at 0, and resets in each sector.
- * @throws IOException
- */
- public byte[] readBlock(int sector, int block) throws IOException {
- checkConnected();
-
- byte addr = (byte) ((firstBlockInSector(sector) + block) & 0xff);
- return readBlock(addr);
-
- }
-
- /**
- * Reads absolute block index.
- * @throws IOException
- */
- public byte[] readBlock(int block) throws IOException {
- checkConnected();
-
- byte addr = (byte) block;
- byte[] blockread_cmd = { 0x30, addr };
-
- return transceive(blockread_cmd);
- }
-
- /**
- * Writes absolute block index.
- * @throws IOException
- */
- public void writeBlock(int block, byte[] data) throws IOException {
- checkConnected();
-
- byte addr = (byte) block;
- byte[] blockwrite_cmd = new byte[data.length + 2];
- blockwrite_cmd[0] = (byte) 0xA0; // MF write command
- blockwrite_cmd[1] = addr;
- System.arraycopy(data, 0, blockwrite_cmd, 2, data.length);
-
- transceive(blockwrite_cmd);
- }
-
- /**
- * Writes relative block in sector.
- * @throws IOException
- */
- public void writeBlock(int sector, int block, byte[] data) throws IOException {
- checkConnected();
-
- byte addr = (byte) ((firstBlockInSector(sector) + block) & 0xff);
-
- writeBlock(addr, data);
- }
-
- public void increment(int block) throws IOException {
- checkConnected();
-
- byte addr = (byte) block;
- byte[] incr_cmd = { (byte) 0xC1, (byte) block };
-
- transceive(incr_cmd);
- }
-
- public void decrement(int block) throws IOException {
- checkConnected();
-
- byte addr = (byte) block;
- byte[] decr_cmd = { (byte) 0xC0, (byte) block };
-
- transceive(decr_cmd);
- }
-
- public void transfer(int block) throws IOException {
- checkConnected();
-
- byte addr = (byte) block;
- byte[] trans_cmd = { (byte) 0xB0, (byte) block };
-
- transceive(trans_cmd);
- }
-
- public void restore(int block) throws IOException {
- checkConnected();
-
- byte addr = (byte) block;
- byte[] rest_cmd = { (byte) 0xC2, (byte) block };
-
- transceive(rest_cmd);
- }
-
- /**
- * Send data to a tag and receive the response.
- * <p>
- * This method will block until the response is received. It can be canceled
- * with {@link #close}.
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- *
- * @param data bytes to send
- * @return bytes received in response
- * @throws IOException if the target is lost or connection closed
- */
- @Override
- public byte[] transceive(byte[] data) throws IOException {
- checkConnected();
-
- try {
- byte[] response = mTagService.transceive(mTag.getServiceHandle(), data, false);
- if (response == null) {
- throw new IOException("transceive failed");
- }
- return response;
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- throw new IOException("NFC service died");
- }
- }
-}
diff --git a/core/java/android/nfc/technology/TagTechnology.java b/core/java/android/nfc/technology/TagTechnology.java
deleted file mode 100644
index 62216c1..0000000
--- a/core/java/android/nfc/technology/TagTechnology.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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.technology;
-
-import android.nfc.Tag;
-
-import java.io.IOException;
-
-public interface TagTechnology {
- /**
- * This object is an instance of {@link NfcA}
- */
- public static final int NFC_A = 1;
-
- /**
- * This object is an instance of {@link NfcB}
- */
- public static final int NFC_B = 2;
-
- /**
- * This object is an instance of {@link IsoDep}
- */
- public static final int ISO_DEP = 3;
-
- /**
- * This object is an instance of {@link NfcF}
- */
- public static final int NFC_F = 4;
-
- /**
- * This object is an instance of {@link NfcV}
- */
- public static final int NFC_V = 5;
-
- /**
- * This object is an instance of {@link Ndef}
- */
- public static final int NDEF = 6;
-
- /**
- * This object is an instance of {@link NdefFormatable}
- */
- public static final int NDEF_FORMATABLE = 7;
-
- /**
- * This object is an instance of {@link MifareClassic}
- */
- public static final int MIFARE_CLASSIC = 8;
-
- /**
- * This object is an instance of {@link MifareUltralight}
- */
- public static final int MIFARE_ULTRALIGHT = 9;
-
- /**
- * Returns the technology type for this tag connection.
- */
- public int getTechnologyId();
-
- /**
- * Get the backing tag object.
- */
- public Tag getTag();
-
- /**
- * @throws IOException
- */
- public void connect() throws IOException;
-
- /**
- * @throws IOException
- */
- public void reconnect() throws IOException;
-
- /**
- * Non-blocking. Immediately causes all blocking calls
- * to throw IOException.
- */
- public void close();
-}
diff --git a/core/java/android/nfc/technology/package.html b/core/java/android/nfc/technology/package.html
deleted file mode 100644
index 26b8a32..0000000
--- a/core/java/android/nfc/technology/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-{@hide}
-</BODY>
-</HTML> \ No newline at end of file
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index eb941e4..557e53f 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -96,9 +96,9 @@ public final class Message implements Parcelable {
// sometimes we store linked lists of these things
/*package*/ Message next;
- private static Object mPoolSync = new Object();
- private static Message mPool;
- private static int mPoolSize = 0;
+ private static final Object sPoolSync = new Object();
+ private static Message sPool;
+ private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 10;
@@ -107,11 +107,12 @@ public final class Message implements Parcelable {
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
- synchronized (mPoolSync) {
- if (mPool != null) {
- Message m = mPool;
- mPool = m.next;
+ synchronized (sPoolSync) {
+ if (sPool != null) {
+ Message m = sPool;
+ sPool = m.next;
m.next = null;
+ sPoolSize--;
return m;
}
}
@@ -248,12 +249,12 @@ public final class Message implements Parcelable {
* freed.
*/
public void recycle() {
- synchronized (mPoolSync) {
- if (mPoolSize < MAX_POOL_SIZE) {
+ synchronized (sPoolSync) {
+ if (sPoolSize < MAX_POOL_SIZE) {
clearForRecycle();
-
- next = mPool;
- mPool = this;
+ next = sPool;
+ sPool = this;
+ sPoolSize++;
}
}
}
diff --git a/core/java/android/os/storage/IObbActionListener.java b/core/java/android/os/storage/IObbActionListener.java
index 35da4b0..d6afbaa 100644
--- a/core/java/android/os/storage/IObbActionListener.java
+++ b/core/java/android/os/storage/IObbActionListener.java
@@ -113,7 +113,7 @@ public interface IObbActionListener extends IInterface {
_data.writeInt(nonce);
_data.writeInt(status);
mRemote.transact(Stub.TRANSACTION_onObbResult, _data, _reply,
- android.os.IBinder.FLAG_ONEWAY);
+ IBinder.FLAG_ONEWAY);
_reply.readException();
} finally {
_reply.recycle();
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 44887ed..95d985d 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -517,8 +517,11 @@ public abstract class WallpaperService extends Service {
mLayout.windowAnimations =
com.android.internal.R.style.Animation_Wallpaper;
mInputChannel = new InputChannel();
- mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets,
- mInputChannel);
+ if (mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets,
+ mInputChannel) < 0) {
+ Log.w(TAG, "Failed to add window while updating wallpaper surface.");
+ return;
+ }
mCreated = true;
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index c46d2c5..6d7b7ce 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -512,10 +512,17 @@ public class TextToSpeech {
Intent intent = new Intent("android.intent.action.START_TTS_SERVICE");
intent.addCategory("android.intent.category.TTS");
- mContext.bindService(intent, mServiceConnection,
- Context.BIND_AUTO_CREATE);
- // TODO handle case where the binding works (should always work) but
- // the plugin fails
+ boolean bound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ if (!bound) {
+ Log.e("TextToSpeech.java", "initTts() failed to bind to service");
+ if (mInitListener != null) {
+ mInitListener.onInit(ERROR);
+ }
+ } else {
+ // initialization listener will be called inside ServiceConnection
+ Log.i("TextToSpeech.java", "initTts() successfully bound to service");
+ }
+ // TODO handle plugin failures
}
@@ -765,8 +772,9 @@ public class TextToSpeech {
{
synchronized (mStartLock) {
int result = ERROR;
- Log.i("TTS", "speak() queueMode=" + queueMode);
+ Log.i("TextToSpeech.java - speak", "speak text of length " + text.length());
if (!mStarted) {
+ Log.e("TextToSpeech.java - speak", "service isn't started");
return result;
}
try {
@@ -1264,10 +1272,13 @@ public class TextToSpeech {
*/
public int synthesizeToFile(String text, HashMap<String,String> params,
String filename) {
- Log.i("TTS", "synthesizeToFile()");
+ Log.i("TextToSpeech.java", "synthesizeToFile()");
synchronized (mStartLock) {
int result = ERROR;
+ Log.i("TextToSpeech.java - synthesizeToFile", "synthesizeToFile text of length "
+ + text.length());
if (!mStarted) {
+ Log.e("TextToSpeech.java - synthesizeToFile", "service isn't started");
return result;
}
try {
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index d24af52..6b44f9e 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -38,7 +38,7 @@ import java.util.HashMap;
* for the device you are running on. For example:
*
* <pre>LayoutInflater inflater = (LayoutInflater)context.getSystemService
- * Context.LAYOUT_INFLATER_SERVICE);</pre>
+ * (Context.LAYOUT_INFLATER_SERVICE);</pre>
*
* <p>
* To create a new LayoutInflater with an additional {@link Factory} for your
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c26fa93..02e5b63 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1171,14 +1171,6 @@ public interface WindowManager extends ViewManager {
gravity = o.gravity;
changes |= LAYOUT_CHANGED;
}
- if (horizontalMargin != o.horizontalMargin) {
- horizontalMargin = o.horizontalMargin;
- changes |= LAYOUT_CHANGED;
- }
- if (verticalMargin != o.verticalMargin) {
- verticalMargin = o.verticalMargin;
- changes |= LAYOUT_CHANGED;
- }
if (format != o.format) {
format = o.format;
changes |= FORMAT_CHANGED;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 38ac37d..70f90d3 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -50,6 +50,6 @@ public class ChooserActivity extends ResolverActivity {
initialIntents[i] = (Intent)pa[i];
}
}
- super.onCreate(savedInstanceState, target, title, initialIntents, false);
+ super.onCreate(savedInstanceState, target, title, initialIntents, null, false);
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 215e9ae..841de06 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -63,11 +63,12 @@ public class ResolverActivity extends AlertActivity implements
protected void onCreate(Bundle savedInstanceState) {
onCreate(savedInstanceState, new Intent(getIntent()),
getResources().getText(com.android.internal.R.string.whichApplication),
- null, true);
+ null, null, true);
}
protected void onCreate(Bundle savedInstanceState, Intent intent,
- CharSequence title, Intent[] initialIntents, boolean alwaysUseOption) {
+ CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
+ boolean alwaysUseOption) {
super.onCreate(savedInstanceState);
mPm = getPackageManager();
intent.setComponent(null);
@@ -88,7 +89,7 @@ public class ResolverActivity extends AlertActivity implements
com.android.internal.R.id.clearDefaultHint);
mClearDefaultHint.setVisibility(View.GONE);
}
- mAdapter = new ResolveListAdapter(this, intent, initialIntents);
+ mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList);
if (mAdapter.getCount() > 1) {
ap.mAdapter = mAdapter;
} else if (mAdapter.getCount() == 1) {
@@ -215,14 +216,16 @@ public class ResolverActivity extends AlertActivity implements
private List<DisplayResolveInfo> mList;
public ResolveListAdapter(Context context, Intent intent,
- Intent[] initialIntents) {
+ Intent[] initialIntents, List<ResolveInfo> rList) {
mIntent = new Intent(intent);
mIntent.setComponent(null);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- List<ResolveInfo> rList = mPm.queryIntentActivities(
- intent, PackageManager.MATCH_DEFAULT_ONLY
- | (mAlwaysCheck != null ? PackageManager.GET_RESOLVED_FILTER : 0));
+ if (rList == null) {
+ rList = mPm.queryIntentActivities(
+ intent, PackageManager.MATCH_DEFAULT_ONLY
+ | (mAlwaysCheck != null ? PackageManager.GET_RESOLVED_FILTER : 0));
+ }
int N;
if ((rList != null) && ((N = rList.size()) > 0)) {
// Only display the first matches that are either of equal
diff --git a/core/java/com/android/internal/nfc/LlcpSocket.java b/core/java/com/android/internal/nfc/LlcpSocket.java
index 73c0925..63888ae 100644
--- a/core/java/com/android/internal/nfc/LlcpSocket.java
+++ b/core/java/com/android/internal/nfc/LlcpSocket.java
@@ -193,7 +193,7 @@ public class LlcpSocket {
throw new IOException();
}
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in send(): ", e);
+ Log.e(TAG, "RemoteException in receive(): ", e);
}
return receivedLength;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index b682947..b3b80f6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4087,7 +4087,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// we have gone through a significant charge (from a very low
// level to a now very high level).
if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
- || level >= 95
+ || level >= 90
|| (mDischargeCurrentLevel < 20 && level >= 80)) {
doWrite = true;
resetAllStatsLocked();
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index bc749d8..0885b6e 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -34,6 +34,7 @@ import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import java.lang.ref.WeakReference;
import java.text.DateFormatSymbols;
import java.util.Calendar;
@@ -54,26 +55,45 @@ public class DigitalClock extends RelativeLayout {
private TextView mTimeDisplayForeground;
private AmPm mAmPm;
private ContentObserver mFormatChangeObserver;
- private boolean mLive = true;
- private boolean mAttached;
+ private int mAttached = 0; // for debugging - tells us whether attach/detach is unbalanced
/* called by system on minute ticks */
private final Handler mHandler = new Handler();
- private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mLive && intent.getAction().equals(
- Intent.ACTION_TIMEZONE_CHANGED)) {
- mCalendar = Calendar.getInstance();
- }
- // Post a runnable to avoid blocking the broadcast.
- mHandler.post(new Runnable() {
- public void run() {
- updateTime();
+ private BroadcastReceiver mIntentReceiver;
+
+ private static class TimeChangedReceiver extends BroadcastReceiver {
+ private WeakReference<DigitalClock> mClock;
+ private Context mContext;
+
+ public TimeChangedReceiver(DigitalClock clock) {
+ mClock = new WeakReference<DigitalClock>(clock);
+ mContext = clock.getContext();
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Post a runnable to avoid blocking the broadcast.
+ final boolean timezoneChanged =
+ intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);
+ final DigitalClock clock = mClock.get();
+ if (clock != null) {
+ clock.mHandler.post(new Runnable() {
+ public void run() {
+ if (timezoneChanged) {
+ clock.mCalendar = Calendar.getInstance();
}
+ clock.updateTime();
+ }
});
+ } else {
+ try {
+ mContext.unregisterReceiver(this);
+ } catch (RuntimeException e) {
+ // Shouldn't happen
+ }
}
- };
+ }
+ };
static class AmPm {
private TextView mAmPm;
@@ -99,14 +119,27 @@ public class DigitalClock extends RelativeLayout {
}
}
- private class FormatChangeObserver extends ContentObserver {
- public FormatChangeObserver() {
+ private static class FormatChangeObserver extends ContentObserver {
+ private WeakReference<DigitalClock> mClock;
+ private Context mContext;
+ public FormatChangeObserver(DigitalClock clock) {
super(new Handler());
+ mClock = new WeakReference<DigitalClock>(clock);
+ mContext = clock.getContext();
}
@Override
public void onChange(boolean selfChange) {
- setDateFormat();
- updateTime();
+ DigitalClock digitalClock = mClock.get();
+ if (digitalClock != null) {
+ digitalClock.setDateFormat();
+ digitalClock.updateTime();
+ } else {
+ try {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ } catch (RuntimeException e) {
+ // Shouldn't happen
+ }
+ }
}
}
@@ -139,11 +172,11 @@ public class DigitalClock extends RelativeLayout {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- if (mAttached) return;
- mAttached = true;
+ mAttached++;
- if (mLive) {
- /* monitor time ticks, time changed, timezone */
+ /* monitor time ticks, time changed, timezone */
+ if (mIntentReceiver == null) {
+ mIntentReceiver = new TimeChangedReceiver(this);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
@@ -152,9 +185,11 @@ public class DigitalClock extends RelativeLayout {
}
/* monitor 12/24-hour display preference */
- mFormatChangeObserver = new FormatChangeObserver();
- mContext.getContentResolver().registerContentObserver(
- Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ if (mFormatChangeObserver == null) {
+ mFormatChangeObserver = new FormatChangeObserver(this);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ }
updateTime();
}
@@ -163,16 +198,19 @@ public class DigitalClock extends RelativeLayout {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (!mAttached) return;
- mAttached = false;
+ mAttached--;
- if (mLive) {
+ if (mIntentReceiver != null) {
mContext.unregisterReceiver(mIntentReceiver);
}
- mContext.getContentResolver().unregisterContentObserver(
- mFormatChangeObserver);
- }
+ if (mFormatChangeObserver != null) {
+ mContext.getContentResolver().unregisterContentObserver(
+ mFormatChangeObserver);
+ }
+ mFormatChangeObserver = null;
+ mIntentReceiver = null;
+ }
void updateTime(Calendar c) {
mCalendar = c;
@@ -180,9 +218,7 @@ public class DigitalClock extends RelativeLayout {
}
private void updateTime() {
- if (mLive) {
- mCalendar.setTimeInMillis(System.currentTimeMillis());
- }
+ mCalendar.setTimeInMillis(System.currentTimeMillis());
CharSequence newTime = DateFormat.format(mFormat, mCalendar);
mTimeDisplayBackground.setText(newTime);
@@ -195,8 +231,4 @@ public class DigitalClock extends RelativeLayout {
? M24 : M12;
mAmPm.setShowAmPm(mFormat.equals(M12));
}
-
- void setLive(boolean live) {
- mLive = live;
- }
}
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
new file mode 100644
index 0000000..2b6dee8
--- /dev/null
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.content;
+
+import android.content.ContentResolver;
+import android.provider.ContactsContract;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class ContentResolverTest extends AndroidTestCase {
+ private ContentResolver mContentResolver;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContentResolver = mContext.getContentResolver();
+ }
+
+ @LargeTest
+ public void testCursorFinalizer() throws Exception {
+ // TODO: Want a test case that more predictably reproduce this issue. Selected
+ // 600 as this causes the problem 100% of the runs on current hw, it might not
+ // do so on some other configuration though.
+ for (int i = 0; i < 600; i++) {
+ mContentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
+ }
+ }
+}