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

Commit 7660d121 authored by Chet Haase's avatar Chet Haase
Browse files

Plug leaks in transitions

Transitions were leaking views due to TransitionsValues holding references
to views/parents. The references were fine, but the retention of the transition
objects themselves were not. There were a few different places that needed to
be plugged:
- clones were not making new copies of some fields, leading to caching references
in the original object (which was then cloned later to other clones)
- Visibility was using a persistent field to cache temporary values. This transition,
when cloned, would retain these instances, keeping references to views
- ViewTreeObserver had a bug that would leak listeners

Issue #10749071 Activity instance leak between TransitionManager and InputMethodManager

Change-Id: I1d5d457dc5e020c7b9e8392a95e3b2c488461119
parent 78d0cf79
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1451,6 +1451,8 @@ public abstract class Transition implements Cloneable {
        try {
            clone = (Transition) super.clone();
            clone.mAnimators = new ArrayList<Animator>();
            clone.mStartValues = new TransitionValuesMaps();
            clone.mEndValues = new TransitionValuesMaps();
        } catch (CloneNotSupportedException e) {}

        return clone;
+18 −11
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.util.Log;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

/**
@@ -68,8 +69,9 @@ public class TransitionManager {
    ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
    ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
            new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
    private static ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>> sRunningTransitions =
            new ThreadLocal<ArrayMap<ViewGroup, ArrayList<Transition>>>();
    private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
            sRunningTransitions =
            new ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>();
    private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();


@@ -184,20 +186,24 @@ public class TransitionManager {
    }

    private static ArrayMap<ViewGroup, ArrayList<Transition>> getRunningTransitions() {
        ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
        WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>> runningTransitions =
                sRunningTransitions.get();
        if (runningTransitions == null) {
            runningTransitions = new ArrayMap<ViewGroup, ArrayList<Transition>>();
        if (runningTransitions == null || runningTransitions.get() == null) {
            ArrayMap<ViewGroup, ArrayList<Transition>> transitions =
                    new ArrayMap<ViewGroup, ArrayList<Transition>>();
            runningTransitions = new WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>(
                    transitions);
            sRunningTransitions.set(runningTransitions);
        }
        return runningTransitions;
        return runningTransitions.get();
    }

    private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
            final Transition transition) {
        if (transition != null) {
            final ViewTreeObserver observer = sceneRoot.getViewTreeObserver();
            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            final ViewTreeObserver.OnPreDrawListener listener =
                    new ViewTreeObserver.OnPreDrawListener() {
                public boolean onPreDraw() {
                    sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
                    sPendingTransitions.remove(sceneRoot);
@@ -236,7 +242,8 @@ public class TransitionManager {
                    // values set on them again and avoid artifacts.
                    return false;
                }
            });
            };
            observer.addOnPreDrawListener(listener);
        }
    }

@@ -355,10 +362,10 @@ public class TransitionManager {
//            if (transition == null) {
//                transition = sDefaultTransition;
//            }
//            final Transition finalTransition = transition.clone();
//            sceneChangeSetup(sceneRoot, transition);
//            final Transition transitionClone = transition.clone();
//            sceneChangeSetup(sceneRoot, transitionClone);
//            Scene.setCurrentScene(sceneRoot, null);
//            sceneChangeRunTransition(sceneRoot, finalTransition);
//            sceneChangeRunTransition(sceneRoot, transitionClone);
//        }
    }
}
+1 −4
Original line number Diff line number Diff line
@@ -65,9 +65,6 @@ public abstract class Visibility extends Transition {
        ViewGroup endParent;
    }

    // Temporary structure, used in calculating state in setup() and play()
    private VisibilityInfo mTmpVisibilityInfo = new VisibilityInfo();

    @Override
    public String[] getTransitionProperties() {
        return sTransitionProperties;
@@ -161,7 +158,7 @@ public abstract class Visibility extends Transition {

    private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
            TransitionValues endValues) {
        final VisibilityInfo visInfo = mTmpVisibilityInfo;
        final VisibilityInfo visInfo = new VisibilityInfo();
        visInfo.visibilityChange = false;
        visInfo.fadeIn = false;
        if (startValues != null) {
+2 −0
Original line number Diff line number Diff line
@@ -992,6 +992,8 @@ public final class ViewTreeObserver {
                mData = mDataCopy;
            }
            mDataCopy = null;
            mAccess.mData.clear();
            mAccess.mSize = 0;
        }

        int size() {