blob: da23f451a6b54431358ef4c561a47d618b9c92ee [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);
75 statusbar.appTransitionStarting(startTime, TRANSITION_DURATION);
76 }
77 } catch (RemoteException e) {
78 Slog.e(mTag, "RemoteException when app transition is starting", e);
79 // re-acquire status bar service next time it is needed.
80 mStatusBarService = null;
81 }
82 }
83 });
84 }
85
86 @Override
87 public void onAppTransitionCancelledLocked() {
88 mHandler.post(new Runnable() {
89 @Override
90 public void run() {
91 try {
92 IStatusBarService statusbar = getStatusBarService();
93 if (statusbar != null) {
94 statusbar.appTransitionCancelled();
95 }
96 } catch (RemoteException e) {
97 Slog.e(mTag, "RemoteException when app transition is cancelled", e);
98 // re-acquire status bar service next time it is needed.
99 mStatusBarService = null;
100 }
101 }
102 });
103 }
104 };
105
106 public StatusBarController() {
107 super("StatusBar",
108 View.STATUS_BAR_TRANSIENT,
109 View.STATUS_BAR_UNHIDE,
110 View.STATUS_BAR_TRANSLUCENT,
111 StatusBarManager.WINDOW_STATUS_BAR,
112 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
113 }
114
115 public AppTransitionListener getAppTransitionListener() {
116 return mAppTransitionListener;
117 }
118
119 /**
120 * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
121 * calculates the timings for the corresponding status bar transition.
122 *
123 * @return the desired start time of the status bar transition, in uptime millis
124 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700125 private static long calculateStatusBarTransitionStartTime(Animation openAnimation,
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100126 Animation closeAnimation) {
127 if (openAnimation != null && closeAnimation != null) {
128 TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
129 TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
130 if (openTranslateAnimation != null) {
131
132 // Some interpolators are extremely quickly mostly finished, but not completely. For
133 // our purposes, we need to find the fraction for which ther interpolator is mostly
134 // there, and use that value for the calculation.
135 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
136 return SystemClock.uptimeMillis()
137 + openTranslateAnimation.getStartOffset()
138 + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
139 } else if (closeTranslateAnimation != null) {
140 return SystemClock.uptimeMillis();
141 } else {
142 return SystemClock.uptimeMillis();
143 }
144 } else {
145 return SystemClock.uptimeMillis();
146 }
147 }
148
149 /**
150 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
151 *
152 * @return the found animation, {@code null} otherwise
153 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700154 private static TranslateAnimation findTranslateAnimation(Animation animation) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100155 if (animation instanceof TranslateAnimation) {
156 return (TranslateAnimation) animation;
157 } else if (animation instanceof AnimationSet) {
158 AnimationSet set = (AnimationSet) animation;
159 for (int i = 0; i < set.getAnimations().size(); i++) {
160 Animation a = set.getAnimations().get(i);
161 if (a instanceof TranslateAnimation) {
162 return (TranslateAnimation) a;
163 }
164 }
165 }
166 return null;
167 }
168
169 /**
170 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
171 * {@code interpolator(t + eps) > 0.99}.
172 */
Filip Gruszczynski170192a2015-08-16 17:46:34 -0700173 private static float findAlmostThereFraction(Interpolator interpolator) {
Jorim Jaggi24bec7c2015-02-04 12:40:14 +0100174 float val = 0.5f;
175 float adj = 0.25f;
176 while (adj >= 0.01f) {
177 if (interpolator.getInterpolation(val) < 0.99f) {
178 val += adj;
179 } else {
180 val -= adj;
181 }
182 adj /= 2;
183 }
184 return val;
185 }
186}