blob: b935f5abc74be9b64373b516047958dc8c486767 [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;
32
33import static android.view.WindowManagerInternal.*;
34
35/**
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() {
50 try {
51 IStatusBarService statusbar = getStatusBarService();
52 if (statusbar != null) {
53 statusbar.appTransitionPending();
54 }
55 } catch (RemoteException e) {
56 Slog.e(mTag, "RemoteException when app transition is pending", e);
57 // re-acquire status bar service next time it is needed.
58 mStatusBarService = null;
59 }
60 }
61 });
62 }
63
64 @Override
65 public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
66 final Animation openAnimation, final Animation closeAnimation) {
67 mHandler.post(new Runnable() {
68 @Override
69 public void run() {
70 try {
71 IStatusBarService statusbar = getStatusBarService();
72 if (statusbar != null) {
73 long startTime = calculateStatusBarTransitionStartTime(openAnimation,
74 closeAnimation);
Jorim Jaggid94d3a22015-08-21 16:52:55 -070075 long duration = closeAnimation != null || openAnimation != null
76 ? TRANSITION_DURATION : 0;
77 statusbar.appTransitionStarting(startTime, duration);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +010078 }
79 } catch (RemoteException e) {
80 Slog.e(mTag, "RemoteException when app transition is starting", e);
81 // re-acquire status bar service next time it is needed.
82 mStatusBarService = null;
83 }
84 }
85 });
86 }
87
88 @Override
89 public void onAppTransitionCancelledLocked() {
90 mHandler.post(new Runnable() {
91 @Override
92 public void run() {
93 try {
94 IStatusBarService statusbar = getStatusBarService();
95 if (statusbar != null) {
96 statusbar.appTransitionCancelled();
97 }
98 } catch (RemoteException e) {
99 Slog.e(mTag, "RemoteException when app transition is cancelled", e);
100 // re-acquire status bar service next time it is needed.
101 mStatusBarService = null;
102 }
103 }
104 });
105 }
106 };
107
108 public StatusBarController() {
109 super("StatusBar",
110 View.STATUS_BAR_TRANSIENT,
111 View.STATUS_BAR_UNHIDE,
112 View.STATUS_BAR_TRANSLUCENT,
113 StatusBarManager.WINDOW_STATUS_BAR,
114 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
115 }
116
117 public AppTransitionListener getAppTransitionListener() {
118 return mAppTransitionListener;
119 }
120
121 /**
122 * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
123 * calculates the timings for the corresponding status bar transition.
124 *
125 * @return the desired start time of the status bar transition, in uptime millis
126 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700127 private static long calculateStatusBarTransitionStartTime(Animation openAnimation,
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100128 Animation closeAnimation) {
129 if (openAnimation != null && closeAnimation != null) {
130 TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
131 TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
132 if (openTranslateAnimation != null) {
133
134 // Some interpolators are extremely quickly mostly finished, but not completely. For
135 // our purposes, we need to find the fraction for which ther interpolator is mostly
136 // there, and use that value for the calculation.
137 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
138 return SystemClock.uptimeMillis()
139 + openTranslateAnimation.getStartOffset()
140 + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
141 } else if (closeTranslateAnimation != null) {
142 return SystemClock.uptimeMillis();
143 } else {
144 return SystemClock.uptimeMillis();
145 }
146 } else {
147 return SystemClock.uptimeMillis();
148 }
149 }
150
151 /**
152 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
153 *
154 * @return the found animation, {@code null} otherwise
155 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700156 private static TranslateAnimation findTranslateAnimation(Animation animation) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100157 if (animation instanceof TranslateAnimation) {
158 return (TranslateAnimation) animation;
159 } else if (animation instanceof AnimationSet) {
160 AnimationSet set = (AnimationSet) animation;
161 for (int i = 0; i < set.getAnimations().size(); i++) {
162 Animation a = set.getAnimations().get(i);
163 if (a instanceof TranslateAnimation) {
164 return (TranslateAnimation) a;
165 }
166 }
167 }
168 return null;
169 }
170
171 /**
172 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
173 * {@code interpolator(t + eps) > 0.99}.
174 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700175 private static float findAlmostThereFraction(Interpolator interpolator) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100176 float val = 0.5f;
177 float adj = 0.25f;
178 while (adj >= 0.01f) {
179 if (interpolator.getInterpolation(val) < 0.99f) {
180 val += adj;
181 } else {
182 val -= adj;
183 }
184 adj /= 2;
185 }
186 return val;
187 }
188}