PhoneStatusBarView.java revision cfc359a9e6798dc7595380314eac7fcfeda14d76
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 17package com.android.systemui.statusbar.phone; 18 19import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; 20import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT; 21 22import android.animation.Animator; 23import android.animation.AnimatorSet; 24import android.animation.ObjectAnimator; 25import android.app.ActivityManager; 26import android.content.Context; 27import android.content.res.Resources; 28import android.content.res.Resources.NotFoundException; 29import android.util.AttributeSet; 30import android.util.EventLog; 31import android.util.Log; 32import android.view.MotionEvent; 33import android.view.View; 34import android.view.accessibility.AccessibilityEvent; 35 36import com.android.systemui.EventLogTags; 37import com.android.systemui.R; 38 39public class PhoneStatusBarView extends PanelBar { 40 private static final String TAG = "PhoneStatusBarView"; 41 private static final boolean DEBUG = PhoneStatusBar.DEBUG; 42 private static final boolean DEBUG_GESTURES = true; 43 44 PhoneStatusBar mBar; 45 int mScrimColor; 46 float mSettingsPanelDragzoneFrac; 47 float mSettingsPanelDragzoneMin; 48 49 boolean mFullWidthNotifications; 50 PanelView mFadingPanel = null; 51 PanelView mLastFullyOpenedPanel = null; 52 PanelView mNotificationPanel, mSettingsPanel; 53 private boolean mShouldFade; 54 private final StatusBarTransitions mBarTransitions; 55 56 private final class StatusBarTransitions extends BarTransitions { 57 private final int mTransparent; 58 private final float mAlphaWhenOpaque; 59 private final float mAlphaWhenTransparent = 1; 60 private View mLeftSide; 61 private View mRightSide; 62 63 public StatusBarTransitions(Context context) { 64 super(context, PhoneStatusBarView.this); 65 final Resources res = context.getResources(); 66 mTransparent = res.getColor(R.color.status_bar_background_transparent); 67 mAlphaWhenOpaque = res.getFraction(R.dimen.status_bar_icon_drawing_alpha, 1, 1); 68 } 69 70 public void init() { 71 mLeftSide = findViewById(R.id.notification_icon_area); 72 mRightSide = findViewById(R.id.system_icon_area); 73 applyMode(getMode(), false /*animate*/); 74 } 75 76 @Override 77 protected Integer getBackgroundColor(int mode) { 78 if (mode == MODE_TRANSPARENT) return mTransparent; 79 return super.getBackgroundColor(mode); 80 } 81 82 public ObjectAnimator animateTransitionTo(View v, float toAlpha) { 83 return ObjectAnimator.ofFloat(v, "alpha", v.getAlpha(), toAlpha); 84 } 85 86 public float getAlphaFor(int mode) { 87 final boolean isTransparent = mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSPARENT; 88 return isTransparent ? mAlphaWhenTransparent : mAlphaWhenOpaque; 89 } 90 91 @Override 92 protected void onTransition(int oldMode, int newMode, boolean animate) { 93 super.onTransition(oldMode, newMode, animate); 94 applyMode(newMode, animate); 95 } 96 97 private void applyMode(int mode, boolean animate) { 98 if (mLeftSide == null || mRightSide == null) return; 99 float newAlpha = getAlphaFor(mode); 100 if (animate) { 101 ObjectAnimator lhs = animateTransitionTo(mLeftSide, newAlpha); 102 ObjectAnimator rhs = animateTransitionTo(mRightSide, newAlpha); 103 AnimatorSet set = new AnimatorSet(); 104 set.playTogether(lhs, rhs); 105 set.start(); 106 } else { 107 mLeftSide.setAlpha(newAlpha); 108 mRightSide.setAlpha(newAlpha); 109 } 110 } 111 } 112 113 public PhoneStatusBarView(Context context, AttributeSet attrs) { 114 super(context, attrs); 115 116 Resources res = getContext().getResources(); 117 mScrimColor = res.getColor(R.color.notification_panel_scrim_color); 118 mSettingsPanelDragzoneMin = res.getDimension(R.dimen.settings_panel_dragzone_min); 119 try { 120 mSettingsPanelDragzoneFrac = res.getFraction(R.dimen.settings_panel_dragzone_fraction, 1, 1); 121 } catch (NotFoundException ex) { 122 mSettingsPanelDragzoneFrac = 0f; 123 } 124 mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f; 125 mBarTransitions = new StatusBarTransitions(context); 126 } 127 128 public BarTransitions getBarTransitions() { 129 return mBarTransitions; 130 } 131 132 public void setBar(PhoneStatusBar bar) { 133 mBar = bar; 134 } 135 136 public boolean hasFullWidthNotifications() { 137 return mFullWidthNotifications; 138 } 139 140 @Override 141 public void onAttachedToWindow() { 142 for (PanelView pv : mPanels) { 143 pv.setRubberbandingEnabled(!mFullWidthNotifications); 144 } 145 mBarTransitions.init(); 146 } 147 148 @Override 149 public void addPanel(PanelView pv) { 150 super.addPanel(pv); 151 if (pv.getId() == R.id.notification_panel) { 152 mNotificationPanel = pv; 153 } else if (pv.getId() == R.id.settings_panel){ 154 mSettingsPanel = pv; 155 } 156 pv.setRubberbandingEnabled(!mFullWidthNotifications); 157 } 158 159 @Override 160 public boolean panelsEnabled() { 161 return mBar.panelsEnabled(); 162 } 163 164 @Override 165 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { 166 if (super.onRequestSendAccessibilityEvent(child, event)) { 167 // The status bar is very small so augment the view that the user is touching 168 // with the content of the status bar a whole. This way an accessibility service 169 // may announce the current item as well as the entire content if appropriate. 170 AccessibilityEvent record = AccessibilityEvent.obtain(); 171 onInitializeAccessibilityEvent(record); 172 dispatchPopulateAccessibilityEvent(record); 173 event.appendRecord(record); 174 return true; 175 } 176 return false; 177 } 178 179 @Override 180 public PanelView selectPanelForTouch(MotionEvent touch) { 181 final float x = touch.getX(); 182 final boolean isLayoutRtl = isLayoutRtl(); 183 184 if (mFullWidthNotifications) { 185 // No double swiping. If either panel is open, nothing else can be pulled down. 186 return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight()) 187 + mNotificationPanel.getExpandedHeight() > 0) 188 ? null 189 : mNotificationPanel; 190 } 191 192 // We split the status bar into thirds: the left 2/3 are for notifications, and the 193 // right 1/3 for quick settings. If you pull the status bar down a second time you'll 194 // toggle panels no matter where you pull it down. 195 196 final float w = getMeasuredWidth(); 197 float region = (w * mSettingsPanelDragzoneFrac); 198 199 if (DEBUG) { 200 Log.v(TAG, String.format( 201 "w=%.1f frac=%.3f region=%.1f min=%.1f x=%.1f w-x=%.1f", 202 w, mSettingsPanelDragzoneFrac, region, mSettingsPanelDragzoneMin, x, (w-x))); 203 } 204 205 if (region < mSettingsPanelDragzoneMin) region = mSettingsPanelDragzoneMin; 206 207 final boolean showSettings = isLayoutRtl ? (x < region) : (w - region < x); 208 return showSettings ? mSettingsPanel : mNotificationPanel; 209 } 210 211 @Override 212 public void onPanelPeeked() { 213 super.onPanelPeeked(); 214 mBar.makeExpandedVisible(); 215 } 216 217 @Override 218 public void startOpeningPanel(PanelView panel) { 219 super.startOpeningPanel(panel); 220 // we only want to start fading if this is the "first" or "last" panel, 221 // which is kind of tricky to determine 222 mShouldFade = (mFadingPanel == null || mFadingPanel.isFullyExpanded()); 223 if (DEBUG) { 224 Log.v(TAG, "start opening: " + panel + " shouldfade=" + mShouldFade); 225 } 226 mFadingPanel = panel; 227 } 228 229 @Override 230 public void onAllPanelsCollapsed() { 231 super.onAllPanelsCollapsed(); 232 // give animations time to settle 233 mBar.makeExpandedInvisibleSoon(); 234 mFadingPanel = null; 235 mLastFullyOpenedPanel = null; 236 } 237 238 @Override 239 public void onPanelFullyOpened(PanelView openPanel) { 240 super.onPanelFullyOpened(openPanel); 241 if (openPanel != mLastFullyOpenedPanel) { 242 openPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 243 } 244 mFadingPanel = openPanel; 245 mLastFullyOpenedPanel = openPanel; 246 mShouldFade = true; // now you own the fade, mister 247 } 248 249 @Override 250 public boolean onTouchEvent(MotionEvent event) { 251 boolean barConsumedEvent = mBar.interceptTouchEvent(event); 252 253 if (DEBUG_GESTURES) { 254 if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { 255 EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH, 256 event.getActionMasked(), (int) event.getX(), (int) event.getY(), 257 barConsumedEvent ? 1 : 0); 258 } 259 } 260 261 return barConsumedEvent || super.onTouchEvent(event); 262 } 263 264 @Override 265 public boolean onInterceptTouchEvent(MotionEvent event) { 266 return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event); 267 } 268 269 @Override 270 public void panelExpansionChanged(PanelView panel, float frac) { 271 super.panelExpansionChanged(panel, frac); 272 273 if (DEBUG) { 274 Log.v(TAG, "panelExpansionChanged: f=" + frac); 275 } 276 277 if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()) { 278 if (mShouldFade) { 279 frac = mPanelExpandedFractionSum; // don't judge me 280 // let's start this 20% of the way down the screen 281 frac = frac * 1.2f - 0.2f; 282 if (frac <= 0) { 283 mBar.mStatusBarWindow.setBackgroundColor(0); 284 } else { 285 // woo, special effects 286 final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f)))); 287 // attenuate background color alpha by k 288 final int color = (int) ((mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF); 289 mBar.mStatusBarWindow.setBackgroundColor(color); 290 } 291 } 292 } 293 294 // fade out the panel as it gets buried into the status bar to avoid overdrawing the 295 // status bar on the last frame of a close animation 296 final int H = mBar.getStatusBarHeight(); 297 final float ph = panel.getExpandedHeight() + panel.getPaddingBottom(); 298 float alpha = 1f; 299 if (ph < 2*H) { 300 if (ph < H) alpha = 0f; 301 else alpha = (ph - H) / H; 302 alpha = alpha * alpha; // get there faster 303 } 304 if (panel.getAlpha() != alpha) { 305 panel.setAlpha(alpha); 306 } 307 308 mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum); 309 310 mBar.updateCarrierLabelVisibility(false); 311 } 312} 313