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.content.Context;
20import android.util.AttributeSet;
21import android.util.EventLog;
22import android.view.MotionEvent;
23import android.view.View;
24import android.view.ViewGroup;
25import android.view.accessibility.AccessibilityEvent;
26
27import com.android.systemui.BatteryMeterView;
28import com.android.systemui.DejankUtils;
29import com.android.systemui.Dependency;
30import com.android.systemui.EventLogTags;
31import com.android.systemui.R;
32import com.android.systemui.statusbar.policy.DarkIconDispatcher;
33import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
34
35public class PhoneStatusBarView extends PanelBar {
36    private static final String TAG = "PhoneStatusBarView";
37    private static final boolean DEBUG = StatusBar.DEBUG;
38    private static final boolean DEBUG_GESTURES = false;
39
40    StatusBar mBar;
41
42    boolean mIsFullyOpenedPanel = false;
43    private final PhoneStatusBarTransitions mBarTransitions;
44    private ScrimController mScrimController;
45    private float mMinFraction;
46    private float mPanelFraction;
47    private Runnable mHideExpandedRunnable = new Runnable() {
48        @Override
49        public void run() {
50            if (mPanelFraction == 0.0f) {
51                mBar.makeExpandedInvisible();
52            }
53        }
54    };
55    private DarkReceiver mBattery;
56
57    public PhoneStatusBarView(Context context, AttributeSet attrs) {
58        super(context, attrs);
59
60        mBarTransitions = new PhoneStatusBarTransitions(this);
61    }
62
63    public BarTransitions getBarTransitions() {
64        return mBarTransitions;
65    }
66
67    public void setBar(StatusBar bar) {
68        mBar = bar;
69    }
70
71    public void setScrimController(ScrimController scrimController) {
72        mScrimController = scrimController;
73    }
74
75    @Override
76    public void onFinishInflate() {
77        mBarTransitions.init();
78        mBattery = findViewById(R.id.battery);
79    }
80
81    @Override
82    protected void onAttachedToWindow() {
83        super.onAttachedToWindow();
84        // Always have Battery meters in the status bar observe the dark/light modes.
85        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
86    }
87
88    @Override
89    protected void onDetachedFromWindow() {
90        super.onDetachedFromWindow();
91        Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery);
92    }
93
94    @Override
95    public boolean panelEnabled() {
96        return mBar.panelsEnabled();
97    }
98
99    @Override
100    public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
101        if (super.onRequestSendAccessibilityEventInternal(child, event)) {
102            // The status bar is very small so augment the view that the user is touching
103            // with the content of the status bar a whole. This way an accessibility service
104            // may announce the current item as well as the entire content if appropriate.
105            AccessibilityEvent record = AccessibilityEvent.obtain();
106            onInitializeAccessibilityEvent(record);
107            dispatchPopulateAccessibilityEvent(record);
108            event.appendRecord(record);
109            return true;
110        }
111        return false;
112    }
113
114    @Override
115    public void onPanelPeeked() {
116        super.onPanelPeeked();
117        mBar.makeExpandedVisible(false);
118    }
119
120    @Override
121    public void onPanelCollapsed() {
122        super.onPanelCollapsed();
123        // Close the status bar in the next frame so we can show the end of the animation.
124        post(mHideExpandedRunnable);
125        mIsFullyOpenedPanel = false;
126    }
127
128    public void removePendingHideExpandedRunnables() {
129        removeCallbacks(mHideExpandedRunnable);
130    }
131
132    @Override
133    public void onPanelFullyOpened() {
134        super.onPanelFullyOpened();
135        if (!mIsFullyOpenedPanel) {
136            mPanel.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
137        }
138        mIsFullyOpenedPanel = true;
139    }
140
141    @Override
142    public boolean onTouchEvent(MotionEvent event) {
143        boolean barConsumedEvent = mBar.interceptTouchEvent(event);
144
145        if (DEBUG_GESTURES) {
146            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
147                EventLog.writeEvent(EventLogTags.SYSUI_PANELBAR_TOUCH,
148                        event.getActionMasked(), (int) event.getX(), (int) event.getY(),
149                        barConsumedEvent ? 1 : 0);
150            }
151        }
152
153        return barConsumedEvent || super.onTouchEvent(event);
154    }
155
156    @Override
157    public void onTrackingStarted() {
158        super.onTrackingStarted();
159        mBar.onTrackingStarted();
160        mScrimController.onTrackingStarted();
161        removePendingHideExpandedRunnables();
162    }
163
164    @Override
165    public void onClosingFinished() {
166        super.onClosingFinished();
167        mBar.onClosingFinished();
168    }
169
170    @Override
171    public void onTrackingStopped(boolean expand) {
172        super.onTrackingStopped(expand);
173        mBar.onTrackingStopped(expand);
174    }
175
176    @Override
177    public void onExpandingFinished() {
178        super.onExpandingFinished();
179        mScrimController.onExpandingFinished();
180    }
181
182    @Override
183    public boolean onInterceptTouchEvent(MotionEvent event) {
184        return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event);
185    }
186
187    @Override
188    public void panelScrimMinFractionChanged(float minFraction) {
189        if (mMinFraction != minFraction) {
190            mMinFraction = minFraction;
191            updateScrimFraction();
192        }
193    }
194
195    @Override
196    public void panelExpansionChanged(float frac, boolean expanded) {
197        super.panelExpansionChanged(frac, expanded);
198        mPanelFraction = frac;
199        updateScrimFraction();
200    }
201
202    private void updateScrimFraction() {
203        float scrimFraction = mPanelFraction;
204        if (mMinFraction < 1.0f) {
205            scrimFraction = Math.max((mPanelFraction - mMinFraction) / (1.0f - mMinFraction),
206                    0);
207        }
208        mScrimController.setPanelExpansion(scrimFraction);
209    }
210
211    public void onDensityOrFontScaleChanged() {
212        ViewGroup.LayoutParams layoutParams = getLayoutParams();
213        layoutParams.height = getResources().getDimensionPixelSize(
214                R.dimen.status_bar_height);
215        setLayoutParams(layoutParams);
216    }
217}
218