diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-18 17:39:46 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-18 17:39:46 -0700 |
commit | 105925376f8d0f6b318c9938c7b83ef7fef094da (patch) | |
tree | 3b19ee2bd8704cb9c6a0da7e42dec6759183de6d /core/java/android/view | |
parent | ba87e3e6c985e7175152993b5efcc7dd2f0e1c93 (diff) | |
download | frameworks_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.java | 2 | ||||
-rw-r--r-- | core/java/android/view/IWindowManager.aidl | 3 | ||||
-rw-r--r-- | core/java/android/view/KeyEvent.java | 72 | ||||
-rw-r--r-- | core/java/android/view/View.java | 5 | ||||
-rw-r--r-- | core/java/android/view/ViewDebug.java | 68 | ||||
-rw-r--r-- | core/java/android/view/ViewRoot.java | 24 | ||||
-rw-r--r-- | core/java/android/view/ViewTreeObserver.java | 106 | ||||
-rw-r--r-- | core/java/android/view/inputmethod/EditorInfo.java | 29 |
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; |