diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 8907420a203a7..bcaa1b26879e5 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2805,6 +2805,7 @@ public final class ViewRootImpl implements ViewParent, if (viewVisibilityChanged) { mAttachInfo.mWindowVisibility = viewVisibility; host.dispatchWindowVisibilityChanged(viewVisibility); + mAttachInfo.mTreeObserver.dispatchOnWindowVisibilityChange(viewVisibility); if (viewUserVisibilityChanged) { host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE); } diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java index 5a99ab2f5bdb2..ed8350afc109c 100644 --- a/core/java/android/view/ViewTreeObserver.java +++ b/core/java/android/view/ViewTreeObserver.java @@ -43,6 +43,7 @@ public final class ViewTreeObserver { // Recursive listeners use CopyOnWriteArrayList private CopyOnWriteArrayList mOnWindowFocusListeners; private CopyOnWriteArrayList mOnWindowAttachListeners; + private CopyOnWriteArrayList mOnWindowVisibilityListeners; private CopyOnWriteArrayList mOnGlobalFocusListeners; @UnsupportedAppUsage private CopyOnWriteArrayList mOnTouchModeChangeListeners; @@ -105,6 +106,21 @@ public final class ViewTreeObserver { public void onWindowFocusChanged(boolean hasFocus); } + /** + * Interface definition for a callback to be invoked when the view hierarchy's window + * visibility changes. + * + * @hide + */ + public interface OnWindowVisibilityChangeListener { + /** + * Callback method to be invoked when the window visibility changes in the view tree. + * + * @param visibility The new visibility of the window. + */ + void onWindowVisibilityChanged(@View.Visibility int visibility); + } + /** * Interface definition for a callback to be invoked when the focus state within * the view tree changes. @@ -386,6 +402,14 @@ public final class ViewTreeObserver { } } + if (observer.mOnWindowVisibilityListeners != null) { + if (mOnWindowVisibilityListeners != null) { + mOnWindowVisibilityListeners.addAll(observer.mOnWindowVisibilityListeners); + } else { + mOnWindowVisibilityListeners = observer.mOnWindowVisibilityListeners; + } + } + if (observer.mOnGlobalFocusListeners != null) { if (mOnGlobalFocusListeners != null) { mOnGlobalFocusListeners.addAll(observer.mOnGlobalFocusListeners); @@ -540,6 +564,49 @@ public final class ViewTreeObserver { } /** + * Register a callback to be invoked when the window visibility changes. + * + * @param listener The callback to add + * + * @throws IllegalStateException If {@link #isAlive()} returns false + * + * @hide + */ + public void addOnWindowVisibilityChangeListener( + @NonNull OnWindowVisibilityChangeListener listener) { + checkIsAlive(); + + if (mOnWindowVisibilityListeners == null) { + mOnWindowVisibilityListeners = + new CopyOnWriteArrayList(); + } + + mOnWindowVisibilityListeners.add(listener); + } + + /** + * Remove a previously installed window visibility callback. + * + * @param victim The callback to remove + * + * @throws IllegalStateException If {@link #isAlive()} returns false + * + * @see #addOnWindowVisibilityChangeListener( + * android.view.ViewTreeObserver.OnWindowVisibilityChangeListener) + * + * @hide + */ + public void removeOnWindowVisibilityChangeListener( + @NonNull OnWindowVisibilityChangeListener victim) { + checkIsAlive(); + if (mOnWindowVisibilityListeners == null) { + return; + } + + mOnWindowVisibilityListeners.remove(victim); + } + + /* * Register a callback to be invoked when the focus state within the view tree changes. * * @param listener The callback to add @@ -1025,6 +1092,23 @@ public final class ViewTreeObserver { } } + /** + * Notifies registered listeners that window visibility has changed. + */ + void dispatchOnWindowVisibilityChange(int visibility) { + // 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 listeners = + mOnWindowVisibilityListeners; + if (listeners != null && listeners.size() > 0) { + for (OnWindowVisibilityChangeListener listener : listeners) { + listener.onWindowVisibilityChanged(visibility); + } + } + } + /** * Notifies registered listeners that focus has changed. */