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

Commit c46181a9 authored by Chet Haase's avatar Chet Haase
Browse files

Use transition-only alpha property for fading transitions

The original bug is fixed already, but showed up some problems in
the underlying fade-transition implementation. This fix addresses
those and other issues. The biggest part of the change should help
transition robustness in general, as it removes the dependency on the
public 'alpha' property of views and uses, instead, a new hidden property
on views called 'transitionAlpha'. This is a value which is normally
opaque (1), but which can be used by transitions (only) to animate the
translucency of views without disturbing the actual 'alpha' value which
might be manipulated outside of transitions. This should make transitions
much more robust in general.

In implementing and testing this overall fix, I noticed a couple of things
about transitions that were simply wrong (such as starting fades from the
wrong start value, and incorrectly avoiding transitions on some views
that didn't happen to have ids), and those are fixed in this CL as well.

Issue #10726905 ActionBar weirdness in People app
Issue #10727937 Menu items in gallery appear in faded color after selecting an image/album by long press

Change-Id: If1618446db10c1bfcff4761449241de4f559afc1
parent e48569a8
Loading
Loading
Loading
Loading
+36 −64
Original line number Diff line number Diff line
@@ -41,7 +41,6 @@ public class Fade extends Visibility {
    private static boolean DBG = Transition.DBG && false;

    private static final String LOG_TAG = "Fade";
    private static final String PROPNAME_ALPHA = "android:fade:alpha";
    private static final String PROPNAME_SCREEN_X = "android:fade:screenX";
    private static final String PROPNAME_SCREEN_Y = "android:fade:screenY";

@@ -90,7 +89,8 @@ public class Fade extends Visibility {
            }
            return null;
        }
        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "transitionAlpha", startAlpha,
                endAlpha);
        if (DBG) {
            Log.d(LOG_TAG, "Created animator " + anim);
        }
