PanelBar.java revision 1689594851a6dd985cff69913e7f4bc548062808
1/*
2 * Copyright (C) 2012 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.Log;
22import android.view.MotionEvent;
23import android.view.View;
24import android.widget.FrameLayout;
25
26import java.util.ArrayList;
27
28public abstract class PanelBar extends FrameLayout {
29    public static final boolean DEBUG = false;
30    public static final String TAG = PanelBar.class.getSimpleName();
31    private static final boolean SPEW = false;
32
33    public static final void LOG(String fmt, Object... args) {
34        if (!DEBUG) return;
35        Log.v(TAG, String.format(fmt, args));
36    }
37
38    public static final int STATE_CLOSED = 0;
39    public static final int STATE_OPENING = 1;
40    public static final int STATE_OPEN = 2;
41
42    PanelHolder mPanelHolder;
43    ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
44    PanelView mTouchingPanel;
45    private int mState = STATE_CLOSED;
46    private boolean mTracking;
47
48    float mPanelExpandedFractionSum;
49
50    public void go(int state) {
51        if (DEBUG) LOG("go state: %d -> %d", mState, state);
52        mState = state;
53    }
54
55    public PanelBar(Context context, AttributeSet attrs) {
56        super(context, attrs);
57    }
58
59    @Override
60    protected void onFinishInflate() {
61        super.onFinishInflate();
62    }
63
64    public void addPanel(PanelView pv) {
65        mPanels.add(pv);
66        pv.setBar(this);
67    }
68
69    public void setPanelHolder(PanelHolder ph) {
70        if (ph == null) {
71            Log.e(TAG, "setPanelHolder: null PanelHolder", new Throwable());
72            return;
73        }
74        ph.setBar(this);
75        mPanelHolder = ph;
76        final int N = ph.getChildCount();
77        for (int i=0; i<N; i++) {
78            final View v = ph.getChildAt(i);
79            if (v != null && v instanceof PanelView) {
80                addPanel((PanelView) v);
81            }
82        }
83    }
84
85    public void setBouncerShowing(boolean showing) {
86        int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
87                : IMPORTANT_FOR_ACCESSIBILITY_AUTO;
88
89        setImportantForAccessibility(important);
90
91        if (mPanelHolder != null) {
92            mPanelHolder.setImportantForAccessibility(important);
93        }
94    }
95
96    public float getBarHeight() {
97        return getMeasuredHeight();
98    }
99
100    public PanelView selectPanelForTouch(MotionEvent touch) {
101        final int N = mPanels.size();
102        return mPanels.get((int)(N * touch.getX() / getMeasuredWidth()));
103    }
104
105    public boolean panelsEnabled() {
106        return true;
107    }
108
109    @Override
110    public boolean onTouchEvent(MotionEvent event) {
111        // Allow subclasses to implement enable/disable semantics
112        if (!panelsEnabled()) {
113            if (event.getAction() == MotionEvent.ACTION_DOWN) {
114                Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)",
115                        (int) event.getX(), (int) event.getY()));
116            }
117            return false;
118        }
119
120        // figure out which panel needs to be talked to here
121        if (event.getAction() == MotionEvent.ACTION_DOWN) {
122            final PanelView panel = selectPanelForTouch(event);
123            if (panel == null) {
124                // panel is not there, so we'll eat the gesture
125                Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)",
126                        (int) event.getX(), (int) event.getY()));
127                mTouchingPanel = null;
128                return true;
129            }
130            boolean enabled = panel.isEnabled();
131            if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
132                    (enabled ? "" : " (disabled)"));
133            if (!enabled) {
134                // panel is disabled, so we'll eat the gesture
135                Log.v(TAG, String.format(
136                        "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)",
137                        panel, (int) event.getX(), (int) event.getY()));
138                mTouchingPanel = null;
139                return true;
140            }
141            startOpeningPanel(panel);
142        }
143        final boolean result = mTouchingPanel != null
144                ? mTouchingPanel.onTouchEvent(event)
145                : true;
146        return result;
147    }
148
149    // called from PanelView when self-expanding, too
150    public void startOpeningPanel(PanelView panel) {
151        if (DEBUG) LOG("startOpeningPanel: " + panel);
152        mTouchingPanel = panel;
153        mPanelHolder.setSelectedPanel(mTouchingPanel);
154        for (PanelView pv : mPanels) {
155            if (pv != panel) {
156                pv.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
157            }
158        }
159    }
160
161    public abstract void panelScrimMinFractionChanged(float minFraction);
162
163    /**
164     * @param panel the panel which changed its expansion state
165     * @param frac the fraction from the expansion in [0, 1]
166     * @param expanded whether the panel is currently expanded; this is independent from the
167     *                 fraction as the panel also might be expanded if the fraction is 0
168     */
169    public void panelExpansionChanged(PanelView panel, float frac, boolean expanded) {
170        boolean fullyClosed = true;
171        PanelView fullyOpenedPanel = null;
172        if (SPEW) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
173        mPanelExpandedFractionSum = 0f;
174        for (PanelView pv : mPanels) {
175            pv.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
176            // adjust any other panels that may be partially visible
177            if (expanded) {
178                if (mState == STATE_CLOSED) {
179                    go(STATE_OPENING);
180                    onPanelPeeked();
181                }
182                fullyClosed = false;
183                final float thisFrac = pv.getExpandedFraction();
184                mPanelExpandedFractionSum += thisFrac;
185                if (SPEW) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
186                if (panel == pv) {
187                    if (thisFrac == 1f) fullyOpenedPanel = panel;
188                }
189            }
190        }
191        mPanelExpandedFractionSum /= mPanels.size();
192        if (fullyOpenedPanel != null && !mTracking) {
193            go(STATE_OPEN);
194            onPanelFullyOpened(fullyOpenedPanel);
195        } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) {
196            go(STATE_CLOSED);
197            onAllPanelsCollapsed();
198        }
199
200        if (SPEW) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
201                (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
202    }
203
204    public void collapseAllPanels(boolean animate, boolean delayed, float speedUpFactor) {
205        boolean waiting = false;
206        for (PanelView pv : mPanels) {
207            if (animate && !pv.isFullyCollapsed()) {
208                pv.collapse(delayed, speedUpFactor);
209                waiting = true;
210            } else {
211                pv.resetViews();
212                pv.setExpandedFraction(0); // just in case
213                pv.cancelPeek();
214            }
215        }
216        if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
217        if (!waiting && mState != STATE_CLOSED) {
218            // it's possible that nothing animated, so we replicate the termination
219            // conditions of panelExpansionChanged here
220            go(STATE_CLOSED);
221            onAllPanelsCollapsed();
222        }
223    }
224
225    public void onPanelPeeked() {
226        if (DEBUG) LOG("onPanelPeeked");
227    }
228
229    public void onAllPanelsCollapsed() {
230        if (DEBUG) LOG("onAllPanelsCollapsed");
231    }
232
233    public void onPanelFullyOpened(PanelView openPanel) {
234        if (DEBUG) LOG("onPanelFullyOpened");
235    }
236
237    public void onTrackingStarted(PanelView panel) {
238        mTracking = true;
239    }
240
241    public void onTrackingStopped(PanelView panel, boolean expand) {
242        mTracking = false;
243    }
244
245    public void onExpandingFinished() {
246        if (DEBUG) LOG("onExpandingFinished");
247    }
248
249    public void onClosingFinished() {
250
251    }
252}
253