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

Commit 4754fdc2 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Controls UI - Motion for activities" into rvc-dev am: 65b3b5e9

Change-Id: I134abb285ac39368467bb63f054681dcfa426563
parents 93ca2e60 65b3b5e9
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
<LinearLayout
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/controls_management_root"
    android:orientation="vertical"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_height="match_parent"
+3 −0
Original line number Original line Diff line number Diff line
@@ -1014,6 +1014,9 @@
    <!-- Margins at the left and right of the power menu and home controls widgets. -->
    <!-- Margins at the left and right of the power menu and home controls widgets. -->
    <dimen name="global_actions_side_margin">16dp</dimen>
    <dimen name="global_actions_side_margin">16dp</dimen>


    <!-- Amount to shift the layout when exiting/entering for controls activities -->
    <dimen name="global_actions_controls_y_translation">20dp</dimen>

    <!-- The maximum offset in either direction that elements are moved horizontally to prevent
    <!-- The maximum offset in either direction that elements are moved horizontally to prevent
         burn-in on AOD. -->
         burn-in on AOD. -->
    <dimen name="burn_in_prevention_offset_x">8dp</dimen>
    <dimen name="burn_in_prevention_offset_x">8dp</dimen>
+6 −1
Original line number Original line Diff line number Diff line
@@ -663,8 +663,13 @@


    <!-- Controls styles -->
    <!-- Controls styles -->
    <style name="Theme.ControlsManagement" parent="@android:style/Theme.DeviceDefault.NoActionBar">
    <style name="Theme.ControlsManagement" parent="@android:style/Theme.DeviceDefault.NoActionBar">
        <item name="android:windowActivityTransitions">true</item>
        <item name="android:windowContentTransitions">false</item>
        <item name="android:windowIsTranslucent">false</item>
        <item name="android:windowIsTranslucent">false</item>
        <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
        <item name="android:windowBackground">@android:color/black</item>
        <item name="android:colorBackground">@android:color/black</item>
        <item name="android:windowAnimationStyle">@null</item>
        <item name="android:statusBarColor">@*android:color/transparent</item>
    </style>
    </style>


    <style name="TextAppearance.Control">
    <style name="TextAppearance.Control">
+180 −0
Original line number Original line 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.controls.management

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.annotation.IdRes
import android.content.Intent

import android.transition.Transition
import android.transition.TransitionValues
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.Window

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent

import com.android.systemui.Interpolators
import com.android.systemui.R

import com.android.systemui.controls.ui.ControlsUiController

object ControlsAnimations {

    private const val ALPHA_EXIT_DURATION = 167L
    private const val ALPHA_ENTER_DELAY = ALPHA_EXIT_DURATION
    private const val ALPHA_ENTER_DURATION = 350L - ALPHA_ENTER_DELAY

    private const val Y_TRANSLATION_EXIT_DURATION = 183L
    private const val Y_TRANSLATION_ENTER_DELAY = Y_TRANSLATION_EXIT_DURATION - ALPHA_ENTER_DELAY
    private const val Y_TRANSLATION_ENTER_DURATION = 400L - Y_TRANSLATION_EXIT_DURATION
    private var translationY: Float = -1f

    /**
     * Setup an activity to handle enter/exit animations. [view] should be the root of the content.
     * Fade and translate together.
     */
    fun observerForAnimations(view: ViewGroup, window: Window, intent: Intent): LifecycleObserver {
        return object : LifecycleObserver {
            var showAnimation = intent.getBooleanExtra(ControlsUiController.EXTRA_ANIMATE, false)

            init {
                // Must flag the parent group to move it all together, and set the initial
                // transitionAlpha to 0.0f. This property is reserved for fade animations.
                view.setTransitionGroup(true)
                view.transitionAlpha = 0.0f

                if (translationY == -1f) {
                    translationY = view.context.resources.getDimensionPixelSize(
                        R.dimen.global_actions_controls_y_translation).toFloat()
                }
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_START)
            fun setup() {
                with(window) {
                    allowEnterTransitionOverlap = true
                    enterTransition = enterWindowTransition(view.getId())
                    exitTransition = exitWindowTransition(view.getId())
                }
            }

            @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
            fun enterAnimation() {
                if (showAnimation) {
                    ControlsAnimations.enterAnimation(view).start()
                    showAnimation = false
                }
            }
        }
    }