@@ -102,8 +102,6 @@ public class Fade extends Visibility {
    }

    private void captureValues(TransitionValues transitionValues) {
        float alpha = transitionValues.view.getAlpha();
        transitionValues.values.put(PROPNAME_ALPHA, alpha);
        int[] loc = new int[2];
        transitionValues.view.getLocationOnScreen(loc);
        transitionValues.values.put(PROPNAME_SCREEN_X, loc[0]);
@@ -116,29 +114,6 @@ public class Fade extends Visibility {
        captureValues(transitionValues);
    }


    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        super.captureEndValues(transitionValues);
    }

    @Override
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
            TransitionValues endValues) {
        Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
        if (animator == null && startValues != null && endValues != null) {
            boolean endVisible = isVisible(endValues);
            final View endView = endValues.view;
            float endAlpha = endView.getAlpha();
            float startAlpha = (Float) startValues.values.get(PROPNAME_ALPHA);
            if ((endVisible && startAlpha < endAlpha && (mFadingMode & Fade.IN) != 0) ||
                    (!endVisible && startAlpha > endAlpha && (mFadingMode & Fade.OUT) != 0)) {
                animator = createAnimation(endView, startAlpha, endAlpha, null);
            }
        }
        return animator;
    }

    @Override
    public Animator onAppear(ViewGroup sceneRoot,
            TransitionValues startValues, int startVisibility,
@@ -152,40 +127,37 @@ public class Fade extends Visibility {
            Log.d(LOG_TAG, "Fade.onAppear: startView, startVis, endView, endVis = " +
                    startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
        }
        // if alpha < 1, just fade it in from the current value
        if (endView.getAlpha() == 1.0f) {
            endView.setAlpha(0);
        endView.setTransitionAlpha(0);
        TransitionListener transitionListener = new TransitionListenerAdapter() {
            boolean mCanceled = false;
            float mPausedAlpha;

            @Override
            public void onTransitionCancel(Transition transition) {
                    endView.setAlpha(1);
                endView.setTransitionAlpha(1);
                mCanceled = true;
            }

            @Override
            public void onTransitionEnd(Transition transition) {
                if (!mCanceled) {
                        endView.setAlpha(1);
                    endView.setTransitionAlpha(1);
                }
            }

            @Override
            public void onTransitionPause(Transition transition) {
                    mPausedAlpha = endView.getAlpha();
                    endView.setAlpha(1);
                mPausedAlpha = endView.getTransitionAlpha();
                endView.setTransitionAlpha(1);
            }

            @Override
            public void onTransitionResume(Transition transition) {
                    endView.setAlpha(mPausedAlpha);
                endView.setTransitionAlpha(mPausedAlpha);
            }
        };
        addListener(transitionListener);
        }
        return createAnimation(endView, endView.getAlpha(), 1, null);
        return createAnimation(endView, 0, 1, null);
    }

    @Override
@@ -236,7 +208,7 @@ public class Fade extends Visibility {
            overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
            sceneRoot.getOverlay().add(overlayView);
            // TODO: add automatic facility to Visibility superclass for keeping views around
            final float startAlpha = view.getAlpha();
            final float startAlpha = 1;
            float endAlpha = 0;
            final View finalView = view;
            final View finalOverlayView = overlayView;
@@ -245,7 +217,7 @@ public class Fade extends Visibility {
            final AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    finalView.setAlpha(startAlpha);
                    finalView.setTransitionAlpha(startAlpha);
                    // TODO: restore view offset from overlay repositioning
                    if (finalViewToKeep != null) {
                        finalViewToKeep.setVisibility(finalVisibility);
@@ -276,7 +248,7 @@ public class Fade extends Visibility {
            // VISIBLE for the duration of the transition
            viewToKeep.setVisibility((View.VISIBLE));
            // TODO: add automatic facility to Visibility superclass for keeping views around
            final float startAlpha = view.getAlpha();
            final float startAlpha = 1;
            float endAlpha = 0;
            final View finalView = view;
            final View finalOverlayView = overlayView;
@@ -291,8 +263,8 @@ public class Fade extends Visibility {
                    if (finalViewToKeep != null && !mCanceled) {
                        finalViewToKeep.setVisibility(finalVisibility);
                    }
                    mPausedAlpha = finalView.getAlpha();
                    finalView.setAlpha(startAlpha);
                    mPausedAlpha = finalView.getTransitionAlpha();
                    finalView.setTransitionAlpha(startAlpha);
                }

                @Override
@@ -300,21 +272,21 @@ public class Fade extends Visibility {
                    if (finalViewToKeep != null && !mCanceled) {
                        finalViewToKeep.setVisibility(View.VISIBLE);
                    }
                    finalView.setAlpha(mPausedAlpha);
                    finalView.setTransitionAlpha(mPausedAlpha);
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                    mCanceled = true;
                    if (mPausedAlpha >= 0) {
                        finalView.setAlpha(mPausedAlpha);
                        finalView.setTransitionAlpha(mPausedAlpha);
                    }
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    if (!mCanceled) {
                        finalView.setAlpha(startAlpha);
                        finalView.setTransitionAlpha(startAlpha);
                    }
                    // TODO: restore view offset from overlay repositioning
                    if (finalViewToKeep != null && !mCanceled) {
+1 −1
Original line number Diff line number Diff line
@@ -353,7 +353,7 @@ public abstract class Transition implements Cloneable {
                if (endValues.viewValues.get(view) != null) {
                    end = endValues.viewValues.get(view);
                    endCopy.remove(view);
                } else {
                } else if (id != View.NO_ID) {
                    end = endValues.idValues.get(id);
                    View removeView = null;
                    for (View viewToRemove : endCopy.keySet()) {
+1 −1
Original line number Diff line number Diff line
@@ -354,7 +354,7 @@ public class TransitionSet extends Transition {
        clone.mTransitions = new ArrayList<Transition>();
        int numTransitions = mTransitions.size();
        for (int i = 0; i < numTransitions; ++i) {
            clone.mTransitions.add((Transition) mTransitions.get(i).clone());
            clone.addTransition((Transition) mTransitions.get(i).clone());
        }
        return clone;
    }
+61 −8
Original line number Diff line number Diff line
@@ -2894,6 +2894,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         */
        @ViewDebug.ExportedProperty
        float mAlpha = 1f;
        /**
         * The opacity of the view as manipulated by the Fade transition. This is a hidden
         * property only used by transitions, which is composited with the other alpha
         * values to calculate the final visual alpha value.
         */
        float mTransitionAlpha = 1f;
    }
    TransformationInfo mTransformationInfo;
@@ -5335,7 +5342,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                View view = (View) current;
                // We have attach info so this view is attached and there is no
                // need to check whether we reach to ViewRootImpl on the way up.
                if (view.getAlpha() <= 0 || view.getVisibility() != VISIBLE) {
                if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 ||
                        view.getVisibility() != VISIBLE) {
                    return false;
                }
                current = view.mParent;
@@ -9786,7 +9794,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                mPrivateFlags &= ~PFLAG_ALPHA_SET;
                invalidateViewProperty(true, false);
                if (mDisplayList != null) {
                    mDisplayList.setAlpha(alpha);
                    mDisplayList.setAlpha(getFinalAlpha());
                }
            }
        }
@@ -9813,13 +9821,58 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            } else {
                mPrivateFlags &= ~PFLAG_ALPHA_SET;
                if (mDisplayList != null) {
                    mDisplayList.setAlpha(alpha);
                    mDisplayList.setAlpha(getFinalAlpha());
                }
            }
        }
        return false;
    }
    /**
     * This property is hidden and intended only for use by the Fade transition, which
     * animates it to produce a visual translucency that does not side-effect (or get
     * affected by) the real alpha property. This value is composited with the other
     * alpha value (and the AlphaAnimation value, when that is present) to produce
     * a final visual translucency result, which is what is passed into the DisplayList.
     *
     * @hide
     */
    public void setTransitionAlpha(float alpha) {
        ensureTransformationInfo();
        if (mTransformationInfo.mTransitionAlpha != alpha) {
            mTransformationInfo.mTransitionAlpha = alpha;
            mPrivateFlags &= ~PFLAG_ALPHA_SET;
            invalidateViewProperty(true, false);
            if (mDisplayList != null) {
                mDisplayList.setAlpha(getFinalAlpha());
            }
        }
    }
    /**
     * Calculates the visual alpha of this view, which is a combination of the actual
     * alpha value and the transitionAlpha value (if set).
     */
    private float getFinalAlpha() {
        if (mTransformationInfo != null) {
            return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha;
        }
        return 1;
    }
    /**
     * This property is hidden and intended only for use by the Fade transition, which
     * animates it to produce a visual translucency that does not side-effect (or get
     * affected by) the real alpha property. This value is composited with the other
     * alpha value (and the AlphaAnimation value, when that is present) to produce
     * a final visual translucency result, which is what is passed into the DisplayList.
     *
     * @hide
     */
    public float getTransitionAlpha() {
        return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1;
    }
    /**
     * Top position of this view relative to its parent.
     *
@@ -10913,7 +10966,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    @ViewDebug.ExportedProperty(category = "drawing")
    public boolean isOpaque() {
        return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK &&
                ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1.0f) >= 1.0f);
                getFinalAlpha() >= 1.0f;
    }
    /**
@@ -13868,7 +13921,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                }
            }
            if (mTransformationInfo != null) {
                alpha *= mTransformationInfo.mAlpha;
                alpha *= getFinalAlpha();
                if (alpha < 1) {
                    final int multipliedAlpha = (int) (255 * alpha);
                    if (onSetAlpha(multipliedAlpha)) {
@@ -14057,7 +14110,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            }
        }
        float alpha = useDisplayListProperties ? 1 : getAlpha();
        float alpha = useDisplayListProperties ? 1 : (getAlpha() * getTransitionAlpha());
        if (transformToApply != null || alpha < 1 ||  !hasIdentityMatrix() ||
                (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
            if (transformToApply != null || !childHasIdentityMatrix) {
@@ -14115,7 +14168,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                            layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
                        }
                        if (useDisplayListProperties) {
                            displayList.setAlpha(alpha * getAlpha());
                            displayList.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                        } else  if (layerType == LAYER_TYPE_NONE) {
                            final int scrollX = hasDisplayList ? 0 : sx;
                            final int scrollY = hasDisplayList ? 0 : sy;