Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.systemui.statusbar.tablet; |
| 18 | |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 19 | import android.animation.Animator; |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 20 | import android.animation.AnimatorListenerAdapter; |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 21 | import android.animation.AnimatorSet; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 22 | import android.animation.ObjectAnimator; |
Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 23 | import android.content.Context; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 24 | import android.graphics.Rect; |
Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 25 | import android.util.AttributeSet; |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 26 | import android.util.Slog; |
Chris Wren | 9b2cd15 | 2012-06-11 10:39:36 -0400 | [diff] [blame^] | 27 | import android.view.Gravity; |
Joe Onorato | cf2b199 | 2010-11-16 21:36:42 -0800 | [diff] [blame] | 28 | import android.view.LayoutInflater; |
Daniel Sandler | 8f491b5 | 2011-03-03 00:00:22 -0500 | [diff] [blame] | 29 | import android.view.MotionEvent; |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 30 | import android.view.View; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 31 | import android.view.ViewGroup; |
Chet Haase | 41bff38 | 2011-08-29 16:00:23 -0700 | [diff] [blame] | 32 | import android.view.ViewTreeObserver; |
| 33 | import android.view.animation.AccelerateInterpolator; |
| 34 | import android.view.animation.DecelerateInterpolator; |
| 35 | import android.view.animation.Interpolator; |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 36 | import android.widget.RelativeLayout; |
Chris Wren | 9b2cd15 | 2012-06-11 10:39:36 -0400 | [diff] [blame^] | 37 | import android.widget.ScrollView; |
Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 38 | |
Chris Wren | 1e8f65d | 2012-06-06 18:08:56 -0400 | [diff] [blame] | 39 | import com.android.systemui.ExpandHelper; |
Joe Onorato | fd52b18 | 2010-11-10 18:00:52 -0800 | [diff] [blame] | 40 | import com.android.systemui.R; |
Chris Wren | 1e8f65d | 2012-06-06 18:08:56 -0400 | [diff] [blame] | 41 | import com.android.systemui.statusbar.policy.NotificationRowLayout; |
Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 42 | |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 43 | public class NotificationPanel extends RelativeLayout implements StatusBarPanel, |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 44 | View.OnClickListener { |
Chris Wren | 1e8f65d | 2012-06-06 18:08:56 -0400 | [diff] [blame] | 45 | private ExpandHelper mExpandHelper; |
| 46 | private NotificationRowLayout latestItems; |
| 47 | |
Daniel Sandler | ef6e936 | 2010-12-17 14:50:03 -0500 | [diff] [blame] | 48 | static final String TAG = "Tablet/NotificationPanel"; |
| 49 | static final boolean DEBUG = false; |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 50 | |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 51 | final static int PANEL_FADE_DURATION = 150; |
| 52 | |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 53 | boolean mShowing; |
Daniel Sandler | 06a0d4b | 2011-08-05 00:19:21 -0400 | [diff] [blame] | 54 | boolean mHasClearableNotifications = false; |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 55 | int mNotificationCount = 0; |
Svetoslav Ganov | 6179ea3 | 2011-06-28 01:12:41 -0700 | [diff] [blame] | 56 | NotificationPanelTitle mTitleArea; |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 57 | View mSettingsButton; |
| 58 | View mNotificationButton; |
| 59 | View mNotificationScroller; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 60 | ViewGroup mContentFrame; |
Joe Onorato | 6223fba | 2011-01-18 18:00:30 -0800 | [diff] [blame] | 61 | Rect mContentArea = new Rect(); |
Joe Onorato | 755cc74 | 2010-11-27 15:45:35 -0800 | [diff] [blame] | 62 | View mSettingsView; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 63 | ViewGroup mContentParent; |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 64 | TabletStatusBar mBar; |
Daniel Sandler | 06a0d4b | 2011-08-05 00:19:21 -0400 | [diff] [blame] | 65 | View mClearButton; |
Chet Haase | 41bff38 | 2011-08-29 16:00:23 -0700 | [diff] [blame] | 66 | static Interpolator sAccelerateInterpolator = new AccelerateInterpolator(); |
| 67 | static Interpolator sDecelerateInterpolator = new DecelerateInterpolator(); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 68 | |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 69 | // amount to slide mContentParent down by when mContentFrame is missing |
| 70 | float mContentFrameMissingTranslation; |
| 71 | |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 72 | Choreographer mChoreo = new Choreographer(); |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 73 | |
Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 74 | public NotificationPanel(Context context, AttributeSet attrs) { |
| 75 | this(context, attrs, 0); |
| 76 | } |
| 77 | |
| 78 | public NotificationPanel(Context context, AttributeSet attrs, int defStyle) { |
| 79 | super(context, attrs, defStyle); |
| 80 | } |
| 81 | |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 82 | public void setBar(TabletStatusBar b) { |
| 83 | mBar = b; |
| 84 | } |
| 85 | |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 86 | @Override |
| 87 | public void onFinishInflate() { |
| 88 | super.onFinishInflate(); |
| 89 | |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 90 | setWillNotDraw(false); |
| 91 | |
| 92 | mContentParent = (ViewGroup)findViewById(R.id.content_parent); |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 93 | mContentParent.bringToFront(); |
Svetoslav Ganov | 6179ea3 | 2011-06-28 01:12:41 -0700 | [diff] [blame] | 94 | mTitleArea = (NotificationPanelTitle) findViewById(R.id.title_area); |
| 95 | mTitleArea.setPanel(this); |
Joe Onorato | cf2b199 | 2010-11-16 21:36:42 -0800 | [diff] [blame] | 96 | |
Svetoslav Ganov | 6179ea3 | 2011-06-28 01:12:41 -0700 | [diff] [blame] | 97 | mSettingsButton = findViewById(R.id.settings_button); |
| 98 | mNotificationButton = findViewById(R.id.notification_button); |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 99 | |
Joe Onorato | 244e415 | 2010-12-16 13:22:34 -0800 | [diff] [blame] | 100 | mNotificationScroller = findViewById(R.id.notification_scroller); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 101 | mContentFrame = (ViewGroup)findViewById(R.id.content_frame); |
Daniel Sandler | 06a0d4b | 2011-08-05 00:19:21 -0400 | [diff] [blame] | 102 | mContentFrameMissingTranslation = 0; // not needed with current assets |
| 103 | |
| 104 | // the "X" that appears in place of the clock when the panel is showing notifications |
| 105 | mClearButton = findViewById(R.id.clear_all_button); |
| 106 | mClearButton.setOnClickListener(mClearButtonListener); |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 107 | |
| 108 | mShowing = false; |
| 109 | |
| 110 | setContentFrameVisible(mNotificationCount > 0, false); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 111 | } |
| 112 | |
Chris Wren | 1e8f65d | 2012-06-06 18:08:56 -0400 | [diff] [blame] | 113 | @Override |
| 114 | protected void onAttachedToWindow () { |
| 115 | super.onAttachedToWindow(); |
| 116 | latestItems = (NotificationRowLayout) findViewById(R.id.content); |
| 117 | int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height); |
| 118 | int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height); |
| 119 | mExpandHelper = new ExpandHelper(mContext, latestItems, minHeight, maxHeight); |
| 120 | mExpandHelper.setEventSource(this); |
Chris Wren | 9b2cd15 | 2012-06-11 10:39:36 -0400 | [diff] [blame^] | 121 | mExpandHelper.setGravity(Gravity.BOTTOM); |
Chris Wren | 1e8f65d | 2012-06-06 18:08:56 -0400 | [diff] [blame] | 122 | } |
| 123 | |
Daniel Sandler | 06a0d4b | 2011-08-05 00:19:21 -0400 | [diff] [blame] | 124 | private View.OnClickListener mClearButtonListener = new View.OnClickListener() { |
| 125 | public void onClick(View v) { |
| 126 | mBar.clearAll(); |
| 127 | } |
| 128 | }; |
| 129 | |
| 130 | public View getClearButton() { |
| 131 | return mClearButton; |
| 132 | } |
| 133 | |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 134 | public void show(boolean show, boolean animate) { |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 135 | if (show && !mShowing) { |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 136 | setContentFrameVisible(mSettingsView != null || mNotificationCount > 0, false); |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 137 | } |
| 138 | |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 139 | if (animate) { |
| 140 | if (mShowing != show) { |
| 141 | mShowing = show; |
| 142 | if (show) { |
| 143 | setVisibility(View.VISIBLE); |
Chet Haase | 41bff38 | 2011-08-29 16:00:23 -0700 | [diff] [blame] | 144 | // Don't start the animation until we've created the layer, which is done |
| 145 | // right before we are drawn |
| 146 | mContentParent.setLayerType(View.LAYER_TYPE_HARDWARE, null); |
| 147 | getViewTreeObserver().addOnPreDrawListener(mPreDrawListener); |
| 148 | } else { |
| 149 | mChoreo.startAnimation(show); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 150 | } |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 151 | } |
| 152 | } else { |
| 153 | mShowing = show; |
| 154 | setVisibility(show ? View.VISIBLE : View.GONE); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 155 | } |
| 156 | } |
| 157 | |
| 158 | /** |
Chet Haase | 41bff38 | 2011-08-29 16:00:23 -0700 | [diff] [blame] | 159 | * This is used only when we've created a hardware layer and are waiting until it's |
| 160 | * been created in order to start the appearing animation. |
| 161 | */ |
| 162 | private ViewTreeObserver.OnPreDrawListener mPreDrawListener = |
| 163 | new ViewTreeObserver.OnPreDrawListener() { |
| 164 | @Override |
| 165 | public boolean onPreDraw() { |
| 166 | getViewTreeObserver().removeOnPreDrawListener(this); |
| 167 | mChoreo.startAnimation(true); |
Chet Haase | 3c4ce72 | 2011-09-02 15:37:25 -0700 | [diff] [blame] | 168 | return false; |
Chet Haase | 41bff38 | 2011-08-29 16:00:23 -0700 | [diff] [blame] | 169 | } |
| 170 | }; |
| 171 | |
| 172 | /** |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 173 | * Whether the panel is showing, or, if it's animating, whether it will be |
| 174 | * when the animation is done. |
| 175 | */ |
| 176 | public boolean isShowing() { |
| 177 | return mShowing; |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | @Override |
| 181 | public void onVisibilityChanged(View v, int vis) { |
| 182 | super.onVisibilityChanged(v, vis); |
| 183 | // when we hide, put back the notifications |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 184 | if (vis != View.VISIBLE) { |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 185 | if (mSettingsView != null) removeSettingsView(); |
| 186 | mNotificationScroller.setVisibility(View.VISIBLE); |
| 187 | mNotificationScroller.setAlpha(1f); |
Joe Onorato | 4386191 | 2010-11-27 16:08:58 -0800 | [diff] [blame] | 188 | mNotificationScroller.scrollTo(0, 0); |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 189 | updatePanelModeButtons(); |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 190 | } |
| 191 | } |
| 192 | |
Svetoslav Ganov | 6179ea3 | 2011-06-28 01:12:41 -0700 | [diff] [blame] | 193 | @Override |
| 194 | public boolean dispatchHoverEvent(MotionEvent event) { |
| 195 | // Ignore hover events outside of this panel bounds since such events |
| 196 | // generate spurious accessibility events with the panel content when |
| 197 | // tapping outside of it, thus confusing the user. |
| 198 | final int x = (int) event.getX(); |
| 199 | final int y = (int) event.getY(); |
| 200 | if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) { |
| 201 | return super.dispatchHoverEvent(event); |
| 202 | } |
| 203 | return true; |
| 204 | } |
| 205 | |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 206 | /* |
Joe Onorato | 4cddc98 | 2010-11-21 11:48:15 -0800 | [diff] [blame] | 207 | @Override |
| 208 | protected void onLayout(boolean changed, int l, int t, int r, int b) { |
| 209 | super.onLayout(changed, l, t, r, b); |
Daniel Sandler | 2f447aa | 2011-01-14 16:39:19 -0500 | [diff] [blame] | 210 | |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 211 | if (DEBUG) Slog.d(TAG, String.format("PANEL: onLayout: (%d, %d, %d, %d)", l, t, r, b)); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | @Override |
| 215 | public void onSizeChanged(int w, int h, int oldw, int oldh) { |
| 216 | super.onSizeChanged(w, h, oldw, oldh); |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 217 | |
| 218 | if (DEBUG) { |
| 219 | Slog.d(TAG, String.format("PANEL: onSizeChanged: (%d -> %d, %d -> %d)", |
| 220 | oldw, w, oldh, h)); |
| 221 | } |
Joe Onorato | 4cddc98 | 2010-11-21 11:48:15 -0800 | [diff] [blame] | 222 | } |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 223 | */ |
Joe Onorato | 4cddc98 | 2010-11-21 11:48:15 -0800 | [diff] [blame] | 224 | |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 225 | public void onClick(View v) { |
Svetoslav Ganov | 6179ea3 | 2011-06-28 01:12:41 -0700 | [diff] [blame] | 226 | if (v == mTitleArea) { |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 227 | swapPanels(); |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 228 | } |
| 229 | } |
| 230 | |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 231 | public void setNotificationCount(int n) { |
Daniel Sandler | 0ffc230 | 2011-03-02 14:33:09 -0500 | [diff] [blame] | 232 | // Slog.d(TAG, "notificationCount=" + n); |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 233 | if (!mShowing) { |
| 234 | // just do it, already |
| 235 | setContentFrameVisible(n > 0, false); |
| 236 | } else if (mSettingsView == null) { |
| 237 | // we're looking at the notifications; time to maybe make some changes |
Daniel Sandler | 2c83180 | 2011-01-30 21:26:24 -0500 | [diff] [blame] | 238 | if ((mNotificationCount > 0) != (n > 0)) { |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 239 | setContentFrameVisible(n > 0, true); |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 240 | } |
| 241 | } |
| 242 | mNotificationCount = n; |
| 243 | } |
| 244 | |
| 245 | public void setContentFrameVisible(final boolean showing, boolean animate) { |
| 246 | if (!animate) { |
| 247 | mContentFrame.setVisibility(showing ? View.VISIBLE : View.GONE); |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 248 | mContentFrame.setAlpha(1f); |
| 249 | // the translation will be patched up when the window is slid into place |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 250 | return; |
| 251 | } |
| 252 | |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 253 | if (showing) { |
| 254 | mContentFrame.setVisibility(View.VISIBLE); |
| 255 | } |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 256 | AnimatorSet set = new AnimatorSet(); |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 257 | set.play(ObjectAnimator.ofFloat( |
| 258 | mContentFrame, "alpha", |
| 259 | showing ? 0f : 1f, |
| 260 | showing ? 1f : 0f)) |
| 261 | .with(ObjectAnimator.ofFloat( |
| 262 | mContentParent, "translationY", |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 263 | showing ? mContentFrameMissingTranslation : 0f, |
| 264 | showing ? 0f : mContentFrameMissingTranslation)) |
| 265 | ; |
| 266 | |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 267 | set.setDuration(200); |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 268 | set.addListener(new AnimatorListenerAdapter() { |
| 269 | @Override |
| 270 | public void onAnimationEnd(Animator _a) { |
| 271 | if (!showing) { |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 272 | mContentFrame.setVisibility(View.GONE); |
| 273 | mContentFrame.setAlpha(1f); |
| 274 | } |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 275 | updateClearButton(); |
| 276 | } |
| 277 | }); |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 278 | set.start(); |
| 279 | } |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 280 | |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 281 | public void swapPanels() { |
| 282 | final View toShow, toHide; |
| 283 | if (mSettingsView == null) { |
| 284 | addSettingsView(); |
| 285 | toShow = mSettingsView; |
| 286 | toHide = mNotificationScroller; |
| 287 | } else { |
| 288 | toShow = mNotificationScroller; |
| 289 | toHide = mSettingsView; |
| 290 | } |
| 291 | Animator a = ObjectAnimator.ofFloat(toHide, "alpha", 1f, 0f) |
| 292 | .setDuration(PANEL_FADE_DURATION); |
| 293 | a.addListener(new AnimatorListenerAdapter() { |
| 294 | @Override |
| 295 | public void onAnimationEnd(Animator _a) { |
| 296 | toHide.setVisibility(View.GONE); |
Daniel Sandler | 40c1545 | 2011-01-22 01:26:22 -0500 | [diff] [blame] | 297 | if (toShow != null) { |
| 298 | if (mNotificationCount == 0) { |
| 299 | // show the frame for settings, hide for notifications |
| 300 | setContentFrameVisible(toShow == mSettingsView, true); |
| 301 | } |
| 302 | |
| 303 | toShow.setVisibility(View.VISIBLE); |
| 304 | if (toShow == mSettingsView || mNotificationCount > 0) { |
| 305 | ObjectAnimator.ofFloat(toShow, "alpha", 0f, 1f) |
| 306 | .setDuration(PANEL_FADE_DURATION) |
| 307 | .start(); |
| 308 | } |
| 309 | |
| 310 | if (toHide == mSettingsView) { |
| 311 | removeSettingsView(); |
| 312 | } |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 313 | } |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 314 | updateClearButton(); |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 315 | updatePanelModeButtons(); |
| 316 | } |
| 317 | }); |
| 318 | a.start(); |
| 319 | } |
| 320 | |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 321 | public void updateClearButton() { |
| 322 | if (mBar != null) { |
| 323 | final boolean showX |
| 324 | = (isShowing() |
Daniel Sandler | 06a0d4b | 2011-08-05 00:19:21 -0400 | [diff] [blame] | 325 | && mHasClearableNotifications |
| 326 | && mNotificationScroller.getVisibility() == View.VISIBLE); |
| 327 | getClearButton().setVisibility(showX ? View.VISIBLE : View.INVISIBLE); |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 328 | } |
| 329 | } |
| 330 | |
Daniel Sandler | 06a0d4b | 2011-08-05 00:19:21 -0400 | [diff] [blame] | 331 | public void setClearable(boolean clearable) { |
| 332 | mHasClearableNotifications = clearable; |
| 333 | } |
| 334 | |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 335 | public void updatePanelModeButtons() { |
| 336 | final boolean settingsVisible = (mSettingsView != null); |
Daniel Sandler | 5962fd5 | 2012-01-11 14:57:04 -0500 | [diff] [blame] | 337 | mSettingsButton.setVisibility(!settingsVisible ? View.VISIBLE : View.GONE); |
| 338 | mNotificationButton.setVisibility(settingsVisible ? View.VISIBLE : View.GONE); |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 339 | } |
| 340 | |
Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 341 | public boolean isInContentArea(int x, int y) { |
Chris Wren | 1e8f65d | 2012-06-06 18:08:56 -0400 | [diff] [blame] | 342 | mContentArea.left = mContentFrame.getLeft() + mContentFrame.getPaddingLeft(); |
| 343 | mContentArea.top = mContentFrame.getTop() + mContentFrame.getPaddingTop() |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 344 | + (int)mContentParent.getTranslationY(); // account for any adjustment |
Chris Wren | 1e8f65d | 2012-06-06 18:08:56 -0400 | [diff] [blame] | 345 | mContentArea.right = mContentFrame.getRight() - mContentFrame.getPaddingRight(); |
| 346 | mContentArea.bottom = mContentFrame.getBottom() - mContentFrame.getPaddingBottom(); |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 347 | |
Joe Onorato | 6223fba | 2011-01-18 18:00:30 -0800 | [diff] [blame] | 348 | offsetDescendantRectToMyCoords(mContentParent, mContentArea); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 349 | return mContentArea.contains(x, y); |
Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 350 | } |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 351 | |
Joe Onorato | 755cc74 | 2010-11-27 15:45:35 -0800 | [diff] [blame] | 352 | void removeSettingsView() { |
| 353 | if (mSettingsView != null) { |
| 354 | mContentFrame.removeView(mSettingsView); |
| 355 | mSettingsView = null; |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 356 | } |
| 357 | } |
| 358 | |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 359 | // NB: it will be invisible until you show it |
Joe Onorato | 755cc74 | 2010-11-27 15:45:35 -0800 | [diff] [blame] | 360 | void addSettingsView() { |
Joe Onorato | cf2b199 | 2010-11-16 21:36:42 -0800 | [diff] [blame] | 361 | LayoutInflater infl = LayoutInflater.from(getContext()); |
Daniel Sandler | 4a066c5 | 2012-04-20 14:49:13 -0400 | [diff] [blame] | 362 | mSettingsView = infl.inflate(R.layout.system_bar_settings_view, mContentFrame, false); |
Daniel Sandler | 14db0bc | 2011-01-20 12:11:23 -0500 | [diff] [blame] | 363 | mSettingsView.setVisibility(View.GONE); |
Daniel Sandler | 2f447aa | 2011-01-14 16:39:19 -0500 | [diff] [blame] | 364 | mContentFrame.addView(mSettingsView); |
Joe Onorato | 8a57671 | 2010-11-15 16:50:34 -0800 | [diff] [blame] | 365 | } |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 366 | |
| 367 | private class Choreographer implements Animator.AnimatorListener { |
Joe Onorato | 244e415 | 2010-12-16 13:22:34 -0800 | [diff] [blame] | 368 | boolean mVisible; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 369 | int mPanelHeight; |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 370 | AnimatorSet mContentAnim; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 371 | |
| 372 | // should group this into a multi-property animation |
Chet Haase | 41bff38 | 2011-08-29 16:00:23 -0700 | [diff] [blame] | 373 | final static int OPEN_DURATION = 250; |
| 374 | final static int CLOSE_DURATION = 250; |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 375 | |
| 376 | // the panel will start to appear this many px from the end |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 377 | final int HYPERSPACE_OFFRAMP = 200; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 378 | |
| 379 | Choreographer() { |
| 380 | } |
| 381 | |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 382 | void createAnimation(boolean appearing) { |
Daniel Sandler | add2620 | 2011-01-20 02:53:43 -0500 | [diff] [blame] | 383 | // mVisible: previous state; appearing: new state |
| 384 | |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 385 | float start, end; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 386 | |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 387 | // 0: on-screen |
| 388 | // height: off-screen |
| 389 | float y = mContentParent.getTranslationY(); |
| 390 | if (appearing) { |
| 391 | // we want to go from near-the-top to the top, unless we're half-open in the right |
| 392 | // general vicinity |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 393 | end = 0; |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 394 | if (mNotificationCount == 0) { |
| 395 | end += mContentFrameMissingTranslation; |
| 396 | } |
Daniel Sandler | 8c98918 | 2011-01-30 01:24:09 -0500 | [diff] [blame] | 397 | start = HYPERSPACE_OFFRAMP+end; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 398 | } else { |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 399 | start = y; |
| 400 | end = y + HYPERSPACE_OFFRAMP; |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 401 | } |
Daniel Sandler | 641a499 | 2011-01-26 21:19:10 -0500 | [diff] [blame] | 402 | |
Daniel Sandler | add2620 | 2011-01-20 02:53:43 -0500 | [diff] [blame] | 403 | Animator posAnim = ObjectAnimator.ofFloat(mContentParent, "translationY", |
| 404 | start, end); |
Chet Haase | 41bff38 | 2011-08-29 16:00:23 -0700 | [diff] [blame] | 405 | posAnim.setInterpolator(appearing ? sDecelerateInterpolator : sAccelerateInterpolator); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 406 | |
Daniel Sandler | f844dc4 | 2011-01-24 23:44:47 -0500 | [diff] [blame] | 407 | if (mContentAnim != null && mContentAnim.isRunning()) { |
| 408 | mContentAnim.cancel(); |
| 409 | } |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 410 | |
Daniel Sandler | 8c98918 | 2011-01-30 01:24:09 -0500 | [diff] [blame] | 411 | Animator fadeAnim = ObjectAnimator.ofFloat(mContentParent, "alpha", |
Chet Haase | 41bff38 | 2011-08-29 16:00:23 -0700 | [diff] [blame] | 412 | appearing ? 1.0f : 0.0f); |
| 413 | fadeAnim.setInterpolator(appearing ? sAccelerateInterpolator : sDecelerateInterpolator); |
Daniel Sandler | 8c98918 | 2011-01-30 01:24:09 -0500 | [diff] [blame] | 414 | |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 415 | mContentAnim = new AnimatorSet(); |
| 416 | mContentAnim |
Daniel Sandler | 8c98918 | 2011-01-30 01:24:09 -0500 | [diff] [blame] | 417 | .play(fadeAnim) |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 418 | .with(posAnim) |
| 419 | ; |
Daniel Sandler | add2620 | 2011-01-20 02:53:43 -0500 | [diff] [blame] | 420 | mContentAnim.setDuration((DEBUG?10:1)*(appearing ? OPEN_DURATION : CLOSE_DURATION)); |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 421 | mContentAnim.addListener(this); |
| 422 | } |
| 423 | |
| 424 | void startAnimation(boolean appearing) { |
| 425 | if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")"); |
| 426 | |
| 427 | createAnimation(appearing); |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 428 | mContentAnim.start(); |
| 429 | |
| 430 | mVisible = appearing; |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 431 | |
| 432 | // we want to start disappearing promptly |
| 433 | if (!mVisible) updateClearButton(); |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 434 | } |
| 435 | |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 436 | public void onAnimationCancel(Animator animation) { |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 437 | if (DEBUG) Slog.d(TAG, "onAnimationCancel"); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 438 | } |
| 439 | |
| 440 | public void onAnimationEnd(Animator animation) { |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 441 | if (DEBUG) Slog.d(TAG, "onAnimationEnd"); |
| 442 | if (! mVisible) { |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 443 | setVisibility(View.GONE); |
| 444 | } |
Daniel Sandler | 7d9ea8c | 2011-01-11 10:28:58 -0500 | [diff] [blame] | 445 | mContentParent.setLayerType(View.LAYER_TYPE_NONE, null); |
| 446 | mContentAnim = null; |
Daniel Sandler | 1347c30 | 2011-08-01 16:47:53 -0400 | [diff] [blame] | 447 | |
| 448 | // we want to show the X lazily |
| 449 | if (mVisible) updateClearButton(); |
Joe Onorato | 7c270fa | 2010-12-08 17:31:42 -0800 | [diff] [blame] | 450 | } |
| 451 | |
| 452 | public void onAnimationRepeat(Animator animation) { |
| 453 | } |
| 454 | |
| 455 | public void onAnimationStart(Animator animation) { |
| 456 | } |
| 457 | } |
Chris Wren | 1e8f65d | 2012-06-06 18:08:56 -0400 | [diff] [blame] | 458 | |
| 459 | @Override |
| 460 | public boolean onInterceptTouchEvent(MotionEvent ev) { |
| 461 | MotionEvent cancellation = MotionEvent.obtain(ev); |
| 462 | cancellation.setAction(MotionEvent.ACTION_CANCEL); |
| 463 | |
| 464 | boolean intercept = mExpandHelper.onInterceptTouchEvent(ev) || |
| 465 | super.onInterceptTouchEvent(ev); |
| 466 | if (intercept) { |
| 467 | latestItems.onInterceptTouchEvent(cancellation); |
| 468 | } |
| 469 | return intercept; |
| 470 | } |
| 471 | |
| 472 | @Override |
| 473 | public boolean onTouchEvent(MotionEvent ev) { |
| 474 | boolean handled = mExpandHelper.onTouchEvent(ev) || |
| 475 | super.onTouchEvent(ev); |
| 476 | return handled; |
| 477 | } |
Joe Onorato | ddf680b | 2010-09-26 13:59:40 -0700 | [diff] [blame] | 478 | } |
| 479 | |