Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be6cf71d authored by Chet Haase's avatar Chet Haase Committed by Android (Google) Code Review
Browse files

Merge "Tweak visibility logic for inflated view scenarios" into klp-dev

parents 04e3a14c 35a457a3
Loading
Loading
Loading
Loading
+72 −32
Original line number Diff line number Diff line
@@ -29,11 +29,25 @@ import android.view.ViewParent;
 * views exist in the current view hierarchy. The class is intended to be a
 * utility for subclasses such as {@link Fade}, which use this visibility
 * information to determine the specific animations to run when visibility
 * changes occur. Subclasses should implement one or more of the methods
 * {@link #appear(ViewGroup, TransitionValues, int, TransitionValues, int)},
 * {@link #disappear(ViewGroup, TransitionValues, int, TransitionValues, int)},
 * {@link #appear(ViewGroup, TransitionValues, int, TransitionValues, int)}, and
 * changes occur. Subclasses should implement one or both of the methods
 * {@link #appear(ViewGroup, TransitionValues, int, TransitionValues, int), and
 * {@link #disappear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
 *
 * <p>Note that a view's visibility change is determined by both whether the view
 * itself is changing and whether its parent hierarchy's visibility is changing.
 * That is, a view that appears in the end scene will only trigger a call to
 * {@link #appear(android.view.ViewGroup, TransitionValues, int, TransitionValues, int)
 * appear()} if its parent hierarchy was stable between the start and end scenes.
 * This is done to avoid causing a visibility transition on every node in a hierarchy
 * when only the top-most node is the one that should be transitioned in/out.
 * Stability is determined by either the parent hierarchy views being the same
 * between scenes or, if scenes are inflated from layout resource files and thus
 * have result in different view instances, if the views represented by
 * the ids of those parents are stable. This means that visibility determination
 * is more effective with inflated view hierarchies if ids are used.
 * The exception to this is when the visibility subclass transition is
 * targeted at specific views, in which case the visibility of parent views
 * is ignored.</p>
 */
public abstract class Visibility extends Transition {

@@ -49,8 +63,8 @@ public abstract class Visibility extends Transition {
        boolean fadeIn;
        int startVisibility;
        int endVisibility;
        View startParent;
        View endParent;
        ViewGroup startParent;
        ViewGroup endParent;
    }

    // Temporary structure, used in calculating state in setup() and play()
@@ -93,28 +107,47 @@ public abstract class Visibility extends Transition {
        return visibility == View.VISIBLE && parent != null;
    }

    private boolean isHierarchyVisibilityChanging(ViewGroup sceneRoot, ViewGroup view) {
    /**
     * Tests whether the hierarchy, up to the scene root, changes visibility between
     * start and end scenes. This is done to ensure that a view that changes visibility
     * is only animated if that view's parent was stable between scenes; we should not
     * fade an entire hierarchy, but rather just the top-most node in the hierarchy that
     * changed visibility. Note that both the start and end parents are passed in
     * because the instances may differ for the same view due to layout inflation
     * between scenes.
     *
     * @param sceneRoot The root of the scene hierarchy
     * @param startView The container view in the start scene
     * @param endView The container view in the end scene
     * @return true if the parent hierarchy experienced a visibility change, false
     * otherwise
     */
    private boolean isHierarchyVisibilityChanging(ViewGroup sceneRoot, ViewGroup startView,
            ViewGroup endView) {

        if (view == sceneRoot) {
        if (startView == sceneRoot || endView == sceneRoot) {
            return false;
        }
        TransitionValues startValues = getTransitionValues(view, true);
        TransitionValues endValues = getTransitionValues(view, false);
        TransitionValues startValues = startView != null ?
                getTransitionValues(startView, true) : getTransitionValues(endView, true);
        TransitionValues endValues = endView != null ?
                getTransitionValues(endView, false) : getTransitionValues(startView, false);

        if (startValues == null || endValues == null) {
            return true;
        }
        int startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
        View startParent = (View) startValues.values.get(PROPNAME_PARENT);
        int endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
        View endParent = (View) endValues.values.get(PROPNAME_PARENT);
        Integer visibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
        int startVisibility = (visibility != null) ? visibility : -1;
        ViewGroup startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
        visibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
        int endVisibility = (visibility != null) ? visibility : -1;
        ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
        if (startVisibility != endVisibility || startParent != endParent) {
            return true;
        }

        ViewParent parent = view.getParent();
        if (parent instanceof ViewGroup && parent != sceneRoot) {
            return isHierarchyVisibilityChanging(sceneRoot, (ViewGroup) parent);
        if (startParent != null || endParent != null) {
            return isHierarchyVisibilityChanging(sceneRoot, startParent, endParent);
        }
        return false;
    }
@@ -126,14 +159,14 @@ public abstract class Visibility extends Transition {
        visInfo.fadeIn = false;
        if (startValues != null) {
            visInfo.startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
            visInfo.startParent = (View) startValues.values.get(PROPNAME_PARENT);
            visInfo.startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
        } else {
            visInfo.startVisibility = -1;
            visInfo.startParent = null;
        }
        if (endValues != null) {
            visInfo.endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
            visInfo.endParent = (View) endValues.values.get(PROPNAME_PARENT);
            visInfo.endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
        } else {
            visInfo.endVisibility = -1;
            visInfo.endParent = null;
@@ -177,12 +210,20 @@ public abstract class Visibility extends Transition {
    protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
            TransitionValues endValues) {
        VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
        // Ensure not in parent hierarchy that's also becoming visible/invisible
        if (visInfo.visibilityChange) {
            ViewGroup parent = (ViewGroup) ((visInfo.endParent != null) ?
                    visInfo.endParent : visInfo.startParent);
            if (parent != null) {
                if (!isHierarchyVisibilityChanging(sceneRoot, parent)) {
            // Only transition views that are either targets of this transition
            // or whose parent hierarchies remain stable between scenes
            boolean isTarget = false;
            if (mTargets != null || mTargetIds != null) {
                View startView = startValues != null ? startValues.view : null;
                View endView = endValues != null ? endValues.view : null;
                int startId = startView != null ? startView.getId() : -1;
                int endId = endView != null ? endView.getId() : -1;
                isTarget = isValidTarget(startView, startId) || isValidTarget(endView, endId);
            }
            if (isTarget || ((visInfo.startParent != null || visInfo.endParent != null) &&
                    !isHierarchyVisibilityChanging(sceneRoot,
                            visInfo.startParent, visInfo.endParent))) {
                if (visInfo.fadeIn) {
                    return appear(sceneRoot, startValues, visInfo.startVisibility,
                            endValues, visInfo.endVisibility);
@@ -193,7 +234,6 @@ public abstract class Visibility extends Transition {
                }
            }
        }
        }
        return null;
    }