    fun enterAnimation(view: View): Animator {
        Log.d(ControlsUiController.TAG, "Enter animation for $view")

        view.transitionAlpha = 0.0f
        view.alpha = 1.0f

        view.translationY = translationY

        val alphaAnimator = ObjectAnimator.ofFloat(view, "transitionAlpha", 0.0f, 1.0f).apply {
            interpolator = Interpolators.DECELERATE_QUINT
            startDelay = ALPHA_ENTER_DELAY
            duration = ALPHA_ENTER_DURATION
        }

        val yAnimator = ObjectAnimator.ofFloat(view, "translationY", 0.0f).apply {
            interpolator = Interpolators.DECELERATE_QUINT
            startDelay = Y_TRANSLATION_ENTER_DURATION
            duration = Y_TRANSLATION_ENTER_DURATION
        }

        return AnimatorSet().apply {
            playTogether(alphaAnimator, yAnimator)
        }
    }

    /**
     * Properly handle animations originating from dialogs. Activity transitions require
     * transitioning between two activities, so expose this method for dialogs to animate
     * on exit.
     */
    @JvmStatic
    fun exitAnimation(view: View, onEnd: Runnable? = null): Animator {
        Log.d(ControlsUiController.TAG, "Exit animation for $view")

        val alphaAnimator = ObjectAnimator.ofFloat(view, "transitionAlpha", 0.0f).apply {
            interpolator = Interpolators.ACCELERATE
            duration = ALPHA_EXIT_DURATION
        }

        view.translationY = 0.0f
        val yAnimator = ObjectAnimator.ofFloat(view, "translationY", -translationY).apply {
            interpolator = Interpolators.ACCELERATE
            duration = Y_TRANSLATION_EXIT_DURATION
        }

        return AnimatorSet().apply {
            playTogether(alphaAnimator, yAnimator)
            onEnd?.let {
                addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator) {
                        it.run()
                    }
                })
            }
        }
    }

    fun enterWindowTransition(@IdRes id: Int) =
        WindowTransition({ view: View -> enterAnimation(view) }).apply {
            addTarget(id)
        }

    fun exitWindowTransition(@IdRes id: Int) =
        WindowTransition({ view: View -> exitAnimation(view) }).apply {
            addTarget(id)
        }
}

/**
 * In order to animate, at least one property must be marked on each view that should move.
 * Setting "item" is just a flag to indicate that it should move by the animator.
 */
class WindowTransition(
    val animator: (view: View) -> Animator
) : Transition() {
    override fun captureStartValues(tv: TransitionValues) {
        tv.values["item"] = 0.0f
    }

    override fun captureEndValues(tv: TransitionValues) {
        tv.values["item"] = 1.0f
    }

    override fun createAnimator(
        sceneRoot: ViewGroup,
        startValues: TransitionValues?,
        endValues: TransitionValues?
    ): Animator? = animator(startValues!!.view)
}
+33 −10
Original line number Original line Diff line number Diff line
@@ -16,11 +16,12 @@


package com.android.systemui.controls.management
package com.android.systemui.controls.management


import android.app.Activity
import android.app.ActivityOptions
import android.content.ComponentName
import android.content.ComponentName
import android.content.Intent
import android.content.Intent
import android.os.Bundle
import android.os.Bundle
import android.view.View
import android.view.View
import android.view.ViewGroup
import android.view.ViewStub
import android.view.ViewStub
import android.widget.Button
import android.widget.Button
import android.widget.TextView
import android.widget.TextView
@@ -32,6 +33,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.util.LifecycleActivity
import javax.inject.Inject
import javax.inject.Inject


