blob: 245518ca28f64687639aeb4cd7452b0719c88cc4 [file] [log] [blame]
Jorim Jaggi24bec7c2015-02-04 12:40:14 +01001/*
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
17package com.android.server.policy;
18
19import android.app.StatusBarManager;
20import android.os.IBinder;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010021import android.os.SystemClock;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010022import android.view.View;
23import android.view.WindowManager;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010024import android.view.animation.Animation;
25import android.view.animation.AnimationSet;
26import android.view.animation.Interpolator;
27import android.view.animation.TranslateAnimation;
28
Jorim Jaggi2adba072016-03-03 13:43:39 +010029import com.android.server.LocalServices;
30import com.android.server.statusbar.StatusBarManagerInternal;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010031
32import static android.view.WindowManagerInternal.*;
33
34/**
35 * Implements status bar specific behavior.
36 */
37public class StatusBarController extends BarController {
38
39 private static final long TRANSITION_DURATION = 120L;
40
41 private final AppTransitionListener mAppTransitionListener
42 = new AppTransitionListener() {
43
44 @Override
45 public void onAppTransitionPendingLocked() {
46 mHandler.post(new Runnable() {
47 @Override
48 public void run() {
Adrian Roosf2efdd82016-04-15 17:43:18 -070049 StatusBarManagerInternal statusbar = getStatusBarInternal();
50 if (statusbar != null) {
51 statusbar.appTransitionPending();
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010052 }
53 }
54 });
55 }
56
57 @Override
58 public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
59 final Animation openAnimation, final Animation closeAnimation) {
60 mHandler.post(new Runnable() {
61 @Override
62 public void run() {
Adrian Roosf2efdd82016-04-15 17:43:18 -070063 StatusBarManagerInternal statusbar = getStatusBarInternal();
64 if (statusbar != null) {
65 long startTime = calculateStatusBarTransitionStartTime(openAnimation,
66 closeAnimation);
67 long duration = closeAnimation != null || openAnimation != null
68 ? TRANSITION_DURATION : 0;
69 statusbar.appTransitionStarting(startTime, duration);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010070 }
71 }
72 });
73 }
74
75 @Override
76 public void onAppTransitionCancelledLocked() {
77 mHandler.post(new Runnable() {
78 @Override
79 public void run() {
Adrian Roosf2efdd82016-04-15 17:43:18 -070080 StatusBarManagerInternal statusbar = getStatusBarInternal();
81 if (statusbar != null) {
82 statusbar.appTransitionCancelled();
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010083 }
84 }
85 });
86 }
Jorim Jaggi2adba072016-03-03 13:43:39 +010087
88 @Override
89 public void onAppTransitionFinishedLocked(IBinder token) {
90 mHandler.post(new Runnable() {
91 @Override
92 public void run() {
93 StatusBarManagerInternal statusbar = LocalServices.getService(
94 StatusBarManagerInternal.class);
95 if (statusbar != null) {
96 statusbar.appTransitionFinished();
97 }
98 }
99 });
100 }
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100101 };
102
103 public StatusBarController() {
104 super("StatusBar",
105 View.STATUS_BAR_TRANSIENT,
106 View.STATUS_BAR_UNHIDE,
107 View.STATUS_BAR_TRANSLUCENT,
108 StatusBarManager.WINDOW_STATUS_BAR,
Jorim Jaggi4fa78922015-11-30 17:13:56 -0800109 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
110 View.STATUS_BAR_TRANSPARENT);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100111 }
112
113 public AppTransitionListener getAppTransitionListener() {
114 return mAppTransitionListener;
115 }
116
117 /**
118 * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
119 * calculates the timings for the corresponding status bar transition.
120 *
121 * @return the desired start time of the status bar transition, in uptime millis
122 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700123 private static long calculateStatusBarTransitionStartTime(Animation openAnimation,
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100124 Animation closeAnimation) {
125 if (openAnimation != null && closeAnimation != null) {
126 TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
127 TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
128 if (openTranslateAnimation != null) {
129
130 // Some interpolators are extremely quickly mostly finished, but not completely. For
131 // our purposes, we need to find the fraction for which ther interpolator is mostly
132 // there, and use that value for the calculation.
133 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
134 return SystemClock.uptimeMillis()
135 + openTranslateAnimation.getStartOffset()
136 + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
137 } else if (closeTranslateAnimation != null) {
138 return SystemClock.uptimeMillis();
139 } else {
140 return SystemClock.uptimeMillis();
141 }
142 } else {
143 return SystemClock.uptimeMillis();
144 }
145 }
146
147 /**
148 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
149 *
150 * @return the found animation, {@code null} otherwise
151 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700152 private static TranslateAnimation findTranslateAnimation(Animation animation) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100153 if (animation instanceof TranslateAnimation) {
154 return (TranslateAnimation) animation;
155 } else if (animation instanceof AnimationSet) {
156 AnimationSet set = (AnimationSet) animation;
157 for (int i = 0; i < set.getAnimations().size(); i++) {
158 Animation a = set.getAnimations().get(i);
159 if (a instanceof TranslateAnimation) {
160 return (TranslateAnimation) a;
161 }
162 }
163 }
164 return null;
165 }
166
167 /**
168 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
169 * {@code interpolator(t + eps) > 0.99}.
170 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700171 private static float findAlmostThereFraction(Interpolator interpolator) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100172 float val = 0.5f;
173 float adj = 0.25f;
174 while (adj >= 0.01f) {
175 if (interpolator.getInterpolation(val) < 0.99f) {
176 val += adj;
177 } else {
178 val -= adj;
179 }
180 adj /= 2;
181 }
182 return val;
183 }
184}