blob: 2ec2af0cf52514e9e230726cef28fd6fbd5e9051 [file] [log] [blame]
Joe Onoratoddf680b2010-09-26 13:59:40 -07001/*
2 * Copyright (C) 2010 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.systemui.statusbar.tablet;
18
Joe Onorato7c270fa2010-12-08 17:31:42 -080019import android.animation.Animator;
Daniel Sandler14db0bc2011-01-20 12:11:23 -050020import android.animation.AnimatorListenerAdapter;
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -050021import android.animation.AnimatorSet;
Joe Onorato7c270fa2010-12-08 17:31:42 -080022import android.animation.ObjectAnimator;
23import android.animation.ValueAnimator;
Joe Onoratoddf680b2010-09-26 13:59:40 -070024import android.content.Context;
Joe Onorato7c270fa2010-12-08 17:31:42 -080025import android.content.res.Resources;
26import android.graphics.Canvas;
27import android.graphics.Rect;
28import android.graphics.drawable.Drawable;
Joe Onoratoddf680b2010-09-26 13:59:40 -070029import android.util.AttributeSet;
Joe Onorato8a576712010-11-15 16:50:34 -080030import android.util.Slog;
Joe Onoratocf2b1992010-11-16 21:36:42 -080031import android.view.LayoutInflater;
Joe Onorato8a576712010-11-15 16:50:34 -080032import android.view.View;
Joe Onorato7c270fa2010-12-08 17:31:42 -080033import android.view.ViewGroup;
34import android.view.animation.AccelerateInterpolator;
Joe Onorato8a576712010-11-15 16:50:34 -080035import android.widget.FrameLayout;
Daniel Sandler14db0bc2011-01-20 12:11:23 -050036import android.widget.FrameLayout;
Joe Onorato4cddc982010-11-21 11:48:15 -080037import android.widget.ImageView;
38import android.widget.LinearLayout;
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -050039import android.widget.RelativeLayout;
Joe Onorato4cddc982010-11-21 11:48:15 -080040import android.widget.TextView;
Joe Onoratoddf680b2010-09-26 13:59:40 -070041
Joe Onoratofd52b182010-11-10 18:00:52 -080042import com.android.systemui.R;
Joe Onoratoddf680b2010-09-26 13:59:40 -070043
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -050044public class NotificationPanel extends RelativeLayout implements StatusBarPanel,
Joe Onorato8a576712010-11-15 16:50:34 -080045 View.OnClickListener {
Daniel Sandleref6e9362010-12-17 14:50:03 -050046 static final String TAG = "Tablet/NotificationPanel";
47 static final boolean DEBUG = false;
Joe Onorato8a576712010-11-15 16:50:34 -080048
Daniel Sandler40c15452011-01-22 01:26:22 -050049 final static int PANEL_FADE_DURATION = 150;
50
Joe Onorato7c270fa2010-12-08 17:31:42 -080051 boolean mShowing;
Daniel Sandler40c15452011-01-22 01:26:22 -050052 int mNotificationCount = 0;
Joe Onoratocf2b1992010-11-16 21:36:42 -080053 View mTitleArea;
Daniel Sandlerbc5d9bb2011-01-20 00:13:11 -050054 View mModeToggle;
Joe Onorato8a576712010-11-15 16:50:34 -080055 View mSettingsButton;
56 View mNotificationButton;
57 View mNotificationScroller;
Joe Onorato7c270fa2010-12-08 17:31:42 -080058 ViewGroup mContentFrame;
Joe Onorato6223fba2011-01-18 18:00:30 -080059 Rect mContentArea = new Rect();
Joe Onorato755cc742010-11-27 15:45:35 -080060 View mSettingsView;
Joe Onorato7c270fa2010-12-08 17:31:42 -080061 ViewGroup mContentParent;
62
Daniel Sandler641a4992011-01-26 21:19:10 -050063 // amount to slide mContentParent down by when mContentFrame is missing
64 float mContentFrameMissingTranslation;
65
Joe Onorato7c270fa2010-12-08 17:31:42 -080066 Choreographer mChoreo = new Choreographer();
Joe Onorato8a576712010-11-15 16:50:34 -080067
Joe Onoratoddf680b2010-09-26 13:59:40 -070068 public NotificationPanel(Context context, AttributeSet attrs) {
69 this(context, attrs, 0);
70 }
71
72 public NotificationPanel(Context context, AttributeSet attrs, int defStyle) {
73 super(context, attrs, defStyle);
74 }
75
Joe Onorato8a576712010-11-15 16:50:34 -080076 @Override
77 public void onFinishInflate() {
78 super.onFinishInflate();
79
Joe Onorato7c270fa2010-12-08 17:31:42 -080080 setWillNotDraw(false);
81
82 mContentParent = (ViewGroup)findViewById(R.id.content_parent);
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -050083 mContentParent.bringToFront();
Joe Onoratocf2b1992010-11-16 21:36:42 -080084 mTitleArea = findViewById(R.id.title_area);
Daniel Sandlerbc5d9bb2011-01-20 00:13:11 -050085 mModeToggle = findViewById(R.id.mode_toggle);
86 mModeToggle.setOnClickListener(this);
Joe Onoratocf2b1992010-11-16 21:36:42 -080087
Joe Onorato8a576712010-11-15 16:50:34 -080088 mSettingsButton = (ImageView)findViewById(R.id.settings_button);
Joe Onorato8a576712010-11-15 16:50:34 -080089 mNotificationButton = (ImageView)findViewById(R.id.notification_button);
Joe Onorato8a576712010-11-15 16:50:34 -080090
Joe Onorato244e4152010-12-16 13:22:34 -080091 mNotificationScroller = findViewById(R.id.notification_scroller);
Joe Onorato7c270fa2010-12-08 17:31:42 -080092 mContentFrame = (ViewGroup)findViewById(R.id.content_frame);
Daniel Sandler641a4992011-01-26 21:19:10 -050093 mContentFrameMissingTranslation =
94 mContentFrame.getBackground().getMinimumHeight() + 10;
95
96 mShowing = false;
97
98 setContentFrameVisible(mNotificationCount > 0, false);
Joe Onorato7c270fa2010-12-08 17:31:42 -080099 }
100
101 public void show(boolean show, boolean animate) {
Daniel Sandler40c15452011-01-22 01:26:22 -0500102 if (show && !mShowing) {
Daniel Sandler641a4992011-01-26 21:19:10 -0500103 setContentFrameVisible(mSettingsView != null || mNotificationCount > 0, false);
Daniel Sandler40c15452011-01-22 01:26:22 -0500104 }
105
Joe Onorato7c270fa2010-12-08 17:31:42 -0800106 if (animate) {
107 if (mShowing != show) {
108 mShowing = show;
109 if (show) {
110 setVisibility(View.VISIBLE);
111 }
112 mChoreo.startAnimation(show);
113 }
114 } else {
115 mShowing = show;
116 setVisibility(show ? View.VISIBLE : View.GONE);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800117 }
118 }
119
120 /**
121 * Whether the panel is showing, or, if it's animating, whether it will be
122 * when the animation is done.
123 */
124 public boolean isShowing() {
125 return mShowing;
Joe Onorato8a576712010-11-15 16:50:34 -0800126 }
127
128 @Override
129 public void onVisibilityChanged(View v, int vis) {
130 super.onVisibilityChanged(v, vis);
131 // when we hide, put back the notifications
Daniel Sandler641a4992011-01-26 21:19:10 -0500132 if (vis != View.VISIBLE) {
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500133 if (mSettingsView != null) removeSettingsView();
134 mNotificationScroller.setVisibility(View.VISIBLE);
135 mNotificationScroller.setAlpha(1f);
Joe Onorato43861912010-11-27 16:08:58 -0800136 mNotificationScroller.scrollTo(0, 0);
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500137 updatePanelModeButtons();
Joe Onorato8a576712010-11-15 16:50:34 -0800138 }
139 }
140
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500141 /*
Joe Onorato4cddc982010-11-21 11:48:15 -0800142 @Override
143 protected void onLayout(boolean changed, int l, int t, int r, int b) {
144 super.onLayout(changed, l, t, r, b);
Daniel Sandler2f447aa2011-01-14 16:39:19 -0500145
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500146 if (DEBUG) Slog.d(TAG, String.format("PANEL: onLayout: (%d, %d, %d, %d)", l, t, r, b));
Joe Onorato7c270fa2010-12-08 17:31:42 -0800147 }
148
149 @Override
150 public void onSizeChanged(int w, int h, int oldw, int oldh) {
151 super.onSizeChanged(w, h, oldw, oldh);
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500152
153 if (DEBUG) {
154 Slog.d(TAG, String.format("PANEL: onSizeChanged: (%d -> %d, %d -> %d)",
155 oldw, w, oldh, h));
156 }
Joe Onorato4cddc982010-11-21 11:48:15 -0800157 }
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500158 */
Joe Onorato4cddc982010-11-21 11:48:15 -0800159
Joe Onorato8a576712010-11-15 16:50:34 -0800160 public void onClick(View v) {
Daniel Sandlerbc5d9bb2011-01-20 00:13:11 -0500161 if (v == mModeToggle) {
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500162 swapPanels();
Joe Onorato8a576712010-11-15 16:50:34 -0800163 }
164 }
165
Daniel Sandler40c15452011-01-22 01:26:22 -0500166 public void setNotificationCount(int n) {
167 Slog.d(TAG, "notificationCount=" + n);
168 if (!mShowing) {
169 // just do it, already
170 setContentFrameVisible(n > 0, false);
171 } else if (mSettingsView == null) {
172 // we're looking at the notifications; time to maybe make some changes
Daniel Sandler2c831802011-01-30 21:26:24 -0500173 if ((mNotificationCount > 0) != (n > 0)) {
Daniel Sandler641a4992011-01-26 21:19:10 -0500174 setContentFrameVisible(n > 0, true);
Daniel Sandler40c15452011-01-22 01:26:22 -0500175 }
176 }
177 mNotificationCount = n;
178 }
179
180 public void setContentFrameVisible(final boolean showing, boolean animate) {
181 if (!animate) {
182 mContentFrame.setVisibility(showing ? View.VISIBLE : View.GONE);
Daniel Sandler641a4992011-01-26 21:19:10 -0500183 mContentFrame.setAlpha(1f);
184 // the translation will be patched up when the window is slid into place
Daniel Sandler40c15452011-01-22 01:26:22 -0500185 return;
186 }
187
Daniel Sandler641a4992011-01-26 21:19:10 -0500188 if (showing) {
189 mContentFrame.setVisibility(View.VISIBLE);
190 }
Daniel Sandler40c15452011-01-22 01:26:22 -0500191 AnimatorSet set = new AnimatorSet();
Daniel Sandler40c15452011-01-22 01:26:22 -0500192 set.play(ObjectAnimator.ofFloat(
193 mContentFrame, "alpha",
194 showing ? 0f : 1f,
195 showing ? 1f : 0f))
196 .with(ObjectAnimator.ofFloat(
197 mContentParent, "translationY",
Daniel Sandler641a4992011-01-26 21:19:10 -0500198 showing ? mContentFrameMissingTranslation : 0f,
199 showing ? 0f : mContentFrameMissingTranslation))
200 ;
201
Daniel Sandler40c15452011-01-22 01:26:22 -0500202 set.setDuration(200);
Daniel Sandler641a4992011-01-26 21:19:10 -0500203 if (!showing) {
204 set.addListener(new AnimatorListenerAdapter() {
205 @Override
206 public void onAnimationEnd(Animator _a) {
207 mContentFrame.setVisibility(View.GONE);
208 mContentFrame.setAlpha(1f);
209 }
210 });
211 }
Daniel Sandler40c15452011-01-22 01:26:22 -0500212 set.start();
213 }
Joe Onorato8a576712010-11-15 16:50:34 -0800214
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500215 public void swapPanels() {
216 final View toShow, toHide;
217 if (mSettingsView == null) {
218 addSettingsView();
219 toShow = mSettingsView;
220 toHide = mNotificationScroller;
221 } else {
222 toShow = mNotificationScroller;
223 toHide = mSettingsView;
224 }
225 Animator a = ObjectAnimator.ofFloat(toHide, "alpha", 1f, 0f)
226 .setDuration(PANEL_FADE_DURATION);
227 a.addListener(new AnimatorListenerAdapter() {
228 @Override
229 public void onAnimationEnd(Animator _a) {
230 toHide.setVisibility(View.GONE);
Daniel Sandler40c15452011-01-22 01:26:22 -0500231 if (toShow != null) {
232 if (mNotificationCount == 0) {
233 // show the frame for settings, hide for notifications
234 setContentFrameVisible(toShow == mSettingsView, true);
235 }
236
237 toShow.setVisibility(View.VISIBLE);
238 if (toShow == mSettingsView || mNotificationCount > 0) {
239 ObjectAnimator.ofFloat(toShow, "alpha", 0f, 1f)
240 .setDuration(PANEL_FADE_DURATION)
241 .start();
242 }
243
244 if (toHide == mSettingsView) {
245 removeSettingsView();
246 }
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500247 }
248 updatePanelModeButtons();
249 }
250 });
251 a.start();
252 }
253
254 public void updatePanelModeButtons() {
255 final boolean settingsVisible = (mSettingsView != null);
256 mSettingsButton.setVisibility(!settingsVisible ? View.VISIBLE : View.INVISIBLE);
257 mNotificationButton.setVisibility(settingsVisible ? View.VISIBLE : View.INVISIBLE);
Joe Onorato8a576712010-11-15 16:50:34 -0800258 }
259
Joe Onoratoddf680b2010-09-26 13:59:40 -0700260 public boolean isInContentArea(int x, int y) {
Daniel Sandler641a4992011-01-26 21:19:10 -0500261 mContentArea.left = mTitleArea.getLeft() + mTitleArea.getPaddingLeft();
262 mContentArea.top = mTitleArea.getTop() + mTitleArea.getPaddingTop()
263 + (int)mContentParent.getTranslationY(); // account for any adjustment
264 mContentArea.right = mTitleArea.getRight() - mTitleArea.getPaddingRight();
265
266 View theBottom = (mContentFrame.getVisibility() == View.VISIBLE)
267 ? mContentFrame : mTitleArea;
268 mContentArea.bottom = theBottom.getBottom() - theBottom.getPaddingBottom();
269
Joe Onorato6223fba2011-01-18 18:00:30 -0800270 offsetDescendantRectToMyCoords(mContentParent, mContentArea);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800271 return mContentArea.contains(x, y);
Joe Onoratoddf680b2010-09-26 13:59:40 -0700272 }
Joe Onorato8a576712010-11-15 16:50:34 -0800273
Joe Onorato755cc742010-11-27 15:45:35 -0800274 void removeSettingsView() {
275 if (mSettingsView != null) {
276 mContentFrame.removeView(mSettingsView);
277 mSettingsView = null;
Joe Onorato8a576712010-11-15 16:50:34 -0800278 }
279 }
280
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500281 // NB: it will be invisible until you show it
Joe Onorato755cc742010-11-27 15:45:35 -0800282 void addSettingsView() {
Joe Onoratocf2b1992010-11-16 21:36:42 -0800283 LayoutInflater infl = LayoutInflater.from(getContext());
Joe Onorato755cc742010-11-27 15:45:35 -0800284 mSettingsView = infl.inflate(R.layout.status_bar_settings_view, mContentFrame, false);
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500285 mSettingsView.setVisibility(View.GONE);
Daniel Sandler2f447aa2011-01-14 16:39:19 -0500286 mContentFrame.addView(mSettingsView);
Joe Onorato8a576712010-11-15 16:50:34 -0800287 }
Joe Onorato7c270fa2010-12-08 17:31:42 -0800288
289 private class Choreographer implements Animator.AnimatorListener {
Joe Onorato244e4152010-12-16 13:22:34 -0800290 boolean mVisible;
Joe Onorato7c270fa2010-12-08 17:31:42 -0800291 int mPanelHeight;
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500292 AnimatorSet mContentAnim;
Joe Onorato7c270fa2010-12-08 17:31:42 -0800293
294 // should group this into a multi-property animation
Daniel Sandler14db0bc2011-01-20 12:11:23 -0500295 final static int OPEN_DURATION = 136;
296 final static int CLOSE_DURATION = 250;
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500297
298 // the panel will start to appear this many px from the end
Daniel Sandleradd26202011-01-20 02:53:43 -0500299 final int HYPERSPACE_OFFRAMP = 100;
Joe Onorato7c270fa2010-12-08 17:31:42 -0800300
301 Choreographer() {
302 }
303
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500304 void createAnimation(boolean appearing) {
Daniel Sandleradd26202011-01-20 02:53:43 -0500305 // mVisible: previous state; appearing: new state
306
307 View root = findViewById(R.id.panel_root);
308 Animator bgAnim = ObjectAnimator.ofInt(root.getBackground(), "alpha",
309 mVisible ? 255 : 0, appearing ? 255 : 0);
Joe Onorato7c270fa2010-12-08 17:31:42 -0800310
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500311 float start, end;
Joe Onorato7c270fa2010-12-08 17:31:42 -0800312
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500313 // 0: on-screen
314 // height: off-screen
315 float y = mContentParent.getTranslationY();
316 if (appearing) {
317 // we want to go from near-the-top to the top, unless we're half-open in the right
318 // general vicinity
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500319 end = 0;
Daniel Sandler641a4992011-01-26 21:19:10 -0500320 if (mNotificationCount == 0) {
321 end += mContentFrameMissingTranslation;
322 }
Daniel Sandler8c989182011-01-30 01:24:09 -0500323 start = HYPERSPACE_OFFRAMP+end;
Joe Onorato7c270fa2010-12-08 17:31:42 -0800324 } else {
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500325 start = y;
326 end = y + HYPERSPACE_OFFRAMP;
Joe Onorato7c270fa2010-12-08 17:31:42 -0800327 }
Daniel Sandler641a4992011-01-26 21:19:10 -0500328
Daniel Sandleradd26202011-01-20 02:53:43 -0500329 Animator posAnim = ObjectAnimator.ofFloat(mContentParent, "translationY",
330 start, end);
Jim Miller85babff2011-01-11 14:26:03 -0800331 posAnim.setInterpolator(appearing
Daniel Sandleradd26202011-01-20 02:53:43 -0500332 ? new android.view.animation.DecelerateInterpolator(1.0f)
333 : new android.view.animation.AccelerateInterpolator(1.0f));
Joe Onorato7c270fa2010-12-08 17:31:42 -0800334
Daniel Sandlerf844dc42011-01-24 23:44:47 -0500335 if (mContentAnim != null && mContentAnim.isRunning()) {
336 mContentAnim.cancel();
337 }
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500338
Daniel Sandler8c989182011-01-30 01:24:09 -0500339 Animator fadeAnim = ObjectAnimator.ofFloat(mContentParent, "alpha",
340 mContentParent.getAlpha(), appearing ? 1.0f : 0.0f);
341 fadeAnim.setInterpolator(appearing
342 ? new android.view.animation.AccelerateInterpolator(2.0f)
343 : new android.view.animation.DecelerateInterpolator(2.0f));
344
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500345 mContentAnim = new AnimatorSet();
346 mContentAnim
Daniel Sandler8c989182011-01-30 01:24:09 -0500347 .play(fadeAnim)
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500348 .with(bgAnim)
349 .with(posAnim)
350 ;
Daniel Sandleradd26202011-01-20 02:53:43 -0500351 mContentAnim.setDuration((DEBUG?10:1)*(appearing ? OPEN_DURATION : CLOSE_DURATION));
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500352 mContentAnim.addListener(this);
353 }
354
355 void startAnimation(boolean appearing) {
356 if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
357
358 createAnimation(appearing);
359
360 mContentParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
361 mContentAnim.start();
362
363 mVisible = appearing;
364 }
365
Joe Onorato7c270fa2010-12-08 17:31:42 -0800366 public void onAnimationCancel(Animator animation) {
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500367 if (DEBUG) Slog.d(TAG, "onAnimationCancel");
Joe Onorato7c270fa2010-12-08 17:31:42 -0800368 }
369
370 public void onAnimationEnd(Animator animation) {
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500371 if (DEBUG) Slog.d(TAG, "onAnimationEnd");
372 if (! mVisible) {
Joe Onorato7c270fa2010-12-08 17:31:42 -0800373 setVisibility(View.GONE);
374 }
Daniel Sandler7d9ea8c2011-01-11 10:28:58 -0500375 mContentParent.setLayerType(View.LAYER_TYPE_NONE, null);
376 mContentAnim = null;
Joe Onorato7c270fa2010-12-08 17:31:42 -0800377 }
378
379 public void onAnimationRepeat(Animator animation) {
380 }
381
382 public void onAnimationStart(Animator animation) {
383 }
384 }
Joe Onoratoddf680b2010-09-26 13:59:40 -0700385}
386