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