blob: 7d67b60a9e9fe92dfc69ee2c2034f8eb16959e41 [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
Jorim Jaggife762342016-10-13 14:33:27 +020059 public int onAppTransitionStartingLocked(int transit, IBinder openToken,
60 IBinder closeToken, final Animation openAnimation, final Animation closeAnimation) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010061 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 });
Jorim Jaggife762342016-10-13 14:33:27 +020074 return 0;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010075 }
76
77 @Override
Jorim Jaggife762342016-10-13 14:33:27 +020078 public void onAppTransitionCancelledLocked(int transit) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010079 mHandler.post(new Runnable() {
80 @Override
81 public void run() {
Adrian Roosf2efdd82016-04-15 17:43:18 -070082 StatusBarManagerInternal statusbar = getStatusBarInternal();
83 if (statusbar != null) {
84 statusbar.appTransitionCancelled();
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010085 }
86 }
87 });
88 }
Jorim Jaggi2adba072016-03-03 13:43:39 +010089
90 @Override
91 public void onAppTransitionFinishedLocked(IBinder token) {
92 mHandler.post(new Runnable() {
93 @Override
94 public void run() {
95 StatusBarManagerInternal statusbar = LocalServices.getService(
96 StatusBarManagerInternal.class);
97 if (statusbar != null) {
98 statusbar.appTransitionFinished();
99 }
100 }
101 });
102 }
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100103 };
104
105 public StatusBarController() {
106 super("StatusBar",
107 View.STATUS_BAR_TRANSIENT,
108 View.STATUS_BAR_UNHIDE,
109 View.STATUS_BAR_TRANSLUCENT,
110 StatusBarManager.WINDOW_STATUS_BAR,
Adrian Roosdb1bc6b2016-04-14 17:49:43 -0700111 FLAG_TRANSLUCENT_STATUS,
Jorim Jaggi4fa78922015-11-30 17:13:56 -0800112 View.STATUS_BAR_TRANSPARENT);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100113 }
114
Adrian Roosdb1bc6b2016-04-14 17:49:43 -0700115 @Override
116 protected boolean skipAnimation() {
117 return mWin.getAttrs().height == MATCH_PARENT;
118 }
119
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100120 public AppTransitionListener getAppTransitionListener() {
121 return mAppTransitionListener;
122 }
123
124 /**
125 * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
126 * calculates the timings for the corresponding status bar transition.
127 *
128 * @return the desired start time of the status bar transition, in uptime millis
129 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700130 private static long calculateStatusBarTransitionStartTime(Animation openAnimation,
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100131 Animation closeAnimation) {
132 if (openAnimation != null && closeAnimation != null) {
133 TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
134 TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
135 if (openTranslateAnimation != null) {
136
137 // Some interpolators are extremely quickly mostly finished, but not completely. For
138 // our purposes, we need to find the fraction for which ther interpolator is mostly
139 // there, and use that value for the calculation.
140 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
141 return SystemClock.uptimeMillis()
142 + openTranslateAnimation.getStartOffset()
143 + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
144 } else if (closeTranslateAnimation != null) {
145 return SystemClock.uptimeMillis();
146 } else {
147 return SystemClock.uptimeMillis();
148 }
149 } else {
150 return SystemClock.uptimeMillis();
151 }
152 }
153
154 /**
155 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
156 *
157 * @return the found animation, {@code null} otherwise
158 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700159 private static TranslateAnimation findTranslateAnimation(Animation animation) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100160 if (animation instanceof TranslateAnimation) {
161 return (TranslateAnimation) animation;
162 } else if (animation instanceof AnimationSet) {
163 AnimationSet set = (AnimationSet) animation;
164 for (int i = 0; i < set.getAnimations().size(); i++) {
165 Animation a = set.getAnimations().get(i);
166 if (a instanceof TranslateAnimation) {
167 return (TranslateAnimation) a;
168 }
169 }
170 }
171 return null;
172 }
173
174 /**
175 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
176 * {@code interpolator(t + eps) > 0.99}.
177 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700178 private static float findAlmostThereFraction(Interpolator interpolator) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100179 float val = 0.5f;
180 float adj = 0.25f;
181 while (adj >= 0.01f) {
182 if (interpolator.getInterpolation(val) < 0.99f) {
183 val += adj;
184 } else {
185 val -= adj;
186 }
187 adj /= 2;
188 }
189 return val;
190 }
191}