blob: 0f9f0563b7fea7c25eceb09473bf14e0107ce15a [file] [log] [blame]
Jorim Jaggi40db0292016-06-27 17:58:03 -07001/*
2 * Copyright (C) 2016 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
17package com.android.systemui.statusbar.phone;
18
19import android.animation.ValueAnimator;
Jason Monk49fa0162017-01-11 09:21:56 -050020import android.os.Bundle;
Jorim Jaggi40db0292016-06-27 17:58:03 -070021import android.os.Handler;
22import android.os.SystemClock;
23
24import com.android.systemui.Interpolators;
25
26/**
27 * Class to control all aspects about light bar changes.
28 */
29public class LightBarTransitionsController {
30
31 public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
Jason Monk49fa0162017-01-11 09:21:56 -050032 private static final String EXTRA_DARK_INTENSITY = "dark_intensity";
Jorim Jaggi40db0292016-06-27 17:58:03 -070033
34 private final Handler mHandler;
35 private final DarkIntensityApplier mApplier;
36
37 private boolean mTransitionDeferring;
38 private long mTransitionDeferringStartTime;
39 private long mTransitionDeferringDuration;
40 private boolean mTransitionPending;
41 private boolean mTintChangePending;
42 private float mPendingDarkIntensity;
43 private ValueAnimator mTintAnimator;
44 private float mDarkIntensity;
Jason Monk49fa0162017-01-11 09:21:56 -050045 private float mNextDarkIntensity;
Jorim Jaggi40db0292016-06-27 17:58:03 -070046
47 private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
48 @Override
49 public void run() {
50 mTransitionDeferring = false;
51 }
52 };
53
54 public LightBarTransitionsController(DarkIntensityApplier applier) {
55 mApplier = applier;
56 mHandler = new Handler();
57 }
58
Jason Monk49fa0162017-01-11 09:21:56 -050059 public void saveState(Bundle outState) {
60 float intensity = mTintAnimator != null && mTintAnimator.isRunning()
61 ? mNextDarkIntensity : mDarkIntensity;
62 outState.putFloat(EXTRA_DARK_INTENSITY, intensity);
63 }
64
65 public void restoreState(Bundle savedInstanceState) {
66 setIconTintInternal(savedInstanceState.getFloat(EXTRA_DARK_INTENSITY, 0));
67 }
68
Jorim Jaggi40db0292016-06-27 17:58:03 -070069 public void appTransitionPending() {
70 mTransitionPending = true;
71 }
72
73 public void appTransitionCancelled() {
74 if (mTransitionPending && mTintChangePending) {
75 mTintChangePending = false;
76 animateIconTint(mPendingDarkIntensity, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
77 }
78 mTransitionPending = false;
79 }
80
81 public void appTransitionStarting(long startTime, long duration) {
82 if (mTransitionPending && mTintChangePending) {
83 mTintChangePending = false;
84 animateIconTint(mPendingDarkIntensity,
85 Math.max(0, startTime - SystemClock.uptimeMillis()),
86 duration);
87
88 } else if (mTransitionPending) {
89
90 // If we don't have a pending tint change yet, the change might come in the future until
91 // startTime is reached.
92 mTransitionDeferring = true;
93 mTransitionDeferringStartTime = startTime;
94 mTransitionDeferringDuration = duration;
95 mHandler.removeCallbacks(mTransitionDeferringDoneRunnable);
96 mHandler.postAtTime(mTransitionDeferringDoneRunnable, startTime);
97 }
98 mTransitionPending = false;
99 }
100
101 public void setIconsDark(boolean dark, boolean animate) {
102 if (!animate) {
103 setIconTintInternal(dark ? 1.0f : 0.0f);
104 } else if (mTransitionPending) {
105 deferIconTintChange(dark ? 1.0f : 0.0f);
106 } else if (mTransitionDeferring) {
107 animateIconTint(dark ? 1.0f : 0.0f,
108 Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()),
109 mTransitionDeferringDuration);
110 } else {
111 animateIconTint(dark ? 1.0f : 0.0f, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
112 }
113 }
114
115 public float getCurrentDarkIntensity() {
116 return mDarkIntensity;
117 }
118
119 private void deferIconTintChange(float darkIntensity) {
120 if (mTintChangePending && darkIntensity == mPendingDarkIntensity) {
121 return;
122 }
123 mTintChangePending = true;
124 mPendingDarkIntensity = darkIntensity;
125 }
126
127 private void animateIconTint(float targetDarkIntensity, long delay,
128 long duration) {
129 if (mTintAnimator != null) {
130 mTintAnimator.cancel();
131 }
132 if (mDarkIntensity == targetDarkIntensity) {
133 return;
134 }
Jason Monk49fa0162017-01-11 09:21:56 -0500135 mNextDarkIntensity = targetDarkIntensity;
Jorim Jaggi40db0292016-06-27 17:58:03 -0700136 mTintAnimator = ValueAnimator.ofFloat(mDarkIntensity, targetDarkIntensity);
137 mTintAnimator.addUpdateListener(
138 animation -> setIconTintInternal((Float) animation.getAnimatedValue()));
139 mTintAnimator.setDuration(duration);
140 mTintAnimator.setStartDelay(delay);
141 mTintAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
142 mTintAnimator.start();
143 }
144
145 private void setIconTintInternal(float darkIntensity) {
146 mDarkIntensity = darkIntensity;
147 mApplier.applyDarkIntensity(darkIntensity);
148 }
149
150 /**
151 * Interface to apply a specific dark intensity.
152 */
153 public interface DarkIntensityApplier {
154 void applyDarkIntensity(float darkIntensity);
155 }
156}