Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Unhide View#dispatch{Start,Finish}TemporaryDetach()
Browse files Browse the repository at this point in the history
In order to fix Bug 18920212, we have to track when a View enters
temporarily detached state and when it exits from that state. To do
that, ListView needs to use View#dispatchStartTemporaryDetach() instead
of directly calling View#onStartTemporaryDetach() because there is no
guarantee that existing applications have internally followed Call-Super
pattern.

With this CL, we are going to expose temporary detach state and its
dispatching methods as public APIs.  Major changes are:
  1. ListView's indirect children will start receiving temporary
     dispatch callbacks. Previously only direct children have received
     View#on{Start, Finish}TemporaryDetach() callbacks.
  2. TextView can no longer assume that ListView never calls
     View#View#dispatchStartTemporaryDetach() but directly call
     View#onStartTemporaryDetach() instead. See the commit message
     of [1] for details.

This also enables us to do the following fixes, which will be handled in
subsequent CLs.
  A. ViewCompat support lib is finally able to rely on temporary
     dispatch mechanism without reflection.
  B. InputMethodManager is now able to ignore focus-in events from
     temporarily detached Views. This will be done in the next CL [2].

  [1]: a440b00
  [2]: Ia79bbd8468f768d546354382b47b39dd31ef7bb5

Bug: 18920212
Bug: 27905921
Change-Id: If8f780f8b71754f7533a65097304113ae1f5cf12
  • Loading branch information
