blob: 86d04682972759aad0669cc2ad1f93728b884c91 [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;
21import android.os.RemoteException;
22import android.os.SystemClock;
23import android.util.Slog;
24import android.view.View;
25import android.view.WindowManager;
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010026import android.view.animation.Animation;
27import android.view.animation.AnimationSet;
28import android.view.animation.Interpolator;
29import android.view.animation.TranslateAnimation;
30
31import com.android.internal.statusbar.IStatusBarService;
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
35import static android.view.WindowManagerInternal.*;
36
37/**
38 * Implements status bar specific behavior.
39 */
40public class StatusBarController extends BarController {
41
42 private static final long TRANSITION_DURATION = 120L;
43
44 private final AppTransitionListener mAppTransitionListener
45 = new AppTransitionListener() {
46
47 @Override
48 public void onAppTransitionPendingLocked() {
49 mHandler.post(new Runnable() {
50 @Override
51 public void run() {
52 try {
53 IStatusBarService statusbar = getStatusBarService();
54 if (statusbar != null) {
55 statusbar.appTransitionPending();
56 }
57 } catch (RemoteException e) {
58 Slog.e(mTag, "RemoteException when app transition is pending", e);
59 // re-acquire status bar service next time it is needed.
60 mStatusBarService = null;
61 }
62 }
63 });
64 }
65
66 @Override
67 public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
68 final Animation openAnimation, final Animation closeAnimation) {
69 mHandler.post(new Runnable() {
70 @Override
71 public void run() {
72 try {
73 IStatusBarService statusbar = getStatusBarService();
74 if (statusbar != null) {
75 long startTime = calculateStatusBarTransitionStartTime(openAnimation,
76 closeAnimation);
Jorim Jaggid94d3a22015-08-21 16:52:55 -070077 long duration = closeAnimation != null || openAnimation != null
78 ? TRANSITION_DURATION : 0;
79 statusbar.appTransitionStarting(startTime, duration);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010080 }
81 } catch (RemoteException e) {
82 Slog.e(mTag, "RemoteException when app transition is starting", e);
83 // re-acquire status bar service next time it is needed.
84 mStatusBarService = null;
85 }
86 }
87 });
88 }
89
90 @Override
91 public void onAppTransitionCancelledLocked() {
92 mHandler.post(new Runnable() {
93 @Override
94 public void run() {
95 try {
96 IStatusBarService statusbar = getStatusBarService();
97 if (statusbar != null) {
98 statusbar.appTransitionCancelled();
99 }
100 } catch (RemoteException e) {
101 Slog.e(mTag, "RemoteException when app transition is cancelled", e);
102 // re-acquire status bar service next time it is needed.
103 mStatusBarService = null;
104 }
105 }
106 });
107 }
Jorim Jaggi2adba072016-03-03 13:43:39 +0100108
109 @Override
110 public void onAppTransitionFinishedLocked(IBinder token) {
111 mHandler.post(new Runnable() {
112 @Override
113 public void run() {
114 StatusBarManagerInternal statusbar = LocalServices.getService(
115 StatusBarManagerInternal.class);
116 if (statusbar != null) {
117 statusbar.appTransitionFinished();
118 }
119 }
120 });
121 }
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100122 };
123
124 public StatusBarController() {
125 super("StatusBar",
126 View.STATUS_BAR_TRANSIENT,
127 View.STATUS_BAR_UNHIDE,
128 View.STATUS_BAR_TRANSLUCENT,
129 StatusBarManager.WINDOW_STATUS_BAR,
Jorim Jaggi4fa78922015-11-30 17:13:56 -0800130 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
131 View.STATUS_BAR_TRANSPARENT);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100132 }
133
134 public AppTransitionListener getAppTransitionListener() {
135 return mAppTransitionListener;
136 }
137
138 /**
139 * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
140 * calculates the timings for the corresponding status bar transition.
141 *
142 * @return the desired start time of the status bar transition, in uptime millis
143 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700144 private static long calculateStatusBarTransitionStartTime(Animation openAnimation,
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100145 Animation closeAnimation) {
146 if (openAnimation != null && closeAnimation != null) {
147 TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
148 TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
149 if (openTranslateAnimation != null) {
150
151 // Some interpolators are extremely quickly mostly finished, but not completely. For
152 // our purposes, we need to find the fraction for which ther interpolator is mostly
153 // there, and use that value for the calculation.
154 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
155 return SystemClock.uptimeMillis()
156 + openTranslateAnimation.getStartOffset()
157 + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
158 } else if (closeTranslateAnimation != null) {
159 return SystemClock.uptimeMillis();
160 } else {
161 return SystemClock.uptimeMillis();
162 }
163 } else {
164 return SystemClock.uptimeMillis();
165 }
166 }
167
168 /**
169 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
170 *
171 * @return the found animation, {@code null} otherwise
172 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700173 private static TranslateAnimation findTranslateAnimation(Animation animation) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100174 if (animation instanceof TranslateAnimation) {
175 return (TranslateAnimation) animation;
176 } else if (animation instanceof AnimationSet) {
177 AnimationSet set = (AnimationSet) animation;
178 for (int i = 0; i < set.getAnimations().size(); i++) {
179 Animation a = set.getAnimations().get(i);
180 if (a instanceof TranslateAnimation) {
181 return (TranslateAnimation) a;
182 }
183 }
184 }
185 return null;
186 }
187
188 /**
189 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
190 * {@code interpolator(t + eps) > 0.99}.
191 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700192 private static float findAlmostThereFraction(Interpolator interpolator) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100193 float val = 0.5f;
194 float adj = 0.25f;
195 while (adj >= 0.01f) {
196 if (interpolator.getInterpolation(val) < 0.99f) {
197 val += adj;
198 } else {
199 val -= adj;
200 }
201 adj /= 2;
202 }
203 return val;
204 }
205}