blob: 1dbc44ea1b22ef822a3c325ae068cf82c4a9f52e [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
Adrian Roosdb1bc6b2016-04-14 17:49:43 -070019import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
20import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
21import static android.view.WindowManagerInternal.AppTransitionListener;
22
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010023import android.app.StatusBarManager;
24import android.os.IBinder;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010025import android.os.SystemClock;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010026import android.view.View;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010027import android.view.animation.Animation;
28import android.view.animation.AnimationSet;
29import android.view.animation.Interpolator;
30import android.view.animation.TranslateAnimation;
31
Jorim Jaggi2adba072016-03-03 13:43:39 +010032import com.android.server.LocalServices;
33import com.android.server.statusbar.StatusBarManagerInternal;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010034
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010035/**
36 * Implements status bar specific behavior.
37 */
38public class StatusBarController extends BarController {
39
40 private static final long TRANSITION_DURATION = 120L;
41
42 private final AppTransitionListener mAppTransitionListener
43 = new AppTransitionListener() {
44
45 @Override
46 public void onAppTransitionPendingLocked() {
47 mHandler.post(new Runnable() {
48 @Override
49 public void run() {
Adrian Roosf2efdd82016-04-15 17:43:18 -070050 StatusBarManagerInternal statusbar = getStatusBarInternal();
51 if (statusbar != null) {
52 statusbar.appTransitionPending();
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010053 }
54 }
55 });
56 }
57
58 @Override
59 public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
60 final Animation openAnimation, final Animation closeAnimation) {
61 mHandler.post(new Runnable() {
62 @Override
63 public void run() {
Adrian Roosf2efdd82016-04-15 17:43:18 -070064 StatusBarManagerInternal statusbar = getStatusBarInternal();
65 if (statusbar != null) {
66 long startTime = calculateStatusBarTransitionStartTime(openAnimation,
67 closeAnimation);
68 long duration = closeAnimation != null || openAnimation != null
69 ? TRANSITION_DURATION : 0;
70 statusbar.appTransitionStarting(startTime, duration);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010071 }
72 }
73 });
74 }
75
76 @Override
77 public void onAppTransitionCancelledLocked() {
78 mHandler.post(new Runnable() {
79 @Override
80 public void run() {
Adrian Roosf2efdd82016-04-15 17:43:18 -070081 StatusBarManagerInternal statusbar = getStatusBarInternal();
82 if (statusbar != null) {
83 statusbar.appTransitionCancelled();
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010084 }
85 }
86 });
87 }
Jorim Jaggi2adba072016-03-03 13:43:39 +010088
89 @Override
90 public void onAppTransitionFinishedLocked(IBinder token) {
91 mHandler.post(new Runnable() {
92 @Override
93 public void run() {
94 StatusBarManagerInternal statusbar = LocalServices.getService(
95 StatusBarManagerInternal.class);
96 if (statusbar != null) {
97 statusbar.appTransitionFinished();
98 }
99 }
100 });
101 }
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100102 };
103
104 public StatusBarController() {
105 super("StatusBar",
106 View.STATUS_BAR_TRANSIENT,
107 View.STATUS_BAR_UNHIDE,
108 View.STATUS_BAR_TRANSLUCENT,
109 StatusBarManager.WINDOW_STATUS_BAR,
Adrian Roosdb1bc6b2016-04-14 17:49:43 -0700110 FLAG_TRANSLUCENT_STATUS,
Jorim Jaggi4fa78922015-11-30 17:13:56 -0800111 View.STATUS_BAR_TRANSPARENT);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100112 }
113
Adrian Roosdb1bc6b2016-04-14 17:49:43 -0700114 @Override
115 protected boolean skipAnimation() {
116 return mWin.getAttrs().height == MATCH_PARENT;
117 }
118
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100119 public AppTransitionListener getAppTransitionListener() {
120 return mAppTransitionListener;
121 }
122
123 /**
124 * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
125 * calculates the timings for the corresponding status bar transition.
126 *
127 * @return the desired start time of the status bar transition, in uptime millis
128 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700129 private static long calculateStatusBarTransitionStartTime(Animation openAnimation,
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100130 Animation closeAnimation) {
131 if (openAnimation != null && closeAnimation != null) {
132 TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
133 TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
134 if (openTranslateAnimation != null) {
135
136 // Some interpolators are extremely quickly mostly finished, but not completely. For
137 // our purposes, we need to find the fraction for which ther interpolator is mostly
138 // there, and use that value for the calculation.
139 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
140 return SystemClock.uptimeMillis()
141 + openTranslateAnimation.getStartOffset()
142 + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
143 } else if (closeTranslateAnimation != null) {
144 return SystemClock.uptimeMillis();
145 } else {
146 return SystemClock.uptimeMillis();
147 }
148 } else {
149 return SystemClock.uptimeMillis();
150 }
151 }
152
153 /**
154 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
155 *
156 * @return the found animation, {@code null} otherwise
157 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700158 private static TranslateAnimation findTranslateAnimation(Animation animation) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100159 if (animation instanceof TranslateAnimation) {
160 return (TranslateAnimation) animation;
161 } else if (animation instanceof AnimationSet) {
162 AnimationSet set = (AnimationSet) animation;
163 for (int i = 0; i < set.getAnimations().size(); i++) {
164 Animation a = set.getAnimations().get(i);
165 if (a instanceof TranslateAnimation) {
166 return (TranslateAnimation) a;
167 }
168 }
169 }
170 return null;
171 }
172
173 /**
174 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
175 * {@code interpolator(t + eps) > 0.99}.
176 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700177 private static float findAlmostThereFraction(Interpolator interpolator) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100178 float val = 0.5f;
179 float adj = 0.25f;
180 while (adj >= 0.01f) {
181 if (interpolator.getInterpolation(val) < 0.99f) {
182 val += adj;
183 } else {
184 val -= adj;
185 }
186 adj /= 2;
187 }
188 return val;
189 }
190}