PhoneStatusBarView.java revision c19418e3f52bd6c88dae433750daf1ce15fafe23
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 android.app.ActivityManager;
20import android.content.Context;
21import android.content.res.Resources;
22import android.content.res.Resources.NotFoundException;
23import android.util.AttributeSet;
24import android.util.EventLog;
25import android.util.Log;
26import android.view.MotionEvent;
27import android.view.View;
28import android.view.accessibility.AccessibilityEvent;
29
30import com.android.systemui.EventLogTags;
31import com.android.systemui.R;
32
33public class PhoneStatusBarView extends PanelBar {
34    private static final String TAG = "PhoneStatusBarView";
35    private static final boolean DEBUG = PhoneStatusBar.DEBUG;
36    private static final boolean DEBUG_GESTURES = true;
37
38    PhoneStatusBar mBar;
39    int mScrimColor;
40    float mSettingsPanelDragzoneFrac;
41    float mSettingsPanelDragzoneMin;
42
43    boolean mFullWidthNotifications;
44    PanelView mFadingPanel = null;
45    PanelView mLastFullyOpenedPanel = null;
46    PanelView mNotificationPanel, mSettingsPanel;
47    private boolean mShouldFade;
48    private final PhoneStatusBarTransitions mBarTransitions;
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        mBarTransitions = new PhoneStatusBarTransitions(this);
63    }
64
65    public BarTransitions getBarTransitions() {
66        return mBarTransitions;
67    }
68
69    public void setBar(PhoneStatusBar bar) {
70        mBar = bar;
71    }
72
73    public boolean hasFullWidthNotifications() {
74        return mFullWidthNotifications;
75    }
76
77    @Override
78    public void onAttachedToWindow() {
79        for (PanelView pv : mPanels) {
80            pv.setRubberbandingEnabled(!mFullWidthNotifications);
81        }
82        mBarTransitions.init();
83    }
84
85    @Override
86    public void addPanel(PanelView pv) {
87        super.addPanel(pv);
88        if (pv.getId() == R.id.notification_panel) {
89            mNotificationPanel = pv;
90        } else if (pv.getId() == R.id.settings_panel){
91            mSettingsPanel = pv;
92        }
93        pv.setRubberbandingEnabled(!mFullWidthNotifications);
94    }
95
96    @Override
97    public boolean panelsEnabled() {
98        return mBar.panelsEnabled();
99    }
100
101    @Override
102    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
103        if (super.onRequestSendAccessibilityEvent(child, event)) {
104            // The status bar is very small so augment the view that the user is touching
105            // with the content of the status bar a whole. This way an accessibility service
106            // may announce the current item as well as the entire content if appropriate.
107            AccessibilityEvent record = AccessibilityEvent.obtain();
108            onInitializeAccessibilityEvent(record);
109            dispatchPopulateAccessibilityEvent(record);
110            event.appendRecord(record);
111            return true;
112        }
113        return false;
114    }
115
116    @Override
117    public PanelView selectPanelForTouch(MotionEvent touch) {
118        final float x = touch.getX();
119        final boolean isLayoutRtl = isLayoutRtl();
120
121        if (mFullWidthNotifications) {
122            // No double swiping. If either panel is open, nothing else can be pulled down.
123            return ((mSettingsPanel == null ? 0 : mSettingsPanel.getExpandedHeight())
124                        + mNotificationPanel.getExpandedHeight() > 0)
125                    ? null
126                    : mNotificationPanel;
127        }
128
129        // We split the status bar into thirds: the left 2/3 are for notifications, and the
130        // right 1/3 for quick settings. If you pull the status bar down a second time you'll
131        // toggle panels no matter where you pull it down.
132
133        final float w = getMeasuredWidth();
134        float region = (w * mSettingsPanelDragzoneFrac);
135
136        if (DEBUG) {
137            Log.v(TAG, String.format(
138                "w=%.1f frac=%.3f region=%.1f min=%.1f x=%.1f w-x=%.1f",
139                w, mSettingsPanelDragzoneFrac, region, mSettingsPanelDragzoneMin, x, (w-x)));
140        }
141
142        if (region < mSettingsPanelDragzoneMin) region = mSettingsPanelDragzoneMin;
143
144        final boolean showSettings = isLayoutRtl ? (x < region) : (w - region < x);
145        return showSettings ? mSettingsPanel : mNotificationPanel;
146    }
147
148    @Override
149    public void onPanelPeeked() {
150        super.onPanelPeeked();
151        mBar.makeExpandedVisible();
152    }
153
154    @Override
155    public void startOpeningPanel(PanelView panel) {
156        super.startOpeningPanel(panel);
157        // we only want to start fading if this is the "first" or "last" panel,
158        // which is kind of tricky to determine
159        mShouldFade = (mFadingPanel == null || mFadingPanel.isFullyExpanded());
160        if (DEBUG) {
161            Log.v(TAG, "start opening: " + panel + " shouldfade=" + mShouldFade);
162        }
163        mFadingPanel = panel;
164    }
165
166    @Override
167    public void onAllPanelsCollapsed() {
168        super.onAllPanelsCollapsed();
169        // give animations time to settle
170        mBar.makeExpandedInvisibleSoon();
171        mFadingPanel = null;
172        mLastFullyOpenedPanel = null;
173        if (mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
174            mBar.mStatusBarWindow.setBackgroundColor(0);
175        }
176    }
177
178    @Override
179    public void onPanelFullyOpened(PanelView openPanel) {
180        super.onPanelFullyOpened(openPanel);
181        if (openPanel != mLastFullyOpenedPanel) {
182            openPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
183        }
184        mFadingPanel = openPanel;
185        mLastFullyOpenedPanel = openPanel;
186        mShouldFade = true; // now you own the fade, mister
187    }
188
189    @Override
190    public boolean onTouchEvent(MotionEvent event) {
191        boolean barConsumedEvent = mBar.interceptTouchEvent(event);
192
193        if (DEBUG_GESTURES) {
194            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
195                EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH,
196                        event.getActionMasked(), (int) event.getX(), (int) event.getY(),
197                        barConsumedEvent ? 1 : 0);
198            }
199        }
200
201        return barConsumedEvent || super.onTouchEvent(event);
202    }
203
204    @Override
205    public boolean onInterceptTouchEvent(MotionEvent event) {
206        return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event);
207    }
208
209    @Override
210    public void panelExpansionChanged(PanelView panel, float frac) {
211        super.panelExpansionChanged(panel, frac);
212
213        if (DEBUG) {
214            Log.v(TAG, "panelExpansionChanged: f=" + frac);
215        }
216
217        if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
218            if (mShouldFade) {
219                frac = mPanelExpandedFractionSum; // don't judge me
220                // let's start this 20% of the way down the screen
221                frac = frac * 1.2f - 0.2f;
222                if (frac <= 0) {
223                    mBar.mStatusBarWindow.setBackgroundColor(0);
224                } else {
225                    // woo, special effects
226                    final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
227                    // attenuate background color alpha by k
228                    final int color = (int) ((mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
229                    mBar.mStatusBarWindow.setBackgroundColor(color);
230                }
231            }
232        }
233
234        // fade out the panel as it gets buried into the status bar to avoid overdrawing the
235        // status bar on the last frame of a close animation
236        final int H = mBar.getStatusBarHeight();
237        final float ph = panel.getExpandedHeight() + panel.getPaddingBottom();
238        float alpha = 1f;
239        if (ph < 2*H) {
240            if (ph < H) alpha = 0f;
241            else alpha = (ph - H) / H;
242            alpha = alpha * alpha; // get there faster
243        }
244        if (panel.getAlpha() != alpha) {
245            panel.setAlpha(alpha);
246        }
247
248        mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum);
249
250        mBar.updateCarrierLabelVisibility(false);
251    }
252}
253