1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.deskclock
18 
19 import android.R
20 import android.animation.Animator
21 import android.animation.AnimatorListenerAdapter
22 import android.animation.ValueAnimator
23 import android.animation.ValueAnimator.AnimatorUpdateListener
24 import android.graphics.drawable.ColorDrawable
25 import android.os.Bundle
26 import android.view.View
27 import androidx.annotation.ColorInt
28 import androidx.appcompat.app.AppCompatActivity
29 
30 /**
31  * Base activity class that changes the app window's color based on the current hour.
32  */
33 abstract class BaseActivity : AppCompatActivity() {
34     /** Sets the app window color on each frame of the [.mAppColorAnimator].  */
35     private val mAppColorAnimationListener = AppColorAnimationListener()
36 
37     /** The current animator that is changing the app window color or `null`.  */
38     private var mAppColorAnimator: ValueAnimator? = null
39 
40     /** Draws the app window's color.  */
41     private var mBackground: ColorDrawable? = null
42 
onCreatenull43     override fun onCreate(savedInstanceState: Bundle?) {
44         super.onCreate(savedInstanceState)
45 
46         // Allow the content to layout behind the status and navigation bars.
47         getWindow().getDecorView().setSystemUiVisibility(
48                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
49                         or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
50                         or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
51 
52         @ColorInt val color = ThemeUtils.resolveColor(this, R.attr.windowBackground)
53         adjustAppColor(color, animate = false)
54     }
55 
onStartnull56     override fun onStart() {
57         super.onStart()
58 
59         // Ensure the app window color is up-to-date.
60         @ColorInt val color = ThemeUtils.resolveColor(this, R.attr.windowBackground)
61         adjustAppColor(color, animate = false)
62     }
63 
64     /**
65      * Adjusts the current app window color of this activity; animates the change if desired.
66      *
67      * @param color the ARGB value to set as the current app window color
68      * @param animate `true` if the change should be animated
69      */
adjustAppColornull70     protected fun adjustAppColor(@ColorInt color: Int, animate: Boolean) {
71         // Create and install the drawable that defines the window color.
72         if (mBackground == null) {
73             mBackground = ColorDrawable(color)
74             getWindow().setBackgroundDrawable(mBackground)
75         }
76 
77         // Cancel the current window color animation if one exists.
78         mAppColorAnimator?.cancel()
79 
80         @ColorInt val currentColor = mBackground!!.color
81         if (currentColor != color) {
82             if (animate) {
83                 mAppColorAnimator = ValueAnimator.ofObject(AnimatorUtils.ARGB_EVALUATOR,
84                         currentColor, color)
85                         .setDuration(3000L)
86                 mAppColorAnimator!!.addUpdateListener(mAppColorAnimationListener)
87                 mAppColorAnimator!!.addListener(mAppColorAnimationListener)
88                 mAppColorAnimator!!.start()
89             } else {
90                 setAppColor(color)
91             }
92         }
93     }
94 
setAppColornull95     private fun setAppColor(@ColorInt color: Int) {
96         mBackground!!.color = color
97     }
98 
99     /**
100      * Sets the app window color to the current color produced by the animator.
101      */
102     private inner class AppColorAnimationListener
103         : AnimatorListenerAdapter(), AnimatorUpdateListener {
onAnimationUpdatenull104         override fun onAnimationUpdate(valueAnimator: ValueAnimator) {
105             @ColorInt val color = valueAnimator.animatedValue as Int
106             setAppColor(color)
107         }
108 
onAnimationEndnull109         override fun onAnimationEnd(animation: Animator) {
110             if (mAppColorAnimator === animation) {
111                 mAppColorAnimator = null
112             }
113         }
114     }
115 }