blob: 092dd49ba617923ef91b0a8e1ae36620576488a1 [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 Monkaa573e92017-01-27 17:00:29 -050020import android.content.Context;
Jason Monk49fa0162017-01-11 09:21:56 -050021import android.os.Bundle;
Jorim Jaggi40db0292016-06-27 17:58:03 -070022import android.os.Handler;
23import android.os.SystemClock;
Charles Chenf3d295c2018-11-30 18:15:21 +080024import android.util.MathUtils;
Adrian Roos1bf60772017-02-03 15:47:43 -080025import android.util.TimeUtils;
Jorim Jaggi40db0292016-06-27 17:58:03 -070026
Jason Monkaa573e92017-01-27 17:00:29 -050027import com.android.systemui.Dependency;
Jorim Jaggiff46d4c2017-07-17 16:46:00 +020028import com.android.systemui.Dumpable;
Jorim Jaggi40db0292016-06-27 17:58:03 -070029import com.android.systemui.Interpolators;
Beverly8fdb5332019-02-04 14:29:49 -050030import com.android.systemui.plugins.statusbar.StatusBarStateController;
Jason Monkaa573e92017-01-27 17:00:29 -050031import com.android.systemui.statusbar.CommandQueue;
32import com.android.systemui.statusbar.CommandQueue.Callbacks;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040033import com.android.systemui.statusbar.policy.KeyguardStateController;
Jorim Jaggi40db0292016-06-27 17:58:03 -070034
Adrian Roos1bf60772017-02-03 15:47:43 -080035import java.io.FileDescriptor;
36import java.io.PrintWriter;
37
Jorim Jaggi40db0292016-06-27 17:58:03 -070038/**
39 * Class to control all aspects about light bar changes.
40 */
Lucas Dupin51d24e02018-11-13 10:46:51 -080041public class LightBarTransitionsController implements Dumpable, Callbacks,
42 StatusBarStateController.StateListener {
Jorim Jaggi40db0292016-06-27 17:58:03 -070043
Matthew Ng355fe212018-12-14 17:42:38 -080044 public static final int DEFAULT_TINT_ANIMATION_DURATION = 120;
Jason Monk49fa0162017-01-11 09:21:56 -050045 private static final String EXTRA_DARK_INTENSITY = "dark_intensity";
Jorim Jaggi40db0292016-06-27 17:58:03 -070046
47 private final Handler mHandler;
48 private final DarkIntensityApplier mApplier;
Lucas Dupinc8f16e82019-09-17 18:24:50 -040049 private final KeyguardStateController mKeyguardStateController;
Lucas Dupin51d24e02018-11-13 10:46:51 -080050 private final StatusBarStateController mStatusBarStateController;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040051 private final CommandQueue mCommandQueue;
Jorim Jaggi40db0292016-06-27 17:58:03 -070052
53 private boolean mTransitionDeferring;
54 private long mTransitionDeferringStartTime;
55 private long mTransitionDeferringDuration;
56 private boolean mTransitionPending;
57 private boolean mTintChangePending;
58 private float mPendingDarkIntensity;
59 private ValueAnimator mTintAnimator;
60 private float mDarkIntensity;
Jason Monk49fa0162017-01-11 09:21:56 -050061 private float mNextDarkIntensity;
Lucas Dupin51d24e02018-11-13 10:46:51 -080062 private float mDozeAmount;
Charles Chenf3d295c2018-11-30 18:15:21 +080063 private int mDisplayId;
Jorim Jaggi40db0292016-06-27 17:58:03 -070064 private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
65 @Override
66 public void run() {
67 mTransitionDeferring = false;
68 }
69 };
70
Matthew Ng355fe212018-12-14 17:42:38 -080071 private final Context mContext;
72
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040073 public LightBarTransitionsController(Context context, DarkIntensityApplier applier,
74 CommandQueue commandQueue) {
Jorim Jaggi40db0292016-06-27 17:58:03 -070075 mApplier = applier;
76 mHandler = new Handler();
Lucas Dupinc8f16e82019-09-17 18:24:50 -040077 mKeyguardStateController = Dependency.get(KeyguardStateController.class);
Lucas Dupin51d24e02018-11-13 10:46:51 -080078 mStatusBarStateController = Dependency.get(StatusBarStateController.class);
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040079 mCommandQueue = commandQueue;
80 mCommandQueue.addCallback(this);
Jason Monkaf08c152018-12-04 11:12:39 -050081 mStatusBarStateController.addCallback(this);
Lucas Dupin51d24e02018-11-13 10:46:51 -080082 mDozeAmount = mStatusBarStateController.getDozeAmount();
Matthew Ng355fe212018-12-14 17:42:38 -080083 mContext = context;
Charles Chenf3d295c2018-11-30 18:15:21 +080084 mDisplayId = mContext.getDisplayId();
Jason Monkaa573e92017-01-27 17:00:29 -050085 }
86
87 public void destroy(Context context) {
Dave Mankoffbcaca8a2019-10-31 18:04:08 -040088 mCommandQueue.removeCallback(this);
Jason Monkaf08c152018-12-04 11:12:39 -050089 mStatusBarStateController.removeCallback(this);
Jorim Jaggi40db0292016-06-27 17:58:03 -070090 }
91
Jason Monk49fa0162017-01-11 09:21:56 -050092 public void saveState(Bundle outState) {
93 float intensity = mTintAnimator != null && mTintAnimator.isRunning()
94 ? mNextDarkIntensity : mDarkIntensity;
95 outState.putFloat(EXTRA_DARK_INTENSITY, intensity);
96 }
97
98 public void restoreState(Bundle savedInstanceState) {
99 setIconTintInternal(savedInstanceState.getFloat(EXTRA_DARK_INTENSITY, 0));
100 }
101
Jason Monkaa573e92017-01-27 17:00:29 -0500102 @Override
Charles Chenf3d295c2018-11-30 18:15:21 +0800103 public void appTransitionPending(int displayId, boolean forced) {
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400104 if (mDisplayId != displayId || mKeyguardStateController.isKeyguardGoingAway() && !forced) {
Jason Monkaa573e92017-01-27 17:00:29 -0500105 return;
106 }
Jorim Jaggi40db0292016-06-27 17:58:03 -0700107 mTransitionPending = true;
108 }
109
Jason Monkaa573e92017-01-27 17:00:29 -0500110 @Override
Charles Chenf3d295c2018-11-30 18:15:21 +0800111 public void appTransitionCancelled(int displayId) {
112 if (mDisplayId != displayId) {
113 return;
114 }
Jorim Jaggi40db0292016-06-27 17:58:03 -0700115 if (mTransitionPending && mTintChangePending) {
116 mTintChangePending = false;
Winson Chunge89f4b52019-03-29 15:01:49 -0700117 animateIconTint(mPendingDarkIntensity, 0 /* delay */,
118 mApplier.getTintAnimationDuration());
Jorim Jaggi40db0292016-06-27 17:58:03 -0700119 }
120 mTransitionPending = false;
121 }
122
Jason Monkaa573e92017-01-27 17:00:29 -0500123 @Override
Charles Chenf3d295c2018-11-30 18:15:21 +0800124 public void appTransitionStarting(int displayId, long startTime, long duration,
125 boolean forced) {
Lucas Dupinc8f16e82019-09-17 18:24:50 -0400126 if (mDisplayId != displayId || mKeyguardStateController.isKeyguardGoingAway() && !forced) {
Jason Monkaa573e92017-01-27 17:00:29 -0500127 return;
128 }
Jorim Jaggi40db0292016-06-27 17:58:03 -0700129 if (mTransitionPending && mTintChangePending) {
130 mTintChangePending = false;
131 animateIconTint(mPendingDarkIntensity,
132 Math.max(0, startTime - SystemClock.uptimeMillis()),
133 duration);
134
135 } else if (mTransitionPending) {
136
137 // If we don't have a pending tint change yet, the change might come in the future until
138 // startTime is reached.
139 mTransitionDeferring = true;
140 mTransitionDeferringStartTime = startTime;
141 mTransitionDeferringDuration = duration;
142 mHandler.removeCallbacks(mTransitionDeferringDoneRunnable);
143 mHandler.postAtTime(mTransitionDeferringDoneRunnable, startTime);
144 }
145 mTransitionPending = false;
146 }
147
148 public void setIconsDark(boolean dark, boolean animate) {
149 if (!animate) {
150 setIconTintInternal(dark ? 1.0f : 0.0f);
Jorim Jaggiff46d4c2017-07-17 16:46:00 +0200151 mNextDarkIntensity = dark ? 1.0f : 0.0f;
Jorim Jaggi40db0292016-06-27 17:58:03 -0700152 } else if (mTransitionPending) {
153 deferIconTintChange(dark ? 1.0f : 0.0f);
154 } else if (mTransitionDeferring) {
155 animateIconTint(dark ? 1.0f : 0.0f,
156 Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()),
157 mTransitionDeferringDuration);
158 } else {
Winson Chunge89f4b52019-03-29 15:01:49 -0700159 animateIconTint(dark ? 1.0f : 0.0f, 0 /* delay */, mApplier.getTintAnimationDuration());
Jorim Jaggi40db0292016-06-27 17:58:03 -0700160 }
161 }
162
163 public float getCurrentDarkIntensity() {
164 return mDarkIntensity;
165 }
166
167 private void deferIconTintChange(float darkIntensity) {
168 if (mTintChangePending && darkIntensity == mPendingDarkIntensity) {
169 return;
170 }
171 mTintChangePending = true;
172 mPendingDarkIntensity = darkIntensity;
173 }
174
175 private void animateIconTint(float targetDarkIntensity, long delay,
176 long duration) {
Jorim Jaggiff46d4c2017-07-17 16:46:00 +0200177 if (mNextDarkIntensity == targetDarkIntensity) {
178 return;
179 }
Jorim Jaggi40db0292016-06-27 17:58:03 -0700180 if (mTintAnimator != null) {
181 mTintAnimator.cancel();
182 }
Jason Monk49fa0162017-01-11 09:21:56 -0500183 mNextDarkIntensity = targetDarkIntensity;
Jorim Jaggi40db0292016-06-27 17:58:03 -0700184 mTintAnimator = ValueAnimator.ofFloat(mDarkIntensity, targetDarkIntensity);
185 mTintAnimator.addUpdateListener(
186 animation -> setIconTintInternal((Float) animation.getAnimatedValue()));
187 mTintAnimator.setDuration(duration);
188 mTintAnimator.setStartDelay(delay);
Lucas Dupin0c1157e2017-07-18 21:40:28 -0700189 mTintAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
Jorim Jaggi40db0292016-06-27 17:58:03 -0700190 mTintAnimator.start();
191 }
192
193 private void setIconTintInternal(float darkIntensity) {
194 mDarkIntensity = darkIntensity;
Lucas Dupin51d24e02018-11-13 10:46:51 -0800195 dispatchDark();
196 }
197
198 private void dispatchDark() {
199 mApplier.applyDarkIntensity(MathUtils.lerp(mDarkIntensity, 0f, mDozeAmount));
Jorim Jaggi40db0292016-06-27 17:58:03 -0700200 }
201
Adrian Roos1bf60772017-02-03 15:47:43 -0800202 @Override
203 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
204 pw.print(" mTransitionDeferring="); pw.print(mTransitionDeferring);
205 if (mTransitionDeferring) {
206 pw.println();
207 pw.print(" mTransitionDeferringStartTime=");
208 pw.println(TimeUtils.formatUptime(mTransitionDeferringStartTime));
209
210 pw.print(" mTransitionDeferringDuration=");
211 TimeUtils.formatDuration(mTransitionDeferringDuration, pw);
212 pw.println();
213 }
214 pw.print(" mTransitionPending="); pw.print(mTransitionPending);
215 pw.print(" mTintChangePending="); pw.println(mTintChangePending);
216
217 pw.print(" mPendingDarkIntensity="); pw.print(mPendingDarkIntensity);
218 pw.print(" mDarkIntensity="); pw.print(mDarkIntensity);
219 pw.print(" mNextDarkIntensity="); pw.println(mNextDarkIntensity);
220 }
221
Lucas Dupin51d24e02018-11-13 10:46:51 -0800222 @Override
223 public void onStateChanged(int newState) { }
224
225 @Override
226 public void onDozeAmountChanged(float linear, float eased) {
227 mDozeAmount = eased;
228 dispatchDark();
229 }
230
Jorim Jaggi40db0292016-06-27 17:58:03 -0700231 /**
232 * Interface to apply a specific dark intensity.
233 */
234 public interface DarkIntensityApplier {
235 void applyDarkIntensity(float darkIntensity);
Winson Chunge89f4b52019-03-29 15:01:49 -0700236 int getTintAnimationDuration();
Jorim Jaggi40db0292016-06-27 17:58:03 -0700237 }
238}