/**
/**
@@ -40,7 +42,7 @@ import javax.inject.Inject
class ControlsEditingActivity @Inject constructor(
class ControlsEditingActivity @Inject constructor(
    private val controller: ControlsControllerImpl,
    private val controller: ControlsControllerImpl,
    broadcastDispatcher: BroadcastDispatcher
    broadcastDispatcher: BroadcastDispatcher
) : Activity() {
) : LifecycleActivity() {


    companion object {
    companion object {
        private const val TAG = "ControlsEditingActivity"
        private const val TAG = "ControlsEditingActivity"
@@ -92,6 +94,15 @@ class ControlsEditingActivity @Inject constructor(


    private fun bindViews() {
    private fun bindViews() {
        setContentView(R.layout.controls_management)
        setContentView(R.layout.controls_management)

        getLifecycle().addObserver(
            ControlsAnimations.observerForAnimations(
                requireViewById<ViewGroup>(R.id.controls_management_root),
                window,
                intent
            )
        )

        requireViewById<ViewStub>(R.id.stub).apply {
        requireViewById<ViewStub>(R.id.stub).apply {
            layoutResource = R.layout.controls_management_editing
            layoutResource = R.layout.controls_management_editing
            inflate()
            inflate()
@@ -113,8 +124,8 @@ class ControlsEditingActivity @Inject constructor(
                    putExtras(this@ControlsEditingActivity.intent)
                    putExtras(this@ControlsEditingActivity.intent)
                    putExtra(ControlsFavoritingActivity.EXTRA_SINGLE_STRUCTURE, true)
                    putExtra(ControlsFavoritingActivity.EXTRA_SINGLE_STRUCTURE, true)
                }
                }
                startActivity(intent)
                startActivity(intent, ActivityOptions
                finish()
                    .makeSceneTransitionAnimation(this@ControlsEditingActivity).toBundle())
            }
            }
        }
        }


@@ -151,22 +162,34 @@ class ControlsEditingActivity @Inject constructor(
        val controls = controller.getFavoritesForStructure(component, structure)
        val controls = controller.getFavoritesForStructure(component, structure)
        model = FavoritesModel(component, controls, favoritesModelCallback)
        model = FavoritesModel(component, controls, favoritesModelCallback)
        val elevation = resources.getFloat(R.dimen.control_card_elevation)
        val elevation = resources.getFloat(R.dimen.control_card_elevation)
        val adapter = ControlAdapter(elevation)
        val recyclerView = requireViewById<RecyclerView>(R.id.list)
        val recycler = requireViewById<RecyclerView>(R.id.list)
        recyclerView.alpha = 0.0f
        val adapter = ControlAdapter(elevation).apply {
            registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
                var hasAnimated = false
                override fun onChanged() {
                    if (!hasAnimated) {
                        hasAnimated = true
                        ControlsAnimations.enterAnimation(recyclerView).start()
                    }
                }
            })
        }

        val margin = resources
        val margin = resources
                .getDimensionPixelSize(R.dimen.controls_card_margin)
                .getDimensionPixelSize(R.dimen.controls_card_margin)
        val itemDecorator = MarginItemDecorator(margin, margin)
        val itemDecorator = MarginItemDecorator(margin, margin)


        recycler.apply {
        recyclerView.apply {
            this.adapter = adapter
            this.adapter = adapter
            layoutManager = GridLayoutManager(recycler.context, 2).apply {
            layoutManager = GridLayoutManager(recyclerView.context, 2).apply {
                spanSizeLookup = adapter.spanSizeLookup
                spanSizeLookup = adapter.spanSizeLookup
            }
            }
            addItemDecoration(itemDecorator)
            addItemDecoration(itemDecorator)
        }
        }
        adapter.changeModel(model)
        adapter.changeModel(model)
        model.attachAdapter(adapter)
        model.attachAdapter(adapter)
        ItemTouchHelper(model.itemTouchHelperCallback).attachToRecyclerView(recycler)
        ItemTouchHelper(model.itemTouchHelperCallback).attachToRecyclerView(recyclerView)
    }
    }


    override fun onDestroy() {
    override fun onDestroy() {
Loading