1 /*
2  * Copyright (C) 2015 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.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ValueAnimator;
22 import android.animation.ValueAnimator.AnimatorUpdateListener;
23 import android.graphics.drawable.ColorDrawable;
24 import android.os.Bundle;
25 import androidx.annotation.ColorInt;
26 import androidx.appcompat.app.AppCompatActivity;
27 import android.view.View;
28 
29 import static com.android.deskclock.AnimatorUtils.ARGB_EVALUATOR;
30 
31 /**
32  * Base activity class that changes the app window's color based on the current hour.
33  */
34 public abstract class BaseActivity extends AppCompatActivity {
35 
36     /** Sets the app window color on each frame of the {@link #mAppColorAnimator}. */
37     private final AppColorAnimationListener mAppColorAnimationListener
38             = new AppColorAnimationListener();
39 
40     /** The current animator that is changing the app window color or {@code null}. */
41     private ValueAnimator mAppColorAnimator;
42 
43     /** Draws the app window's color. */
44     private ColorDrawable mBackground;
45 
46     @Override
onCreate(Bundle savedInstanceState)47     protected void onCreate(Bundle savedInstanceState) {
48         super.onCreate(savedInstanceState);
49 
50         // Allow the content to layout behind the status and navigation bars.
51         getWindow().getDecorView().setSystemUiVisibility(
52                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
53                         | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
54                         | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
55 
56         final @ColorInt int color = ThemeUtils.resolveColor(this, android.R.attr.windowBackground);
57         adjustAppColor(color, false /* animate */);
58     }
59 
60     @Override
onStart()61     protected void onStart() {
62         super.onStart();
63 
64         // Ensure the app window color is up-to-date.
65         final @ColorInt int color = ThemeUtils.resolveColor(this, android.R.attr.windowBackground);
66         adjustAppColor(color, false /* animate */);
67     }
68 
69     /**
70      * Adjusts the current app window color of this activity; animates the change if desired.
71      *
72      * @param color   the ARGB value to set as the current app window color
73      * @param animate {@code true} if the change should be animated
74      */
adjustAppColor(@olorInt int color, boolean animate)75     protected void adjustAppColor(@ColorInt int color, boolean animate) {
76         // Create and install the drawable that defines the window color.
77         if (mBackground == null) {
78             mBackground = new ColorDrawable(color);
79             getWindow().setBackgroundDrawable(mBackground);
80         }
81 
82         // Cancel the current window color animation if one exists.
83         if (mAppColorAnimator != null) {
84             mAppColorAnimator.cancel();
85         }
86 
87         final @ColorInt int currentColor = mBackground.getColor();
88         if (currentColor != color) {
89             if (animate) {
90                 mAppColorAnimator = ValueAnimator.ofObject(ARGB_EVALUATOR, currentColor, color)
91                         .setDuration(3000L);
92                 mAppColorAnimator.addUpdateListener(mAppColorAnimationListener);
93                 mAppColorAnimator.addListener(mAppColorAnimationListener);
94                 mAppColorAnimator.start();
95             } else {
96                 setAppColor(color);
97             }
98         }
99     }
100 
setAppColor(@olorInt int color)101     private void setAppColor(@ColorInt int color) {
102         mBackground.setColor(color);
103     }
104 
105     /**
106      * Sets the app window color to the current color produced by the animator.
107      */
108     private final class AppColorAnimationListener extends AnimatorListenerAdapter
109             implements AnimatorUpdateListener {
110         @Override
onAnimationUpdate(ValueAnimator valueAnimator)111         public void onAnimationUpdate(ValueAnimator valueAnimator) {
112             final @ColorInt int color = (int) valueAnimator.getAnimatedValue();
113             setAppColor(color);
114         }
115 
116         @Override
onAnimationEnd(Animator animation)117         public void onAnimationEnd(Animator animation) {
118             if (mAppColorAnimator == animation) {
119                 mAppColorAnimator = null;
120             }
121         }
122     }
123 }
124