Home | History | Annotate | Download | only in phone
      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 
     17 package com.android.systemui.statusbar.phone;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.StatusBarManager;
     21 import android.content.Context;
     22 import android.content.res.Resources;
     23 import android.content.res.Resources.NotFoundException;
     24 import android.util.AttributeSet;
     25 import android.util.EventLog;
     26 import android.util.Slog;
     27 import android.view.MotionEvent;
     28 import android.view.View;
     29 import android.view.accessibility.AccessibilityEvent;
     30 
     31 import com.android.systemui.EventLogTags;
     32 import com.android.systemui.R;
     33 
     34 public class PhoneStatusBarView extends PanelBar {
     35     private static final String TAG = "PhoneStatusBarView";
     36     private static final boolean DEBUG = PhoneStatusBar.DEBUG;
     37     private static final boolean DEBUG_GESTURES = true;
     38 
     39     PhoneStatusBar mBar;
     40     int mScrimColor;
     41     float mSettingsPanelDragzoneFrac;
     42     float mSettingsPanelDragzoneMin;
     43 
     44     boolean mFullWidthNotifications;
     45     PanelView mFadingPanel = null;
     46     PanelView mLastFullyOpenedPanel = null;
     47     PanelView mNotificationPanel, mSettingsPanel;
     48     private boolean mShouldFade;
     49 
     50     public PhoneStatusBarView(Context context, AttributeSet attrs) {
     51         super(context, attrs);
     52 
     53         Resources res = getContext().getResources();
     54         mScrimColor = res.getColor(R.color.notification_panel_scrim_color);
     55         mSettingsPanelDragzoneMin = res.getDimension(R.dimen.settings_panel_dragzone_min);
     56         try {
     57             mSettingsPanelDragzoneFrac = res.getFraction(R.dimen.settings_panel_dragzone_fraction, 1, 1);
     58         } catch (NotFoundException ex) {
     59             mSettingsPanelDragzoneFrac = 0f;
     60         }
     61         mFullWidthNotifications = mSettingsPanelDragzoneFrac <= 0f;
     62     }
     63 
     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 
     79     @Override
     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         }
     87         pv.setRubberbandingEnabled(!mFullWidthNotifications);
     88     }
     89 
     90     @Override
     91     public boolean panelsEnabled() {
     92         return ((mBar.mDisabled & StatusBarManager.DISABLE_EXPAND) == 0);
     93     }
     94 
     95     @Override
     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     }
    109 
    110     @Override
    111     public PanelView selectPanelForTouch(MotionEvent touch) {
    112         final float x = touch.getX();
    113         final boolean isLayoutRtl = isLayoutRtl();
    114 
    115         if (mFullWidthNotifications) {
    116             // No double swiping. If either panel is open, nothing else can be pulled down.
    117             return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight())
    118                         + mNotificationPanel.getExpandedHeight() > 0)
    119                     ? null
    120                     : mNotificationPanel;
    121         }
    122 
    123         // We split the status bar into thirds: the left 2/3 are for notifications, and the
    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.
    126 
    127         final float w = getMeasuredWidth();
    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)));
    134         }
    135 
    136         if (region < mSettingsPanelDragzoneMin) region = mSettingsPanelDragzoneMin;
    137 
    138         final boolean showSettings = isLayoutRtl ? (x < region) : (w - region < x);
    139         return showSettings ? mSettingsPanel : mNotificationPanel;
    140     }
    141 
    142     @Override
    143     public void onPanelPeeked() {
    144         super.onPanelPeeked();
    145         mBar.makeExpandedVisible(true);
    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);
    156         }
    157         mFadingPanel = panel;
    158     }
    159 
    160     @Override
    161     public void onAllPanelsCollapsed() {
    162         super.onAllPanelsCollapsed();
    163         // give animations time to settle
    164         mBar.makeExpandedInvisibleSoon();
    165         mFadingPanel = null;
    166         mLastFullyOpenedPanel = null;
    167     }
    168 
    169     @Override
    170     public void onPanelFullyOpened(PanelView openPanel) {
    171         super.onPanelFullyOpened(openPanel);
    172         if (openPanel != mLastFullyOpenedPanel) {
    173             openPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    174         }
    175         mFadingPanel = openPanel;
    176         mLastFullyOpenedPanel = openPanel;
    177         mShouldFade = true; // now you own the fade, mister
    178     }
    179 
    180     @Override
    181     public boolean onTouchEvent(MotionEvent event) {
    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);
    193     }
    194 
    195     @Override
    196     public boolean onInterceptTouchEvent(MotionEvent event) {
    197         return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event);
    198     }
    199 
    200     @Override
    201     public void panelExpansionChanged(PanelView panel, float frac) {
    202         super.panelExpansionChanged(panel, frac);
    203 
    204         if (DEBUG) {
    205             Slog.v(TAG, "panelExpansionChanged: f=" + frac);
    206         }
    207 
    208         if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
    209             if (mShouldFade) {
    210                 frac = mPanelExpandedFractionSum; // don't judge me
    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                 }
    222             }
    223         }
    224 
    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 
    239         mBar.updateCarrierLabelVisibility(false);
    240     }
    241 }
    242