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

Commit edbea0fc authored by Nick Chameyev's avatar Nick Chameyev
Browse files

Add statusbar unfold animation

Adds move from center animation to statusbar elements
such as battery icon, notification icons, etc.
when unfolding the device

Bug: 193794564
Test: manual
Change-Id: Ibd4548ee4c33ed3f2dfe7909916f6f64026bb71f
parent 73ad0800
Loading
Loading
Loading
Loading
+56 −30
Original line number Diff line number Diff line
@@ -36,6 +36,13 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(
     * [View.setTranslationY]
     */
    private val translationApplier: TranslationApplier = object : TranslationApplier {},
    /**
     * Allows to set custom implementation for getting
     * view location. Could be useful if logical view bounds
     * are different than actual bounds (e.g. view container may
     * have larger width than width of the items in the container)
     */
    private val viewCenterProvider: ViewCenterProvider = object : ViewCenterProvider {}
) : UnfoldTransitionProgressProvider.TransitionProgressListener {

    private val screenSize = Point()
@@ -43,6 +50,8 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(

    private val animatedViews: MutableList<AnimatedView> = arrayListOf()

    private var lastAnimationProgress: Float = 0f

    /**
     * Updates display properties in order to calculate the initial position for the views
     * Must be called before [registerViewForAnimation]
@@ -57,6 +66,19 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(
            windowManager.defaultDisplay.rotation == Surface.ROTATION_180
    }

    /**
     * If target view positions have changed (e.g. because of layout changes) call this method
     * to re-query view positions and update the translations
     */
    fun updateViewPositions() {
        animatedViews.forEach { animatedView ->
            animatedView.view.get()?.let {
                animatedView.updateAnimatedView(it)
            }
        }
        onTransitionProgress(lastAnimationProgress)
    }

    /**
     * Registers a view to be animated, the view should be measured and layouted
     * After finishing the animation it is necessary to clear
@@ -85,45 +107,30 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(
                )
            }
        }
        lastAnimationProgress = progress
    }

    private fun createAnimatedView(view: View): AnimatedView {
        val viewCenter = getViewCenter(view)
    private fun createAnimatedView(view: View): AnimatedView =
        AnimatedView(view = WeakReference(view)).updateAnimatedView(view)

    private fun AnimatedView.updateAnimatedView(view: View): AnimatedView {
        val viewCenter = Point()
        viewCenterProvider.getViewCenter(view, viewCenter)

        val viewCenterX = viewCenter.x
        val viewCenterY = viewCenter.y

        val translationX: Float
        val translationY: Float

        if (isVerticalFold) {
            val distanceFromScreenCenterToViewCenter = screenSize.x / 2 - viewCenterX
            translationX = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
            translationY = 0f
            startTranslationX = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
            startTranslationY = 0f
        } else {
            val distanceFromScreenCenterToViewCenter = screenSize.y / 2 - viewCenterY
            translationX = 0f
            translationY = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
            startTranslationX = 0f
            startTranslationY = distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE
        }

        return AnimatedView(
            view = WeakReference(view),
            startTranslationX = translationX,
            startTranslationY = translationY
        )
    }

    private fun getViewCenter(view: View): Point {
        val viewLocation = IntArray(2)
        view.getLocationOnScreen(viewLocation)

        val viewX = viewLocation[0]
        val viewY = viewLocation[1]

        val outPoint = Point()
        outPoint.x = viewX + view.width / 2
        outPoint.y = viewY + view.height / 2

        return outPoint
        return this
    }

    /**
@@ -139,10 +146,29 @@ class UnfoldMoveFromCenterAnimator @JvmOverloads constructor(
        }
    }

    /**
     * Interface that allows to use custom logic to get the center of the view
     */
    interface ViewCenterProvider {
        /**
         * Called when we need to get the center of the view
         */
        fun getViewCenter(view: View, outPoint: Point) {
            val viewLocation = IntArray(2)
            view.getLocationOnScreen(viewLocation)

            val viewX = viewLocation[0]
            val viewY = viewLocation[1]

            outPoint.x = viewX + view.width / 2
            outPoint.y = viewY + view.height / 2
        }
    }

    private class AnimatedView(
        val view: WeakReference<View>,
        val startTranslationX: Float,
        val startTranslationY: Float
        var startTranslationX: Float = 0f,
        var startTranslationY: Float = 0f
    )
}

+0 −39
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.statusbar.phone;

import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.util.ViewController;

/** Controller for {@link PhoneStatusBarView}. */
public class PhoneStatusBarViewController extends ViewController<PhoneStatusBarView> {

    protected PhoneStatusBarViewController(
            PhoneStatusBarView view,
            CommandQueue commandQueue) {
        super(view);
        mView.setPanelEnabledProvider(commandQueue::panelsEnabled);
    }

    @Override
    protected void onViewAttached() {
    }

    @Override
    protected void onViewDetached() {
    }
}
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.statusbar.phone

import android.graphics.Point
import android.view.View
import android.view.ViewGroup
import com.android.systemui.R
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.ViewController

/** Controller for [PhoneStatusBarView].  */
class PhoneStatusBarViewController(
    view: PhoneStatusBarView,
    commandQueue: CommandQueue,
    statusBarMoveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?
) : ViewController<PhoneStatusBarView>(view) {

    override fun onViewAttached() {}
    override fun onViewDetached() {}

    init {
        mView.setPanelEnabledProvider {
            commandQueue.panelsEnabled()
        }

        statusBarMoveFromCenterAnimationController?.let { animationController ->
            val statusBarLeftSide: View = mView.findViewById(R.id.status_bar_left_side)
            val systemIconArea: ViewGroup = mView.findViewById(R.id.system_icon_area)

            val viewCenterProvider = StatusBarViewsCenterProvider()
            val viewsToAnimate = arrayOf(
                statusBarLeftSide,
                systemIconArea
            )

            animationController.init(viewsToAnimate, viewCenterProvider)

            mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
                val widthChanged = right - left != oldRight - oldLeft
                if (widthChanged) {
                    statusBarMoveFromCenterAnimationController.onStatusBarWidthChanged()
                }
            }
        }
    }

    private class StatusBarViewsCenterProvider : UnfoldMoveFromCenterAnimator.ViewCenterProvider {
        override fun getViewCenter(view: View, outPoint: Point) =
            when (view.id) {
                R.id.status_bar_left_side -> {
                    // items aligned to the start, return start center point
                    getViewEdgeCenter(view, outPoint, isStart = true)
                }
                R.id.system_icon_area -> {
                    // items aligned to the end, return end center point
                    getViewEdgeCenter(view, outPoint, isStart = false)
                }
                else -> super.getViewCenter(view, outPoint)
            }

        /**
         * Returns start or end (based on [isStart]) center point of the view
         */
        private fun getViewEdgeCenter(view: View, outPoint: Point, isStart: Boolean) {
            val isRtl = view.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
            val isLeftEdge = isRtl xor isStart

            val viewLocation = IntArray(2)
            view.getLocationOnScreen(viewLocation)

            val viewX = viewLocation[0]
            val viewY = viewLocation[1]

            outPoint.x = viewX + if (isLeftEdge) view.height / 2 else view.width - view.height / 2
            outPoint.y = viewY + view.height / 2
        }
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -536,6 +536,7 @@ public class StatusBar extends SystemUI implements
    private final FeatureFlags mFeatureFlags;
    private final UnfoldTransitionConfig mUnfoldTransitionConfig;
    private final Lazy<UnfoldLightRevealOverlayAnimation> mUnfoldLightRevealOverlayAnimation;
    private final Lazy<StatusBarMoveFromCenterAnimationController> mMoveFromCenterAnimation;
    private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
    private final MessageRouter mMessageRouter;
    private final WallpaperManager mWallpaperManager;
@@ -768,6 +769,7 @@ public class StatusBar extends SystemUI implements
            BrightnessSlider.Factory brightnessSliderFactory,
            UnfoldTransitionConfig unfoldTransitionConfig,
            Lazy<UnfoldLightRevealOverlayAnimation> unfoldLightRevealOverlayAnimation,
            Lazy<StatusBarMoveFromCenterAnimationController> statusBarUnfoldAnimationController,
            OngoingCallController ongoingCallController,
            SystemStatusAnimationScheduler animationScheduler,
            StatusBarLocationPublisher locationPublisher,
@@ -860,6 +862,7 @@ public class StatusBar extends SystemUI implements
        mBrightnessSliderFactory = brightnessSliderFactory;
        mUnfoldTransitionConfig = unfoldTransitionConfig;
        mUnfoldLightRevealOverlayAnimation = unfoldLightRevealOverlayAnimation;
        mMoveFromCenterAnimation = statusBarUnfoldAnimationController;
        mOngoingCallController = ongoingCallController;
        mAnimationScheduler = animationScheduler;
        mStatusBarLocationPublisher = locationPublisher;
@@ -1141,8 +1144,13 @@ public class StatusBar extends SystemUI implements
                        sendInitialExpansionAmount(listener);
                    }

                    StatusBarMoveFromCenterAnimationController moveFromCenterAnimation = null;
                    if (mUnfoldTransitionConfig.isEnabled()) {
                        moveFromCenterAnimation = mMoveFromCenterAnimation.get();
                    }
                    mPhoneStatusBarViewController =
                            new PhoneStatusBarViewController(mStatusBarView, mCommandQueue);
                            new PhoneStatusBarViewController(mStatusBarView, mCommandQueue,
                                    moveFromCenterAnimation);
                    mPhoneStatusBarViewController.init();

                    mBatteryMeterViewController = new BatteryMeterViewController(
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.statusbar.phone

import android.view.View
import android.view.WindowManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.ViewCenterProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import javax.inject.Inject

@SysUISingleton
class StatusBarMoveFromCenterAnimationController @Inject constructor(
    private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
    private val windowManager: WindowManager
) {

    private lateinit var moveFromCenterAnimator: UnfoldMoveFromCenterAnimator

    fun init(viewsToAnimate: Array<View>, viewCenterProvider: ViewCenterProvider) {
        moveFromCenterAnimator = UnfoldMoveFromCenterAnimator(windowManager,
            viewCenterProvider = viewCenterProvider)

        unfoldTransitionProgressProvider.addCallback(object : TransitionProgressListener {
            override fun onTransitionStarted() {
                moveFromCenterAnimator.updateDisplayProperties()

                viewsToAnimate.forEach {
                    moveFromCenterAnimator.registerViewForAnimation(it)
                }
            }

            override fun onTransitionFinished() {
                moveFromCenterAnimator.onTransitionFinished()
                moveFromCenterAnimator.clearRegisteredViews()
            }

            override fun onTransitionProgress(progress: Float) {
                moveFromCenterAnimator.onTransitionProgress(progress)
            }
        })
    }

    fun onStatusBarWidthChanged() {
        moveFromCenterAnimator.updateViewPositions()
    }
}
Loading