summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/animation/LayoutTransition.java45
-rw-r--r--core/java/android/app/Activity.java14
-rw-r--r--core/java/android/app/ActivityThread.java36
-rw-r--r--core/java/android/app/AlertDialog.java74
-rw-r--r--core/java/android/app/Dialog.java10
-rw-r--r--core/java/android/app/Instrumentation.java1
-rw-r--r--core/java/android/app/LoaderManager.java2
-rw-r--r--core/java/android/app/Notification.java5
-rw-r--r--core/java/android/app/OnActivityPausedListener.java31
-rw-r--r--core/java/android/app/StatusBarManager.java57
-rw-r--r--core/java/android/content/AsyncTaskLoader.java18
-rw-r--r--core/java/android/content/Loader.java35
-rw-r--r--core/java/android/hardware/SensorManager.java29
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java56
-rw-r--r--core/java/android/net/ConnectivityManager.java2
-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.java174
-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.java140
-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/MifareUltralight.java133
-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/storage/IMountService.java35
-rwxr-xr-xcore/java/android/speech/tts/TextToSpeech.java23
-rw-r--r--core/java/android/text/TextUtils.java2
-rw-r--r--core/java/android/view/DragEvent.java328
-rw-r--r--core/java/android/view/LayoutInflater.java13
-rw-r--r--core/java/android/view/MenuInflater.java8
-rw-r--r--core/java/android/view/SurfaceView.java22
-rw-r--r--core/java/android/view/View.java578
-rw-r--r--core/java/android/view/ViewRoot.java2
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java4
-rw-r--r--core/java/android/webkit/WebView.java50
-rw-r--r--core/java/android/webkit/WebViewCore.java16
-rw-r--r--core/java/android/webkit/ZoomManager.java29
-rw-r--r--core/java/android/widget/DatePicker.java12
-rw-r--r--core/java/android/widget/StackView.java8
-rw-r--r--core/java/android/widget/TabWidget.java12
-rw-r--r--core/java/android/widget/TextView.java63
-rw-r--r--core/java/android/widget/TimePicker.java28
-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/statusbar/IStatusBar.aidl3
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl3
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rw-r--r--core/java/com/android/internal/widget/DigitalClock.java108
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java4
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java35
70 files changed, 3097 insertions, 1684 deletions
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index f13d940..d3e10f3 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -166,6 +166,7 @@ public class LayoutTransition {
* we cache all of the current animations in this map for possible cancellation on
* another layout event.
*/
+ private final HashMap<View, Animator> pendingAnimations = new HashMap<View, Animator>();
private final HashMap<View, Animator> currentChangingAnimations = new HashMap<View, Animator>();
private final HashMap<View, Animator> currentVisibilityAnimations =
new HashMap<View, Animator>();
@@ -542,6 +543,8 @@ public class LayoutTransition {
// reset the inter-animation delay, in case we use it later
staggerDelay = 0;
+ final long duration = (changeReason == APPEARING) ?
+ mChangingAppearingDuration : mChangingDisappearingDuration;
final ViewTreeObserver observer = parent.getViewTreeObserver(); // used for later cleanup
if (!observer.isAlive()) {
@@ -556,12 +559,6 @@ public class LayoutTransition {
// only animate the views not being added or removed
if (child != newView) {
- // If there's an animation running on this view already, cancel it
- Animator currentAnimation = currentChangingAnimations.get(child);
- if (currentAnimation != null) {
- currentAnimation.cancel();
- currentChangingAnimations.remove(child);
- }
// Make a copy of the appropriate animation
final Animator anim = baseAnimator.clone();
@@ -573,6 +570,30 @@ public class LayoutTransition {
// its target object
anim.setupStartValues();
+ // If there's an animation running on this view already, cancel it
+ Animator currentAnimation = pendingAnimations.get(child);
+ if (currentAnimation != null) {
+ currentAnimation.cancel();
+ pendingAnimations.remove(child);
+ }
+ // Cache the animation in case we need to cancel it later
+ pendingAnimations.put(child, anim);
+
+ // For the animations which don't get started, we have to have a means of
+ // removing them from the cache, lest we leak them and their target objects.
+ // We run an animator for the default duration+100 (an arbitrary time, but one
+ // which should far surpass the delay between setting them up here and
+ // handling layout events which start them.
+ ValueAnimator pendingAnimRemover = ValueAnimator.ofFloat(0f, 1f).
+ setDuration(duration+100);
+ pendingAnimRemover.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ pendingAnimations.remove(child);
+ }
+ });
+ pendingAnimRemover.start();
+
// Add a listener to track layout changes on this view. If we don't get a callback,
// then there's nothing to animate.
final View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
@@ -583,19 +604,25 @@ public class LayoutTransition {
anim.setupEndValues();
long startDelay;
- long duration;
if (changeReason == APPEARING) {
startDelay = mChangingAppearingDelay + staggerDelay;
staggerDelay += mChangingAppearingStagger;
- duration = mChangingAppearingDuration;
} else {
startDelay = mChangingDisappearingDelay + staggerDelay;
staggerDelay += mChangingDisappearingStagger;
- duration = mChangingDisappearingDuration;
}
anim.setStartDelay(startDelay);
anim.setDuration(duration);
+ Animator prevAnimation = currentChangingAnimations.get(child);
+ if (prevAnimation != null) {
+ prevAnimation.cancel();
+ currentChangingAnimations.remove(child);
+ }
+ Animator pendingAnimation = pendingAnimations.get(child);
+ if (pendingAnimation != null) {
+ pendingAnimations.remove(child);
+ }
// Cache the animation in case we need to cancel it later
currentChangingAnimations.put(child, anim);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 055984f..8b6b819 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;
@@ -4268,7 +4268,7 @@ public class Activity extends ContextThemeWrapper
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
- mWindow.getLayoutInflater().setFactory2(this);
+ mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
@@ -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/AlertDialog.java b/core/java/android/app/AlertDialog.java
index 428f4e3..e83d104 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -58,29 +58,69 @@ import android.widget.ListView;
public class AlertDialog extends Dialog implements DialogInterface {
private AlertController mAlert;
+ /**
+ * Special theme constant for {@link #AlertDialog(Context, int)}: use
+ * the traditional (pre-Holo) alert dialog theme.
+ */
+ public static final int THEME_TRADITIONAL = 1;
+
+ /**
+ * Special theme constant for {@link #AlertDialog(Context, int)}: use
+ * the holographic alert theme with a dark background.
+ */
+ public static final int THEME_HOLO_DARK = 2;
+
+ /**
+ * Special theme constant for {@link #AlertDialog(Context, int)}: use
+ * the holographic alert theme with a light background.
+ */
+ public static final int THEME_HOLO_LIGHT = 3;
+
protected AlertDialog(Context context) {
- this(context, getDefaultDialogTheme(context));
+ this(context, resolveDialogTheme(context, 0), true);
}
+ /**
+ * Construct an AlertDialog that uses an explicit theme. The actual style
+ * that an AlertDialog uses is a private implementation, however you can
+ * here supply either the name of an attribute in the theme from which
+ * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
+ * or one of the constants {@link #THEME_TRADITIONAL},
+ * {@link #THEME_HOLO_DARK}, or {@link #THEME_HOLO_LIGHT}.
+ */
protected AlertDialog(Context context, int theme) {
- super(context, theme == 0 ? getDefaultDialogTheme(context) : theme);
+ this(context, theme, true);
+ }
+
+ AlertDialog(Context context, int theme, boolean createContextWrapper) {
+ super(context, resolveDialogTheme(context, theme), createContextWrapper);
mWindow.alwaysReadCloseOnTouchAttr();
- mAlert = new AlertController(context, this, getWindow());
+ mAlert = new AlertController(getContext(), this, getWindow());
}
protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
- super(context, getDefaultDialogTheme(context));
+ super(context, resolveDialogTheme(context, 0));
mWindow.alwaysReadCloseOnTouchAttr();
setCancelable(cancelable);
setOnCancelListener(cancelListener);
mAlert = new AlertController(context, this, getWindow());
}
- private static int getDefaultDialogTheme(Context context) {
- TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
- outValue, true);
- return outValue.resourceId;
+ static int resolveDialogTheme(Context context, int resid) {
+ if (resid == THEME_TRADITIONAL) {
+ return com.android.internal.R.style.Theme_Dialog_Alert;
+ } else if (resid == THEME_HOLO_DARK) {
+ return com.android.internal.R.style.Theme_Holo_Dialog_Alert;
+ } else if (resid == THEME_HOLO_LIGHT) {
+ return com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert;
+ } else if (resid >= 0x01000000) { // start of real resource IDs.
+ return resid;
+ } else {
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
+ outValue, true);
+ return outValue.resourceId;
+ }
}
/**
@@ -294,15 +334,23 @@ public class AlertDialog extends Dialog implements DialogInterface {
* Constructor using a context for this builder and the {@link AlertDialog} it creates.
*/
public Builder(Context context) {
- this(context, getDefaultDialogTheme(context));
+ this(context, resolveDialogTheme(context, 0));
}
/**
* Constructor using a context and theme for this builder and
- * the {@link AlertDialog} it creates.
+ * the {@link AlertDialog} it creates. The actual theme
+ * that an AlertDialog uses is a private implementation, however you can
+ * here supply either the name of an attribute in the theme from which
+ * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
+ * or one of the constants
+ * {@link AlertDialog#THEME_TRADITIONAL AlertDialog.THEME_TRADITIONAL},
+ * {@link AlertDialog#THEME_HOLO_DARK AlertDialog.THEME_HOLO_DARK}, or
+ * {@link AlertDialog#THEME_HOLO_LIGHT AlertDialog.THEME_HOLO_LIGHT}.
*/
public Builder(Context context, int theme) {
- P = new AlertController.AlertParams(new ContextThemeWrapper(context, theme));
+ P = new AlertController.AlertParams(new ContextThemeWrapper(
+ context, resolveDialogTheme(context, theme)));
mTheme = theme;
}
@@ -840,7 +888,7 @@ public class AlertDialog extends Dialog implements DialogInterface {
* to do and want this to be created and displayed.
*/
public AlertDialog create() {
- final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
+ final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
P.apply(dialog.mAlert);
dialog.setCancelable(P.mCancelable);
dialog.setOnCancelListener(P.mOnCancelListener);
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index f4fa567..23d4065 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -119,7 +119,7 @@ public class Dialog implements DialogInterface, Window.Callback,
* present its UI.
*/
public Dialog(Context context) {
- this(context, 0);
+ this(context, 0, true);
}
/**
@@ -135,6 +135,10 @@ public class Dialog implements DialogInterface, Window.Callback,
* <var>context</var>. If 0, the default dialog theme will be used.
*/
public Dialog(Context context, int theme) {
+ this(context, theme, true);
+ }
+
+ Dialog(Context context, int theme, boolean createContextWrapper) {
if (theme == 0) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
@@ -142,7 +146,7 @@ public class Dialog implements DialogInterface, Window.Callback,
theme = outValue.resourceId;
}
- mContext = new ContextThemeWrapper(context, theme);
+ mContext = createContextWrapper ? new ContextThemeWrapper(context, theme) : context;
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Window w = PolicyManager.makeNewWindow(mContext);
mWindow = w;
@@ -152,7 +156,7 @@ public class Dialog implements DialogInterface, Window.Callback,
mUiThread = Thread.currentThread();
mListenersHandler = new ListenersHandler(this);
}
-
+
/**
* @deprecated
* @hide
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/LoaderManager.java b/core/java/android/app/LoaderManager.java
index 431be05..1ee386d 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -587,6 +587,7 @@ class LoaderManagerImpl extends LoaderManager {
if (DEBUG) Log.v(TAG, " Removing last inactive loader: " + info);
inactive.mDeliveredData = false;
inactive.destroy();
+ info.mLoader.abandon();
mInactiveLoaders.put(id, info);
} else {
// We already have an inactive loader for this ID that we are
@@ -617,6 +618,7 @@ class LoaderManagerImpl extends LoaderManager {
// Keep track of the previous instance of this loader so we can destroy
// it when the new one completes.
if (DEBUG) Log.v(TAG, " Making last loader inactive: " + info);
+ info.mLoader.abandon();
mInactiveLoaders.put(id, info);
}
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index de84c56..5049e19 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -927,9 +927,8 @@ public class Notification implements Parcelable
if (mContentInfo != null) {
contentView.setTextViewText(R.id.info, mContentInfo);
} else if (mNumber > 0) {
- if (mNumber > 100) {
- contentView.setTextViewText(R.id.info, mContext.getString(
- R.string.status_bar_notification_info_overflow));
+ if (mNumber > 999) {
+ contentView.setTextViewText(R.id.info, "999+");
} else {
NumberFormat f = NumberFormat.getIntegerInstance();
contentView.setTextViewText(R.id.info, f.format(mNumber));
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/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 97e6931..1af0983 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -22,6 +22,7 @@ import android.os.Binder;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.ServiceManager;
+import android.view.View;
import com.android.internal.statusbar.IStatusBarService;
@@ -31,52 +32,24 @@ import com.android.internal.statusbar.IStatusBarService;
* @hide
*/
public class StatusBarManager {
- /**
- * Flag for {@link #disable} to make the status bar not expandable. Unless you also
- * set {@link #DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show.
- */
- public static final int DISABLE_EXPAND = 0x00000001;
-
- /**
- * Flag for {@link #disable} to hide notification icons and scrolling ticker text.
- */
- public static final int DISABLE_NOTIFICATION_ICONS = 0x00000002;
-
- /**
- * Flag for {@link #disable} to disable incoming notification alerts. This will not block
- * icons, but it will block sound, vibrating and other visual or aural notifications.
- */
- public static final int DISABLE_NOTIFICATION_ALERTS = 0x00000004;
- /**
- * Flag for {@link #disable} to hide only the scrolling ticker. Note that
- * {@link #DISABLE_NOTIFICATION_ICONS} implies {@link #DISABLE_NOTIFICATION_TICKER}.
- */
- public static final int DISABLE_NOTIFICATION_TICKER = 0x00000008;
+ public static final int DISABLE_EXPAND = View.STATUS_BAR_DISABLE_EXPAND;
+ public static final int DISABLE_NOTIFICATION_ICONS = View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS;
+ public static final int DISABLE_NOTIFICATION_ALERTS
+ = View.STATUS_BAR_DISABLE_NOTIFICATION_ALERTS;
+ public static final int DISABLE_NOTIFICATION_TICKER
+ = View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER;
+ public static final int DISABLE_SYSTEM_INFO = View.STATUS_BAR_DISABLE_SYSTEM_INFO;
+ public static final int DISABLE_NAVIGATION = View.STATUS_BAR_DISABLE_NAVIGATION;
+ public static final int DISABLE_BACK = View.STATUS_BAR_DISABLE_BACK;
+ public static final int DISABLE_CLOCK = View.STATUS_BAR_DISABLE_CLOCK;
- /**
- * Flag for {@link #disable} to hide the center system info area.
- */
- public static final int DISABLE_SYSTEM_INFO = 0x00000010;
-
- /**
- * Flag for {@link #disable} to hide only the navigation buttons. Don't use this
- * unless you're a special part of the system UI (i.e., setup wizard, keyguard).
- */
- public static final int DISABLE_NAVIGATION = 0x00000020;
-
- /**
- * Flag for {@link #disable} to hide only the clock. You might use this if your activity has
- * its own clock making the status bar's clock redundant.
- */
- public static final int DISABLE_CLOCK = 0x00000040;
-
-
- /**
- * Re-enable all of the status bar features that you've disabled.
- */
public static final int DISABLE_NONE = 0x00000000;
+ public static final int DISABLE_MASK = DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS
+ | DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
+ | DISABLE_SYSTEM_INFO| DISABLE_NAVIGATION | DISABLE_BACK | DISABLE_CLOCK;
+
private Context mContext;
private IStatusBarService mService;
private IBinder mToken = new Binder();
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index a7dd5fb..383cb6b 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -169,11 +169,6 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
* to properly dispose of the result.
*/
public void onCanceled(D data) {
- onCancelled(data);
- }
-
- @Deprecated
- public void onCancelled(D data) {
}
void executePendingTask() {
@@ -214,10 +209,15 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
if (DEBUG) Slog.v(TAG, "Load complete of old task, trying to cancel");
dispatchOnCancelled(task, data);
} else {
- mLastLoadCompleteTime = SystemClock.uptimeMillis();
- mTask = null;
- if (DEBUG) Slog.v(TAG, "Delivering result");
- deliverResult(data);
+ if (isAbandoned()) {
+ // This cursor has been abandoned; just cancel the new data.
+ onCanceled(data);
+ } else {
+ mLastLoadCompleteTime = SystemClock.uptimeMillis();
+ mTask = null;
+ if (DEBUG) Slog.v(TAG, "Delivering result");
+ deliverResult(data);
+ }
}
}
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index d63fe69..a9d6117 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -45,6 +45,7 @@ public class Loader<D> {
OnLoadCompleteListener<D> mListener;
Context mContext;
boolean mStarted = false;
+ boolean mAbandoned = false;
boolean mReset = true;
boolean mContentChanged = false;
@@ -151,6 +152,15 @@ public class Loader<D> {
}
/**
+ * Return whether this loader has been abandoned. In this state, the
+ * loader <em>must not</em> report any new data, and <em>must</em> keep
+ * its last reported data valid until it is finally reset.
+ */
+ public boolean isAbandoned() {
+ return mAbandoned;
+ }
+
+ /**
* Return whether this load has been reset. That is, either the loader
* has not yet been started for the first time, or its {@link #reset()}
* has been called.
@@ -177,6 +187,7 @@ public class Loader<D> {
public final void startLoading() {
mStarted = true;
mReset = false;
+ mAbandoned = false;
onStartLoading();
}
@@ -236,6 +247,28 @@ public class Loader<D> {
}
/**
+ * Tell the Loader that it is being abandoned. This is called prior
+ * to {@link #reset} to have it retain its current data but not report
+ * any new data.
+ */
+ public void abandon() {
+ mAbandoned = true;
+ onAbandon();
+ }
+
+ /**
+ * Subclasses implement this to take care of being abandoned. This is
+ * an optional intermediate state prior to {@link #onReset()} -- it means that
+ * the client is no longer interested in any new data from the loader,
+ * so the loader must not report any further updates. However, the
+ * loader <em>must</em> keep its last reported data valid until the final
+ * {@link #onReset()} happens. You can retrieve the current abandoned
+ * state with {@link #isAbandoned}.
+ */
+ protected void onAbandon() {
+ }
+
+ /**
* Resets the state of the Loader. The Loader should at this point free
* all of its resources, since it may never be called again; however, its
* {@link #startLoading()} may later be called at which point it must be
@@ -251,6 +284,7 @@ public class Loader<D> {
onReset();
mReset = true;
mStarted = false;
+ mAbandoned = false;
mContentChanged = false;
}
@@ -327,6 +361,7 @@ public class Loader<D> {
writer.print(" mListener="); writer.println(mListener);
writer.print(prefix); writer.print("mStarted="); writer.print(mStarted);
writer.print(" mContentChanged="); writer.print(mContentChanged);
+ writer.print(" mAbandoned="); writer.print(mAbandoned);
writer.print(" mReset="); writer.println(mReset);
}
} \ No newline at end of file
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/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 255eb6c..feb246e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -219,7 +219,34 @@ import java.io.PrintWriter;
public class InputMethodService extends AbstractInputMethodService {
static final String TAG = "InputMethodService";
static final boolean DEBUG = false;
-
+
+ /**
+ * The back button will close the input window.
+ */
+ public static final int BACK_DISPOSITION_DEFAULT = 0; // based on window
+
+ /**
+ * This input method will not consume the back key.
+ */
+ public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // back
+
+ /**
+ * This input method will consume the back key.
+ */
+ public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // down
+
+ /**
+ * @hide
+ * The IME is active. It may or may not be visible.
+ */
+ public static final int IME_ACTIVE = 0x1;
+
+ /**
+ * @hide
+ * The IME is visible.
+ */
+ public static final int IME_VISIBLE = 0x2;
+
InputMethodManager mImm;
int mTheme = 0;
@@ -271,6 +298,7 @@ public class InputMethodService extends AbstractInputMethodService {
boolean mIsInputViewShown;
int mStatusIcon;
+ int mBackDisposition;
final Insets mTmpInsets = new Insets();
final int[] mTmpLocation = new int[2];
@@ -394,9 +422,9 @@ public class InputMethodService extends AbstractInputMethodService {
showWindow(true);
}
// If user uses hard keyboard, IME button should always be shown.
- if (!onEvaluateInputViewShown()) {
- mImm.setIMEButtonVisible(mToken, true);
- }
+ boolean showing = onEvaluateInputViewShown();
+ mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
+ mBackDisposition);
if (resultReceiver != null) {
resultReceiver.send(wasVis != isInputViewShown()
? InputMethodManager.RESULT_SHOWN
@@ -704,9 +732,9 @@ public class InputMethodService extends AbstractInputMethodService {
hideWindow();
}
// If user uses hard keyboard, IME button should always be shown.
- if (!onEvaluateInputViewShown()) {
- mImm.setIMEButtonVisible(mToken, true);
- }
+ boolean showing = onEvaluateInputViewShown();
+ mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
+ mBackDisposition);
}
}
@@ -736,6 +764,14 @@ public class InputMethodService extends AbstractInputMethodService {
return mWindow;
}
+ public void setBackDisposition(int disposition) {
+ mBackDisposition = disposition;
+ }
+
+ public int getBackDisposition() {
+ return mBackDisposition;
+ }
+
/**
* Return the maximum width, in pixels, available the input method.
* Input methods are positioned at the bottom of the screen and, unless
@@ -1029,7 +1065,7 @@ public class InputMethodService extends AbstractInputMethodService {
public boolean onEvaluateInputViewShown() {
Configuration config = getResources().getConfiguration();
return config.keyboard == Configuration.KEYBOARD_NOKEYS
- || config.hardKeyboardHidden == Configuration.KEYBOARDHIDDEN_YES;
+ || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
}
/**
@@ -1378,7 +1414,7 @@ public class InputMethodService extends AbstractInputMethodService {
if (!wasVisible) {
if (DEBUG) Log.v(TAG, "showWindow: showing!");
- mImm.setIMEButtonVisible(mToken, true);
+ mImm.setImeWindowStatus(mToken, IME_ACTIVE, mBackDisposition);
onWindowShown();
mWindow.show();
}
@@ -1394,7 +1430,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
mInputViewStarted = false;
mCandidatesViewStarted = false;
- mImm.setIMEButtonVisible(mToken, false);
+ mImm.setImeWindowStatus(mToken, 0, mBackDisposition);
if (mWindowVisible) {
mWindow.hide();
mWindowVisible = false;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 7e809f5..cab8ed2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -221,6 +221,8 @@ public class ConnectivityManager
/** {@hide} */
public static final int TYPE_DUMMY = 8;
+ /** {@hide} */
+ public static final int TYPE_ETHERNET = 9;
/** {@hide} TODO: Need to adjust this for WiMAX. */
public static final int MAX_RADIO_TYPE = TYPE_DUMMY;
/** {@hide} TODO: Need to adjust this for WiMAX. */
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..32a850d
--- /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() throws IOException {
+ 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..774982e
--- /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() throws IOException {
+ 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..d337ead
--- /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 compatible card of unknown type */
+ public static final int TYPE_UNKNOWN = -1;
+ /** 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;
+
+ /** 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);
+ }
+
+ /**
+ * 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 static 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 static 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);
+ }
+ }
+
+ private static void validateValueOperand(int value) {
+ if (value < 0) {
+ throw new IllegalArgumentException("value operand negative");
+ }
+ }
+}
diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/core/java/android/nfc/tech/MifareUltralight.java
new file mode 100644
index 0000000..b514f1c
--- /dev/null
+++ b/core/java/android/nfc/tech/MifareUltralight.java
@@ -0,0 +1,174 @@
+/*
+ * 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.RemoteException;
+
+import java.io.IOException;
+
+//TOOD: Ultralight C 3-DES authentication, one-way counter
+
+/**
+ * Technology class representing MIFARE Ultralight and MIFARE Ultralight C tags.
+ *
+ * <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.
+ *
+ * <p>MIFARE Ultralight compatible tags have 4 byte pages. The read command
+ * returns 4 pages (16 bytes) at a time, for speed. The write command operates
+ * on a single page (4 bytes) to minimize EEPROM write cycles.
+ *
+ * <p>The original MIFARE Ultralight consists of a 64 byte EEPROM. The first
+ * 4 pages are for the OTP area, manufacturer data, and locking bits. They are
+ * readable and some bits are writable. The final 12 pages are the user
+ * read/write area. For more information see the NXP data sheet MF0ICU1.
+ *
+ * <p>The MIFARE Ultralight C consists of a 192 byte EEPROM. The first 4 pages
+ * are for OTP, manufacturer data, and locking bits. The next 36 pages are the
+ * user read/write area. The next 4 pages are additional locking bits, counters
+ * and authentication configuration and are readable. The final 4 pages are for
+ * the authentication key and are not readable. For more information see the
+ * NXP data sheet MF0ICU2.
+ */
+public final class MifareUltralight extends BasicTagTechnology {
+ /** A MIFARE Ultralight compatible tag of unknown type */
+ public static final int TYPE_UNKNOWN = -1;
+ /** A MIFARE Ultralight tag */
+ public static final int TYPE_ULTRALIGHT = 1;
+ /** A MIFARE Ultralight C tag */
+ public static final int TYPE_ULTRALIGHT_C = 2;
+
+ /** Size of a MIFARE Ultralight page in bytes */
+ public static final int PAGE_SIZE = 4;
+
+ private static final int NXP_MANUFACTURER_ID = 0x04;
+ private static final int MAX_PAGE_COUNT = 256;
+
+ private int mType;
+
+ /**
+ * 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.get(tag);
+
+ mType = TYPE_UNKNOWN;
+
+ if (a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID) {
+ // could be UL or UL-C
+ //TODO: stack should use NXP AN1303 procedure to make a best guess
+ // attempt at classifying Ultralight vs Ultralight C.
+ mType = TYPE_ULTRALIGHT;
+ }
+ }
+
+ /** Returns the type of the tag.
+ * <p>It is very hard to always accurately classify a MIFARE Ultralight
+ * compatible tag as Ultralight original or Ultralight C. So consider
+ * {@link #getType} a hint. */
+ public int getType() {
+ return mType;
+ }
+
+ // Methods that require connect()
+ /**
+ * Read 4 pages (16 bytes).
+ * <p>The MIFARE Ultralight protocol always reads 4 pages at a time.
+ * <p>If the read spans past the last readable block, then the tag will
+ * return pages that have been wrapped back to the first blocks. MIFARE
+ * Ultralight tags have readable blocks 0x00 through 0x0F. So a read to
+ * block offset 0x0E would return blocks 0x0E, 0x0F, 0x00, 0x01. MIFARE
+ * Ultralight C tags have readable blocks 0x00 through 0x2B. So a read to
+ * block 0x2A would return blocks 0x2A, 0x2B, 0x00, 0x01.
+ * <p>This requires that the tag be connected.
+ *
+ * @return 4 pages (16 bytes)
+ * @throws IOException
+ */
+ public byte[] readPages(int pageOffset) throws IOException {
+ validatePageOffset(pageOffset);
+ checkConnected();
+
+ byte[] cmd = { 0x30, (byte) pageOffset};
+ return transceive(cmd, false);
+ }
+
+ /**
+ * Write 1 page (4 bytes).
+ * <p>The MIFARE Ultralight protocol always writes 1 page at a time.
+ * <p>This requires that the tag be connected.
+ *
+ * @param pageOffset The offset of the page to write
+ * @param data The data to write
+ * @throws IOException
+ */
+ public void writePage(int pageOffset, byte[] data) throws IOException {
+ validatePageOffset(pageOffset);
+ checkConnected();
+
+ byte[] cmd = new byte[data.length + 2];
+ cmd[0] = (byte) 0xA2;
+ cmd[1] = (byte) pageOffset;
+ System.arraycopy(data, 0, cmd, 2, data.length);
+
+ 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 static void validatePageOffset(int pageOffset) {
+ // Do not be too strict on upper bounds checking, since some cards
+ // may have more addressable memory than they report.
+ // Note that issuing a command to an out-of-bounds block is safe - the
+ // tag will wrap the read to an addressable area. This validation is a
+ // helper to guard against obvious programming mistakes.
+ if (pageOffset < 0 || pageOffset >= MAX_PAGE_COUNT) {
+ throw new IndexOutOfBoundsException("page out of bounds: " + pageOffset);
+ }
+ }
+}
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..c8ccdcf
--- /dev/null
+++ b/core/java/android/nfc/tech/TagTechnology.java
@@ -0,0 +1,140 @@
+/*
+ * 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.Closeable;
+import java.io.IOException;
+
+public interface TagTechnology extends Closeable {
+ /**
+ * 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() throws IOException;
+}
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/MifareUltralight.java b/core/java/android/nfc/technology/MifareUltralight.java
deleted file mode 100644
index 7103b4d..0000000
--- a/core/java/android/nfc/technology/MifareUltralight.java
+++ /dev/null
@@ -1,133 +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.NfcAdapter;
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-/**
- * Concrete class for TagTechnology.MIFARE_ULTRALIGHT
- *
- * 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 MifareUltralight extends BasicTagTechnology {
- public static final int TYPE_ULTRALIGHT = 1;
- public static final int TYPE_ULTRALIGHT_C = 2;
- 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);
-
- // Check if this could actually be a Mifare
- NfcA a = (NfcA) tag.getTechnology(adapter, TagTechnology.NFC_A);
-
- mType = TYPE_UNKNOWN;
-
- if( a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID ) {
- // could be UL or UL-C
- mType = TYPE_ULTRALIGHT;
- }
- }
-
- public int getType() {
- return mType;
- }
-
- // Methods that require connect()
- /**
- * @throws IOException
- */
- public byte[] readBlock(int block) throws IOException {
- checkConnected();
-
- byte[] blockread_cmd = { 0x30, (byte)block }; // phHal_eMifareRead
- return transceive(blockread_cmd);
- }
-
- /**
- * @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 {
- checkConnected();
-
- byte[] pagewrite_cmd = new byte[data.length + 2];
- pagewrite_cmd[0] = (byte) 0xA2;
- pagewrite_cmd[1] = (byte) block;
- 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);
- }
-
- /**
- * 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/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index b9d4711..4c83515 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -26,7 +26,7 @@ import android.os.RemoteException;
* WARNING! Update IMountService.h and IMountService.cpp if you change this
* file. In particular, the ordering of the methods below must match the
* _TRANSACTION enum in IMountService.cpp
- *
+ *
* @hide - Applications should use android.os.storage.StorageManager to access
* storage functions.
*/
@@ -620,6 +620,23 @@ public interface IMountService extends IInterface {
}
return _result;
}
+
+ public int changeEncryptionPassword(String password) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(password);
+ mRemote.transact(Stub.TRANSACTION_changeEncryptionPassword, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
}
private static final String DESCRIPTOR = "IMountService";
@@ -680,6 +697,8 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_encryptStorage = IBinder.FIRST_CALL_TRANSACTION + 27;
+ static final int TRANSACTION_changeEncryptionPassword = IBinder.FIRST_CALL_TRANSACTION + 28;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -977,6 +996,14 @@ public interface IMountService extends IInterface {
reply.writeInt(result);
return true;
}
+ case TRANSACTION_changeEncryptionPassword: {
+ data.enforceInterface(DESCRIPTOR);
+ String password = data.readString();
+ int result = changeEncryptionPassword(password);
+ reply.writeNoException();
+ reply.writeInt(result);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1146,4 +1173,10 @@ public interface IMountService extends IInterface {
* Encrypts storage.
*/
public int encryptStorage(String password) throws RemoteException;
+
+ /**
+ * Changes the encryption password.
+ */
+ public int changeEncryptionPassword(String password) throws RemoteException;
+
}
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/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 7748265..d5010c6 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1142,7 +1142,7 @@ public class TextUtils {
// XXX this is probably ok, but need to look at it more
tempMt.setPara(format, 0, format.length(), request);
- float moreWid = mt.addStyleRun(p, mt.mLen, null);
+ float moreWid = tempMt.addStyleRun(p, tempMt.mLen, null);
if (w + moreWid <= avail) {
ok = i + 1;
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 4d83891..8f491ef 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -21,7 +21,100 @@ import android.content.ClipDescription;
import android.os.Parcel;
import android.os.Parcelable;
-/** !!! TODO: real docs */
+//TODO: Improve Javadoc
+/**
+ * Represents an event that is sent out by the system at various times during a drag and drop
+ * operation. It is a complex data structure that contains several important pieces of data about
+ * the operation and the underlying data.
+ * <p>
+ * View objects that receive a DragEvent call {@link #getAction()}, which returns
+ * an action type that indicates the state of the drag and drop operation. This allows a View
+ * object to react to a change in state by changing its appearance or performing other actions.
+ * For example, a View can react to the {@link #ACTION_DRAG_ENTERED} action type by
+ * by changing one or more colors in its displayed image.
+ * </p>
+ * <p>
+ * During a drag and drop operation, the system displays an image that the user drags. This image
+ * is called a drag shadow. Several action types reflect the position of the drag shadow relative
+ * to the View receiving the event.
+ * </p>
+ * <p>
+ * Most methods return valid data only for certain event actions. This is summarized in the
+ * following table. Each possible {@link #getAction()} value is listed in the first column. The
+ * other columns indicate which method or methods return valid data for that getAction() value:
+ * </p>
+ * <table>
+ * <tr>
+ * <th scope="col">getAction() Value</th>
+ * <th scope="col">getClipDescription()</th>
+ * <th scope="col">getLocalState()</th>
+ * <th scope="col">getX()</th>
+ * <th scope="col">getY()</th>
+ * <th scope="col">getClipData()</th>
+ * <th scope="col">getResult()</th>
+ * </tr>
+ * <tr>
+ * <td>ACTION_DRAG_STARTED</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>ACTION_DRAG_ENTERED</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>ACTION_DRAG_LOCATION</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>ACTION_DRAG_EXITED</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>ACTION_DROP</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>ACTION_DRAG_ENDED</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">X</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">&nbsp;</td>
+ * <td style="text-align: center;">X</td>
+ * </tr>
+ * </table>
+ * <p>
+ * The {@link android.view.DragEvent#getAction()},
+ * {@link android.view.DragEvent#describeContents()},
+ * {@link android.view.DragEvent#writeToParcel(Parcel,int)}, and
+ * {@link android.view.DragEvent#toString()} methods always return valid data.
+ * </p>
+ */
public class DragEvent implements Parcelable {
private static final boolean TRACK_RECYCLED_LOCATION = false;
@@ -42,89 +135,113 @@ public class DragEvent implements Parcelable {
private static DragEvent gRecyclerTop = null;
/**
- * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose
- * action is ACTION_DRAG_STARTED means that a drag operation has been initiated. The
- * view receiving this DragEvent should inspect the metadata of the dragged content,
- * available via {@link #getClipDescription()}, and return {@code true} from
- * {@link View#onDragEvent(DragEvent)} if the view is prepared to accept a drop of
- * that clip data. If the view chooses to present a visual indication that it is
- * a valid target of the ongoing drag, then it should draw that indication in response
- * to this event.
+ * Action constant returned by {@link #getAction()}: Signals the start of a
+ * drag and drop operation. The View should return {@code true} from its
+ * {@link View#onDragEvent(DragEvent) onDragEvent()} handler method or
+ * {@link View.View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()} listener
+ * if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
+ * from {@link #getClipDescription()} to determine if they can accept the data contained in
+ * this drag. For an operation that doesn't represent data transfer, these methods may
+ * perform other actions to determine whether or not the View should accept the drag.
+ * If the View wants to indicate that it is a valid drop target, it can also react by
+ * changing its appearance.
* <p>
- * A view will only receive ACTION_DRAG_ENTERED, ACTION_DRAG_LOCATION, ACTION_DRAG_EXITED,
- * and ACTION_DRAG_LOCATION events if it returns {@code true} in response to the
- * ACTION_DRAG_STARTED event.
+ * A View only receives further drag events if it returns {@code true} in response to
+ * ACTION_DRAG_STARTED.
+ * </p>
+ * @see #ACTION_DRAG_ENDED
*/
public static final int ACTION_DRAG_STARTED = 1;
/**
- * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose
- * action is ACTION_DRAG_LOCATION means that the drag operation is currently hovering
- * over the view. The {@link #getX()} and {@link #getY()} methods supply the location
- * of the drag point within the view's coordinate system.
+ * Action constant returned by {@link #getAction()}: Sent to a View after
+ * {@link #ACTION_DRAG_ENTERED} if the drag shadow is still within the View object's bounding
+ * box. The {@link #getX()} and {@link #getY()} methods supply
+ * the X and Y position of of the drag point within the View object's bounding box.
+ * <p>
+ * A View receives an {@link #ACTION_DRAG_ENTERED} event before receiving any
+ * ACTION_DRAG_LOCATION events.
+ * </p>
* <p>
- * A view will receive an ACTION_DRAG_ENTERED event before receiving any
- * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an
- * ACTION_DRAG_EXITED event is delivered to the view, after which no more
- * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view,
- * of course).
+ * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
+ * drag shadow out of the View object's bounding box. If the user moves the drag shadow back
+ * into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
+ * receiving any more ACTION_DRAG_LOCATION events.
+ * </p>
+ * @see #ACTION_DRAG_ENTERED
+ * @see #getX()
+ * @see #getY()
*/
public static final int ACTION_DRAG_LOCATION = 2;
/**
- * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose
- * action is ACTION_DROP means that the dragged content has been dropped on this view.
- * The view should retrieve the content via {@link #getClipData()} and act on it
- * appropriately. The {@link #getX()} and {@link #getY()} methods supply the location
- * of the drop point within the view's coordinate system.
+ * Action constant returned by {@link #getAction()}: Signals to a View that the user
+ * has released the drag shadow, and the drag point is within the bounding box of the View.
+ * The View should retrieve the data from the DragEvent by calling {@link #getClipData()}.
+ * The methods {@link #getX()} and {@link #getY()} return the X and Y position of the drop point
+ * within the View object's bounding box.
+ * <p>
+ * The View should return {@code true} from its {@link View#onDragEvent(DragEvent)}
+ * handler or {@link View.View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()}
+ * listener if it accepted the drop, and {@code false} if it ignored the drop.
+ * </p>
* <p>
- * The view should return {@code true} from its {@link View#onDragEvent(DragEvent)}
- * method in response to this event if it accepted the content, and {@code false}
- * if it ignored the drop.
+ * The View can also react to this action by changing its appearance.
+ * </p>
+ * @see #getClipData()
+ * @see #getX()
+ * @see #getY()
*/
public static final int ACTION_DROP = 3;
/**
- * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose
- * action is ACTION_DRAG_ENDED means that the drag operation has concluded. A view
- * that is drawing a visual indication of drag acceptance should return to its usual
- * drawing state in response to this event.
+ * Action constant returned by {@link #getAction()}: Signals to a View that the drag and drop
+ * operation has concluded. A View that changed its appearance during the operation should
+ * return to its usual drawing state in response to this event.
* <p>
* All views that received an ACTION_DRAG_STARTED event will receive the
- * ACTION_DRAG_ENDED event even if they are not currently visible when the drag
- * ends.
+ * ACTION_DRAG_ENDED event even if they are not currently visible when the drag ends.
+ * </p>
+ * <p>
+ * The View object can call {@link #getResult()} to see the result of the operation.
+ * If a View returned {@code true} in response to {@link #ACTION_DROP}, then
+ * getResult() returns {@code true}, otherwise it returns {@code false}.
+ * </p>
+ * @see #ACTION_DRAG_STARTED
+ * @see #getResult()
*/
public static final int ACTION_DRAG_ENDED = 4;
/**
- * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose
- * action is ACTION_DRAG_ENTERED means that the drag point has entered the view's
- * bounds. If the view changed its visual state in response to the ACTION_DRAG_ENTERED
- * event, it should return to its normal drag-in-progress visual state in response to
- * this event.
+ * Action constant returned by {@link #getAction()}: Signals to a View that the drag point has
+ * entered the bounding box of the View.
* <p>
- * A view will receive an ACTION_DRAG_ENTERED event before receiving any
- * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an
- * ACTION_DRAG_EXITED event is delivered to the view, after which no more
- * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view,
- * of course).
+ * If the View can accept a drop, it can react to ACTION_DRAG_ENTERED
+ * by changing its appearance in a way that tells the user that the View is the current
+ * drop target.
+ * </p>
+ * The system stops sending ACTION_DRAG_LOCATION events to a View once the user moves the
+ * drag shadow out of the View object's bounding box. If the user moves the drag shadow back
+ * into the View object's bounding box, the View receives an ACTION_DRAG_ENTERED again before
+ * receiving any more ACTION_DRAG_LOCATION events.
+ * </p>
+ * @see #ACTION_DRAG_ENTERED
+ * @see #ACTION_DRAG_LOCATION
*/
public static final int ACTION_DRAG_ENTERED = 5;
/**
- * Action constant returned by {@link #getAction()}. Delivery of a DragEvent whose
- * action is ACTION_DRAG_ENTERED means that the drag point has entered the view's
- * bounds. If the view chooses to present a visual indication that it will receive
- * the drop if it occurs now, then it should draw that indication in response to
- * this event.
+ * Action constant returned by {@link #getAction()}: Signals that the user has moved the
+ * drag shadow outside the bounding box of the View.
+ * The View can react by changing its appearance in a way that tells the user that
+ * View is no longer the immediate drop target.
* <p>
- * A view will receive an ACTION_DRAG_ENTERED event before receiving any
- * ACTION_DRAG_LOCATION events. If the drag point leaves the view, then an
- * ACTION_DRAG_EXITED event is delivered to the view, after which no more
- * ACTION_DRAG_LOCATION events will be sent (unless the drag re-enters the view,
- * of course).
+ * After the system sends an ACTION_DRAG_EXITED event to the View, the View receives no more
+ * ACTION_DRAG_LOCATION events until the user drags the drag shadow back over the View.
+ * </p>
+ *
*/
-public static final int ACTION_DRAG_EXITED = 6;
+ public static final int ACTION_DRAG_EXITED = 6;
private DragEvent() {
}
@@ -175,64 +292,101 @@ public static final int ACTION_DRAG_EXITED = 6;
/**
* Inspect the action value of this event.
- * @return One of {@link #ACTION_DRAG_STARTED}, {@link #ACTION_DRAG_ENDED},
- * {@link #ACTION_DROP}, {@link #ACTION_DRAG_ENTERED}, {@link #ACTION_DRAG_EXITED},
- * or {@link #ACTION_DRAG_LOCATION}.
+ * @return One of the following action constants, in the order in which they usually occur
+ * during a drag and drop operation:
+ * <ul>
+ * <li>{@link #ACTION_DRAG_STARTED}</li>
+ * <li>{@link #ACTION_DRAG_ENTERED}</li>
+ * <li>{@link #ACTION_DRAG_LOCATION}</li>
+ * <li>{@link #ACTION_DROP}</li>
+ * <li>{@link #ACTION_DRAG_EXITED}</li>
+ * <li>{@link #ACTION_DRAG_ENDED}</li>
+ * </ul>
*/
public int getAction() {
return mAction;
}
/**
- * For ACTION_DRAG_LOCATION and ACTION_DROP events, returns the x coordinate of the
- * drag point.
- * @return The current drag point's x coordinate, when relevant.
+ * Gets the X coordinate of the drag point. The value is only valid if the event action is
+ * {@link #ACTION_DRAG_LOCATION} or {@link #ACTION_DROP}.
+ * @return The current drag point's Y coordinate
*/
public float getX() {
return mX;
}
/**
- * For ACTION_DRAG_LOCATION and ACTION_DROP events, returns the y coordinate of the
- * drag point.
- * @return The current drag point's y coordinate, when relevant.
+ * Gets the Y coordinate of the drag point. The value is valid if the
+ * event action is {@link #ACTION_DRAG_ENTERED}, {@link #ACTION_DRAG_LOCATION},
+ * {@link #ACTION_DROP}, or {@link #ACTION_DRAG_EXITED}.
+ * @return The current drag point's Y coordinate
*/
public float getY() {
return mY;
}
/**
- * Provides the data payload of the drag operation. This payload is only available
- * for events whose action value is ACTION_DROP.
- * @return The ClipData containing the data being dropped on the view.
+ * Returns the {@link android.content.ClipData} object sent to the system as part of the call
+ * to
+ * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+ * This method only returns valid data if the event action is {@link #ACTION_DROP}.
+ * @return The ClipData sent to the system by startDrag().
*/
public ClipData getClipData() {
return mClipData;
}
/**
- * Provides a description of the drag operation's data payload. This payload is
- * available for all DragEvents other than ACTION_DROP.
- * @return A ClipDescription describing the contents of the data being dragged.
+ * Returns the {@link android.content.ClipDescription} object contained in the
+ * {@link android.content.ClipData} object sent to the system as part of the call to
+ * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+ * The drag handler or listener for a View can use the metadata in this object to decide if the
+ * View can accept the dragged View object's data.
+ * <p>
+ * This method returns valid data for all event actions.
+ * @return The ClipDescription that was part of the ClipData sent to the system by startDrag().
*/
public ClipDescription getClipDescription() {
return mClipDescription;
}
/**
- * Provides the local state object passed as the {@code myLocalState} parameter to
- * View.startDrag(). The object will always be null here if the application receiving
- * the DragEvent is not the one that started the drag.
+ * Returns the local state object sent to the system as part of the call to
+ * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+ * The object is intended to provide local information about the drag and drop operation. For
+ * example, it can indicate whether the drag and drop operation is a copy or a move.
+ * <p>
+ * This method returns valid data for all event actions.
+ * </p>
+ * @return The local state object sent to the system by startDrag().
*/
public Object getLocalState() {
return mLocalState;
}
/**
- * Provides an indication of whether the drag operation concluded successfully.
- * This method is only available on ACTION_DRAG_ENDED events.
- * @return {@code true} if the drag operation ended with an accepted drop; {@code false}
- * otherwise.
+ * <p>
+ * Returns an indication of the result of the drag and drop operation.
+ * This method only returns valid data if the action type is {@link #ACTION_DRAG_ENDED}.
+ * The return value depends on what happens after the user releases the drag shadow.
+ * </p>
+ * <p>
+ * If the user releases the drag shadow on a View that can accept a drop, the system sends an
+ * {@link #ACTION_DROP} event to the View object's drag event listener. If the listener
+ * returns {@code true}, then getResult() will return {@code true}.
+ * If the listener returns {@code false}, then getResult() returns {@code false}.
+ * </p>
+ * <p>
+ * Notice that getResult() also returns {@code false} if no {@link #ACTION_DROP} is sent. This
+ * happens, for example, when the user releases the drag shadow over an area outside of the
+ * application. In this case, the system sends out {@link #ACTION_DRAG_ENDED} for the current
+ * operation, but never sends out {@link #ACTION_DROP}.
+ * </p>
+ * @return {@code true} if a drag event listener returned {@code true} in response to
+ * {@link #ACTION_DROP}. If the system did not send {@link #ACTION_DROP} before
+ * {@link #ACTION_DRAG_ENDED}, or if the listener returned {@code false} in response to
+ * {@link #ACTION_DROP}, then {@code false} is returned.
*/
public boolean getResult() {
return mDragResult;
@@ -271,6 +425,11 @@ public static final int ACTION_DRAG_EXITED = 6;
}
}
+ /**
+ * Returns a string containing a concise, human-readable representation of this DragEvent
+ * object.
+ * @return A string representation of the DragEvent object.
+ */
@Override
public String toString() {
return "DragEvent{" + Integer.toHexString(System.identityHashCode(this))
@@ -281,10 +440,20 @@ public static final int ACTION_DRAG_EXITED = 6;
/* Parcelable interface */
+ /**
+ * Returns information about the {@link android.os.Parcel} representation of this DragEvent
+ * object.
+ * @return Information about the {@link android.os.Parcel} representation.
+ */
public int describeContents() {
return 0;
}
+ /**
+ * Creates a {@link android.os.Parcel} object from this DragEvent object.
+ * @param dest A {@link android.os.Parcel} object in which to put the DragEvent object.
+ * @param flags Flags to store in the Parcel.
+ */
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mAction);
dest.writeFloat(mX);
@@ -304,6 +473,9 @@ public static final int ACTION_DRAG_EXITED = 6;
}
}
+ /**
+ * A container for creating a DragEvent from a Parcel.
+ */
public static final Parcelable.Creator<DragEvent> CREATOR =
new Parcelable.Creator<DragEvent>() {
public DragEvent createFromParcel(Parcel in) {
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index d24af52..a17ed9d 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -68,6 +68,7 @@ public abstract class LayoutInflater {
private boolean mFactorySet;
private Factory mFactory;
private Factory2 mFactory2;
+ private Factory2 mPrivateFactory;
private Filter mFilter;
private final Object[] mConstructorArgs = new Object[2];
@@ -193,6 +194,7 @@ public abstract class LayoutInflater {
mContext = newContext;
mFactory = original.mFactory;
mFactory2 = original.mFactory2;
+ mPrivateFactory = original.mPrivateFactory;
mFilter = original.mFilter;
}
@@ -300,6 +302,13 @@ public abstract class LayoutInflater {
}
/**
+ * @hide for use by framework
+ */
+ public void setPrivateFactory(Factory2 factory) {
+ mPrivateFactory = factory;
+ }
+
+ /**
* @return The {@link Filter} currently used by this LayoutInflater to restrict the set of Views
* that are allowed to be inflated.
*/
@@ -651,6 +660,10 @@ public abstract class LayoutInflater {
else if (mFactory != null) view = mFactory.onCreateView(name, mContext, attrs);
else view = null;
+ if (view == null && mPrivateFactory != null) {
+ view = mPrivateFactory.onCreateView(parent, name, mContext, attrs);
+ }
+
if (view == null) {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs);
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index ab515c9..372ac15 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -228,8 +228,8 @@ public class MenuInflater {
private boolean itemAdded;
private int itemId;
private int itemCategoryOrder;
- private String itemTitle;
- private String itemTitleCondensed;
+ private CharSequence itemTitle;
+ private CharSequence itemTitleCondensed;
private int itemIconResId;
private char itemAlphabeticShortcut;
private char itemNumericShortcut;
@@ -311,8 +311,8 @@ public class MenuInflater {
final int category = a.getInt(com.android.internal.R.styleable.MenuItem_menuCategory, groupCategory);
final int order = a.getInt(com.android.internal.R.styleable.MenuItem_orderInCategory, groupOrder);
itemCategoryOrder = (category & Menu.CATEGORY_MASK) | (order & Menu.USER_MASK);
- itemTitle = a.getString(com.android.internal.R.styleable.MenuItem_title);
- itemTitleCondensed = a.getString(com.android.internal.R.styleable.MenuItem_titleCondensed);
+ itemTitle = a.getText(com.android.internal.R.styleable.MenuItem_title);
+ itemTitleCondensed = a.getText(com.android.internal.R.styleable.MenuItem_titleCondensed);
itemIconResId = a.getResourceId(com.android.internal.R.styleable.MenuItem_icon, 0);
itemAlphabeticShortcut =
getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_alphabeticShortcut));
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 966bd8d..87b3d79 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -174,6 +174,7 @@ public class SurfaceView extends View {
return true;
}
};
+ private boolean mGlobalListenersAdded;
public SurfaceView(Context context) {
super(context);
@@ -212,9 +213,13 @@ public class SurfaceView extends View {
mLayout.token = getWindowToken();
mLayout.setTitle("SurfaceView");
mViewVisibility = getVisibility() == VISIBLE;
- ViewTreeObserver observer = getViewTreeObserver();
- observer.addOnScrollChangedListener(mScrollChangedListener);
- observer.addOnPreDrawListener(mDrawListener);
+
+ if (!mGlobalListenersAdded) {
+ ViewTreeObserver observer = getViewTreeObserver();
+ observer.addOnScrollChangedListener(mScrollChangedListener);
+ observer.addOnPreDrawListener(mDrawListener);
+ mGlobalListenersAdded = true;
+ }
}
@Override
@@ -275,9 +280,13 @@ public class SurfaceView extends View {
@Override
protected void onDetachedFromWindow() {
- ViewTreeObserver observer = getViewTreeObserver();
- observer.removeOnScrollChangedListener(mScrollChangedListener);
- observer.removeOnPreDrawListener(mDrawListener);
+ if (mGlobalListenersAdded) {
+ ViewTreeObserver observer = getViewTreeObserver();
+ observer.removeOnScrollChangedListener(mScrollChangedListener);
+ observer.removeOnPreDrawListener(mDrawListener);
+ mGlobalListenersAdded = false;
+ }
+
mRequestedVisible = false;
updateWindow(false, false);
mHaveFrame = false;
@@ -285,6 +294,7 @@ public class SurfaceView extends View {
try {
mSession.remove(mWindow);
} catch (RemoteException ex) {
+ // Not much we can do here...
}
mWindow = null;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d0b150b..f111f98 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -521,7 +521,7 @@ import java.util.WeakHashMap;
* The framework provides basic support for views that wish to internally
* scroll their content. This includes keeping track of the X and Y scroll
* offset as well as mechanisms for drawing scrollbars. See
- * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and
+ * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and
* {@link #awakenScrollBars()} for more details.
* </p>
*
@@ -1645,27 +1645,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @hide
*/
static final int OPAQUE_MASK = 0x01800000;
-
+
/**
* Indicates a prepressed state;
* the short time between ACTION_DOWN and recognizing
* a 'real' press. Prepressed is used to recognize quick taps
* even when they are shorter than ViewConfiguration.getTapTimeout().
- *
+ *
* @hide
*/
private static final int PREPRESSED = 0x02000000;
-
+
/**
* Indicates whether the view is temporarily detached.
*
* @hide
*/
static final int CANCEL_NEXT_UP_EVENT = 0x04000000;
-
+
/**
* Indicates that we should awaken scroll bars once attached
- *
+ *
* @hide
*/
private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;
@@ -1720,18 +1720,114 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* View has requested the status bar to be visible (the default).
*
- * @see #setSystemUiVisibility(int)
+ * @see #setSystemUiVisibility(int)
*/
public static final int STATUS_BAR_VISIBLE = 0;
/**
* View has requested the status bar to be visible (the default).
*
- * @see #setSystemUiVisibility(int)
+ * @see #setSystemUiVisibility(int)
*/
public static final int STATUS_BAR_HIDDEN = 0x00000001;
/**
+ * @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to make the status bar not expandable. Unless you also
+ * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show.
+ */
+ public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000;
+
+ /**
+ * @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to hide notification icons and scrolling ticker text.
+ */
+ public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000;
+
+ /**
+ * @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to disable incoming notification alerts. This will not block
+ * icons, but it will block sound, vibrating and other visual or aural notifications.
+ */
+ public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000;
+
+ /**
+ * @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to hide only the scrolling ticker. Note that
+ * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies
+ * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}.
+ */
+ public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000;
+
+ /**
+ * @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to hide the center system info area.
+ */
+ public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000;
+
+ /**
+ * @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to hide only the navigation buttons. Don't use this
+ * unless you're a special part of the system UI (i.e., setup wizard, keyguard).
+ *
+ * THIS DOES NOT DISABLE THE BACK BUTTON
+ */
+ public static final int STATUS_BAR_DISABLE_NAVIGATION = 0x00200000;
+
+ /**
+ * @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to hide only the back button. Don't use this
+ * unless you're a special part of the system UI (i.e., setup wizard, keyguard).
+ */
+ public static final int STATUS_BAR_DISABLE_BACK = 0x00400000;
+
+ /**
+ * @hide
+ *
+ * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+ * out of the public fields to keep the undefined bits out of the developer's way.
+ *
+ * Flag to hide only the clock. You might use this if your activity has
+ * its own clock making the status bar's clock redundant.
+ */
+ public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000;
+
+
+ /**
+ * @hide
+ */
+ public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = STATUS_BAR_HIDDEN;
+
+
+ /**
* Controls the over-scroll mode for this view.
* See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)},
* {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS},
@@ -1773,6 +1869,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* This view's request for the visibility of the status bar.
* @hide
*/
+ @ViewDebug.ExportedProperty()
int mSystemUiVisibility;
/**
@@ -1854,8 +1951,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
private int mPrevWidth = -1;
private int mPrevHeight = -1;
- private boolean mLastIsOpaque;
-
+ private boolean mLastIsOpaque;
+
/**
* Convenience value to check for float values that are close enough to zero to be considered
* zero.
@@ -2129,7 +2226,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
private CheckForLongPress mPendingCheckForLongPress;
private CheckForTap mPendingCheckForTap = null;
private PerformClick mPerformClick;
-
+
private UnsetPressedState mUnsetPressedState;
/**
@@ -2170,7 +2267,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* Special tree observer used when mAttachInfo is null.
*/
private ViewTreeObserver mFloatingTreeObserver;
-
+
/**
* Cache the touch slop from the context that created the view.
*/
@@ -2210,11 +2307,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* Indicates that the view does not have a layer.
- *
- * @see #getLayerType()
- * @see #setLayerType(int, android.graphics.Paint)
+ *
+ * @see #getLayerType()
+ * @see #setLayerType(int, android.graphics.Paint)
* @see #LAYER_TYPE_SOFTWARE
- * @see #LAYER_TYPE_HARDWARE
+ * @see #LAYER_TYPE_HARDWARE
*/
public static final int LAYER_TYPE_NONE = 0;
@@ -2222,7 +2319,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* <p>Indicates that the view has a software layer. A software layer is backed
* by a bitmap and causes the view to be rendered using Android's software
* rendering pipeline, even if hardware acceleration is enabled.</p>
- *
+ *
* <p>Software layers have various usages:</p>
* <p>When the application is not using hardware acceleration, a software layer
* is useful to apply a specific color filter and/or blending mode and/or
@@ -2238,11 +2335,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* potentially be slow (particularly when hardware acceleration is turned on
* since the layer will have to be uploaded into a hardware texture after every
* update.)</p>
- *
- * @see #getLayerType()
- * @see #setLayerType(int, android.graphics.Paint)
+ *
+ * @see #getLayerType()
+ * @see #setLayerType(int, android.graphics.Paint)
* @see #LAYER_TYPE_NONE
- * @see #LAYER_TYPE_HARDWARE
+ * @see #LAYER_TYPE_HARDWARE
*/
public static final int LAYER_TYPE_SOFTWARE = 1;
@@ -2253,7 +2350,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* rendering pipeline, but only if hardware acceleration is turned on for the
* view hierarchy. When hardware acceleration is turned off, hardware layers
* behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p>
- *
+ *
* <p>A hardware layer is useful to apply a specific color filter and/or
* blending mode and/or translucency to a view and all its children.</p>
* <p>A hardware layer can be used to cache a complex view tree into a
@@ -2263,14 +2360,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* <p>A hardware layer can also be used to increase the rendering quality when
* rotation transformations are applied on a view. It can also be used to
* prevent potential clipping issues when applying 3D transforms on a view.</p>
- *
- * @see #getLayerType()
+ *
+ * @see #getLayerType()
* @see #setLayerType(int, android.graphics.Paint)
* @see #LAYER_TYPE_NONE
* @see #LAYER_TYPE_SOFTWARE
*/
public static final int LAYER_TYPE_HARDWARE = 2;
-
+
@ViewDebug.ExportedProperty(category = "drawing", mapping = {
@ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"),
@ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"),
@@ -2572,7 +2669,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
break;
case R.styleable.View_onClick:
if (context.isRestricted()) {
- throw new IllegalStateException("The android:onClick attribute cannot "
+ throw new IllegalStateException("The android:onClick attribute cannot "
+ "be used within a restricted context");
}
@@ -2811,19 +2908,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
initScrollCache();
final ScrollabilityCache scrollabilityCache = mScrollCache;
-
+
if (scrollabilityCache.scrollBar == null) {
scrollabilityCache.scrollBar = new ScrollBarDrawable();
}
-
+
final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true);
if (!fadeScrollbars) {
scrollabilityCache.state = ScrollabilityCache.ON;
}
scrollabilityCache.fadeScrollBars = fadeScrollbars;
-
-
+
+
scrollabilityCache.scrollBarFadeDuration = a.getInt(
R.styleable.View_scrollbarFadeDuration, ViewConfiguration
.getScrollBarFadeDuration());
@@ -2831,7 +2928,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
R.styleable.View_scrollbarDefaultDelayBeforeFade,
ViewConfiguration.getScrollDefaultDelay());
-
+
scrollabilityCache.scrollBarSize = a.getDimensionPixelSize(
com.android.internal.R.styleable.View_scrollbarSize,
ViewConfiguration.get(mContext).getScaledScrollBarSize());
@@ -3067,8 +3164,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * Register a callback to be invoked when a drag event is sent to this view.
- * @param l The drag listener to attach to this view
+ * Register a drag event listener callback object for this View. The parameter is
+ * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a
+ * View, the system calls the
+ * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method.
+ * @param l An implementation of {@link android.view.View.OnDragListener}.
*/
public void setOnDragListener(OnDragListener l) {
mOnDragListener = l;
@@ -3279,7 +3379,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (mOnFocusChangeListener != null) {
mOnFocusChangeListener.onFocusChange(this, gainFocus);
}
-
+
if (mAttachInfo != null) {
mAttachInfo.mKeyDispatchState.reset(this);
}
@@ -4427,7 +4527,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public KeyEvent.DispatcherState getKeyDispatcherState() {
return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null;
}
-
+
/**
* Dispatch a key event before it is processed by any input method
* associated with the view hierarchy. This can be used to intercept
@@ -4505,7 +4605,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*
* @param event The motion event to be filtered.
* @return True if the event should be dispatched, false if the event should be dropped.
- *
+ *
* @see #getFilterTouchesWhenObscured
*/
public boolean onFilterTouchEventForSecurity(MotionEvent event) {
@@ -4612,7 +4712,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* a View moves out of the screen, it might receives a display hint indicating
* the view is not displayed. Applications should not <em>rely</em> on this hint
* as there is no guarantee that they will receive one.
- *
+ *
* @param hint A hint about whether or not this view is displayed:
* {@link #VISIBLE} or {@link #INVISIBLE}.
*/
@@ -4625,7 +4725,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* a View moves out of the screen, it might receives a display hint indicating
* the view is not displayed. Applications should not <em>rely</em> on this hint
* as there is no guarantee that they will receive one.
- *
+ *
* @param hint A hint about whether or not this view is displayed:
* {@link #VISIBLE} or {@link #INVISIBLE}.
*/
@@ -5078,7 +5178,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mPrivateFlags |= PRESSED;
refreshDrawableState();
}
-
+
if (!mHasPerformedLongPress) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
@@ -5581,7 +5681,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* Returns true if the transform matrix is the identity matrix.
* Recomputes the matrix if necessary.
- *
+ *
* @return True if the transform matrix is the identity matrix, false otherwise.
*/
final boolean hasIdentityMatrix() {
@@ -5922,16 +6022,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* <p>Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is
* completely transparent and 1 means the view is completely opaque.</p>
- *
+ *
* <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is
* responsible for applying the opacity itself. Otherwise, calling this method is
* equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
- * setting a hardware layer.</p>
+ * setting a hardware layer.</p>
*
* @param alpha The opacity of the view.
*
- * @see #setLayerType(int, android.graphics.Paint)
- *
+ * @see #setLayerType(int, android.graphics.Paint)
+ *
* @attr ref android.R.styleable#View_alpha
*/
public void setAlpha(float alpha) {
@@ -6197,7 +6297,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* The visual x position of this view, in pixels. This is equivalent to the
* {@link #setTranslationX(float) translationX} property plus the current
- * {@link #getLeft() left} property.
+ * {@link #getLeft() left} property.
*
* @return The visual x position of this view, in pixels.
*/
@@ -6594,7 +6694,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* provides animated scrolling, the start delay should equal the duration of
* the scrolling animation.
* </p>
- *
+ *
* <p>
* The animation starts only if at least one of the scrollbars is enabled,
* as specified by {@link #isHorizontalScrollBarEnabled()} and
@@ -6603,17 +6703,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* started, this method calls {@link #invalidate()}; in that case the caller
* should not call {@link #invalidate()}.
* </p>
- *
+ *
* <p>
* This method should be invoked everytime a subclass directly updates the
* scroll parameters.
* </p>
- *
+ *
* @param startDelay the delay, in milliseconds, after which the animation
* should start; when the delay is 0, the animation starts
* immediately
* @return true if the animation is played, false otherwise
- *
+ *
* @see #scrollBy(int, int)
* @see #scrollTo(int, int)
* @see #isHorizontalScrollBarEnabled()
@@ -6624,7 +6724,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
protected boolean awakenScrollBars(int startDelay) {
return awakenScrollBars(startDelay, true);
}
-
+
/**
* <p>
* Trigger the scrollbars to draw. When invoked this method starts an
@@ -6632,30 +6732,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* provides animated scrolling, the start delay should equal the duration of
* the scrolling animation.
* </p>
- *
+ *
* <p>
* The animation starts only if at least one of the scrollbars is enabled,
* as specified by {@link #isHorizontalScrollBarEnabled()} and
* {@link #isVerticalScrollBarEnabled()}. When the animation is started,
* this method returns true, and false otherwise. If the animation is
- * started, this method calls {@link #invalidate()} if the invalidate parameter
+ * started, this method calls {@link #invalidate()} if the invalidate parameter
* is set to true; in that case the caller
* should not call {@link #invalidate()}.
* </p>
- *
+ *
* <p>
* This method should be invoked everytime a subclass directly updates the
* scroll parameters.
* </p>
- *
+ *
* @param startDelay the delay, in milliseconds, after which the animation
* should start; when the delay is 0, the animation starts
* immediately
- *
+ *
* @param invalidate Wheter this method should call invalidate
- *
+ *
* @return true if the animation is played, false otherwise
- *
+ *
* @see #scrollBy(int, int)
* @see #scrollTo(int, int)
* @see #isHorizontalScrollBarEnabled()
@@ -6665,7 +6765,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*/
protected boolean awakenScrollBars(int startDelay, boolean invalidate) {
final ScrollabilityCache scrollCache = mScrollCache;
-
+
if (scrollCache == null || !scrollCache.fadeScrollBars) {
return false;
}
@@ -6798,7 +6898,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public void invalidate() {
invalidate(true);
}
-
+
/**
* This is where the invalidate() work actually happens. A full invalidate()
* causes the drawing cache to be invalidated, but this function can be called with
@@ -6860,7 +6960,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
((View) mParent).mPrivateFlags |= INVALIDATED;
}
}
-
+
/**
* Used to indicate that the parent of this view should be invalidated. This functionality
* is used to force the parent to rebuild its display list (when hardware-accelerated),
@@ -7289,12 +7389,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
protected void recomputePadding() {
setPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom);
}
-
+
/**
* Define whether scrollbars will fade when the view is not scrolling.
- *
+ *
* @param fadeScrollbars wheter to enable fading
- *
+ *
*/
public void setScrollbarFadingEnabled(boolean fadeScrollbars) {
initScrollCache();
@@ -7306,17 +7406,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
scrollabilityCache.state = ScrollabilityCache.ON;
}
}
-
+
/**
- *
+ *
* Returns true if scrollbars will fade when this view is not scrolling
- *
+ *
* @return true if scrollbar fading is enabled
*/
public boolean isScrollbarFadingEnabled() {
- return mScrollCache != null && mScrollCache.fadeScrollBars;
+ return mScrollCache != null && mScrollCache.fadeScrollBars;
}
-
+
/**
* <p>Specify the style of the scrollbars. The scrollbars can be overlaid or
* inset. When inset, they add to the padding of the view. And the scrollbars
@@ -7483,30 +7583,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* scrollbars are painted only if they have been awakened first.</p>
*
* @param canvas the canvas on which to draw the scrollbars
- *
+ *
* @see #awakenScrollBars(int)
*/
protected final void onDrawScrollBars(Canvas canvas) {
// scrollbars are drawn only when the animation is running
final ScrollabilityCache cache = mScrollCache;
if (cache != null) {
-
+
int state = cache.state;
-
+
if (state == ScrollabilityCache.OFF) {
return;
}
-
+
boolean invalidate = false;
-
+
if (state == ScrollabilityCache.FADING) {
// We're fading -- get our fade interpolation
if (cache.interpolatorValues == null) {
cache.interpolatorValues = new float[1];
}
-
+
float[] values = cache.interpolatorValues;
-
+
// Stops the animation if we're done
if (cache.scrollBarInterpolator.timeToValues(values) ==
Interpolator.Result.FREEZE_END) {
@@ -7514,8 +7614,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
} else {
cache.scrollBar.setAlpha(Math.round(values[0]));
}
-
- // This will make the scroll bars inval themselves after
+
+ // This will make the scroll bars inval themselves after
// drawing. We only want this when we're fading so that
// we prevent excessive redraws
invalidate = true;
@@ -7525,7 +7625,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
cache.scrollBar.setAlpha(255);
}
-
+
final int viewFlags = mViewFlags;
final boolean drawHorizontalScrollBar =
@@ -7545,7 +7645,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
int left, top, right, bottom;
-
+
if (drawHorizontalScrollBar) {
int size = scrollBar.getSize(false);
if (size <= 0) {
@@ -7557,7 +7657,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
computeHorizontalScrollExtent(), false);
final int verticalScrollBarGap = drawVerticalScrollBar ?
getVerticalScrollbarWidth() : 0;
- top = scrollY + height - size - (mUserPaddingBottom & inside);
+ top = scrollY + height - size - (mUserPaddingBottom & inside);
left = scrollX + (mPaddingLeft & inside);
right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
bottom = top + size;
@@ -7801,7 +7901,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
void dispatchDetachedFromWindow() {
- //System.out.println("Detached! " + this);
AttachInfo info = mAttachInfo;
if (info != null) {
int vis = info.mWindowVisibility;
@@ -7811,10 +7910,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
onDetachedFromWindow();
- if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) {
+
+ if ((mPrivateFlags & SCROLL_CONTAINER_ADDED) != 0) {
mAttachInfo.mScrollContainers.remove(this);
mPrivateFlags &= ~SCROLL_CONTAINER_ADDED;
}
+
mAttachInfo = null;
}
@@ -7941,8 +8042,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (state != BaseSavedState.EMPTY_STATE && state != null) {
throw new IllegalArgumentException("Wrong state class, expecting View State but "
+ "received " + state.getClass().toString() + " instead. This usually happens "
- + "when two views of different type have the same id in the same hierarchy. "
- + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure "
+ + "when two views of different type have the same id in the same hierarchy. "
+ + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure "
+ "other views do not use the same id.");
}
}
@@ -7967,7 +8068,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*
* <p>Note: if this view's parent addStateFromChildren property is enabled and this
* property is enabled, an exception will be thrown.</p>
- *
+ *
* <p>Note: if the child view uses and updates additionnal states which are unknown to the
* parent, these states should not be affected by this method.</p>
*
@@ -7998,7 +8099,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* <p>Specifies the type of layer backing this view. The layer can be
* {@link #LAYER_TYPE_NONE disabled}, {@link #LAYER_TYPE_SOFTWARE software} or
* {@link #LAYER_TYPE_HARDWARE hardware}.</p>
- *
+ *
* <p>A layer is associated with an optional {@link android.graphics.Paint}
* instance that controls how the layer is composed on screen. The following
* properties of the paint are taken into account when composing the layer:</p>
@@ -8007,35 +8108,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li>
* <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
* </ul>
- *
+ *
* <p>If this view has an alpha value set to < 1.0 by calling
* {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
* this view's alpha value. Calling {@link #setAlpha(float)} is therefore
* equivalent to setting a hardware layer on this view and providing a paint with
* the desired alpha value.<p>
- *
+ *
* <p>Refer to the documentation of {@link #LAYER_TYPE_NONE disabled},
* {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware}
* for more information on when and how to use layers.</p>
- *
+ *
* @param layerType The ype of layer to use with this view, must be one of
* {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
* {@link #LAYER_TYPE_HARDWARE}
* @param paint The paint used to compose the layer. This argument is optional
* and can be null. It is ignored when the layer type is
* {@link #LAYER_TYPE_NONE}
- *
- * @see #getLayerType()
+ *
+ * @see #getLayerType()
* @see #LAYER_TYPE_NONE
* @see #LAYER_TYPE_SOFTWARE
* @see #LAYER_TYPE_HARDWARE
- * @see #setAlpha(float)
- *
+ * @see #setAlpha(float)
+ *
* @attr ref android.R.styleable#View_layerType
*/
public void setLayerType(int layerType, Paint paint) {
if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) {
- throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
+ throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
+ "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
}
@@ -8055,7 +8156,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mDrawingCache.recycle();
mDrawingCache = null;
}
-
+
if (mUnscaledDrawingCache != null) {
mUnscaledDrawingCache.recycle();
mUnscaledDrawingCache = null;
@@ -8083,11 +8184,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}.
* Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)}
* for more information on the different types of layers.
- *
+ *
* @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
* {@link #LAYER_TYPE_HARDWARE}
- *
- * @see #setLayerType(int, android.graphics.Paint)
+ *
+ * @see #setLayerType(int, android.graphics.Paint)
* @see #LAYER_TYPE_NONE
* @see #LAYER_TYPE_SOFTWARE
* @see #LAYER_TYPE_HARDWARE
@@ -8095,7 +8196,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public int getLayerType() {
return mLayerType;
}
-
+
/**
* <p>Returns a hardware layer that can be used to draw this view again
* without executing its draw method.</p>
@@ -8109,7 +8210,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
final int width = mRight - mLeft;
final int height = mBottom - mTop;
-
+
if (width == 0 || height == 0) {
return null;
}
@@ -8136,7 +8237,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
canvas.translate(-mScrollX, -mScrollY);
mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
-
+
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
mPrivateFlags &= ~DIRTY_MASK;
@@ -8144,7 +8245,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
} else {
draw(canvas);
}
-
+
canvas.restoreToCount(restoreCount);
} finally {
canvas.onPostDraw();
@@ -8163,7 +8264,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* the cache is enabled. To benefit from the cache, you must request the drawing cache by
* calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not
* null.</p>
- *
+ *
* <p>Enabling the drawing cache is similar to
* {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware
* acceleration is turned off. When hardware acceleration is turned on, enabling the
@@ -8181,7 +8282,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @see #isDrawingCacheEnabled()
* @see #getDrawingCache()
* @see #buildDrawingCache()
- * @see #setLayerType(int, android.graphics.Paint)
+ * @see #setLayerType(int, android.graphics.Paint)
*/
public void setDrawingCacheEnabled(boolean enabled) {
setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED);
@@ -8203,7 +8304,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* Debugging utility which recursively outputs the dirty state of a view and its
* descendants.
- *
+ *
* @hide
*/
public void outputDirtyFlags(String indent, boolean clear, int clearMask) {
@@ -8248,11 +8349,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
return true;
}
-
+
/**
* <p>Returns a display list that can be used to draw this view again
* without executing its draw method.</p>
- *
+ *
* @return A DisplayList ready to replay, or null if caching is not enabled.
*
* @hide
@@ -8301,7 +8402,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
computeScroll();
canvas.translate(-mScrollX, -mScrollY);
mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
-
+
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
mPrivateFlags &= ~DIRTY_MASK;
@@ -8309,7 +8410,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
} else {
draw(canvas);
}
-
+
canvas.restoreToCount(restoreCount);
} finally {
canvas.onPostDraw();
@@ -8326,9 +8427,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
- *
+ *
* @return A non-scaled bitmap representing this view or null if cache is disabled.
- *
+ *
* @see #getDrawingCache(boolean)
*/
public Bitmap getDrawingCache() {
@@ -8342,7 +8443,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* draw from the cache when the cache is enabled. To benefit from the cache, you must
* request the drawing cache by calling this method and draw it on screen if the
* returned bitmap is not null.</p>
- *
+ *
* <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled,
* this method will create a bitmap of the same size as this view. Because this bitmap
* will be drawn scaled by the parent ViewGroup, the result on screen might show
@@ -8350,13 +8451,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* the auto scaling to true. Doing so, however, will generate a bitmap of a different
* size than the view. This implies that your application must be able to handle this
* size.</p>
- *
+ *
* @param autoScale Indicates whether the generated bitmap should be scaled based on
* the current density of the screen when the application is in compatibility
* mode.
*
* @return A bitmap representing this view or null if cache is disabled.
- *
+ *
* @see #setDrawingCacheEnabled(boolean)
* @see #isDrawingCacheEnabled()
* @see #buildDrawingCache(boolean)
@@ -8422,7 +8523,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p>
- *
+ *
* @see #buildDrawingCache(boolean)
*/
public void buildDrawingCache() {
@@ -8435,7 +8536,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* <p>If you call {@link #buildDrawingCache()} manually without calling
* {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you
* should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p>
- *
+ *
* <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled,
* this method will create a bitmap of the same size as this view. Because this bitmap
* will be drawn scaled by the parent ViewGroup, the result on screen might show
@@ -8443,10 +8544,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* the auto scaling to true. Doing so, however, will generate a bitmap of a different
* size than the view. This implies that your application must be able to handle this
* size.</p>
- *
+ *
* <p>You should avoid calling this method when hardware acceleration is enabled. If
* you do not need the drawing cache bitmap, calling this method will increase memory
- * usage and cause the view to be rendered in software once, thus negatively impacting
+ * usage and cause the view to be rendered in software once, thus negatively impacting
* performance.</p>
*
* @see #getDrawingCache()
@@ -8559,12 +8660,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
computeScroll();
final int restoreCount = canvas.save();
-
+
if (autoScale && scalingRequired) {
final float scale = attachInfo.mApplicationScale;
canvas.scale(scale, scale);
}
-
+
canvas.translate(-mScrollX, -mScrollY);
mPrivateFlags |= DRAWN;
@@ -8605,14 +8706,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
width = (int) ((width * scale) + 0.5f);
height = (int) ((height * scale) + 0.5f);
-
+
Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality);
if (bitmap == null) {
throw new OutOfMemoryError();
}
bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
-
+
Canvas canvas;
if (attachInfo != null) {
canvas = attachInfo.mCanvas;
@@ -8762,7 +8863,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
* <p>Indicates whether this view is attached to an hardware accelerated
* window or not.</p>
- *
+ *
* <p>Even if this method returns true, it does not mean that every call
* to {@link #draw(android.graphics.Canvas)} will be made with an hardware
* accelerated {@link android.graphics.Canvas}. For instance, if this view
@@ -8770,14 +8871,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* window is hardware accelerated,
* {@link android.graphics.Canvas#isHardwareAccelerated()} will likely
* return false, and this method will return true.</p>
- *
+ *
* @return True if the view is attached to a window and the window is
* hardware accelerated; false in any other case.
*/
public boolean isHardwareAccelerated() {
return mAttachInfo != null && mAttachInfo.mHardwareAccelerated;
}
-
+
/**
* Manually render this view (and all of its children) to the given Canvas.
* The view must have already done a full layout before this function is
@@ -10837,28 +10938,42 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
/**
*/
public void dispatchSystemUiVisibilityChanged(int visibility) {
- mSystemUiVisibility = visibility;
if (mOnSystemUiVisibilityChangeListener != null) {
- mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange(visibility);
+ mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange(
+ visibility & ~PUBLIC_STATUS_BAR_VISIBILITY_MASK);
}
}
/**
- * !!! TODO: real docs
- *
- * The base class implementation makes the shadow the same size and appearance
- * as the view itself, and positions it with its center at the touch point.
+ * Creates an image that the system displays during the drag and drop
+ * operation. This is called a &quot;drag shadow&quot;. The default implementation
+ * for a DragShadowBuilder based on a View returns an image that has exactly the same
+ * appearance as the given View. The default also positions the center of the drag shadow
+ * directly under the touch point. If no View is provided (the constructor with no parameters
+ * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and
+ * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overriden, then the
+ * default is an invisible drag shadow.
+ * <p>
+ * You are not required to use the View you provide to the constructor as the basis of the
+ * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw
+ * anything you want as the drag shadow.
+ * </p>
+ * <p>
+ * You pass a DragShadowBuilder object to the system when you start the drag. The system
+ * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the
+ * size and position of the drag shadow. It uses this data to construct a
+ * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()}
+ * so that your application can draw the shadow image in the Canvas.
+ * </p>
*/
public static class DragShadowBuilder {
private final WeakReference<View> mView;
/**
- * Construct a shadow builder object for use with the given View object. The
- * default implementation will construct a drag shadow the same size and
- * appearance as the supplied View.
- *
- * @param view A view within the application's layout whose appearance
- * should be replicated as the drag shadow.
+ * Constructs a shadow image builder based on a View. By default, the resulting drag
+ * shadow will have the same appearance and dimensions as the View, with the touch point
+ * over the center of the View.
+ * @param view A View. Any View in scope can be used.
*/
public DragShadowBuilder(View view) {
mView = new WeakReference<View>(view);
@@ -10869,7 +10984,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)}
* and {@link #onDrawShadow(Canvas)} methods are also overridden in order
* to supply the drag shadow's dimensions and appearance without
- * reference to any View object.
+ * reference to any View object. If they are not overridden, then the result is an
+ * invisible drag shadow.
*/
public DragShadowBuilder() {
mView = new WeakReference<View>(null);
@@ -10890,22 +11006,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * Provide the draggable-shadow metrics for the operation: the dimensions of
- * the shadow image itself, and the point within that shadow that should
+ * Provides the metrics for the shadow image. These include the dimensions of
+ * the shadow image, and the point within that shadow that should
* be centered under the touch location while dragging.
* <p>
* The default implementation sets the dimensions of the shadow to be the
- * same as the dimensions of the View object that had been supplied to the
- * {@link #View.DragShadowBuilder(View)} constructor
- * when the builder object was instantiated, and centers the shadow under the touch
- * point.
+ * same as the dimensions of the View itself and centers the shadow under
+ * the touch point.
+ * </p>
+ *
+ * @param shadowSize A {@link android.graphics.Point} containing the width and height
+ * of the shadow image. Your application must set {@link android.graphics.Point#x} to the
+ * desired width and must set {@link android.graphics.Point#y} to the desired height of the
+ * image.
*
- * @param shadowSize The application should set the {@code x} member of this
- * parameter to the desired shadow width, and the {@code y} member to
- * the desired height.
- * @param shadowTouchPoint The application should set this point to be the
- * location within the shadow that should track directly underneath
- * the touch point on the screen during a drag.
+ * @param shadowTouchPoint A {@link android.graphics.Point} for the position within the
+ * shadow image that should be underneath the touch point during the drag and drop
+ * operation. Your application must set {@link android.graphics.Point#x} to the
+ * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position.
*/
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
final View view = mView.get();
@@ -10918,16 +11036,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * Draw the shadow image for the upcoming drag. The shadow canvas was
- * created with the dimensions supplied by the
+ * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object
+ * based on the dimensions it received from the
* {@link #onProvideShadowMetrics(Point, Point)} callback.
- * <p>
- * The default implementation replicates the appearance of the View object
- * that had been supplied to the
- * {@link #View.DragShadowBuilder(View)}
- * constructor when the builder object was instantiated.
*
- * @param canvas
+ * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image.
*/
public void onDrawShadow(Canvas canvas) {
final View view = mView.get();
@@ -10940,24 +11053,43 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * Drag and drop. App calls startDrag(), then callbacks to the shadow builder's
- * {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} and
- * {@link DragShadowBuilder#onDrawShadow(Canvas)} methods happen, then the drag
- * operation is handed over to the OS.
- * !!! TODO: real docs
- *
- * @param data !!! TODO
- * @param shadowBuilder !!! TODO
- * @param myLocalState An arbitrary object that will be passed as part of every DragEvent
- * delivered to the calling application during the course of the current drag operation.
- * This object is private to the application that called startDrag(), and is not
- * visible to other applications. It provides a lightweight way for the application to
- * propagate information from the initiator to the recipient of a drag within its own
- * application; for example, to help disambiguate between 'copy' and 'move' semantics.
- * @param flags Flags affecting the drag operation. At present no flags are defined;
- * pass 0 for this parameter.
- * @return {@code true} if the drag operation was initiated successfully; {@code false} if
- * an error prevented the drag from taking place.
+ * Starts a drag and drop operation. When your application calls this method, it passes a
+ * {@link android.view.View.DragShadowBuilder} object to the system. The
+ * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)}
+ * to get metrics for the drag shadow, and then calls the object's
+ * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself.
+ * <p>
+ * Once the system has the drag shadow, it begins the drag and drop operation by sending
+ * drag events to all the View objects in your application that are currently visible. It does
+ * this either by calling the View object's drag listener (an implementation of
+ * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the
+ * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method.
+ * Both are passed a {@link android.view.DragEvent} object that has a
+ * {@link android.view.DragEvent#getAction()} value of
+ * {@link android.view.DragEvent#ACTION_DRAG_STARTED}.
+ * </p>
+ * <p>
+ * Your application can invoke startDrag() on any attached View object. The View object does not
+ * need to be the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to
+ * be related to the View the user selected for dragging.
+ * </p>
+ * @param data A {@link android.content.ClipData} object pointing to the data to be
+ * transferred by the drag and drop operation.
+ * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
+ * drag shadow.
+ * @param myLocalState An {@link java.lang.Object} containing local data about the drag and
+ * drop operation. This Object is put into every DragEvent object sent by the system during the
+ * current drag.
+ * <p>
+ * myLocalState is a lightweight mechanism for the sending information from the dragged View
+ * to the target Views. For example, it can contain flags that differentiate between a
+ * a copy operation and a move operation.
+ * </p>
+ * @param flags Flags that control the drag and drop operation. No flags are currently defined,
+ * so the parameter should be set to 0.
+ * @return {@code true} if the method completes successfully, or
+ * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to
+ * do a drag, and so no drag operation is in progress.
*/
public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder,
Object myLocalState, int flags) {
@@ -11016,42 +11148,48 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * Drag-and-drop event dispatch. The event.getAction() verb is one of the DragEvent
- * constants DRAG_STARTED_EVENT, DRAG_EVENT, DROP_EVENT, and DRAG_ENDED_EVENT.
- *
- * For DRAG_STARTED_EVENT, event.getClipDescription() describes the content
- * being dragged. onDragEvent() should return 'true' if the view can handle
- * a drop of that content. A view that returns 'false' here will receive no
- * further calls to onDragEvent() about the drag/drop operation.
- *
- * For DRAG_ENTERED, event.getClipDescription() describes the content being
- * dragged. This will be the same content description passed in the
- * DRAG_STARTED_EVENT invocation.
- *
- * For DRAG_EXITED, event.getClipDescription() describes the content being
- * dragged. This will be the same content description passed in the
- * DRAG_STARTED_EVENT invocation. The view should return to its approriate
- * drag-acceptance visual state.
- *
- * For DRAG_LOCATION_EVENT, event.getX() and event.getY() give the location in View
- * coordinates of the current drag point. The view must return 'true' if it
- * can accept a drop of the current drag content, false otherwise.
- *
- * For DROP_EVENT, event.getX() and event.getY() give the location of the drop
- * within the view; also, event.getClipData() returns the full data payload
- * being dropped. The view should return 'true' if it consumed the dropped
- * content, 'false' if it did not.
- *
- * For DRAG_ENDED_EVENT, the 'event' argument may be null. The view should return
- * to its normal visual state.
+ * Handles drag events sent by the system following a call to
+ * {@link android.view.View#startDrag(ClipData,DragShadowBuilder,Object,int) startDrag()}.
+ *<p>
+ * When the system calls this method, it passes a
+ * {@link android.view.DragEvent} object. A call to
+ * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined
+ * in DragEvent. The method uses these to determine what is happening in the drag and drop
+ * operation.
+ * @param event The {@link android.view.DragEvent} sent by the system.
+ * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined
+ * in DragEvent, indicating the type of drag event represented by this object.
+ * @return {@code true} if the method was successful, otherwise {@code false}.
+ * <p>
+ * The method should return {@code true} in response to an action type of
+ * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current
+ * operation.
+ * </p>
+ * <p>
+ * The method should also return {@code true} in response to an action type of
+ * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or
+ * {@code false} if it didn't.
+ * </p>
*/
public boolean onDragEvent(DragEvent event) {
return false;
}
/**
- * Views typically don't need to override dispatchDragEvent(); it just calls
- * onDragEvent(event) and passes the result up appropriately.
+ * Detects if this View is enabled and has a drag event listener.
+ * If both are true, then it calls the drag event listener with the
+ * {@link android.view.DragEvent} it received. If the drag event listener returns
+ * {@code true}, then dispatchDragEvent() returns {@code true}.
+ * <p>
+ * For all other cases, the method calls the
+ * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler
+ * method and returns its result.
+ * </p>
+ * <p>
+ * This ensures that a drag event is always consumed, even if the View does not have a drag
+ * event listener. However, if the View has a listener and the listener returns true, then
+ * onDragEvent() is not called.
+ * </p>
*/
public boolean dispatchDragEvent(DragEvent event) {
if (mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
@@ -11068,7 +11206,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*/
public void onCloseSystemDialogs(String reason) {
}
-
+
/**
* Given a Drawable whose bounds have been set to draw into this view,
* update a Region being computed for {@link #gatherTransparentRegion} so
@@ -11400,7 +11538,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
mOriginalWindowAttachCount = mWindowAttachCount;
}
}
-
+
private final class CheckForTap implements Runnable {
public void run() {
mPrivateFlags &= ~PREPRESSED;
@@ -11422,7 +11560,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public void hackTurnOffWindowResizeAnim(boolean off) {
mAttachInfo.mTurnOffWindowResizeAnim = off;
}
-
+
/**
* Interface definition for a callback to be invoked when a key event is
* dispatched to this view. The callback will be invoked before the key
@@ -11485,11 +11623,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* Called when a drag event is dispatched to a view. This allows listeners
* to get a chance to override base View behavior.
*
- * @param v The view the drag has been dispatched to.
- * @param event The DragEvent object containing full information
- * about the event.
- * @return true if the listener consumed the DragEvent, false in order to fall
- * back to the view's default handling.
+ * @param v The View that received the drag event.
+ * @param event The {@link android.view.DragEvent} object for the drag event.
+ * @return {@code true} if the drag event was handled successfully, or {@code false}
+ * if the drag event was not handled. Note that {@code false} will trigger the View
+ * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler.
*/
boolean onDrag(View v, DragEvent event);
}
@@ -11677,7 +11815,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
boolean mHardwareAccelerated;
boolean mHardwareAccelerationRequested;
HardwareRenderer mHardwareRenderer;
-
+
/**
* Scale factor used by the compatibility mode
*/
@@ -11692,7 +11830,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* If set, ViewRoot doesn't use its lame animation for when the window resizes.
*/
boolean mTurnOffWindowResizeAnim;
-
+
/**
* Left position of this view's window
*/
@@ -11885,7 +12023,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* instances of View.</p>
*/
private static class ScrollabilityCache implements Runnable {
-
+
/**
* Scrollbars are not visible
*/
@@ -11902,7 +12040,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public static final int FADING = 2;
public boolean fadeScrollBars;
-
+
public int fadingEdgeLength;
public int scrollBarDefaultDelayBeforeFade;
public int scrollBarFadeDuration;
@@ -11920,7 +12058,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
private static final float[] OPAQUE = { 255 };
private static final float[] TRANSPARENT = { 0.0f };
-
+
/**
* When fading should start. This time moves into the future every time
* a new scroll happens. Measured based on SystemClock.uptimeMillis()
@@ -11965,7 +12103,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
paint.setXfermode(null);
}
}
-
+
public void run() {
long now = AnimationUtils.currentAnimationTimeMillis();
if (now >= fadeStartTime) {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index b21af41..b1d509a 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1551,11 +1551,13 @@ public final class ViewRoot extends Handler implements ViewParent,
Log.e(TAG, "OutOfResourcesException locking surface", e);
// TODO: we should ask the window manager to do something!
// for now we just do nothing
+ mLayoutRequested = true; // ask wm for a new surface next time.
return;
} catch (IllegalArgumentException e) {
Log.e(TAG, "IllegalArgumentException locking surface", e);
// TODO: we should ask the window manager to do something!
// for now we just do nothing
+ mLayoutRequested = true; // ask wm for a new surface next time.
return;
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7edfd7b..cb67b78 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -531,9 +531,9 @@ public final class InputMethodManager {
}
/** @hide */
- public void setIMEButtonVisible(IBinder imeToken, boolean visible) {
+ public void setImeWindowStatus(IBinder imeToken, int vis, int backDisposition) {
try {
- mService.setIMEButtonVisible(imeToken, visible);
+ mService.setImeWindowStatus(imeToken, vis, backDisposition);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6363299..fcfcc03 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -350,6 +350,7 @@ public class WebView extends AbsoluteLayout
private ZoomManager mZoomManager;
private Rect mGLRectViewport = new Rect();
+ private boolean mGLViewportEmpty = false;
/**
* Transportation object for returning WebView across thread boundaries.
@@ -2505,6 +2506,7 @@ public class WebView extends AbsoluteLayout
// Rect.equals() checks for null input.
if (!rect.equals(mLastVisibleRectSent)) {
Point pos = new Point(rect.left, rect.top);
+ mWebViewCore.removeMessages(EventHub.SET_SCROLL_OFFSET);
mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
nativeMoveGeneration(), mUserScroll ? 1 : 0, pos);
mLastVisibleRectSent = rect;
@@ -3734,6 +3736,10 @@ public class WebView extends AbsoluteLayout
return;
}
+ if (canvas.isHardwareAccelerated()) {
+ mZoomManager.setHardwareAccelerated();
+ }
+
int saveCount = canvas.save();
if (mInOverScrollMode && !getSettings()
.getUseWebViewBackgroundForOverscrollBackground()) {
@@ -4071,7 +4077,8 @@ public class WebView extends AbsoluteLayout
}
if (canvas.isHardwareAccelerated()) {
- int functor = nativeGetDrawGLFunction(mGLRectViewport, getScale(), extras);
+ int functor = nativeGetDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport,
+ getScale(), extras);
((HardwareCanvas) canvas).callDrawGLFunction(functor);
} else {
DrawFilter df = null;
@@ -5155,16 +5162,21 @@ public class WebView extends AbsoluteLayout
void setGLRectViewport() {
// Use the getGlobalVisibleRect() to get the intersection among the parents
- getGlobalVisibleRect(mGLRectViewport);
-
- // Then need to invert the Y axis, just for GL
- View rootView = getRootView();
- int rootViewHeight = rootView.getHeight();
- int savedWebViewBottom = mGLRectViewport.bottom;
- mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight();
- mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
-
- nativeUpdateDrawGLFunction(mGLRectViewport);
+ // visible == false means we're clipped - send a null rect down to indicate that
+ // we should not draw
+ boolean visible = getGlobalVisibleRect(mGLRectViewport);
+ if (visible) {
+ // Then need to invert the Y axis, just for GL
+ View rootView = getRootView();
+ int rootViewHeight = rootView.getHeight();
+ int savedWebViewBottom = mGLRectViewport.bottom;
+ mGLRectViewport.bottom = rootViewHeight - mGLRectViewport.top - getVisibleTitleHeight();
+ mGLRectViewport.top = rootViewHeight - savedWebViewBottom;
+ mGLViewportEmpty = false;
+ } else {
+ mGLViewportEmpty = true;
+ }
+ nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport);
}
/**
@@ -6613,15 +6625,10 @@ public class WebView extends AbsoluteLayout
* @param y New y position of the WebTextView in view coordinates
*/
/* package */ void scrollFocusedTextInputY(int y) {
- if (!inEditingMode()) {
+ if (!inEditingMode() || mWebViewCore == null) {
return;
}
- int xPos = viewToContentX((mWebTextView.getLeft() + mWebTextView.getRight()) / 2);
- int yPos = viewToContentY((mWebTextView.getTop() + mWebTextView.getBottom()) / 2);
- int layer = nativeScrollableLayer(xPos, yPos, null, null);
- if (layer != 0) {
- nativeScrollLayer(layer, 0, viewToContentDimension(y));
- }
+ mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, 0, viewToContentDimension(y));
}
/**
@@ -6824,7 +6831,7 @@ public class WebView extends AbsoluteLayout
previouslyFocusedRect);
} else {
result = super.requestFocus(direction, previouslyFocusedRect);
- if (mWebViewCore.getSettings().getNeedInitialFocus()) {
+ if (mWebViewCore.getSettings().getNeedInitialFocus() && !isInTouchMode()) {
// For cases such as GMail, where we gain focus from a direction,
// we want to move to the first available link.
// FIXME: If there are no visible links, we may not want to
@@ -7968,18 +7975,15 @@ public class WebView extends AbsoluteLayout
* @param node Pointer to the node touched.
* @param x x-position of the touch.
* @param y y-position of the touch.
- * @param scrollY Only used when touching on a textarea. Otherwise, use -1.
- * Tells how much the textarea is scrolled.
*/
private void sendMotionUp(int touchGeneration,
- int frame, int node, int x, int y, int scrollY) {
+ int frame, int node, int x, int y) {
WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData();
touchUpData.mMoveGeneration = touchGeneration;
touchUpData.mFrame = frame;
touchUpData.mNode = node;
touchUpData.mX = x;
touchUpData.mY = y;
- touchUpData.mScrollY = scrollY;
mWebViewCore.sendMessage(EventHub.TOUCH_UP, touchUpData);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 3bde000..b949a41 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -559,7 +559,7 @@ final class WebViewCore {
private native String nativeRetrieveImageSource(int x, int y);
private native void nativeTouchUp(int touchGeneration,
- int framePtr, int nodePtr, int x, int y, int scrollY);
+ int framePtr, int nodePtr, int x, int y);
private native boolean nativeHandleTouchEvent(int action, int[] idArray,
int[] xArray, int[] yArray, int count, int metaState);
@@ -777,8 +777,6 @@ final class WebViewCore {
int mNode;
int mX;
int mY;
- // Used in the case of a scrolled textarea
- int mScrollY;
}
static class TouchHighlightData {
@@ -1086,8 +1084,13 @@ final class WebViewCore {
break;
case SCROLL_TEXT_INPUT:
- nativeScrollFocusedTextInput(
- ((Float) msg.obj).floatValue(), msg.arg1);
+ float xPercent;
+ if (msg.obj == null) {
+ xPercent = 0f;
+ } else {
+ xPercent = ((Float) msg.obj).floatValue();
+ }
+ nativeScrollFocusedTextInput(xPercent, msg.arg2);
break;
case LOAD_URL: {
@@ -1307,8 +1310,7 @@ final class WebViewCore {
TouchUpData touchUpData = (TouchUpData) msg.obj;
nativeTouchUp(touchUpData.mMoveGeneration,
touchUpData.mFrame, touchUpData.mNode,
- touchUpData.mX, touchUpData.mY,
- touchUpData.mScrollY);
+ touchUpData.mX, touchUpData.mY);
break;
case TOUCH_EVENT: {
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index b47fe86..efbcd58 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -183,6 +183,9 @@ class ZoomManager {
private ScaleGestureDetector mScaleDetector;
private boolean mPinchToZoomAnimating = false;
+ private boolean mHardwareAccelerated = false;
+ private boolean mInHWAcceleratedZoom = false;
+
public ZoomManager(WebView webView, CallbackProxy callbackProxy) {
mWebView = webView;
mCallbackProxy = callbackProxy;
@@ -384,6 +387,10 @@ class ZoomManager {
scale = getReadingLevelScale();
}
+ if (mHardwareAccelerated) {
+ mInHWAcceleratedZoom = true;
+ }
+
setZoomScale(scale, reflowText);
if (oldScale != mActualScale) {
@@ -447,8 +454,18 @@ class ZoomManager {
- titleHeight, mWebView.getViewHeight(), Math.round(mWebView.getContentHeight()
* zoomScale)) + titleHeight) + mWebView.getScrollY();
- canvas.translate(tx, ty);
- canvas.scale(zoomScale, zoomScale);
+ if (mHardwareAccelerated) {
+ mWebView.updateScrollCoordinates(mWebView.getScrollX() - tx, mWebView.getScrollY() - ty);
+ setZoomScale(zoomScale, false);
+
+ if (mZoomScale == 0) {
+ // We've reached the end of the zoom animation.
+ mInHWAcceleratedZoom = false;
+ }
+ } else {
+ canvas.translate(tx, ty);
+ canvas.scale(zoomScale, zoomScale);
+ }
}
public boolean isZoomAnimating() {
@@ -493,12 +510,14 @@ class ZoomManager {
mActualScale = scale;
mInvActualScale = 1 / scale;
- if (!mWebView.drawHistory()) {
+ if (!mWebView.drawHistory() && !mInHWAcceleratedZoom) {
// If history Picture is drawn, don't update scroll. They will
// be updated when we get out of that mode.
// update our scroll so we don't appear to jump
// i.e. keep the center of the doc in the center of the view
+ // If this is part of a zoom on a HW accelerated canvas, we
+ // have already updated the scroll so don't do it again.
int oldX = mWebView.getScrollX();
int oldY = mWebView.getScrollY();
float ratio = scale * oldInvScale;
@@ -1020,4 +1039,8 @@ class ZoomManager {
return null;
}
}
+
+ public void setHardwareAccelerated() {
+ mHardwareAccelerated = true;
+ }
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 7293572..4a34b45 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -30,6 +30,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.NumberPicker.OnValueChangeListener;
import java.text.ParseException;
@@ -353,6 +354,16 @@ public class DatePicker extends FrameLayout {
return mIsEnabled;
}
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
+ | DateUtils.FORMAT_SHOW_YEAR;
+ String selectedDateUtterance = DateUtils.formatDateTime(mContext,
+ mCurrentDate.getTimeInMillis(), flags);
+ event.getText().add(selectedDateUtterance);
+ return true;
+ }
+
/**
* Gets whether the {@link CalendarView} is shown.
*
@@ -641,6 +652,7 @@ public class DatePicker extends FrameLayout {
* Notifies the listener, if such, for a change in the selected date.
*/
private void notifyDateChanged() {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
if (mOnDateChangedListener != null) {
mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth());
}
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 7a74241..6a09d35 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -546,12 +546,16 @@ public class StackView extends AdapterViewAnimator {
private void onLayout() {
if (!mFirstLayoutHappened) {
- mSlideAmount = Math.round(SLIDE_UP_RATIO * getMeasuredHeight());
- mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO * mSlideAmount);
mFirstLayoutHappened = true;
updateChildTransforms();
}
+ final int newSlideAmount = Math.round(SLIDE_UP_RATIO * getMeasuredHeight());
+ if (mSlideAmount != newSlideAmount) {
+ mSlideAmount = newSlideAmount;
+ mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO * newSlideAmount);
+ }
+
if (Float.compare(mPerspectiveShiftY, mNewPerspectiveShiftY) != 0 ||
Float.compare(mPerspectiveShiftX, mNewPerspectiveShiftX) != 0) {
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 51ece33..1a4ff29 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -132,7 +132,17 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
mRightStrip = resources.getDrawable(
com.android.internal.R.drawable.tab_bottom_right_v4);
}
- }
+ } else {
+ // Use modern color scheme for Eclair and beyond
+ if (mLeftStrip == null) {
+ mLeftStrip = resources.getDrawable(
+ com.android.internal.R.drawable.tab_bottom_left);
+ }
+ if (mRightStrip == null) {
+ mRightStrip = resources.getDrawable(
+ com.android.internal.R.drawable.tab_bottom_right);
+ }
+ }
// Deal with focus, as we don't want the focus to go by default
// to a tab other than the current tab
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4ba907f..e7c33ab 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4615,9 +4615,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mInput.onKeyDown(this, (Editable)mText, keyCode, down);
mInput.onKeyUp(this, (Editable)mText, keyCode, up);
}
- if (mError != null && !mErrorWasChanged) {
- setError(null, null);
- }
+ hideErrorIfUnchanged();
} else if (which == 2) {
mMovement.onKeyUp(this, (Spannable)mText, keyCode, up);
@@ -4738,23 +4736,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if (mInput != null) {
- /*
- * Keep track of what the error was before doing the input
- * so that if an input filter changed the error, we leave
- * that error showing. Otherwise, we take down whatever
- * error was showing when the user types something.
- */
- mErrorWasChanged = false;
+ resetErrorChangedFlag();
boolean doDown = true;
if (otherEvent != null) {
try {
beginBatchEdit();
- boolean handled = mInput.onKeyOther(this, (Editable) mText,
- otherEvent);
- if (mError != null && !mErrorWasChanged) {
- setError(null, null);
- }
+ final boolean handled = mInput.onKeyOther(this, (Editable) mText, otherEvent);
+ hideErrorIfUnchanged();
doDown = false;
if (handled) {
return -1;
@@ -4769,14 +4758,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (doDown) {
beginBatchEdit();
- if (mInput.onKeyDown(this, (Editable) mText, keyCode, event)) {
- endBatchEdit();
- if (mError != null && !mErrorWasChanged) {
- setError(null, null);
- }
- return 1;
- }
+ final boolean handled = mInput.onKeyDown(this, (Editable) mText, keyCode, event);
endBatchEdit();
+ hideErrorIfUnchanged();
+ if (handled) return 1;
}
}
@@ -4807,6 +4792,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return 0;
}
+ /**
+ * Resets the mErrorWasChanged flag, so that future calls to {@link #setError(CharSequence)}
+ * can be recorded.
+ * @hide
+ */
+ public void resetErrorChangedFlag() {
+ /*
+ * Keep track of what the error was before doing the input
+ * so that if an input filter changed the error, we leave
+ * that error showing. Otherwise, we take down whatever
+ * error was showing when the user types something.
+ */
+ mErrorWasChanged = false;
+ }
+
+ /**
+ * @hide
+ */
+ public void hideErrorIfUnchanged() {
+ if (mError != null && !mErrorWasChanged) {
+ setError(null, null);
+ }
+ }
+
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (!isEnabled()) {
@@ -7386,12 +7395,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (!mInsertionControllerEnabled) {
hideInsertionPointCursorController();
- mInsertionPointCursorController = null;
+ if (mInsertionPointCursorController != null) {
+ mInsertionPointCursorController.onDetached();
+ mInsertionPointCursorController = null;
+ }
}
if (!mSelectionControllerEnabled) {
stopSelectionActionMode();
- mSelectionModifierCursorController = null;
+ if (mSelectionModifierCursorController != null) {
+ mSelectionModifierCursorController.onDetached();
+ mSelectionModifierCursorController = null;
+ }
}
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 2688b95..4b37beb 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -23,9 +23,11 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.NumberPicker.OnValueChangeListener;
import java.text.DateFormatSymbols;
@@ -88,6 +90,8 @@ public class TimePicker extends FrameLayout {
// callbacks
private OnTimeChangedListener mOnTimeChangedListener;
+ private Calendar mTempCalendar;
+
/**
* The callback interface used to indicate the time has been adjusted.
*/
@@ -214,12 +218,12 @@ public class TimePicker extends FrameLayout {
updateAmPmControl();
// initialize to current time
- Calendar calendar = Calendar.getInstance();
+ mTempCalendar = Calendar.getInstance();
setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
// set to current time
- setCurrentHour(calendar.get(Calendar.HOUR_OF_DAY));
- setCurrentMinute(calendar.get(Calendar.MINUTE));
+ setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
+ setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));
if (!isEnabled()) {
setEnabled(false);
@@ -406,6 +410,22 @@ public class TimePicker extends FrameLayout {
return mHourSpinner.getBaseline();
}
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ int flags = DateUtils.FORMAT_SHOW_TIME;
+ if (mIs24HourView) {
+ flags |= DateUtils.FORMAT_24HOUR;
+ } else {
+ flags |= DateUtils.FORMAT_12HOUR;
+ }
+ mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour());
+ mTempCalendar.set(Calendar.MINUTE, getCurrentMinute());
+ String selectedDateUtterance = DateUtils.formatDateTime(mContext,
+ mTempCalendar.getTimeInMillis(), flags);
+ event.getText().add(selectedDateUtterance);
+ return true;
+ }
+
private void updateHourControl() {
if (is24HourView()) {
mHourSpinner.setMinValue(0);
@@ -435,9 +455,11 @@ public class TimePicker extends FrameLayout {
mAmPmButton.setVisibility(View.VISIBLE);
}
}
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
private void onTimeChanged() {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
if (mOnTimeChangedListener != null) {
mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
}
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/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 1cc068f..7f23ed5 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -32,6 +32,7 @@ oneway interface IStatusBar
void animateCollapse();
void setLightsOn(boolean on);
void setMenuKeyVisible(boolean visible);
- void setIMEButtonVisible(in IBinder token, boolean visible);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
+ void setHardKeyboardStatus(boolean available, boolean enabled);
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index d1ea52e..d6ca426 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -31,7 +31,7 @@ interface IStatusBarService
void setIconVisibility(String slot, boolean visible);
void removeIcon(String slot);
void setMenuKeyVisible(boolean visible);
- void setIMEButtonVisible(in IBinder token, boolean visible);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
// ---- Methods below are for use by the status bar policy services ----
// You need the STATUS_BAR_SERVICE permission
@@ -45,4 +45,5 @@ interface IStatusBarService
void onClearAllNotifications();
void onNotificationClear(String pkg, String tag, int id);
void setSystemUiVisibility(int vis);
+ void setHardKeyboardEnabled(boolean enabled);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index b2fbd3a..611d987 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -59,7 +59,7 @@ interface IInputMethodManager {
void hideMySoftInput(in IBinder token, int flags);
void showMySoftInput(in IBinder token, int flags);
void updateStatusIcon(in IBinder token, String packageName, int iconId);
- void setIMEButtonVisible(in IBinder token, boolean visible);
+ void setImeWindowStatus(in IBinder token, int vis, int backDisposition);
InputMethodSubtype getCurrentInputMethodSubtype();
boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
boolean switchToLastInputMethod(in IBinder token);
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/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index e992e7c..9f9f020 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -138,9 +138,9 @@ public class EditableInputConnection extends BaseInputConnection {
return super.commitText(text, newCursorPosition);
}
- CharSequence errorBefore = mTextView.getError();
+ mTextView.resetErrorChangedFlag();
boolean success = super.commitText(text, newCursorPosition);
- CharSequence errorAfter = mTextView.getError();
+ mTextView.hideErrorIfUnchanged();
return success;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index bf59753..2621dd0 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -16,13 +16,19 @@
package com.android.internal.widget;
+import com.android.internal.R;
+import com.android.internal.telephony.ITelephony;
+import com.google.android.collect.Lists;
+
import android.app.admin.DevicePolicyManager;
import android.content.ContentResolver;
import android.content.Context;
import android.os.FileObserver;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.storage.IMountService;
import android.provider.Settings;
import android.security.MessageDigest;
import android.telephony.TelephonyManager;
@@ -30,10 +36,6 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
-import com.android.internal.R;
-import com.android.internal.telephony.ITelephony;
-import com.google.android.collect.Lists;
-
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -139,6 +141,7 @@ public class LockPatternUtils {
int fileObserverMask = FileObserver.CLOSE_WRITE | FileObserver.DELETE |
FileObserver.MOVED_TO | FileObserver.CREATE;
sPasswordObserver = new FileObserver(dataSystemDirectory, fileObserverMask) {
+ @Override
public void onEvent(int event, String path) {
if (LOCK_PATTERN_FILE.equals(path)) {
Log.d(TAG, "lock pattern file changed");
@@ -439,6 +442,27 @@ public class LockPatternUtils {
return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
}
+ /** Update the encryption password if it is enabled **/
+ private void updateEncryptionPassword(String password) {
+ DevicePolicyManager dpm = getDevicePolicyManager();
+ if (dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
+ return;
+ }
+
+ IBinder service = ServiceManager.getService("mount");
+ if (service == null) {
+ Log.e(TAG, "Could not find the mount service to update the encryption password");
+ return;
+ }
+
+ IMountService mountService = IMountService.Stub.asInterface(service);
+ try {
+ mountService.changeEncryptionPassword(password);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error changing encryption password", e);
+ }
+ }
+
/**
* Save a lock password. Does not ensure that the password is as good
* as the requested mode, but will adjust the mode to be as good as the
@@ -461,6 +485,9 @@ public class LockPatternUtils {
raf.close();
DevicePolicyManager dpm = getDevicePolicyManager();
if (password != null) {
+ // Update the encryption password.
+ updateEncryptionPassword(password);
+
int computedQuality = computePasswordQuality(password);
setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality));
if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {