am a73c3a54: Merge "Add View#cancelPendingInputEvents API" into klp-dev

* commit 'a73c3a54886c302cc72e469d27603ef6bb92a6a1':
  Add View#cancelPendingInputEvents API
This commit is contained in:
Adam Powell
2013-09-05 12:39:34 -07:00
committed by Android Git Automerger
9 changed files with 133 additions and 6 deletions

View File

@@ -27388,6 +27388,7 @@ package android.view {
method public boolean canScrollHorizontally(int);
method public boolean canScrollVertically(int);
method public void cancelLongPress();
method public final void cancelPendingInputEvents();
method public boolean checkInputConnectionProxy(android.view.View);
method public void clearAnimation();
method public void clearFocus();
@@ -27615,6 +27616,7 @@ package android.view {
method protected void onAnimationEnd();
method protected void onAnimationStart();
method protected void onAttachedToWindow();
method public void onCancelPendingInputEvents();
method public boolean onCheckIsTextEditor();
method protected void onConfigurationChanged(android.content.res.Configuration);
method protected void onCreateContextMenu(android.view.ContextMenu);

View File

@@ -17,6 +17,7 @@
package android.app;
import android.util.ArrayMap;
import android.util.SuperNotCalledException;
import com.android.internal.app.ActionBarImpl;
import com.android.internal.policy.PolicyManager;
@@ -3436,6 +3437,12 @@ public class Activity extends ContextThemeWrapper
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
final View decor = mWindow != null ? mWindow.peekDecorView() : null;
if (decor != null) {
decor.cancelPendingInputEvents();
}
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);

View File

@@ -76,6 +76,7 @@ import android.util.Log;
import android.util.LogPrinter;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SuperNotCalledException;
import android.view.Display;
import android.view.HardwareRenderer;
import android.view.View;
@@ -116,12 +117,6 @@ import libcore.io.IoUtils;
import dalvik.system.CloseGuard;
final class SuperNotCalledException extends AndroidRuntimeException {
public SuperNotCalledException(String msg) {
super(msg);
}
}
final class RemoteServiceException extends AndroidRuntimeException {
public RemoteServiceException(String msg) {
super(msg);

View File

@@ -31,6 +31,7 @@ import android.util.AttributeSet;
import android.util.DebugUtils;
import android.util.Log;
import android.util.SparseArray;
import android.util.SuperNotCalledException;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;

View File

@@ -31,6 +31,7 @@ import android.util.DebugUtils;
import android.util.Log;
import android.util.LogWriter;
import android.util.SparseArray;
import android.util.SuperNotCalledException;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2013 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.util;
/**
* @hide
*/
public final class SuperNotCalledException extends AndroidRuntimeException {
public SuperNotCalledException(String msg) {
super(msg);
}
}

View File

@@ -57,6 +57,7 @@ import android.util.LongSparseLongArray;
import android.util.Pools.SynchronizedPool;
import android.util.Property;
import android.util.SparseArray;
import android.util.SuperNotCalledException;
import android.util.TypedValue;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -2204,6 +2205,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8;
/**
* Flag indicating that an overridden method correctly called down to
* the superclass implementation as required by the API spec.
*/
static final int PFLAG3_CALLED_SUPER = 0x10;
/* End of masks for mPrivateFlags3 */
@@ -5955,6 +5962,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Invalidate too, since the default behavior for views is to be
// be drawn at 50% alpha rather than to change the drawable.
invalidate(true);
if (!enabled) {
cancelPendingInputEvents();
}
}
/**
@@ -12363,6 +12374,61 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
/**
* Cancel any deferred high-level input events that were previously posted to the event queue.
*
* <p>Many views post high-level events such as click handlers to the event queue
* to run deferred in order to preserve a desired user experience - clearing visible
* pressed states before executing, etc. This method will abort any events of this nature
* that are currently in flight.</p>
*
* <p>Custom views that generate their own high-level deferred input events should override
* {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p>
*
* <p>This will also cancel pending input events for any child views.</p>
*
* <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases.
* This will not impact newer events posted after this call that may occur as a result of
* lower-level input events still waiting in the queue. If you are trying to prevent
* double-submitted events for the duration of some sort of asynchronous transaction
* you should also take other steps to protect against unexpected double inputs e.g. calling
* {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when
* the transaction completes, tracking already submitted transaction IDs, etc.</p>
*/
public final void cancelPendingInputEvents() {
dispatchCancelPendingInputEvents();
}
/**
* Called by {@link #cancelPendingInputEvents()} to cancel input events in flight.
* Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling.
*/
void dispatchCancelPendingInputEvents() {
mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER;
onCancelPendingInputEvents();
if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) {
throw new SuperNotCalledException("View " + getClass().getSimpleName() +
" did not call through to super.onCancelPendingInputEvents()");
}
}
/**
* Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or
* a parent view.
*
* <p>This method is responsible for removing any pending high-level input events that were
* posted to the event queue to run later. Custom view classes that post their own deferred
* high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or
* {@link android.os.Handler} should override this method, call
* <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate.
* </p>
*/
public void onCancelPendingInputEvents() {
removePerformClickCallback();
cancelLongPress();
mPrivateFlags3 |= PFLAG3_CALLED_SUPER;
}
/**
* Store this view hierarchy's frozen state into the given container.
*

View File

@@ -3182,6 +3182,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
@Override
void dispatchCancelPendingInputEvents() {
super.dispatchCancelPendingInputEvents();
final View[] children = mChildren;
final int count = mChildrenCount;
for (int i = 0; i < count; i++) {
children[i].dispatchCancelPendingInputEvents();
}
}
/**
* When this property is set to true, this ViewGroup supports static transformations on
* children; this causes

View File

@@ -2843,6 +2843,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
return new AdapterContextMenuInfo(view, position, id);
}
@Override
public void onCancelPendingInputEvents() {
super.onCancelPendingInputEvents();
if (mPerformClick != null) {
removeCallbacks(mPerformClick);
}
if (mPendingCheckForTap != null) {
removeCallbacks(mPendingCheckForTap);
}
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
}
if (mPendingCheckForKeyLongPress != null) {
removeCallbacks(mPendingCheckForKeyLongPress);
}
}
/**
* A base class for Runnables that will check that their view is still attached to
* the original window as when the Runnable was created.