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

Commit 8081f094 authored by Selim Cinek's avatar Selim Cinek
Browse files

Fixed an issue where GONE Views would show during transitions

Because we're clipping children and MotionLayout doesn't hide them
when collapsed, views could flicker onto the screen

Test: add media notification, swipe down to shade and back, observe no flickering
Bug: 154137987
Change-Id: Ida591706e779215e13c6d3047be7e3b5318b4d19
parent b28ec0a3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -356,6 +356,7 @@
            android:id="@+id/media_progress_bar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:alpha="0.0"
            app:layout_constraintTop_toBottomOf="@id/album_art"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
@@ -364,6 +365,7 @@

        <Constraint
            android:id="@+id/notification_media_progress_time"
            android:alpha="0.0"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="35dp"
+52 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */
package com.android.systemui.media

import android.graphics.Rect
import android.view.View
import android.view.ViewGroup

private val EMPTY_RECT = Rect(0,0,0,0)

private val LAYOUT_CHANGE_LISTENER = object : View.OnLayoutChangeListener {

    override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int,
                                oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
        v?.let {
            if (v.visibility == View.GONE) {
                v.clipBounds = EMPTY_RECT
            } else {
                v.clipBounds = null
            }
        }
    }
}
/**
 * A helper class that clips all GONE children. Useful for transitions in motionlayout which
 * don't clip its children.
 */
class GoneChildrenHideHelper private constructor() {
    companion object {
        @JvmStatic
        fun clipGoneChildrenOnLayout(layout: ViewGroup) {
            val childCount = layout.childCount
            for (i in 0 until childCount) {
                val child = layout.getChildAt(i)
                child.addOnLayoutChangeListener(LAYOUT_CHANGE_LISTENER)
            }
        }
    }
}
 No newline at end of file
+19 −13
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.service.media.MediaBrowserService;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -181,6 +180,7 @@ public class MediaControlPanel {
        mMediaNotifView = (MotionLayout) inflater.inflate(R.layout.qs_media_panel, parent, false);
        mBackground = mMediaNotifView.findViewById(R.id.media_background);
        mLayoutAnimationHelper = new LayoutAnimationHelper(mMediaNotifView);
        GoneChildrenHideHelper.clipGoneChildrenOnLayout(mMediaNotifView);
        mKeyFrames = mMediaNotifView.getDefinedTransitions().get(0).getKeyFrameList();
        mLocalMediaManager = routeManager;
        mForegroundExecutor = foregroundExecutor;
@@ -255,6 +255,9 @@ public class MediaControlPanel {

        mController = new MediaController(mContext, mToken);

        ConstraintSet expandedSet = mMediaNotifView.getConstraintSet(R.id.expanded);
        ConstraintSet collapsedSet = mMediaNotifView.getConstraintSet(R.id.collapsed);

        // Try to find a browser service component for this app
        // TODO also check for a media button receiver intended for restarting (b/154127084)
        // Only check if we haven't tried yet or the session token changed
@@ -323,6 +326,8 @@ public class MediaControlPanel {
        if (mSeamless != null) {
            if (mLocalMediaManager != null) {
                mSeamless.setVisibility(View.VISIBLE);
                setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
                setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
                updateDevice(mLocalMediaManager.getCurrentConnectedDevice());
                mSeamless.setOnClickListener(v -> {
                    final Intent intent = new Intent()
@@ -344,9 +349,6 @@ public class MediaControlPanel {
            Log.d(TAG, "PlaybackInfo was null. Defaulting to local playback.");
            mIsRemotePlayback = false;
        }

        ConstraintSet expandedSet = mMediaNotifView.getConstraintSet(R.id.expanded);
        ConstraintSet collapsedSet = mMediaNotifView.getConstraintSet(R.id.collapsed);
        List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
        // Media controls
        int i = 0;
@@ -376,15 +378,14 @@ public class MediaControlPanel {
            });
            boolean visibleInCompat = actionsWhenCollapsed.contains(i);
            updateKeyFrameVisibility(actionId, visibleInCompat);
            collapsedSet.setVisibility(actionId,
                    visibleInCompat ? ConstraintSet.VISIBLE : ConstraintSet.GONE);
            expandedSet.setVisibility(actionId, ConstraintSet.VISIBLE);
            setVisibleAndAlpha(collapsedSet, actionId, visibleInCompat);
            setVisibleAndAlpha(expandedSet, actionId, true /*visible */);
        }

        // Hide any unused buttons
        for (; i < ACTION_IDS.length; i++) {
            expandedSet.setVisibility(ACTION_IDS[i], ConstraintSet.GONE);
            collapsedSet.setVisibility(ACTION_IDS[i], ConstraintSet.GONE);
            setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */);
            setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
        }

        // Seek Bar
@@ -604,8 +605,8 @@ public class MediaControlPanel {
        ConstraintSet expandedSet = mMediaNotifView.getConstraintSet(R.id.expanded);
        ConstraintSet collapsedSet = mMediaNotifView.getConstraintSet(R.id.collapsed);
        for (int i = 1; i < ACTION_IDS.length; i++) {
            expandedSet.setVisibility(ACTION_IDS[i], ConstraintSet.GONE);
            collapsedSet.setVisibility(ACTION_IDS[i], ConstraintSet.GONE);
            setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */);
            setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
        }

        // Add a restart button
@@ -631,8 +632,8 @@ public class MediaControlPanel {
        });
        btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
        btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
        expandedSet.setVisibility(ACTION_IDS[0], ConstraintSet.VISIBLE);
        collapsedSet.setVisibility(ACTION_IDS[0], ConstraintSet.VISIBLE);
        setVisibleAndAlpha(expandedSet, ACTION_IDS[0], true /*visible */);
        setVisibleAndAlpha(collapsedSet, ACTION_IDS[0], true /*visible */);

        mSeekBarViewModel.clearController();
        // TODO: fix guts
@@ -647,6 +648,11 @@ public class MediaControlPanel {
        });
    }

    private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
        set.setVisibility(actionId, visible? ConstraintSet.VISIBLE : ConstraintSet.GONE);
        set.setAlpha(actionId, visible ? 1.0f : 0.0f);
    }

    private void makeActive() {
        Assert.isMainThread();
        if (!mIsRegistered) {