summaryrefslogtreecommitdiffstats
path: root/core/java/android/view
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-18 17:39:46 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-18 17:39:46 -0700
commit105925376f8d0f6b318c9938c7b83ef7fef094da (patch)
tree3b19ee2bd8704cb9c6a0da7e42dec6759183de6d /core/java/android/view
parentba87e3e6c985e7175152993b5efcc7dd2f0e1c93 (diff)
downloadframeworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.zip
frameworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.tar.gz
frameworks_base-105925376f8d0f6b318c9938c7b83ef7fef094da.tar.bz2
auto import from //branches/cupcake_rel/...@140373
Diffstat (limited to 'core/java/android/view')
-rw-r--r--core/java/android/view/GestureDetector.java2
-rw-r--r--core/java/android/view/IWindowManager.aidl3
-rw-r--r--core/java/android/view/KeyEvent.java72
-rw-r--r--core/java/android/view/View.java5
-rw-r--r--core/java/android/view/ViewDebug.java68
-rw-r--r--core/java/android/view/ViewRoot.java24
-rw-r--r--core/java/android/view/ViewTreeObserver.java106
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java29
8 files changed, 226 insertions, 83 deletions
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index f7ac522..23f3e3c 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -201,8 +201,6 @@ public class GestureDetector {
private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
- // TODO make new double-tap timeout, and define its events (i.e. either time
- // between down-down or time between up-down)
private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
// constants for Message.what used by GestureHandler below
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a856b24..15e7eb2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -62,7 +62,8 @@ interface IWindowManager
void addAppToken(int addPos, IApplicationToken token,
int groupId, int requestedOrientation, boolean fullscreen);
void setAppGroupId(IBinder token, int groupId);
- Configuration updateOrientationFromAppTokens(IBinder freezeThisOneIfNeeded);
+ Configuration updateOrientationFromAppTokens(in Configuration currentConfig,
+ IBinder freezeThisOneIfNeeded);
void setAppOrientation(IApplicationToken token, int requestedOrientation);
int getAppOrientation(IApplicationToken token);
void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 430cc71..41779ba 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -235,6 +235,22 @@ public class KeyEvent implements Parcelable {
public static final int FLAG_KEEP_TOUCH_MODE = 0x4;
/**
+ * This mask is set if an event was known to come from a trusted part
+ * of the system. That is, the event is known to come from the user,
+ * and could not have been spoofed by a third party component.
+ */
+ public static final int FLAG_FROM_SYSTEM = 0x8;
+
+ /**
+ * This mask is used for compatibility, to identify enter keys that are
+ * coming from an IME whose enter key has been auto-labelled "next" or
+ * "done". This allows TextView to dispatch these as normal enter keys
+ * for old applications, but still do the appropriate action when
+ * receiving them.
+ */
+ public static final int FLAG_EDITOR_ACTION = 0x10;
+
+ /**
* Returns the maximum keycode.
*/
public static int getMaxKeyCode() {
@@ -440,6 +456,22 @@ public class KeyEvent implements Parcelable {
}
/**
+ * Make an exact copy of an existing key event.
+ */
+ public KeyEvent(KeyEvent origEvent) {
+ mDownTime = origEvent.mDownTime;
+ mEventTime = origEvent.mEventTime;
+ mAction = origEvent.mAction;
+ mKeyCode = origEvent.mKeyCode;
+ mRepeatCount = origEvent.mRepeatCount;
+ mMetaState = origEvent.mMetaState;
+ mDeviceId = origEvent.mDeviceId;
+ mScancode = origEvent.mScancode;
+ mFlags = origEvent.mFlags;
+ mCharacters = origEvent.mCharacters;
+ }
+
+ /**
* Copy an existing key event, modifying its time and repeat count.
*
* @param origEvent The existing event to be copied.
@@ -461,12 +493,26 @@ public class KeyEvent implements Parcelable {
}
/**
+ * Create a new key event that is the same as the given one, but whose
+ * event time and repeat count are replaced with the given value.
+ *
+ * @param event The existing event to be copied. This is not modified.
+ * @param eventTime The new event time
+ * (in {@link android.os.SystemClock#uptimeMillis}) of the event.
+ * @param newRepeat The new repeat count of the event.
+ */
+ public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime,
+ int newRepeat) {
+ return new KeyEvent(event, eventTime, newRepeat);
+ }
+
+ /**
* Copy an existing key event, modifying its action.
*
* @param origEvent The existing event to be copied.
* @param action The new action code of the event.
*/
- public KeyEvent(KeyEvent origEvent, int action) {
+ private KeyEvent(KeyEvent origEvent, int action) {
mDownTime = origEvent.mDownTime;
mEventTime = origEvent.mEventTime;
mAction = action;
@@ -481,6 +527,30 @@ public class KeyEvent implements Parcelable {
}
/**
+ * Create a new key event that is the same as the given one, but whose
+ * action is replaced with the given value.
+ *
+ * @param event The existing event to be copied. This is not modified.
+ * @param action The new action code of the event.
+ */
+ public static KeyEvent changeAction(KeyEvent event, int action) {
+ return new KeyEvent(event, action);
+ }
+
+ /**
+ * Create a new key event that is the same as the given one, but whose
+ * flags are replaced with the given value.
+ *
+ * @param event The existing event to be copied. This is not modified.
+ * @param flags The new flags constant.
+ */
+ public static KeyEvent changeFlags(KeyEvent event, int flags) {
+ event = new KeyEvent(event);
+ event.mFlags = flags;
+ return event;
+ }
+
+ /**
* Don't use in new code, instead explicitly check
* {@link #getAction()}.
*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c3e00c4..04447ca 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3409,6 +3409,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
imm.focusOut(this);
}
+ if (mPendingCheckForLongPress != null) {
+ removeCallbacks(mPendingCheckForLongPress);
+ }
} else if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
imm.focusIn(this);
}
@@ -7656,7 +7659,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback {
private int mOriginalWindowAttachCount;
public void run() {
- if (isPressed() && (mParent != null) && hasWindowFocus()
+ if (isPressed() && (mParent != null)
&& mOriginalWindowAttachCount == mWindowAttachCount) {
if (performLongClick()) {
mHasPerformedLongPress = true;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 6ea7a82..f604bc5 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -19,6 +19,7 @@ package android.view;
import android.util.Log;
import android.util.DisplayMetrics;
import android.content.res.Resources;
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.os.Environment;
@@ -800,7 +801,7 @@ public class ViewDebug {
View view = root.getRootView();
if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
- dumpViewHierarchyWithProperties(group, out, 0);
+ dumpViewHierarchyWithProperties(group.getContext(), group, out, 0);
}
out.write("DONE.");
out.newLine();
@@ -838,9 +839,9 @@ public class ViewDebug {
return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
}
- private static void dumpViewHierarchyWithProperties(ViewGroup group,
+ private static void dumpViewHierarchyWithProperties(Context context, ViewGroup group,
BufferedWriter out, int level) {
- if (!dumpViewWithProperties(group, out, level)) {
+ if (!dumpViewWithProperties(context, group, out, level)) {
return;
}
@@ -848,14 +849,16 @@ public class ViewDebug {
for (int i = 0; i < count; i++) {
final View view = group.getChildAt(i);
if (view instanceof ViewGroup) {
- dumpViewHierarchyWithProperties((ViewGroup) view, out, level + 1);
+ dumpViewHierarchyWithProperties(context, (ViewGroup) view, out, level + 1);
} else {
- dumpViewWithProperties(view, out, level + 1);
+ dumpViewWithProperties(context, view, out, level + 1);
}
}
}
- private static boolean dumpViewWithProperties(View view, BufferedWriter out, int level) {
+ private static boolean dumpViewWithProperties(Context context, View view,
+ BufferedWriter out, int level) {
+
try {
for (int i = 0; i < level; i++) {
out.write(' ');
@@ -864,7 +867,7 @@ public class ViewDebug {
out.write('@');
out.write(Integer.toHexString(view.hashCode()));
out.write(' ');
- dumpViewProperties(view, out);
+ dumpViewProperties(context, view, out);
out.newLine();
} catch (IOException e) {
Log.w("View", "Error while dumping hierarchy tree");
@@ -945,23 +948,26 @@ public class ViewDebug {
return methods;
}
- private static void dumpViewProperties(Object view, BufferedWriter out) throws IOException {
- dumpViewProperties(view, out, "");
+ private static void dumpViewProperties(Context context, Object view,
+ BufferedWriter out) throws IOException {
+
+ dumpViewProperties(context, view, out, "");
}
- private static void dumpViewProperties(Object view, BufferedWriter out, String prefix)
- throws IOException {
+ private static void dumpViewProperties(Context context, Object view,
+ BufferedWriter out, String prefix) throws IOException {
+
Class<?> klass = view.getClass();
do {
- exportFields(view, out, klass, prefix);
- exportMethods(view, out, klass, prefix);
+ exportFields(context, view, out, klass, prefix);
+ exportMethods(context, view, out, klass, prefix);
klass = klass.getSuperclass();
} while (klass != Object.class);
}
- private static void exportMethods(Object view, BufferedWriter out, Class<?> klass,
- String prefix) throws IOException {
+ private static void exportMethods(Context context, Object view, BufferedWriter out,
+ Class<?> klass, String prefix) throws IOException {
final Method[] methods = getExportedPropertyMethods(klass);
@@ -976,9 +982,9 @@ public class ViewDebug {
if (returnType == int.class) {
final ExportedProperty property = sAnnotations.get(method);
- if (property.resolveId() && view instanceof View) {
+ if (property.resolveId() && context != null) {
final int id = (Integer) methodValue;
- methodValue = resolveId(view, id);
+ methodValue = resolveId(context, id);
} else {
final IntToString[] mapping = property.mapping();
if (mapping.length > 0) {
@@ -1005,11 +1011,11 @@ public class ViewDebug {
final String valuePrefix = prefix + method.getName() + '_';
final String suffix = "()";
- exportUnrolledArray(view, out, property, array, valuePrefix, suffix);
+ exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
} else if (!returnType.isPrimitive()) {
final ExportedProperty property = sAnnotations.get(method);
if (property.deepExport()) {
- dumpViewProperties(methodValue, out, prefix + property.prefix());
+ dumpViewProperties(context, methodValue, out, prefix + property.prefix());
continue;
}
}
@@ -1021,8 +1027,9 @@ public class ViewDebug {
}
}
- private static void exportFields(Object view, BufferedWriter out, Class<?> klass, String prefix)
- throws IOException {
+ private static void exportFields(Context context, Object view, BufferedWriter out,
+ Class<?> klass, String prefix) throws IOException {
+
final Field[] fields = getExportedPropertyFields(klass);
int count = fields.length;
@@ -1036,9 +1043,9 @@ public class ViewDebug {
if (type == int.class) {
final ExportedProperty property = sAnnotations.get(field);
- if (property.resolveId() && view instanceof View) {
+ if (property.resolveId() && context != null) {
final int id = field.getInt(view);
- fieldValue = resolveId(view, id);
+ fieldValue = resolveId(context, id);
} else {
final IntToString[] mapping = property.mapping();
if (mapping.length > 0) {
@@ -1063,14 +1070,15 @@ public class ViewDebug {
final String valuePrefix = prefix + field.getName() + '_';
final String suffix = "";
- exportUnrolledArray(view, out, property, array, valuePrefix, suffix);
+ exportUnrolledArray(context, out, property, array, valuePrefix, suffix);
// We exit here!
return;
} else if (!type.isPrimitive()) {
final ExportedProperty property = sAnnotations.get(field);
if (property.deepExport()) {
- dumpViewProperties(field.get(view), out, prefix + property.prefix());
+ dumpViewProperties(context, field.get(view), out,
+ prefix + property.prefix());
continue;
}
}
@@ -1096,7 +1104,7 @@ public class ViewDebug {
out.write(' ');
}
- private static void exportUnrolledArray(Object view, BufferedWriter out,
+ private static void exportUnrolledArray(Context context, BufferedWriter out,
ExportedProperty property, int[] array, String prefix, String suffix)
throws IOException {
@@ -1106,7 +1114,7 @@ public class ViewDebug {
final IntToString[] mapping = property.mapping();
final boolean hasMapping = mapping.length > 0;
- final boolean resolveId = property.resolveId() && view instanceof View;
+ final boolean resolveId = property.resolveId() && context != null;
final int valuesCount = array.length;
for (int j = 0; j < valuesCount; j++) {
@@ -1140,16 +1148,16 @@ public class ViewDebug {
}
if (resolveId) {
- value = (String) resolveId(view, intValue);
+ value = (String) resolveId(context, intValue);
}
writeEntry(out, prefix, name, suffix, value);
}
}
- private static Object resolveId(Object view, int id) {
+ private static Object resolveId(Context context, int id) {
Object fieldValue;
- final Resources resources = ((View) view).getContext().getResources();
+ final Resources resources = context.getResources();
if (id >= 0) {
try {
fieldValue = resources.getResourceTypeName(id) + '/' +
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index dd2b154..fbb4d42 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -470,11 +470,20 @@ public final class ViewRoot extends Handler implements ViewParent,
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
+ int oldSoftInputMode = mWindowAttributes.softInputMode;
mWindowAttributes.copyFrom(attrs);
if (newView) {
mSoftInputMode = attrs.softInputMode;
requestLayout();
}
+ // Don't lose the mode we last auto-computed.
+ if ((attrs.softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
+ mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
+ & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ | (oldSoftInputMode
+ & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST);
+ }
mWindowAttributesChanged = true;
scheduleTraversals();
}
@@ -1485,7 +1494,7 @@ public final class ViewRoot extends Handler implements ViewParent,
+ msg.obj + " to " + mView);
deliverKeyEvent((KeyEvent)msg.obj, true);
break;
- case DISPATCH_POINTER:
+ case DISPATCH_POINTER: {
MotionEvent event = (MotionEvent)msg.obj;
boolean didFinish;
@@ -1571,7 +1580,7 @@ public final class ViewRoot extends Handler implements ViewParent,
// Let the exception fall through -- the looper will catch
// it and take care of the bad app for us.
}
- break;
+ } break;
case DISPATCH_TRACKBALL:
deliverTrackballEvent((MotionEvent)msg.obj);
break;
@@ -1657,12 +1666,19 @@ public final class ViewRoot extends Handler implements ViewParent,
case DIE:
dispatchDetachedFromWindow();
break;
- case DISPATCH_KEY_FROM_IME:
+ case DISPATCH_KEY_FROM_IME: {
if (LOCAL_LOGV) Log.v(
"ViewRoot", "Dispatching key "
+ msg.obj + " from IME to " + mView);
+ KeyEvent event = (KeyEvent)msg.obj;
+ if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
+ // The IME is trying to say this event is from the
+ // system! Bad bad bad!
+ event = KeyEvent.changeFlags(event,
+ event.getFlags()&~KeyEvent.FLAG_FROM_SYSTEM);
+ }
deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false);
- break;
+ } break;
case FINISH_INPUT_CONNECTION: {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 47b52e4..4230afa 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -18,7 +18,7 @@ package android.view;
import android.graphics.Rect;
-import java.util.ArrayList;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
* A view tree observer is used to register listeners that can be notified of global
@@ -30,12 +30,12 @@ import java.util.ArrayList;
* for more information.
*/
public final class ViewTreeObserver {
- private ArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
- private ArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
- private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
- private ArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
- private ArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
- private ArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
+ private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
+ private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
+ private CopyOnWriteArrayList<OnPreDrawListener> mOnPreDrawListeners;
+ private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
+ private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
+ private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
private boolean mAlive = true;
@@ -283,7 +283,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnGlobalFocusListeners == null) {
- mOnGlobalFocusListeners = new ArrayList<OnGlobalFocusChangeListener>();
+ mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
}
mOnGlobalFocusListeners.add(listener);
@@ -318,7 +318,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnGlobalLayoutListeners == null) {
- mOnGlobalLayoutListeners = new ArrayList<OnGlobalLayoutListener>();
+ mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
}
mOnGlobalLayoutListeners.add(listener);
@@ -352,7 +352,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnPreDrawListeners == null) {
- mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
+ mOnPreDrawListeners = new CopyOnWriteArrayList<OnPreDrawListener>();
}
mOnPreDrawListeners.add(listener);
@@ -388,7 +388,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnScrollChangedListeners == null) {
- mOnScrollChangedListeners = new ArrayList<OnScrollChangedListener>();
+ mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
}
mOnScrollChangedListeners.add(listener);
@@ -424,7 +424,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnTouchModeChangeListeners == null) {
- mOnTouchModeChangeListeners = new ArrayList<OnTouchModeChangeListener>();
+ mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
}
mOnTouchModeChangeListeners.add(listener);
@@ -460,7 +460,8 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnComputeInternalInsetsListeners == null) {
- mOnComputeInternalInsetsListeners = new ArrayList<OnComputeInternalInsetsListener>();
+ mOnComputeInternalInsetsListeners =
+ new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
}
mOnComputeInternalInsetsListeners.add(listener);
@@ -518,11 +519,14 @@ public final class ViewTreeObserver {
* Notifies registered listeners that focus has changed.
*/
final void dispatchOnGlobalFocusChange(View oldFocus, View newFocus) {
- final ArrayList<OnGlobalFocusChangeListener> globaFocusListeners = mOnGlobalFocusListeners;
- if (globaFocusListeners != null) {
- final int count = globaFocusListeners.size();
- for (int i = count - 1; i >= 0; i--) {
- globaFocusListeners.get(i).onGlobalFocusChanged(oldFocus, newFocus);
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
+ if (listeners != null) {
+ for (OnGlobalFocusChangeListener listener : listeners) {
+ listener.onGlobalFocusChanged(oldFocus, newFocus);
}
}
}
@@ -533,11 +537,14 @@ public final class ViewTreeObserver {
* not attached to a Window or in the GONE state.
*/
public final void dispatchOnGlobalLayout() {
- final ArrayList<OnGlobalLayoutListener> globaLayoutListeners = mOnGlobalLayoutListeners;
- if (globaLayoutListeners != null) {
- final int count = globaLayoutListeners.size();
- for (int i = count - 1; i >= 0; i--) {
- globaLayoutListeners.get(i).onGlobalLayout();
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
+ if (listeners != null) {
+ for (OnGlobalLayoutListener listener : listeners) {
+ listener.onGlobalLayout();
}
}
}
@@ -551,12 +558,15 @@ public final class ViewTreeObserver {
* @return True if the current draw should be canceled and resceduled, false otherwise.
*/
public final boolean dispatchOnPreDraw() {
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
boolean cancelDraw = false;
- final ArrayList<OnPreDrawListener> preDrawListeners = mOnPreDrawListeners;
- if (preDrawListeners != null) {
- final int count = preDrawListeners.size();
- for (int i = count - 1; i >= 0; i--) {
- cancelDraw |= !preDrawListeners.get(i).onPreDraw();
+ final CopyOnWriteArrayList<OnPreDrawListener> listeners = mOnPreDrawListeners;
+ if (listeners != null) {
+ for (OnPreDrawListener listener : listeners) {
+ cancelDraw |= !listener.onPreDraw();
}
}
return cancelDraw;
@@ -568,11 +578,15 @@ public final class ViewTreeObserver {
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
*/
final void dispatchOnTouchModeChanged(boolean inTouchMode) {
- final ArrayList<OnTouchModeChangeListener> touchModeListeners = mOnTouchModeChangeListeners;
- if (touchModeListeners != null) {
- final int count = touchModeListeners.size();
- for (int i = count - 1; i >= 0; i--) {
- touchModeListeners.get(i).onTouchModeChanged(inTouchMode);
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
+ mOnTouchModeChangeListeners;
+ if (listeners != null) {
+ for (OnTouchModeChangeListener listener : listeners) {
+ listener.onTouchModeChanged(inTouchMode);
}
}
}
@@ -581,11 +595,14 @@ public final class ViewTreeObserver {
* Notifies registered listeners that something has scrolled.
*/
final void dispatchOnScrollChanged() {
- final ArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
-
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
if (listeners != null) {
- for (OnScrollChangedListener scl : mOnScrollChangedListeners) {
- scl.onScrollChanged();
+ for (OnScrollChangedListener listener : listeners) {
+ listener.onScrollChanged();
}
}
}
@@ -594,7 +611,8 @@ public final class ViewTreeObserver {
* Returns whether there are listeners for computing internal insets.
*/
final boolean hasComputeInternalInsetsListeners() {
- final ArrayList<OnComputeInternalInsetsListener> listeners = mOnComputeInternalInsetsListeners;
+ final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
+ mOnComputeInternalInsetsListeners;
return (listeners != null && listeners.size() > 0);
}
@@ -602,11 +620,15 @@ public final class ViewTreeObserver {
* Calls all listeners to compute the current insets.
*/
final void dispatchOnComputeInternalInsets(InternalInsetsInfo inoutInfo) {
- final ArrayList<OnComputeInternalInsetsListener> listeners = mOnComputeInternalInsetsListeners;
+ // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
+ // perform the dispatching. The iterator is a safe guard against listeners that
+ // could mutate the list by calling the various add/remove methods. This prevents
+ // the array from being modified while we iterate it.
+ final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
+ mOnComputeInternalInsetsListeners;
if (listeners != null) {
- final int count = listeners.size();
- for (int i = count - 1; i >= 0; i--) {
- listeners.get(i).onComputeInternalInsets(inoutInfo);
+ for (OnComputeInternalInsetsListener listener : listeners) {
+ listener.onComputeInternalInsets(inoutInfo);
}
}
}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index b00e565..c718bac 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -78,12 +78,37 @@ public class EditorInfo implements InputType, Parcelable {
public static final int IME_ACTION_DONE = 0x00000006;
/**
+ * Flag of {@link #imeOptions}: used to specify that the IME does not need
+ * to show its extracted text UI. For input methods that may be fullscreen,
+ * often when in landscape mode, this allows them to be smaller and let part
+ * of the application be shown behind. Though there will likely be limited
+ * access to the application available from the user, it can make the
+ * experience of a (mostly) fullscreen IME less jarring. Note that when
+ * this flag is specified the IME may <em>not</em> be set up to be able
+ * to display text, so it should only be used in situations where this is
+ * not needed.
+ */
+ public static final int IME_FLAG_NO_EXTRACT_UI = 0x10000000;
+
+ /**
+ * Flag of {@link #imeOptions}: used in conjunction with
+ * {@link #IME_MASK_ACTION}, this indicates that the action should not
+ * be available as an accessory button when the input method is full-screen.
+ * Note that by setting this flag, there can be cases where the action
+ * is simply never available to the user. Setting this generally means
+ * that you think showing text being edited is more important than the
+ * action you have supplied.
+ */
+ public static final int IME_FLAG_NO_ACCESSORY_ACTION = 0x20000000;
+
+ /**
* Flag of {@link #imeOptions}: used in conjunction with
* {@link #IME_MASK_ACTION}, this indicates that the action should not
- * be available in-line as the same as a "enter" key. Typically this is
+ * be available in-line as a replacement for "enter" key. Typically this is
* because the action has such a significant impact or is not recoverable
* enough that accidentally hitting it should be avoided, such as sending
- * a message.
+ * a message. Note that {@link android.widget.TextView} will automatically set this
+ * flag for you on multi-line text views.
*/
public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000;