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 
17 package com.android.systemui.statusbar.phone;
18 
19 import android.content.Context;
20 import android.util.AttributeSet;
21 import android.util.Log;
22 import android.view.MotionEvent;
23 import android.view.View;
24 import android.widget.FrameLayout;
25 
26 import java.util.ArrayList;
27 
28 public 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 
LOG(String fmt, Object... args)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 
go(int state)50     public void go(int state) {
51         if (DEBUG) LOG("go state: %d -> %d", mState, state);
52         mState = state;
53     }
54 
PanelBar(Context context, AttributeSet attrs)55     public PanelBar(Context context, AttributeSet attrs) {
56         super(context, attrs);
57     }
58 
59     @Override
onFinishInflate()60     protected void onFinishInflate() {
61         super.onFinishInflate();
62     }
63 
addPanel(PanelView pv)64     public void addPanel(PanelView pv) {
65         mPanels.add(pv);
66         pv.setBar(this);
67     }
68 
setPanelHolder(PanelHolder ph)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 
setBouncerShowing(boolean showing)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 
getBarHeight()96     public float getBarHeight() {
97         return getMeasuredHeight();
98     }
99 
selectPanelForTouch(MotionEvent touch)100     public PanelView selectPanelForTouch(MotionEvent touch) {
101         final int N = mPanels.size();
102         return mPanels.get((int)(N * touch.getX() / getMeasuredWidth()));
103     }
104 
panelsEnabled()105     public boolean panelsEnabled() {
106         return true;
107     }
108 
109     @Override
onTouchEvent(MotionEvent event)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
startOpeningPanel(PanelView panel)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 
panelScrimMinFractionChanged(float minFraction)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      */
panelExpansionChanged(PanelView panel, float frac, boolean expanded)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 
collapseAllPanels(boolean animate, boolean delayed, float speedUpFactor)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 
onPanelPeeked()225     public void onPanelPeeked() {
226         if (DEBUG) LOG("onPanelPeeked");
227     }
228 
onAllPanelsCollapsed()229     public void onAllPanelsCollapsed() {
230         if (DEBUG) LOG("onAllPanelsCollapsed");
231     }
232 
onPanelFullyOpened(PanelView openPanel)233     public void onPanelFullyOpened(PanelView openPanel) {
234         if (DEBUG) LOG("onPanelFullyOpened");
235     }
236 
onTrackingStarted(PanelView panel)237     public void onTrackingStarted(PanelView panel) {
238         mTracking = true;
239     }
240 
onTrackingStopped(PanelView panel, boolean expand)241     public void onTrackingStopped(PanelView panel, boolean expand) {
242         mTracking = false;
243     }
244 
onExpandingFinished()245     public void onExpandingFinished() {
246         if (DEBUG) LOG("onExpandingFinished");
247     }
248 
onClosingFinished()249     public void onClosingFinished() {
250 
251     }
252 }
253