140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi/* 240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * Copyright (C) 2016 The Android Open Source Project 340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * 440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License"); 540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * you may not use this file except in compliance with the License. 640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * You may obtain a copy of the License at 740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * 840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * http://www.apache.org/licenses/LICENSE-2.0 940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * 1040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * Unless required by applicable law or agreed to in writing, software 1140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS, 1240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * See the License for the specific language governing permissions and 1440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * limitations under the License 1540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi */ 1640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 1740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggipackage com.android.systemui.statusbar.phone; 1840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 1940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggiimport android.animation.ValueAnimator; 20aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monkimport android.content.Context; 2149fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.os.Bundle; 2240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggiimport android.os.Handler; 2340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggiimport android.os.SystemClock; 241bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roosimport android.util.TimeUtils; 2540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 26aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monkimport com.android.systemui.Dependency; 27ff46d4c935752f22808865b2fb60f883ae02a1c5Jorim Jaggiimport com.android.systemui.Dumpable; 2840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggiimport com.android.systemui.Interpolators; 29aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monkimport com.android.systemui.SysUiServiceProvider; 30aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monkimport com.android.systemui.statusbar.CommandQueue; 31aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monkimport com.android.systemui.statusbar.CommandQueue.Callbacks; 32aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monkimport com.android.systemui.statusbar.policy.KeyguardMonitor; 3340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 341bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roosimport java.io.FileDescriptor; 351bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roosimport java.io.PrintWriter; 361bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos 3740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi/** 3840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * Class to control all aspects about light bar changes. 3940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi */ 40aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monkpublic class LightBarTransitionsController implements Dumpable, Callbacks { 4140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 4240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi public static final long DEFAULT_TINT_ANIMATION_DURATION = 120; 4349fa016a98cef9940c883b3f620a0e90537a204eJason Monk private static final String EXTRA_DARK_INTENSITY = "dark_intensity"; 4440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 4540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private final Handler mHandler; 4640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private final DarkIntensityApplier mApplier; 47aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk private final KeyguardMonitor mKeyguardMonitor; 4840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 4940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private boolean mTransitionDeferring; 5040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private long mTransitionDeferringStartTime; 5140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private long mTransitionDeferringDuration; 5240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private boolean mTransitionPending; 5340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private boolean mTintChangePending; 5440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private float mPendingDarkIntensity; 5540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private ValueAnimator mTintAnimator; 5640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private float mDarkIntensity; 5749fa016a98cef9940c883b3f620a0e90537a204eJason Monk private float mNextDarkIntensity; 5840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private final Runnable mTransitionDeferringDoneRunnable = new Runnable() { 5940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi @Override 6040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi public void run() { 6140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTransitionDeferring = false; 6240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 6340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi }; 6440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 65aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk public LightBarTransitionsController(Context context, DarkIntensityApplier applier) { 6640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mApplier = applier; 6740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mHandler = new Handler(); 68aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); 69aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk SysUiServiceProvider.getComponent(context, CommandQueue.class) 70aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk .addCallbacks(this); 71aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk } 72aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk 73aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk public void destroy(Context context) { 74aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk SysUiServiceProvider.getComponent(context, CommandQueue.class) 75aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk .removeCallbacks(this); 7640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 7740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 7849fa016a98cef9940c883b3f620a0e90537a204eJason Monk public void saveState(Bundle outState) { 7949fa016a98cef9940c883b3f620a0e90537a204eJason Monk float intensity = mTintAnimator != null && mTintAnimator.isRunning() 8049fa016a98cef9940c883b3f620a0e90537a204eJason Monk ? mNextDarkIntensity : mDarkIntensity; 8149fa016a98cef9940c883b3f620a0e90537a204eJason Monk outState.putFloat(EXTRA_DARK_INTENSITY, intensity); 8249fa016a98cef9940c883b3f620a0e90537a204eJason Monk } 8349fa016a98cef9940c883b3f620a0e90537a204eJason Monk 8449fa016a98cef9940c883b3f620a0e90537a204eJason Monk public void restoreState(Bundle savedInstanceState) { 8549fa016a98cef9940c883b3f620a0e90537a204eJason Monk setIconTintInternal(savedInstanceState.getFloat(EXTRA_DARK_INTENSITY, 0)); 8649fa016a98cef9940c883b3f620a0e90537a204eJason Monk } 8749fa016a98cef9940c883b3f620a0e90537a204eJason Monk 88aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk @Override 89aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk public void appTransitionPending(boolean forced) { 90aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) { 91aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk return; 92aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk } 9340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTransitionPending = true; 9440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 9540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 96aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk @Override 9740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi public void appTransitionCancelled() { 9840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi if (mTransitionPending && mTintChangePending) { 9940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintChangePending = false; 10040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi animateIconTint(mPendingDarkIntensity, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION); 10140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 10240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTransitionPending = false; 10340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 10440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 105aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk @Override 106aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk public void appTransitionStarting(long startTime, long duration, boolean forced) { 107aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) { 108aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk return; 109aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk } 11040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi if (mTransitionPending && mTintChangePending) { 11140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintChangePending = false; 11240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi animateIconTint(mPendingDarkIntensity, 11340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi Math.max(0, startTime - SystemClock.uptimeMillis()), 11440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi duration); 11540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 11640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } else if (mTransitionPending) { 11740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 11840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi // If we don't have a pending tint change yet, the change might come in the future until 11940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi // startTime is reached. 12040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTransitionDeferring = true; 12140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTransitionDeferringStartTime = startTime; 12240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTransitionDeferringDuration = duration; 12340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mHandler.removeCallbacks(mTransitionDeferringDoneRunnable); 12440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mHandler.postAtTime(mTransitionDeferringDoneRunnable, startTime); 12540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 12640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTransitionPending = false; 12740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 12840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 12940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi public void setIconsDark(boolean dark, boolean animate) { 13040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi if (!animate) { 13140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi setIconTintInternal(dark ? 1.0f : 0.0f); 132ff46d4c935752f22808865b2fb60f883ae02a1c5Jorim Jaggi mNextDarkIntensity = dark ? 1.0f : 0.0f; 13340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } else if (mTransitionPending) { 13440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi deferIconTintChange(dark ? 1.0f : 0.0f); 13540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } else if (mTransitionDeferring) { 13640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi animateIconTint(dark ? 1.0f : 0.0f, 13740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()), 13840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTransitionDeferringDuration); 13940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } else { 14040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi animateIconTint(dark ? 1.0f : 0.0f, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION); 14140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 14240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 14340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 14440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi public float getCurrentDarkIntensity() { 14540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi return mDarkIntensity; 14640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 14740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 14840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private void deferIconTintChange(float darkIntensity) { 14940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi if (mTintChangePending && darkIntensity == mPendingDarkIntensity) { 15040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi return; 15140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 15240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintChangePending = true; 15340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mPendingDarkIntensity = darkIntensity; 15440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 15540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 15640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private void animateIconTint(float targetDarkIntensity, long delay, 15740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi long duration) { 158ff46d4c935752f22808865b2fb60f883ae02a1c5Jorim Jaggi if (mNextDarkIntensity == targetDarkIntensity) { 159ff46d4c935752f22808865b2fb60f883ae02a1c5Jorim Jaggi return; 160ff46d4c935752f22808865b2fb60f883ae02a1c5Jorim Jaggi } 16140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi if (mTintAnimator != null) { 16240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintAnimator.cancel(); 16340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 16449fa016a98cef9940c883b3f620a0e90537a204eJason Monk mNextDarkIntensity = targetDarkIntensity; 16540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintAnimator = ValueAnimator.ofFloat(mDarkIntensity, targetDarkIntensity); 16640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintAnimator.addUpdateListener( 16740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi animation -> setIconTintInternal((Float) animation.getAnimatedValue())); 16840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintAnimator.setDuration(duration); 16940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintAnimator.setStartDelay(delay); 1700c1157efb3be02bc36a7cb41ee619091c10547feLucas Dupin mTintAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); 17140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mTintAnimator.start(); 17240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 17340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 17440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi private void setIconTintInternal(float darkIntensity) { 17540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mDarkIntensity = darkIntensity; 17640db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi mApplier.applyDarkIntensity(darkIntensity); 17740db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 17840db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi 1791bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos @Override 1801bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1811bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.print(" mTransitionDeferring="); pw.print(mTransitionDeferring); 1821bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos if (mTransitionDeferring) { 1831bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.println(); 1841bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.print(" mTransitionDeferringStartTime="); 1851bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.println(TimeUtils.formatUptime(mTransitionDeferringStartTime)); 1861bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos 1871bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.print(" mTransitionDeferringDuration="); 1881bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos TimeUtils.formatDuration(mTransitionDeferringDuration, pw); 1891bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.println(); 1901bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos } 1911bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.print(" mTransitionPending="); pw.print(mTransitionPending); 1921bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.print(" mTintChangePending="); pw.println(mTintChangePending); 1931bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos 1941bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.print(" mPendingDarkIntensity="); pw.print(mPendingDarkIntensity); 1951bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.print(" mDarkIntensity="); pw.print(mDarkIntensity); 1961bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos pw.print(" mNextDarkIntensity="); pw.println(mNextDarkIntensity); 1971bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos } 1981bf6077afeecec35fe0d57072e851f9810e937cdAdrian Roos 19940db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi /** 20040db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi * Interface to apply a specific dark intensity. 20140db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi */ 20240db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi public interface DarkIntensityApplier { 20340db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi void applyDarkIntensity(float darkIntensity); 20440db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi } 20540db029cfeb263b5b672ca687c347e58ed2ad2aeJorim Jaggi} 206