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

Commit 254bbae7 authored by Daniel Lehmann's avatar Daniel Lehmann Committed by Android (Google) Code Review
Browse files

Merge "Fix some QC issues" into jb-dev

parents 888ed02d 2426cb01
Loading
Loading
Loading
Loading
+67 −34
Original line number Diff line number Diff line
@@ -23,15 +23,13 @@ import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.PopupWindow;
@@ -53,11 +51,30 @@ public class FloatingChildLayout extends FrameLayout {
    private static final String TAG = "FloatingChildLayout";
    private int mFixedTopPosition;
    private View mChild;
    private boolean mIsShowingChild;
    private Rect mTargetScreen = new Rect();
    private final int mAnimationDuration;
    private final TransitionDrawable mBackground;

    /** The phase of the background dim. This is one of the values of {@link BackgroundPhase}  */
    private int mBackgroundPhase = BackgroundPhase.BEFORE;

    private interface BackgroundPhase {
        public static final int BEFORE = 0;
        public static final int APPEARING_OR_VISIBLE = 1;
        public static final int DISAPPEARING_OR_GONE = 3;
    }

    /** The phase of the contents window. This is one of the values of {@link ForegroundPhase}  */
    private int mForegroundPhase = ForegroundPhase.BEFORE;

    private interface ForegroundPhase {
        public static final int BEFORE = 0;
        public static final int APPEARING = 1;
        public static final int IDLE = 2;
        public static final int DISAPPEARING = 3;
        public static final int AFTER = 4;
    }

    // Black, 50% alpha as per the system default.
    private static final int DIM_BACKGROUND_COLOR = 0x7F000000;

@@ -83,8 +100,6 @@ public class FloatingChildLayout extends FrameLayout {
        mChild.setScaleX(0.5f);
        mChild.setScaleY(0.5f);
        mChild.setAlpha(0.0f);

        mIsShowingChild = false;
    }

    public View getChild() {
@@ -163,43 +178,51 @@ public class FloatingChildLayout extends FrameLayout {
        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
    }

    /** Begin animating {@link #getChild()} visible. */
    public void showChild(final Runnable onAnimationEndRunnable) {
        if (mIsShowingChild) return;
        mIsShowingChild = true;

        // TODO: understand this.
        // For some reason this needs wait a tick in order to avoid jank.
        // Maybe because we set up a hardware layer in animateScale()?
        // Probably not, since it should also be required in hideChild().
        new Handler().post(new Runnable() {
            @Override public void run() {
                animateBackground(false);
    public void fadeInBackground() {
        if (mBackgroundPhase == BackgroundPhase.BEFORE) {
            mBackgroundPhase = BackgroundPhase.APPEARING_OR_VISIBLE;
            mBackground.startTransition(mAnimationDuration);
        }
    }
        });

        animateScale(false, onAnimationEndRunnable);
    public void fadeOutBackground() {
        if (mBackgroundPhase == BackgroundPhase.APPEARING_OR_VISIBLE) {
            mBackgroundPhase = BackgroundPhase.DISAPPEARING_OR_GONE;
            mBackground.reverseTransition(mAnimationDuration);
        }
    }

    /** Begin animating {@link #getChild()} invisible. */
    public void hideChild(final Runnable onAnimationEndRunnable) {
        if (!mIsShowingChild) return;
        mIsShowingChild = false;
    public boolean isContentFullyVisible() {
        return mForegroundPhase == ForegroundPhase.IDLE;
    }

        animateBackground(true);
        animateScale(true, onAnimationEndRunnable);
    /** Begin animating {@link #getChild()} visible. */
    public void showContent(final Runnable onAnimationEndRunnable) {
        if (mForegroundPhase == ForegroundPhase.BEFORE) {
            mForegroundPhase = ForegroundPhase.APPEARING;
            animateScale(false, onAnimationEndRunnable);
        }
    }

    private void animateBackground(boolean isExitAnimation) {
        if (isExitAnimation) {
            mBackground.reverseTransition(mAnimationDuration);
    /**
     * Begin animating {@link #getChild()} invisible. Returns false if animation is not valid in
     * this state
     */
    public boolean hideContent(final Runnable onAnimationEndRunnable) {
        if (mForegroundPhase == ForegroundPhase.APPEARING ||
                mForegroundPhase == ForegroundPhase.IDLE) {
            mForegroundPhase = ForegroundPhase.DISAPPEARING;
            animateScale(true, onAnimationEndRunnable);
            return true;
        } else {
            mBackground.startTransition(mAnimationDuration);
            return false;
        }
    }

    /** Creates the open/close animation */
    private void animateScale(boolean isExitAnimation, final Runnable onAnimationEndRunnable) {
    private void animateScale(
            final boolean isExitAnimation,
            final Runnable onAnimationEndRunnable) {
        mChild.setPivotX(mTargetScreen.centerX() - mChild.getLeft());
        mChild.setPivotY(mTargetScreen.centerY() - mChild.getTop());

@@ -208,7 +231,7 @@ public class FloatingChildLayout extends FrameLayout {
                : android.R.interpolator.decelerate_quint;
        final float scaleTarget = isExitAnimation ? 0.5f : 1.0f;

        ViewPropertyAnimator animator = mChild.animate().withLayer()
        mChild.animate().withLayer()
                .setDuration(mAnimationDuration)
                .setInterpolator(AnimationUtils.loadInterpolator(getContext(), scaleInterpolator))
                .scaleX(scaleTarget)
@@ -217,8 +240,18 @@ public class FloatingChildLayout extends FrameLayout {
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        if (isExitAnimation) {
                            if (mForegroundPhase == ForegroundPhase.DISAPPEARING) {
                                mForegroundPhase = ForegroundPhase.AFTER;
                                if (onAnimationEndRunnable != null) onAnimationEndRunnable.run();
                            }
                        } else {
                            if (mForegroundPhase == ForegroundPhase.APPEARING) {
                                mForegroundPhase = ForegroundPhase.IDLE;
                                if (onAnimationEndRunnable != null) onAnimationEndRunnable.run();
                            }
                        }
                    }
                });
    }

+25 −33
Original line number Diff line number Diff line
@@ -98,9 +98,6 @@ public class QuickContactActivity extends Activity {
    private String[] mExcludeMimes;
    private List<String> mSortedActionMimeTypes = Lists.newArrayList();

    private boolean mHasFinishedAnimatingIn = false;
    private boolean mHasStartedAnimatingOut = false;

    private FloatingChildLayout mFloatingLayout;

    private View mPhotoContainer;
@@ -154,6 +151,8 @@ public class QuickContactActivity extends Activity {
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        if (TRACE_LAUNCH) android.os.Debug.startMethodTracing(TRACE_TAG);

        // Show QuickContact in front of soft input
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
@@ -172,7 +171,8 @@ public class QuickContactActivity extends Activity {
        mFloatingLayout.setOnOutsideTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return handleOutsideTouch();
                handleOutsideTouch();
                return true;
            }
        });

@@ -183,7 +183,7 @@ public class QuickContactActivity extends Activity {
                mContactLoader.cacheResult();
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                startActivity(intent);
                hide(false);
                close(false);
            }
        };
        mOpenDetailsButton.setOnClickListener(openDetailsClickHandler);
@@ -191,15 +191,6 @@ public class QuickContactActivity extends Activity {
        mListPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
        mListPager.setOnPageChangeListener(new PageChangeListener());

        show();
    }

    private void show() {

        if (TRACE_LAUNCH) {
            android.os.Debug.startMethodTracing(TRACE_TAG);
        }

        final Intent intent = getIntent();

        Uri lookupUri = intent.getData();
@@ -226,23 +217,23 @@ public class QuickContactActivity extends Activity {

        mContactLoader = (ContactLoader) getLoaderManager().initLoader(
                LOADER_ID, null, mLoaderCallbacks);
    }

    private boolean handleOutsideTouch() {
        if (!mHasFinishedAnimatingIn) return false;
        if (mHasStartedAnimatingOut) return false;
        mFloatingLayout.fadeInBackground();
    }

        mHasStartedAnimatingOut = true;
        hide(true);
        return true;
    private void handleOutsideTouch() {
        if (mFloatingLayout.isContentFullyVisible()) {
            close(true);
        }
    }

    private void hide(boolean withAnimation) {
    private void close(boolean withAnimation) {
        // cancel any pending queries
        getLoaderManager().destroyLoader(LOADER_ID);

        if (withAnimation) {
            mFloatingLayout.hideChild(new Runnable() {
            mFloatingLayout.fadeOutBackground();
            final boolean animated = mFloatingLayout.hideContent(new Runnable() {
                @Override
                public void run() {
                    // Wait until the final animation frame has been drawn, otherwise
@@ -266,15 +257,19 @@ public class QuickContactActivity extends Activity {
                    });
                }
            });
            if (!animated) {
                // If we were in the wrong state, simply quit (this can happen for example
                // if the user pushes BACK before anything has loaded)
                finish();
            }
        } else {
            mFloatingLayout.hideChild(null);
            finish();
        }
    }

    @Override
    public void onBackPressed() {
        hide(true);
        close(true);
    }

    /** Assign this string to the view if it is not empty. */
@@ -480,7 +475,7 @@ public class QuickContactActivity extends Activity {
        @Override
        public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
            if (isFinishing()) {
                hide(false);
                close(false);
                return;
            }
            if (data.isError()) {
@@ -492,25 +487,22 @@ public class QuickContactActivity extends Activity {
                Log.i(TAG, "No contact found: " + ((ContactLoader)loader).getLookupUri());
                Toast.makeText(QuickContactActivity.this, R.string.invalidContactMessage,
                        Toast.LENGTH_LONG).show();
                hide(false);
                close(false);
                return;
            }

            bindData(data);

            if (TRACE_LAUNCH) {
                android.os.Debug.stopMethodTracing();
            }
            if (TRACE_LAUNCH) android.os.Debug.stopMethodTracing();

            // Data bound and ready, pull curtain to show. Put this on the Handler to ensure
            // that the layout passes are completed
            SchedulingUtils.doAfterLayout(mFloatingLayout, new Runnable() {
                @Override
                public void run() {
                    mFloatingLayout.showChild(new Runnable() {
                    mFloatingLayout.showContent(new Runnable() {
                        @Override
                        public void run() {
                            mHasFinishedAnimatingIn = true;
                            mContactLoader.upgradeToFullContact();
                        }
                    });
@@ -599,7 +591,7 @@ public class QuickContactActivity extends Activity {
                                Toast.LENGTH_SHORT).show();
                    }

                    hide(false);
                    close(false);
                }
            };
            // Defer the action to make the window properly repaint