blob: 9d353c6c0ed726eb308777c030a0ff30070d01e8 [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,
Jorim Jaggi4fa78922015-11-30 17:13:56 -0800114 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
115 View.STATUS_BAR_TRANSPARENT);
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100116 }
117
118 public AppTransitionListener getAppTransitionListener() {
119 return mAppTransitionListener;
120 }
121
122 /**
123 * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
124 * calculates the timings for the corresponding status bar transition.
125 *
126 * @return the desired start time of the status bar transition, in uptime millis
127 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700128 private static long calculateStatusBarTransitionStartTime(Animation openAnimation,
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100129 Animation closeAnimation) {
130 if (openAnimation != null && closeAnimation != null) {
131 TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
132 TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
133 if (openTranslateAnimation != null) {
134
135 // Some interpolators are extremely quickly mostly finished, but not completely. For
136 // our purposes, we need to find the fraction for which ther interpolator is mostly
137 // there, and use that value for the calculation.
138 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
139 return SystemClock.uptimeMillis()
140 + openTranslateAnimation.getStartOffset()
141 + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
142 } else if (closeTranslateAnimation != null) {
143 return SystemClock.uptimeMillis();
144 } else {
145 return SystemClock.uptimeMillis();
146 }
147 } else {
148 return SystemClock.uptimeMillis();
149 }
150 }
151
152 /**
153 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
154 *
155 * @return the found animation, {@code null} otherwise
156 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700157 private static TranslateAnimation findTranslateAnimation(Animation animation) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100158 if (animation instanceof TranslateAnimation) {
159 return (TranslateAnimation) animation;
160 } else if (animation instanceof AnimationSet) {
161 AnimationSet set = (AnimationSet) animation;
162 for (int i = 0; i < set.getAnimations().size(); i++) {
163 Animation a = set.getAnimations().get(i);
164 if (a instanceof TranslateAnimation) {
165 return (TranslateAnimation) a;
166 }
167 }
168 }
169 return null;
170 }
171
172 /**
173 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
174 * {@code interpolator(t + eps) > 0.99}.
175 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700176 private static float findAlmostThereFraction(Interpolator interpolator) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100177 float val = 0.5f;
178 float adj = 0.25f;
179 while (adj >= 0.01f) {
180 if (interpolator.getInterpolation(val) < 0.99f) {
181 val += adj;
182 } else {
183 val -= adj;
184 }
185 adj /= 2;
186 }
187 return val;
188 }
189}