Loading core/java/android/widget/PopupWindow.java +152 −100 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,8 @@ import android.os.Build; import android.os.IBinder; import android.os.IBinder; import android.transition.Transition; import android.transition.Transition; import android.transition.Transition.EpicenterCallback; import android.transition.Transition.EpicenterCallback; import android.transition.Transition.TransitionListener; import android.transition.Transition.TransitionListenerAdapter; import android.transition.TransitionInflater; import android.transition.TransitionInflater; import android.transition.TransitionManager; import android.transition.TransitionManager; import android.transition.TransitionSet; import android.transition.TransitionSet; Loading @@ -39,12 +41,13 @@ import android.view.MotionEvent; import android.view.View; import android.view.View; import android.view.View.OnTouchListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.ViewTreeObserver.OnScrollChangedListener; import android.view.ViewTreeObserver.OnScrollChangedListener; import android.view.WindowManager; import android.view.WindowManager; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.List; /** /** * <p>A popup window that can be used to display an arbitrary view. The popup * <p>A popup window that can be used to display an arbitrary view. The popup Loading Loading @@ -96,14 +99,12 @@ public class PopupWindow { private WindowManager mWindowManager; private WindowManager mWindowManager; private boolean mIsShowing; private boolean mIsShowing; private boolean mIsTransitioningToDismiss; private boolean mIsDropdown; private boolean mIsDropdown; /** View that handles event dispatch and content transitions. */ /** View that handles event dispatch and content transitions. */ private PopupDecorView mDecorView; private PopupDecorView mDecorView; /** View that holds the popup background. May be the content view. */ private View mBackgroundView; /** The contents of the popup. */ /** The contents of the popup. */ private View mContentView; private View mContentView; Loading Loading @@ -1183,23 +1184,30 @@ public class PopupWindow { + "calling setContentView() before attempting to show the popup."); + "calling setContentView() before attempting to show the popup."); } } // The old decor view may be transitioning out. Make sure it finishes // and cleans up before we try to create another one. if (mDecorView != null) { mDecorView.cancelTransitions(); } // When a background is available, we embed the content view within // When a background is available, we embed the content view within // another view that owns the background drawable. // another view that owns the background drawable. final View backgroundView; if (mBackground != null) { if (mBackground != null) { mBackgroundView = createBackgroundView(mContentView); backgroundView = createBackgroundView(mContentView); mBackgroundView.setBackground(mBackground); backgroundView.setBackground(mBackground); } else { } else { mBackgroundView = mContentView; backgroundView = mContentView; } } mDecorView = createDecorView(mBackgroundView); mDecorView = createDecorView(backgroundView); // The background owner should be elevated so that it casts a shadow. // The background owner should be elevated so that it casts a shadow. mBackgroundView.setElevation(mElevation); backgroundView.setElevation(mElevation); // We may wrap that in another view, so we'll need to manually specify // We may wrap that in another view, so we'll need to manually specify // the surface insets. // the surface insets. final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2); final int surfaceInset = (int) Math.ceil(backgroundView.getZ() * 2); p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset); p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset); p.hasManualSurfaceInsets = true; p.hasManualSurfaceInsets = true; Loading Loading @@ -1268,26 +1276,13 @@ public class PopupWindow { p.packageName = mContext.getPackageName(); p.packageName = mContext.getPackageName(); } } final View rootView = mContentView.getRootView(); final PopupDecorView decorView = mDecorView; rootView.setFitsSystemWindows(mLayoutInsetDecor); decorView.setFitsSystemWindows(mLayoutInsetDecor); setLayoutDirectionFromAnchor(); decorView.requestEnterTransition(mEnterTransition); mWindowManager.addView(rootView, p); setLayoutDirectionFromAnchor(); // Postpone enter transition until the scene root has been laid out. if (mEnterTransition != null) { mEnterTransition.addTarget(mBackgroundView); mEnterTransition.addListener(new Transition.TransitionListenerAdapter() { @Override public void onTransitionEnd(Transition transition) { transition.removeListener(this); transition.removeTarget(mBackgroundView); } }); mDecorView.getViewTreeObserver().addOnGlobalLayoutListener( mWindowManager.addView(decorView, p); new PostLayoutTransitionListener(mDecorView, mEnterTransition)); } } } private void setLayoutDirectionFromAnchor() { private void setLayoutDirectionFromAnchor() { Loading Loading @@ -1591,35 +1586,38 @@ public class PopupWindow { * @see #showAsDropDown(android.view.View) * @see #showAsDropDown(android.view.View) */ */ public void dismiss() { public void dismiss() { if (!isShowing()) { if (!isShowing() || mIsTransitioningToDismiss) { return; return; } } final PopupDecorView decorView = mDecorView; final View contentView = mContentView; final ViewGroup contentHolder; final ViewParent contentParent = contentView.getParent(); if (contentParent instanceof ViewGroup) { contentHolder = ((ViewGroup) contentParent); } else { contentHolder = null; } // Ensure any ongoing or pending transitions are canceled. decorView.cancelTransitions(); unregisterForScrollChanged(); unregisterForScrollChanged(); mIsShowing = false; mIsShowing = false; mIsTransitioningToDismiss = true; if (mExitTransition != null) { if (mExitTransition != null && decorView.isLaidOut()) { // Cache the content view, since it may change without notice. decorView.startExitTransition(mExitTransition, new TransitionListenerAdapter() { final View contentView = mContentView; mExitTransition.addTarget(mBackgroundView); mExitTransition.addListener(new Transition.TransitionListenerAdapter() { @Override @Override public void onTransitionEnd(Transition transition) { public void onTransitionEnd(Transition transition) { transition.removeListener(this); dismissImmediate(decorView, contentHolder, contentView); transition.removeTarget(mBackgroundView); dismissImmediate(contentView); } } }); }); TransitionManager.beginDelayedTransition(mDecorView, mExitTransition); // Transition to invisible. mBackgroundView.setVisibility(View.INVISIBLE); } else { } else { dismissImmediate(mContentView); dismissImmediate(decorView, contentHolder, contentView); } } if (mOnDismissListener != null) { if (mOnDismissListener != null) { Loading @@ -1631,24 +1629,22 @@ public class PopupWindow { * Removes the popup from the window manager and tears down the supporting * Removes the popup from the window manager and tears down the supporting * view hierarchy, if necessary. * view hierarchy, if necessary. */ */ private void dismissImmediate(View contentView) { private void dismissImmediate(View decorView, ViewGroup contentHolder, View contentView) { if (mDecorView == null || mBackgroundView == null) { // If this method gets called and the decor view doesn't have a parent, throw new RuntimeException("Popup window already dismissed"); // then it was either never added or was already removed. That should // never happen, but it's worth checking to avoid potential crashes. if (decorView.getParent() != null) { mWindowManager.removeViewImmediate(decorView); } } try { if (contentHolder != null) { if (mDecorView.isAttachedToWindow()) { contentHolder.removeView(contentView); mWindowManager.removeViewImmediate(mDecorView); } } } finally { mDecorView.removeView(mBackgroundView); mDecorView = null; if (mBackgroundView != contentView) { // This needs to stay until after all transitions have ended since we ((ViewGroup) mBackgroundView).removeView(contentView); // need the reference to cancel transitions in preparePopup(). } mDecorView = null; mBackgroundView = null; mIsTransitioningToDismiss = false; } } } /** /** Loading Loading @@ -1909,47 +1905,9 @@ public class PopupWindow { mAnchoredGravity = gravity; mAnchoredGravity = gravity; } } /** * Layout listener used to run a transition immediately after a view is * laid out. Forces the view to transition from invisible to visible. */ private static class PostLayoutTransitionListener implements ViewTreeObserver.OnGlobalLayoutListener { private final ViewGroup mSceneRoot; private final Transition mTransition; public PostLayoutTransitionListener(ViewGroup sceneRoot, Transition transition) { mSceneRoot = sceneRoot; mTransition = transition; } @Override public void onGlobalLayout() { final ViewTreeObserver observer = mSceneRoot.getViewTreeObserver(); if (observer == null) { // View has been detached. return; } observer.removeOnGlobalLayoutListener(this); // Set all targets to be initially invisible. final List<View> targets = mTransition.getTargets(); final int N = targets.size(); for (int i = 0; i < N; i++) { targets.get(i).setVisibility(View.INVISIBLE); } TransitionManager.beginDelayedTransition(mSceneRoot, mTransition); // Transition targets to visible. for (int i = 0; i < N; i++) { targets.get(i).setVisibility(View.VISIBLE); } } } private class PopupDecorView extends FrameLayout { private class PopupDecorView extends FrameLayout { private TransitionListenerAdapter mPendingExitListener; public PopupDecorView(Context context) { public PopupDecorView(Context context) { super(context); super(context); } } Loading Loading @@ -2004,6 +1962,100 @@ public class PopupWindow { return super.onTouchEvent(event); return super.onTouchEvent(event); } } } } /** * Requests that an enter transition run after the next layout pass. */ public void requestEnterTransition(Transition transition) { final ViewTreeObserver observer = getViewTreeObserver(); if (observer != null && transition != null) { final Transition enterTransition = transition.clone(); // Postpone the enter transition after the first layout pass. observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { final ViewTreeObserver observer = getViewTreeObserver(); if (observer != null) { observer.removeOnGlobalLayoutListener(this); } startEnterTransition(enterTransition); } }); } } /** * Starts the pending enter transition, if one is set. */ private void startEnterTransition(Transition enterTransition) { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); enterTransition.addTarget(child); child.setVisibility(View.INVISIBLE); } TransitionManager.beginDelayedTransition(this, enterTransition); for (int i = 0; i < count; i++) { final View child = getChildAt(i); child.setVisibility(View.VISIBLE); } } /** * Starts an exit transition immediately. * <p> * <strong>Note:</strong> The transition listener is guaranteed to have * its {@code onTransitionEnd} method called even if the transition * never starts; however, it may be called with a {@code null} argument. */ public void startExitTransition(Transition transition, final TransitionListener listener) { if (transition == null) { return; } // The exit listener MUST be called for cleanup, even if the // transition never starts or ends. Stash it for later. mPendingExitListener = new TransitionListenerAdapter() { @Override public void onTransitionEnd(Transition transition) { listener.onTransitionEnd(transition); // The listener was called. Our job here is done. mPendingExitListener = null; } }; final Transition exitTransition = transition.clone(); exitTransition.addListener(mPendingExitListener); final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); exitTransition.addTarget(child); } TransitionManager.beginDelayedTransition(this, exitTransition); for (int i = 0; i < count; i++) { final View child = getChildAt(i); child.setVisibility(View.INVISIBLE); } } /** * Cancels all pending or current transitions. */ public void cancelTransitions() { TransitionManager.endTransitions(this); if (mPendingExitListener != null) { mPendingExitListener.onTransitionEnd(null); } } } } private class PopupBackgroundView extends FrameLayout { private class PopupBackgroundView extends FrameLayout { Loading core/java/com/android/internal/view/menu/MenuPopupHelper.java +13 −2 Original line number Original line Diff line number Diff line Loading @@ -43,8 +43,6 @@ import java.util.ArrayList; public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener, public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener, ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener, ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener, View.OnAttachStateChangeListener, MenuPresenter { View.OnAttachStateChangeListener, MenuPresenter { private static final String TAG = "MenuPopupHelper"; static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout; static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout; private final Context mContext; private final Context mContext; Loading Loading @@ -132,7 +130,18 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On return mPopup; return mPopup; } } /** * Attempts to show the popup anchored to the view specified by * {@link #setAnchorView(View)}. * * @return {@code true} if the popup was shown or was already showing prior * to calling this method, {@code false} otherwise */ public boolean tryShow() { public boolean tryShow() { if (isShowing()) { return true; } mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes); mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes); mPopup.setOnDismissListener(this); mPopup.setOnDismissListener(this); mPopup.setOnItemClickListener(this); mPopup.setOnItemClickListener(this); Loading Loading @@ -169,6 +178,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On } } } } @Override public void onDismiss() { public void onDismiss() { mPopup = null; mPopup = null; mMenu.close(); mMenu.close(); Loading @@ -190,6 +200,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); } } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { dismiss(); dismiss(); Loading Loading
core/java/android/widget/PopupWindow.java +152 −100 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,8 @@ import android.os.Build; import android.os.IBinder; import android.os.IBinder; import android.transition.Transition; import android.transition.Transition; import android.transition.Transition.EpicenterCallback; import android.transition.Transition.EpicenterCallback; import android.transition.Transition.TransitionListener; import android.transition.Transition.TransitionListenerAdapter; import android.transition.TransitionInflater; import android.transition.TransitionInflater; import android.transition.TransitionManager; import android.transition.TransitionManager; import android.transition.TransitionSet; import android.transition.TransitionSet; Loading @@ -39,12 +41,13 @@ import android.view.MotionEvent; import android.view.View; import android.view.View; import android.view.View.OnTouchListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.ViewTreeObserver.OnScrollChangedListener; import android.view.ViewTreeObserver.OnScrollChangedListener; import android.view.WindowManager; import android.view.WindowManager; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.List; /** /** * <p>A popup window that can be used to display an arbitrary view. The popup * <p>A popup window that can be used to display an arbitrary view. The popup Loading Loading @@ -96,14 +99,12 @@ public class PopupWindow { private WindowManager mWindowManager; private WindowManager mWindowManager; private boolean mIsShowing; private boolean mIsShowing; private boolean mIsTransitioningToDismiss; private boolean mIsDropdown; private boolean mIsDropdown; /** View that handles event dispatch and content transitions. */ /** View that handles event dispatch and content transitions. */ private PopupDecorView mDecorView; private PopupDecorView mDecorView; /** View that holds the popup background. May be the content view. */ private View mBackgroundView; /** The contents of the popup. */ /** The contents of the popup. */ private View mContentView; private View mContentView; Loading Loading @@ -1183,23 +1184,30 @@ public class PopupWindow { + "calling setContentView() before attempting to show the popup."); + "calling setContentView() before attempting to show the popup."); } } // The old decor view may be transitioning out. Make sure it finishes // and cleans up before we try to create another one. if (mDecorView != null) { mDecorView.cancelTransitions(); } // When a background is available, we embed the content view within // When a background is available, we embed the content view within // another view that owns the background drawable. // another view that owns the background drawable. final View backgroundView; if (mBackground != null) { if (mBackground != null) { mBackgroundView = createBackgroundView(mContentView); backgroundView = createBackgroundView(mContentView); mBackgroundView.setBackground(mBackground); backgroundView.setBackground(mBackground); } else { } else { mBackgroundView = mContentView; backgroundView = mContentView; } } mDecorView = createDecorView(mBackgroundView); mDecorView = createDecorView(backgroundView); // The background owner should be elevated so that it casts a shadow. // The background owner should be elevated so that it casts a shadow. mBackgroundView.setElevation(mElevation); backgroundView.setElevation(mElevation); // We may wrap that in another view, so we'll need to manually specify // We may wrap that in another view, so we'll need to manually specify // the surface insets. // the surface insets. final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2); final int surfaceInset = (int) Math.ceil(backgroundView.getZ() * 2); p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset); p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset); p.hasManualSurfaceInsets = true; p.hasManualSurfaceInsets = true; Loading Loading @@ -1268,26 +1276,13 @@ public class PopupWindow { p.packageName = mContext.getPackageName(); p.packageName = mContext.getPackageName(); } } final View rootView = mContentView.getRootView(); final PopupDecorView decorView = mDecorView; rootView.setFitsSystemWindows(mLayoutInsetDecor); decorView.setFitsSystemWindows(mLayoutInsetDecor); setLayoutDirectionFromAnchor(); decorView.requestEnterTransition(mEnterTransition); mWindowManager.addView(rootView, p); setLayoutDirectionFromAnchor(); // Postpone enter transition until the scene root has been laid out. if (mEnterTransition != null) { mEnterTransition.addTarget(mBackgroundView); mEnterTransition.addListener(new Transition.TransitionListenerAdapter() { @Override public void onTransitionEnd(Transition transition) { transition.removeListener(this); transition.removeTarget(mBackgroundView); } }); mDecorView.getViewTreeObserver().addOnGlobalLayoutListener( mWindowManager.addView(decorView, p); new PostLayoutTransitionListener(mDecorView, mEnterTransition)); } } } private void setLayoutDirectionFromAnchor() { private void setLayoutDirectionFromAnchor() { Loading Loading @@ -1591,35 +1586,38 @@ public class PopupWindow { * @see #showAsDropDown(android.view.View) * @see #showAsDropDown(android.view.View) */ */ public void dismiss() { public void dismiss() { if (!isShowing()) { if (!isShowing() || mIsTransitioningToDismiss) { return; return; } } final PopupDecorView decorView = mDecorView; final View contentView = mContentView; final ViewGroup contentHolder; final ViewParent contentParent = contentView.getParent(); if (contentParent instanceof ViewGroup) { contentHolder = ((ViewGroup) contentParent); } else { contentHolder = null; } // Ensure any ongoing or pending transitions are canceled. decorView.cancelTransitions(); unregisterForScrollChanged(); unregisterForScrollChanged(); mIsShowing = false; mIsShowing = false; mIsTransitioningToDismiss = true; if (mExitTransition != null) { if (mExitTransition != null && decorView.isLaidOut()) { // Cache the content view, since it may change without notice. decorView.startExitTransition(mExitTransition, new TransitionListenerAdapter() { final View contentView = mContentView; mExitTransition.addTarget(mBackgroundView); mExitTransition.addListener(new Transition.TransitionListenerAdapter() { @Override @Override public void onTransitionEnd(Transition transition) { public void onTransitionEnd(Transition transition) { transition.removeListener(this); dismissImmediate(decorView, contentHolder, contentView); transition.removeTarget(mBackgroundView); dismissImmediate(contentView); } } }); }); TransitionManager.beginDelayedTransition(mDecorView, mExitTransition); // Transition to invisible. mBackgroundView.setVisibility(View.INVISIBLE); } else { } else { dismissImmediate(mContentView); dismissImmediate(decorView, contentHolder, contentView); } } if (mOnDismissListener != null) { if (mOnDismissListener != null) { Loading @@ -1631,24 +1629,22 @@ public class PopupWindow { * Removes the popup from the window manager and tears down the supporting * Removes the popup from the window manager and tears down the supporting * view hierarchy, if necessary. * view hierarchy, if necessary. */ */ private void dismissImmediate(View contentView) { private void dismissImmediate(View decorView, ViewGroup contentHolder, View contentView) { if (mDecorView == null || mBackgroundView == null) { // If this method gets called and the decor view doesn't have a parent, throw new RuntimeException("Popup window already dismissed"); // then it was either never added or was already removed. That should // never happen, but it's worth checking to avoid potential crashes. if (decorView.getParent() != null) { mWindowManager.removeViewImmediate(decorView); } } try { if (contentHolder != null) { if (mDecorView.isAttachedToWindow()) { contentHolder.removeView(contentView); mWindowManager.removeViewImmediate(mDecorView); } } } finally { mDecorView.removeView(mBackgroundView); mDecorView = null; if (mBackgroundView != contentView) { // This needs to stay until after all transitions have ended since we ((ViewGroup) mBackgroundView).removeView(contentView); // need the reference to cancel transitions in preparePopup(). } mDecorView = null; mBackgroundView = null; mIsTransitioningToDismiss = false; } } } /** /** Loading Loading @@ -1909,47 +1905,9 @@ public class PopupWindow { mAnchoredGravity = gravity; mAnchoredGravity = gravity; } } /** * Layout listener used to run a transition immediately after a view is * laid out. Forces the view to transition from invisible to visible. */ private static class PostLayoutTransitionListener implements ViewTreeObserver.OnGlobalLayoutListener { private final ViewGroup mSceneRoot; private final Transition mTransition; public PostLayoutTransitionListener(ViewGroup sceneRoot, Transition transition) { mSceneRoot = sceneRoot; mTransition = transition; } @Override public void onGlobalLayout() { final ViewTreeObserver observer = mSceneRoot.getViewTreeObserver(); if (observer == null) { // View has been detached. return; } observer.removeOnGlobalLayoutListener(this); // Set all targets to be initially invisible. final List<View> targets = mTransition.getTargets(); final int N = targets.size(); for (int i = 0; i < N; i++) { targets.get(i).setVisibility(View.INVISIBLE); } TransitionManager.beginDelayedTransition(mSceneRoot, mTransition); // Transition targets to visible. for (int i = 0; i < N; i++) { targets.get(i).setVisibility(View.VISIBLE); } } } private class PopupDecorView extends FrameLayout { private class PopupDecorView extends FrameLayout { private TransitionListenerAdapter mPendingExitListener; public PopupDecorView(Context context) { public PopupDecorView(Context context) { super(context); super(context); } } Loading Loading @@ -2004,6 +1962,100 @@ public class PopupWindow { return super.onTouchEvent(event); return super.onTouchEvent(event); } } } } /** * Requests that an enter transition run after the next layout pass. */ public void requestEnterTransition(Transition transition) { final ViewTreeObserver observer = getViewTreeObserver(); if (observer != null && transition != null) { final Transition enterTransition = transition.clone(); // Postpone the enter transition after the first layout pass. observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { final ViewTreeObserver observer = getViewTreeObserver(); if (observer != null) { observer.removeOnGlobalLayoutListener(this); } startEnterTransition(enterTransition); } }); } } /** * Starts the pending enter transition, if one is set. */ private void startEnterTransition(Transition enterTransition) { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); enterTransition.addTarget(child); child.setVisibility(View.INVISIBLE); } TransitionManager.beginDelayedTransition(this, enterTransition); for (int i = 0; i < count; i++) { final View child = getChildAt(i); child.setVisibility(View.VISIBLE); } } /** * Starts an exit transition immediately. * <p> * <strong>Note:</strong> The transition listener is guaranteed to have * its {@code onTransitionEnd} method called even if the transition * never starts; however, it may be called with a {@code null} argument. */ public void startExitTransition(Transition transition, final TransitionListener listener) { if (transition == null) { return; } // The exit listener MUST be called for cleanup, even if the // transition never starts or ends. Stash it for later. mPendingExitListener = new TransitionListenerAdapter() { @Override public void onTransitionEnd(Transition transition) { listener.onTransitionEnd(transition); // The listener was called. Our job here is done. mPendingExitListener = null; } }; final Transition exitTransition = transition.clone(); exitTransition.addListener(mPendingExitListener); final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); exitTransition.addTarget(child); } TransitionManager.beginDelayedTransition(this, exitTransition); for (int i = 0; i < count; i++) { final View child = getChildAt(i); child.setVisibility(View.INVISIBLE); } } /** * Cancels all pending or current transitions. */ public void cancelTransitions() { TransitionManager.endTransitions(this); if (mPendingExitListener != null) { mPendingExitListener.onTransitionEnd(null); } } } } private class PopupBackgroundView extends FrameLayout { private class PopupBackgroundView extends FrameLayout { Loading
core/java/com/android/internal/view/menu/MenuPopupHelper.java +13 −2 Original line number Original line Diff line number Diff line Loading @@ -43,8 +43,6 @@ import java.util.ArrayList; public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener, public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener, ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener, ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener, View.OnAttachStateChangeListener, MenuPresenter { View.OnAttachStateChangeListener, MenuPresenter { private static final String TAG = "MenuPopupHelper"; static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout; static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout; private final Context mContext; private final Context mContext; Loading Loading @@ -132,7 +130,18 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On return mPopup; return mPopup; } } /** * Attempts to show the popup anchored to the view specified by * {@link #setAnchorView(View)}. * * @return {@code true} if the popup was shown or was already showing prior * to calling this method, {@code false} otherwise */ public boolean tryShow() { public boolean tryShow() { if (isShowing()) { return true; } mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes); mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes); mPopup.setOnDismissListener(this); mPopup.setOnDismissListener(this); mPopup.setOnItemClickListener(this); mPopup.setOnItemClickListener(this); Loading Loading @@ -169,6 +178,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On } } } } @Override public void onDismiss() { public void onDismiss() { mPopup = null; mPopup = null; mMenu.close(); mMenu.close(); Loading @@ -190,6 +200,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); } } @Override public boolean onKey(View v, int keyCode, KeyEvent event) { public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { dismiss(); dismiss(); Loading