yukawa committed Apr 1, 2016
1 parent 9a99629 commit 24df931
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 47 deletions.
3 changes: 3 additions & 0 deletions api/current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42314,6 +42314,7 @@ package android.view {
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
Expand All @@ -42333,6 +42334,7 @@ package android.view {
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
Expand Down Expand Up @@ -42545,6 +42547,7 @@ package android.view {
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
Expand Down
3 changes: 3 additions & 0 deletions api/system-current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45040,6 +45040,7 @@ package android.view {
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
Expand All @@ -45059,6 +45060,7 @@ package android.view {
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
Expand Down Expand Up @@ -45271,6 +45273,7 @@ package android.view {
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
Expand Down
3 changes: 3 additions & 0 deletions api/test-current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42388,6 +42388,7 @@ package android.view {
method public boolean dispatchDragEvent(android.view.DragEvent);
method protected void dispatchDraw(android.graphics.Canvas);
method public void dispatchDrawableHotspotChanged(float, float);
method public void dispatchFinishTemporaryDetach();
method protected boolean dispatchGenericFocusedEvent(android.view.MotionEvent);
method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
method protected boolean dispatchGenericPointerEvent(android.view.MotionEvent);
Expand All @@ -42407,6 +42408,7 @@ package android.view {
method protected void dispatchSetActivated(boolean);
method protected void dispatchSetPressed(boolean);
method protected void dispatchSetSelected(boolean);
method public void dispatchStartTemporaryDetach();
method public void dispatchSystemUiVisibilityChanged(int);
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
Expand Down Expand Up @@ -42619,6 +42621,7 @@ package android.view {
method public boolean isSelected();
method public boolean isShown();
method public boolean isSoundEffectsEnabled();
method public final boolean isTemporarilyDetached();
method public boolean isTextAlignmentResolved();
method public boolean isTextDirectionResolved();
method public boolean isVerticalFadingEdgeEnabled();
Expand Down
28 changes: 26 additions & 2 deletions core/java/android/view/View.java
Original file line number Diff line number Diff line change
Expand Up @@ -2434,6 +2434,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* 11111111 PFLAG3_POINTER_ICON_MASK
* 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
* 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
* 1 PFLAG3_TEMPORARY_DETACH
* |-------|-------|-------|-------|
*/

Expand Down Expand Up @@ -2667,6 +2668,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000;

/**
* Flag indicating that the view is temporarily detached from the parent view.
*
* @see #onStartTemporaryDetach()
* @see #onFinishTemporaryDetach()
*/
static final int PFLAG3_TEMPORARY_DETACH = 0x2000000;

/* End of masks for mPrivateFlags3 */

/**
Expand Down Expand Up @@ -9735,9 +9744,20 @@ public TextSegmentIterator getIteratorForGranularity(int granularity) {
}

/**
* @hide
* @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()}
* and {@link #onFinishTemporaryDetach()}.
*/
public final boolean isTemporarilyDetached() {
return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0;
}

/**
* Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is
* a container View.
*/
@CallSuper
public void dispatchStartTemporaryDetach() {
mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH;
onStartTemporaryDetach();
}

Expand All @@ -9753,10 +9773,13 @@ public void onStartTemporaryDetach() {
}

/**
* @hide
* Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is
* a container View.
*/
@CallSuper
public void dispatchFinishTemporaryDetach() {
onFinishTemporaryDetach();
mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
}

/**
Expand Down Expand Up @@ -15187,6 +15210,7 @@ protected void onDetachedFromWindow() {
protected void onDetachedFromWindowInternal() {
mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT;
mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;

removeUnsetPressCallback();
removeLongPressCallback();
Expand Down
2 changes: 1 addition & 1 deletion core/java/android/widget/AutoCompleteTextView.java
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,7 @@ protected void onDisplayHint(int hint) {
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);

if (mTemporaryDetach) {
if (isTemporarilyDetached()) {
// If we are temporarily in the detach state, then do nothing.
return;
}
Expand Down
5 changes: 1 addition & 4 deletions core/java/android/widget/Editor.java
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ public TextRenderNode(String name) {
boolean mShowSoftInputOnFocus = true;
private boolean mPreserveSelection;
private boolean mRestartActionModeOnNextRefresh;
boolean mTemporaryDetach;

boolean mIsBeingLongClicked;

Expand Down Expand Up @@ -367,7 +366,6 @@ void onAttachedToWindow() {
showError();
mShowErrorAfterAttach = false;
}
mTemporaryDetach = false;

final ViewTreeObserver observer = mTextView.getViewTreeObserver();
// No need to create the controller.
Expand Down Expand Up @@ -429,7 +427,6 @@ void onDetachedFromWindow() {

hideCursorAndSpanControllers();
stopTextActionModeWithPreservingSelection();
mTemporaryDetach = false;
}

private void discardTextDisplayLists() {
Expand Down Expand Up @@ -1212,7 +1209,7 @@ void onFocusChanged(boolean focused, int direction) {
stopTextActionModeWithPreservingSelection();
} else {
hideCursorAndSpanControllers();
if (mTemporaryDetach) {
if (mTextView.isTemporarilyDetached()) {
stopTextActionModeWithPreservingSelection();
} else {
stopTextActionMode();
Expand Down
4 changes: 2 additions & 2 deletions core/java/android/widget/ListView.java
Original file line number Diff line number Diff line change
Expand Up @@ -1673,7 +1673,7 @@ protected void layoutChildren() {
focusLayoutRestoreView = findFocus();
if (focusLayoutRestoreView != null) {
// Tell it we are going to mess with it.
focusLayoutRestoreView.onStartTemporaryDetach();
focusLayoutRestoreView.dispatchStartTemporaryDetach();
}
}
requestFocus();
Expand Down Expand Up @@ -1850,7 +1850,7 @@ protected void layoutChildren() {
// our view hierarchy.
if (focusLayoutRestoreView != null
&& focusLayoutRestoreView.getWindowToken() != null) {
focusLayoutRestoreView.onFinishTemporaryDetach();
focusLayoutRestoreView.dispatchFinishTemporaryDetach();
}

mLayoutMode = LAYOUT_NORMAL;
Expand Down
39 changes: 1 addition & 38 deletions core/java/android/widget/TextView.java
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mCurTextColor;
private int mCurHintTextColor;
private boolean mFreezesText;
private boolean mDispatchTemporaryDetach;

/** Whether this view is temporarily detached from the parent view. */
boolean mTemporaryDetach;

private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
Expand Down Expand Up @@ -5391,8 +5387,6 @@ public boolean onPreDraw() {
protected void onAttachedToWindow() {
super.onAttachedToWindow();

mTemporaryDetach = false;

if (mEditor != null) mEditor.onAttachedToWindow();

if (mPreDrawListenerDetached) {
Expand Down Expand Up @@ -8353,40 +8347,9 @@ void spanChange(Spanned buf, Object what, int oldStart, int newStart, int oldEnd
}
}

/**
* @hide
*/
@Override
public void dispatchFinishTemporaryDetach() {
mDispatchTemporaryDetach = true;
super.dispatchFinishTemporaryDetach();
mDispatchTemporaryDetach = false;
}

@Override
public void onStartTemporaryDetach() {
super.onStartTemporaryDetach();
// Only track when onStartTemporaryDetach() is called directly,
// usually because this instance is an editable field in a list
if (!mDispatchTemporaryDetach) mTemporaryDetach = true;

// Tell the editor that we are temporarily detached. It can use this to preserve
// selection state as needed.
if (mEditor != null) mEditor.mTemporaryDetach = true;
}

@Override
public void onFinishTemporaryDetach() {
super.onFinishTemporaryDetach();
// Only track when onStartTemporaryDetach() is called directly,
// usually because this instance is an editable field in a list
if (!mDispatchTemporaryDetach) mTemporaryDetach = false;
if (mEditor != null) mEditor.mTemporaryDetach = false;
}

@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (mTemporaryDetach) {
if (isTemporarilyDetached()) {
// If we are temporarily in the detach state, then do nothing.
super.onFocusChanged(focused, direction, previouslyFocusedRect);
return;
Expand Down

0 comments on commit 24df931

Please sign in to comment.