blob: d55754b7cbff872df852edb17a4a0461af0881be [file] [log] [blame]
Daniel Sandler50a53132012-10-24 15:02:27 -04001/*
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
Daniel Sandler08d05e32012-08-08 16:39:54 -040017package com.android.systemui.statusbar.phone;
18
Daniel Sandler08d05e32012-08-08 16:39:54 -040019import android.content.Context;
20import android.util.AttributeSet;
John Spurlockcd686b52013-06-05 10:13:46 -040021import android.util.Log;
Daniel Sandler08d05e32012-08-08 16:39:54 -040022import android.view.MotionEvent;
Daniel Sandler173bae22012-09-25 14:37:42 -040023import android.view.View;
Daniel Sandler08d05e32012-08-08 16:39:54 -040024import android.widget.FrameLayout;
25
John Spurlockde84f0e2013-06-12 12:41:00 -040026import java.util.ArrayList;
27
Daniel Sandler08d05e32012-08-08 16:39:54 -040028public class PanelBar extends FrameLayout {
Daniel Sandlerbf4aa9d2012-08-15 10:49:28 -040029 public static final boolean DEBUG = false;
Daniel Sandler198a0302012-08-17 16:04:31 -040030 public static final String TAG = PanelBar.class.getSimpleName();
Daniel Sandler08d05e32012-08-08 16:39:54 -040031 public static final void LOG(String fmt, Object... args) {
32 if (!DEBUG) return;
John Spurlockcd686b52013-06-05 10:13:46 -040033 Log.v(TAG, String.format(fmt, args));
Daniel Sandler08d05e32012-08-08 16:39:54 -040034 }
35
Daniel Sandler198a0302012-08-17 16:04:31 -040036 public static final int STATE_CLOSED = 0;
37 public static final int STATE_OPENING = 1;
38 public static final int STATE_OPEN = 2;
39
Daniel Sandler67eab792012-10-02 17:08:23 -040040 PanelHolder mPanelHolder;
41 ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
42 PanelView mTouchingPanel;
Daniel Sandler978f8532012-08-15 15:48:16 -040043 private int mState = STATE_CLOSED;
44 private boolean mTracking;
45
Daniel Sandler67eab792012-10-02 17:08:23 -040046 float mPanelExpandedFractionSum;
47
Daniel Sandler198a0302012-08-17 16:04:31 -040048 public void go(int state) {
Daniel Sandler67eab792012-10-02 17:08:23 -040049 if (DEBUG) LOG("go state: %d -> %d", mState, state);
Daniel Sandler978f8532012-08-15 15:48:16 -040050 mState = state;
51 }
Daniel Sandler08d05e32012-08-08 16:39:54 -040052
53 public PanelBar(Context context, AttributeSet attrs) {
54 super(context, attrs);
55 }
56
57 @Override
58 protected void onFinishInflate() {
59 super.onFinishInflate();
60 }
61
62 public void addPanel(PanelView pv) {
63 mPanels.add(pv);
64 pv.setBar(this);
65 }
66
67 public void setPanelHolder(PanelHolder ph) {
68 if (ph == null) {
John Spurlockcd686b52013-06-05 10:13:46 -040069 Log.e(TAG, "setPanelHolder: null PanelHolder", new Throwable());
Daniel Sandler08d05e32012-08-08 16:39:54 -040070 return;
71 }
72 ph.setBar(this);
73 mPanelHolder = ph;
74 final int N = ph.getChildCount();
75 for (int i=0; i<N; i++) {
Daniel Sandlere111ad32012-10-13 15:17:45 -040076 final View v = ph.getChildAt(i);
77 if (v != null && v instanceof PanelView) {
78 addPanel((PanelView) v);
Daniel Sandler08d05e32012-08-08 16:39:54 -040079 }
80 }
81 }
82
83 public float getBarHeight() {
84 return getMeasuredHeight();
85 }
86
Daniel Sandlerefb0faf2012-10-10 14:15:34 -070087 public PanelView selectPanelForTouch(MotionEvent touch) {
Daniel Sandlercf591db2012-08-15 16:11:55 -040088 final int N = mPanels.size();
Daniel Sandlerefb0faf2012-10-10 14:15:34 -070089 return mPanels.get((int)(N * touch.getX() / getMeasuredWidth()));
Daniel Sandlercf591db2012-08-15 16:11:55 -040090 }
91
Daniel Sandler50508132012-08-16 14:10:53 -040092 public boolean panelsEnabled() {
Daniel Sandler1e8feef2012-08-16 11:37:41 -040093 return true;
94 }
95
Daniel Sandler08d05e32012-08-08 16:39:54 -040096 @Override
97 public boolean onTouchEvent(MotionEvent event) {
Daniel Sandler1e8feef2012-08-16 11:37:41 -040098 // Allow subclasses to implement enable/disable semantics
Daniel Sandler2b99a492013-02-05 13:05:44 -050099 if (!panelsEnabled()) {
100 if (event.getAction() == MotionEvent.ACTION_DOWN) {
John Spurlockcd686b52013-06-05 10:13:46 -0400101 Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)",
Daniel Sandler2b99a492013-02-05 13:05:44 -0500102 (int) event.getX(), (int) event.getY()));
103 }
104 return false;
105 }
Daniel Sandler1e8feef2012-08-16 11:37:41 -0400106
Daniel Sandler08d05e32012-08-08 16:39:54 -0400107 // figure out which panel needs to be talked to here
108 if (event.getAction() == MotionEvent.ACTION_DOWN) {
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700109 final PanelView panel = selectPanelForTouch(event);
110 if (panel == null) {
111 // panel is not there, so we'll eat the gesture
John Spurlockcd686b52013-06-05 10:13:46 -0400112 Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)",
Daniel Sandler2b99a492013-02-05 13:05:44 -0500113 (int) event.getX(), (int) event.getY()));
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700114 mTouchingPanel = null;
115 return true;
116 }
John Spurlock919adac2012-10-02 16:41:12 -0400117 boolean enabled = panel.isEnabled();
Daniel Sandler67eab792012-10-02 17:08:23 -0400118 if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
John Spurlock919adac2012-10-02 16:41:12 -0400119 (enabled ? "" : " (disabled)"));
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700120 if (!enabled) {
121 // panel is disabled, so we'll eat the gesture
John Spurlockcd686b52013-06-05 10:13:46 -0400122 Log.v(TAG, String.format(
Daniel Sandler2b99a492013-02-05 13:05:44 -0500123 "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)",
124 panel, (int) event.getX(), (int) event.getY()));
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700125 mTouchingPanel = null;
126 return true;
127 }
Daniel Sandler198a0302012-08-17 16:04:31 -0400128 startOpeningPanel(panel);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400129 }
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700130 final boolean result = mTouchingPanel != null
Daniel Sandler040c2e42012-10-17 00:56:33 -0400131 ? mTouchingPanel.onTouchEvent(event)
Daniel Sandlerefb0faf2012-10-10 14:15:34 -0700132 : true;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400133 return result;
134 }
135
Daniel Sandler198a0302012-08-17 16:04:31 -0400136 // called from PanelView when self-expanding, too
137 public void startOpeningPanel(PanelView panel) {
Daniel Sandler67eab792012-10-02 17:08:23 -0400138 if (DEBUG) LOG("startOpeningPanel: " + panel);
Daniel Sandler198a0302012-08-17 16:04:31 -0400139 mTouchingPanel = panel;
140 mPanelHolder.setSelectedPanel(mTouchingPanel);
Daniel Sandler67eab792012-10-02 17:08:23 -0400141 for (PanelView pv : mPanels) {
142 if (pv != panel) {
143 pv.collapse();
144 }
145 }
Daniel Sandler198a0302012-08-17 16:04:31 -0400146 }
147
Daniel Sandler08d05e32012-08-08 16:39:54 -0400148 public void panelExpansionChanged(PanelView panel, float frac) {
149 boolean fullyClosed = true;
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400150 PanelView fullyOpenedPanel = null;
Daniel Sandler67eab792012-10-02 17:08:23 -0400151 if (DEBUG) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
152 mPanelExpandedFractionSum = 0f;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400153 for (PanelView pv : mPanels) {
Daniel Sandler173bae22012-09-25 14:37:42 -0400154 final boolean visible = pv.getVisibility() == View.VISIBLE;
Daniel Sandler978f8532012-08-15 15:48:16 -0400155 // adjust any other panels that may be partially visible
Daniel Sandler08d05e32012-08-08 16:39:54 -0400156 if (pv.getExpandedHeight() > 0f) {
Daniel Sandler198a0302012-08-17 16:04:31 -0400157 if (mState == STATE_CLOSED) {
158 go(STATE_OPENING);
159 onPanelPeeked();
160 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400161 fullyClosed = false;
162 final float thisFrac = pv.getExpandedFraction();
Daniel Sandler67eab792012-10-02 17:08:23 -0400163 mPanelExpandedFractionSum += (visible ? thisFrac : 0);
164 if (DEBUG) LOG("panelExpansionChanged: -> %s: f=%.1f", pv.getName(), thisFrac);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400165 if (panel == pv) {
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400166 if (thisFrac == 1f) fullyOpenedPanel = panel;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400167 }
168 }
Daniel Sandler173bae22012-09-25 14:37:42 -0400169 if (pv.getExpandedHeight() > 0f) {
170 if (!visible) pv.setVisibility(View.VISIBLE);
171 } else {
172 if (visible) pv.setVisibility(View.GONE);
173 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400174 }
Daniel Sandler67eab792012-10-02 17:08:23 -0400175 mPanelExpandedFractionSum /= mPanels.size();
Daniel Sandler978f8532012-08-15 15:48:16 -0400176 if (fullyOpenedPanel != null && !mTracking) {
177 go(STATE_OPEN);
178 onPanelFullyOpened(fullyOpenedPanel);
Daniel Sandler198a0302012-08-17 16:04:31 -0400179 } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) {
Daniel Sandler978f8532012-08-15 15:48:16 -0400180 go(STATE_CLOSED);
181 onAllPanelsCollapsed();
182 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400183
Daniel Sandler67eab792012-10-02 17:08:23 -0400184 if (DEBUG) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400185 (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
Daniel Sandler08d05e32012-08-08 16:39:54 -0400186 }
187
188 public void collapseAllPanels(boolean animate) {
Daniel Sandler198a0302012-08-17 16:04:31 -0400189 boolean waiting = false;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400190 for (PanelView pv : mPanels) {
Daniel Sandler198a0302012-08-17 16:04:31 -0400191 if (animate && !pv.isFullyCollapsed()) {
192 pv.collapse();
193 waiting = true;
Daniel Sandler08d05e32012-08-08 16:39:54 -0400194 } else {
195 pv.setExpandedFraction(0); // just in case
Daniel Sandler67eab792012-10-02 17:08:23 -0400196 pv.setVisibility(View.GONE);
Daniel Sandler08d05e32012-08-08 16:39:54 -0400197 }
198 }
Daniel Sandler67eab792012-10-02 17:08:23 -0400199 if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
Daniel Sandlerc38bbc32012-10-05 12:21:38 -0400200 if (!waiting && mState != STATE_CLOSED) {
John Spurlock209bede2013-07-17 12:23:27 -0400201 // it's possible that nothing animated, so we replicate the termination
Daniel Sandler198a0302012-08-17 16:04:31 -0400202 // conditions of panelExpansionChanged here
203 go(STATE_CLOSED);
204 onAllPanelsCollapsed();
205 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400206 }
207
208 public void onPanelPeeked() {
Daniel Sandler67eab792012-10-02 17:08:23 -0400209 if (DEBUG) LOG("onPanelPeeked");
Daniel Sandler08d05e32012-08-08 16:39:54 -0400210 }
211
212 public void onAllPanelsCollapsed() {
Daniel Sandler67eab792012-10-02 17:08:23 -0400213 if (DEBUG) LOG("onAllPanelsCollapsed");
Daniel Sandler08d05e32012-08-08 16:39:54 -0400214 }
215
Daniel Sandler8e72c9e2012-08-15 00:09:26 -0400216 public void onPanelFullyOpened(PanelView openPanel) {
Daniel Sandler67eab792012-10-02 17:08:23 -0400217 if (DEBUG) LOG("onPanelFullyOpened");
Daniel Sandler08d05e32012-08-08 16:39:54 -0400218 }
Daniel Sandler978f8532012-08-15 15:48:16 -0400219
220 public void onTrackingStarted(PanelView panel) {
221 mTracking = true;
Daniel Sandler67eab792012-10-02 17:08:23 -0400222 if (DEBUG && panel != mTouchingPanel) {
Daniel Sandler978f8532012-08-15 15:48:16 -0400223 LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)",
224 panel, mTouchingPanel);
225 }
226 }
227
228 public void onTrackingStopped(PanelView panel) {
229 mTracking = false;
230 panelExpansionChanged(panel, panel.getExpandedFraction());
231 }
Daniel Sandler08d05e32012-08-08 16:39:54 -0400232}