Kenny Root | 15a4d2f | 2010-03-11 18:20:12 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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 | |
Joe Onorato | fd52b18 | 2010-11-10 18:00:52 -0800 | [diff] [blame] | 17 | package com.android.systemui.statusbar.phone; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 18 | |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 19 | import android.app.ActivityManager; |
Daniel Sandler | 1e8feef | 2012-08-16 11:37:41 -0400 | [diff] [blame] | 20 | import android.app.StatusBarManager; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 21 | import android.content.Context; |
Daniel Sandler | 1c1edaa | 2012-08-14 11:14:45 -0400 | [diff] [blame] | 22 | import android.content.res.Resources; |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 23 | import android.content.res.Resources.NotFoundException; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 24 | import android.util.AttributeSet; |
Chris Wren | 64161cc | 2012-12-17 16:49:30 -0500 | [diff] [blame] | 25 | import android.util.EventLog; |
Daniel Sandler | 198a030 | 2012-08-17 16:04:31 -0400 | [diff] [blame] | 26 | import android.util.Slog; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 27 | import android.view.MotionEvent; |
| 28 | import android.view.View; |
Svetoslav Ganov | 6179ea3 | 2011-06-28 01:12:41 -0700 | [diff] [blame] | 29 | import android.view.accessibility.AccessibilityEvent; |
Chris Wren | 64161cc | 2012-12-17 16:49:30 -0500 | [diff] [blame] | 30 | |
| 31 | import com.android.systemui.EventLogTags; |
Joe Onorato | 79de0c5 | 2010-05-26 17:03:26 -0400 | [diff] [blame] | 32 | import com.android.systemui.R; |
| 33 | |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 34 | public class PhoneStatusBarView extends PanelBar { |
Joe Onorato | fd52b18 | 2010-11-10 18:00:52 -0800 | [diff] [blame] | 35 | private static final String TAG = "PhoneStatusBarView"; |
Daniel Sandler | 198a030 | 2012-08-17 16:04:31 -0400 | [diff] [blame] | 36 | private static final boolean DEBUG = PhoneStatusBar.DEBUG; |
Chris Wren | 64161cc | 2012-12-17 16:49:30 -0500 | [diff] [blame] | 37 | private static final boolean DEBUG_GESTURES = true; |
Daniel Sandler | 198a030 | 2012-08-17 16:04:31 -0400 | [diff] [blame] | 38 | |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 39 | PhoneStatusBar mBar; |
Daniel Sandler | 1c1edaa | 2012-08-14 11:14:45 -0400 | [diff] [blame] | 40 | int mScrimColor; |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 41 | float mSettingsPanelDragzoneFrac; |
| 42 | float mSettingsPanelDragzoneMin; |
| 43 | |
Chris Wren | b8ea2f5 | 2012-08-24 11:50:55 -0400 | [diff] [blame] | 44 | boolean mFullWidthNotifications; |
Daniel Sandler | 8e72c9e | 2012-08-15 00:09:26 -0400 | [diff] [blame] | 45 | PanelView mFadingPanel = null; |
Casey Burkhardt | bac221f | 2012-10-03 18:13:58 -0700 | [diff] [blame] | 46 | PanelView mLastFullyOpenedPanel = null; |
Daniel Sandler | cf591db | 2012-08-15 16:11:55 -0400 | [diff] [blame] | 47 | PanelView mNotificationPanel, mSettingsPanel; |
Daniel Sandler | 67eab79 | 2012-10-02 17:08:23 -0400 | [diff] [blame] | 48 | private boolean mShouldFade; |
Joe Onorato | 119a401 | 2010-06-30 14:49:51 -0400 | [diff] [blame] | 49 | |
Joe Onorato | fd52b18 | 2010-11-10 18:00:52 -0800 | [diff] [blame] | 50 | public PhoneStatusBarView(Context context, AttributeSet attrs) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 51 | super(context, attrs); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 52 | |
Daniel Sandler | 1c1edaa | 2012-08-14 11:14:45 -0400 | [diff] [blame] | 53 | Resources res = getContext().getResources(); |
| 54 | mScrimColor = res.getColor(R.color.notification_panel_scrim_color); |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 55 | mSettingsPanelDragzoneMin = res.getDimension(R.dimen.settings_panel_dragzone_min); |
Chris Wren | b8ea2f5 | 2012-08-24 11:50:55 -0400 | [diff] [blame] | 56 | try { |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 57 | mSettingsPanelDragzoneFrac = res.getFraction(R.dimen.settings_panel_dragzone_fraction, 1, 1); |
| 58 | } catch (NotFoundException ex) { |
| 59 | mSettingsPanelDragzoneFrac = 0f; |
Chris Wren | b8ea2f5 | 2012-08-24 11:50:55 -0400 | [diff] [blame] | 60 | } |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 61 | mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f; |
Daniel Sandler | 1c1edaa | 2012-08-14 11:14:45 -0400 | [diff] [blame] | 62 | } |
| 63 | |
Daniel Sandler | efb0faf | 2012-10-10 14:15:34 -0700 | [diff] [blame] | 64 | public void setBar(PhoneStatusBar bar) { |
| 65 | mBar = bar; |
| 66 | } |
| 67 | |
| 68 | public boolean hasFullWidthNotifications() { |
| 69 | return mFullWidthNotifications; |
| 70 | } |
| 71 | |
| 72 | @Override |
| 73 | public void onAttachedToWindow() { |
| 74 | for (PanelView pv : mPanels) { |
| 75 | pv.setRubberbandingEnabled(!mFullWidthNotifications); |
| 76 | } |
| 77 | } |
| 78 | |
Daniel Sandler | 1c1edaa | 2012-08-14 11:14:45 -0400 | [diff] [blame] | 79 | @Override |
Daniel Sandler | cf591db | 2012-08-15 16:11:55 -0400 | [diff] [blame] | 80 | public void addPanel(PanelView pv) { |
| 81 | super.addPanel(pv); |
| 82 | if (pv.getId() == R.id.notification_panel) { |
| 83 | mNotificationPanel = pv; |
| 84 | } else if (pv.getId() == R.id.settings_panel){ |
| 85 | mSettingsPanel = pv; |
| 86 | } |
Daniel Sandler | efb0faf | 2012-10-10 14:15:34 -0700 | [diff] [blame] | 87 | pv.setRubberbandingEnabled(!mFullWidthNotifications); |
Daniel Sandler | cf591db | 2012-08-15 16:11:55 -0400 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | @Override |
Daniel Sandler | 5050813 | 2012-08-16 14:10:53 -0400 | [diff] [blame] | 91 | public boolean panelsEnabled() { |
Daniel Sandler | 1e8feef | 2012-08-16 11:37:41 -0400 | [diff] [blame] | 92 | return ((mBar.mDisabled & StatusBarManager.DISABLE_EXPAND) == 0); |
| 93 | } |
| 94 | |
| 95 | @Override |
Svetoslav Ganov | 6179ea3 | 2011-06-28 01:12:41 -0700 | [diff] [blame] | 96 | public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { |
| 97 | if (super.onRequestSendAccessibilityEvent(child, event)) { |
| 98 | // The status bar is very small so augment the view that the user is touching |
| 99 | // with the content of the status bar a whole. This way an accessibility service |
| 100 | // may announce the current item as well as the entire content if appropriate. |
| 101 | AccessibilityEvent record = AccessibilityEvent.obtain(); |
| 102 | onInitializeAccessibilityEvent(record); |
| 103 | dispatchPopulateAccessibilityEvent(record); |
| 104 | event.appendRecord(record); |
| 105 | return true; |
| 106 | } |
| 107 | return false; |
| 108 | } |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 109 | |
| 110 | @Override |
Daniel Sandler | efb0faf | 2012-10-10 14:15:34 -0700 | [diff] [blame] | 111 | public PanelView selectPanelForTouch(MotionEvent touch) { |
| 112 | final float x = touch.getX(); |
Fabrice Di Meglio | 8afcd14 | 2012-07-27 18:27:11 -0700 | [diff] [blame] | 113 | final boolean isLayoutRtl = isLayoutRtl(); |
Daniel Sandler | efb0faf | 2012-10-10 14:15:34 -0700 | [diff] [blame] | 114 | |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 115 | if (mFullWidthNotifications) { |
Daniel Sandler | efb0faf | 2012-10-10 14:15:34 -0700 | [diff] [blame] | 116 | // No double swiping. If either panel is open, nothing else can be pulled down. |
Daniel Sandler | e111ad3 | 2012-10-13 15:17:45 -0400 | [diff] [blame] | 117 | return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight()) |
| 118 | + mNotificationPanel.getExpandedHeight() > 0) |
Daniel Sandler | efb0faf | 2012-10-10 14:15:34 -0700 | [diff] [blame] | 119 | ? null |
| 120 | : mNotificationPanel; |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 121 | } |
| 122 | |
| 123 | // We split the status bar into thirds: the left 2/3 are for notifications, and the |
Daniel Sandler | cf591db | 2012-08-15 16:11:55 -0400 | [diff] [blame] | 124 | // right 1/3 for quick settings. If you pull the status bar down a second time you'll |
| 125 | // toggle panels no matter where you pull it down. |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 126 | |
Daniel Sandler | 67eab79 | 2012-10-02 17:08:23 -0400 | [diff] [blame] | 127 | final float w = getMeasuredWidth(); |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 128 | float region = (w * mSettingsPanelDragzoneFrac); |
| 129 | |
| 130 | if (DEBUG) { |
| 131 | Slog.v(TAG, String.format( |
| 132 | "w=%.1f frac=%.3f region=%.1f min=%.1f x=%.1f w-x=%.1f", |
| 133 | w, mSettingsPanelDragzoneFrac, region, mSettingsPanelDragzoneMin, x, (w-x))); |
Daniel Sandler | cf591db | 2012-08-15 16:11:55 -0400 | [diff] [blame] | 134 | } |
Daniel Sandler | 5a8aefa | 2012-09-25 01:21:12 -0400 | [diff] [blame] | 135 | |
| 136 | if (region < mSettingsPanelDragzoneMin) region = mSettingsPanelDragzoneMin; |
| 137 | |
Fabrice Di Meglio | 8afcd14 | 2012-07-27 18:27:11 -0700 | [diff] [blame] | 138 | final boolean showSettings = isLayoutRtl ? (x < region) : (w - region < x); |
| 139 | return showSettings ? mSettingsPanel : mNotificationPanel; |
Daniel Sandler | cf591db | 2012-08-15 16:11:55 -0400 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | @Override |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 143 | public void onPanelPeeked() { |
| 144 | super.onPanelPeeked(); |
| 145 | mBar.makeExpandedVisible(true); |
Daniel Sandler | 67eab79 | 2012-10-02 17:08:23 -0400 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | @Override |
| 149 | public void startOpeningPanel(PanelView panel) { |
| 150 | super.startOpeningPanel(panel); |
| 151 | // we only want to start fading if this is the "first" or "last" panel, |
| 152 | // which is kind of tricky to determine |
| 153 | mShouldFade = (mFadingPanel == null || mFadingPanel.isFullyExpanded()); |
| 154 | if (DEBUG) { |
| 155 | Slog.v(TAG, "start opening: " + panel + " shouldfade=" + mShouldFade); |
Daniel Sandler | 8e72c9e | 2012-08-15 00:09:26 -0400 | [diff] [blame] | 156 | } |
Daniel Sandler | 67eab79 | 2012-10-02 17:08:23 -0400 | [diff] [blame] | 157 | mFadingPanel = panel; |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | @Override |
| 161 | public void onAllPanelsCollapsed() { |
| 162 | super.onAllPanelsCollapsed(); |
Daniel Sandler | 6e2810b | 2012-10-17 09:40:09 -0400 | [diff] [blame] | 163 | // give animations time to settle |
| 164 | mBar.makeExpandedInvisibleSoon(); |
Daniel Sandler | 8e72c9e | 2012-08-15 00:09:26 -0400 | [diff] [blame] | 165 | mFadingPanel = null; |
Casey Burkhardt | bac221f | 2012-10-03 18:13:58 -0700 | [diff] [blame] | 166 | mLastFullyOpenedPanel = null; |
Daniel Sandler | 8e72c9e | 2012-08-15 00:09:26 -0400 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | @Override |
| 170 | public void onPanelFullyOpened(PanelView openPanel) { |
Daniel Sandler | 750bb9b | 2012-10-03 16:24:00 -0400 | [diff] [blame] | 171 | super.onPanelFullyOpened(openPanel); |
Casey Burkhardt | bac221f | 2012-10-03 18:13:58 -0700 | [diff] [blame] | 172 | if (openPanel != mLastFullyOpenedPanel) { |
| 173 | openPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); |
| 174 | } |
Daniel Sandler | 8e72c9e | 2012-08-15 00:09:26 -0400 | [diff] [blame] | 175 | mFadingPanel = openPanel; |
Casey Burkhardt | bac221f | 2012-10-03 18:13:58 -0700 | [diff] [blame] | 176 | mLastFullyOpenedPanel = openPanel; |
Daniel Sandler | 67eab79 | 2012-10-02 17:08:23 -0400 | [diff] [blame] | 177 | mShouldFade = true; // now you own the fade, mister |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | @Override |
| 181 | public boolean onTouchEvent(MotionEvent event) { |
Chris Wren | 64161cc | 2012-12-17 16:49:30 -0500 | [diff] [blame] | 182 | boolean barConsumedEvent = mBar.interceptTouchEvent(event); |
| 183 | |
| 184 | if (DEBUG_GESTURES) { |
| 185 | if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { |
| 186 | EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH, |
| 187 | event.getActionMasked(), (int) event.getX(), (int) event.getY(), |
| 188 | barConsumedEvent ? 1 : 0); |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | return barConsumedEvent || super.onTouchEvent(event); |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | @Override |
| 196 | public boolean onInterceptTouchEvent(MotionEvent event) { |
| 197 | return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event); |
| 198 | } |
| 199 | |
| 200 | @Override |
Daniel Sandler | 67eab79 | 2012-10-02 17:08:23 -0400 | [diff] [blame] | 201 | public void panelExpansionChanged(PanelView panel, float frac) { |
| 202 | super.panelExpansionChanged(panel, frac); |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 203 | |
Daniel Sandler | 198a030 | 2012-08-17 16:04:31 -0400 | [diff] [blame] | 204 | if (DEBUG) { |
| 205 | Slog.v(TAG, "panelExpansionChanged: f=" + frac); |
| 206 | } |
| 207 | |
Daniel Sandler | 67eab79 | 2012-10-02 17:08:23 -0400 | [diff] [blame] | 208 | if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()) { |
| 209 | if (mShouldFade) { |
| 210 | frac = mPanelExpandedFractionSum; // don't judge me |
Daniel Sandler | 3679bf5 | 2012-10-16 21:30:28 -0400 | [diff] [blame] | 211 | // let's start this 20% of the way down the screen |
| 212 | frac = frac * 1.2f - 0.2f; |
| 213 | if (frac <= 0) { |
| 214 | mBar.mStatusBarWindow.setBackgroundColor(0); |
| 215 | } else { |
| 216 | // woo, special effects |
| 217 | final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f)))); |
| 218 | // attenuate background color alpha by k |
| 219 | final int color = (int) ((mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF); |
| 220 | mBar.mStatusBarWindow.setBackgroundColor(color); |
| 221 | } |
Daniel Sandler | 67eab79 | 2012-10-02 17:08:23 -0400 | [diff] [blame] | 222 | } |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 223 | } |
| 224 | |
Daniel Sandler | 025e7cb | 2012-10-17 10:15:37 -0400 | [diff] [blame] | 225 | // fade out the panel as it gets buried into the status bar to avoid overdrawing the |
| 226 | // status bar on the last frame of a close animation |
| 227 | final int H = mBar.getStatusBarHeight(); |
| 228 | final float ph = panel.getExpandedHeight() + panel.getPaddingBottom(); |
| 229 | float alpha = 1f; |
| 230 | if (ph < 2*H) { |
| 231 | if (ph < H) alpha = 0f; |
| 232 | else alpha = (ph - H) / H; |
| 233 | alpha = alpha * alpha; // get there faster |
| 234 | } |
| 235 | if (panel.getAlpha() != alpha) { |
| 236 | panel.setAlpha(alpha); |
| 237 | } |
| 238 | |
Daniel Sandler | 08d05e3 | 2012-08-08 16:39:54 -0400 | [diff] [blame] | 239 | mBar.updateCarrierLabelVisibility(false); |
| 240 | } |
Svetoslav Ganov | 6179ea3 | 2011-06-28 01:12:41 -0700 | [diff] [blame] | 241 | } |