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 java.util.ArrayList; 20 21import android.content.Context; 22import android.util.AttributeSet; 23import android.util.Slog; 24import android.view.MotionEvent; 25import android.view.View; 26import android.widget.FrameLayout; 27 28public class PanelBar extends FrameLayout { 29 public static final boolean DEBUG = false; 30 public static final String TAG = PanelBar.class.getSimpleName(); 31 public static final void LOG(String fmt, Object... args) { 32 if (!DEBUG) return; 33 Slog.v(TAG, String.format(fmt, args)); 34 } 35 36 public static final int STATE_CLOSED = 0; 37 public static final int STATE_OPENING = 1; 38 public static final int STATE_OPEN = 2; 39 40 PanelHolder mPanelHolder; 41 ArrayList<PanelView> mPanels = new ArrayList<PanelView>(); 42 PanelView mTouchingPanel; 43 private int mState = STATE_CLOSED; 44 private boolean mTracking; 45 46 float mPanelExpandedFractionSum; 47 48 public void go(int state) { 49 if (DEBUG) LOG("go state: %d -> %d", mState, state); 50 mState = state; 51 } 52 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) { 69 Slog.e(TAG, "setPanelHolder: null PanelHolder", new Throwable()); 70 return; 71 } 72 ph.setBar(this); 73 mPanelHolder = ph; 74 final int N = ph.getChildCount(); 75 for (int i=0; i<N; i++) { 76 final View v = ph.getChildAt(i); 77 if (v != null && v instanceof PanelView) { 78 addPanel((PanelView) v); 79 } 80 } 81 } 82 83 public float getBarHeight() { 84 return getMeasuredHeight(); 85 } 86 87 public PanelView selectPanelForTouch(MotionEvent touch) { 88 final int N = mPanels.size(); 89 return mPanels.get((int)(N * touch.getX() / getMeasuredWidth())); 90 } 91 92 public boolean panelsEnabled() { 93 return true; 94 } 95 96 @Override 97 public boolean onTouchEvent(MotionEvent event) { 98 // Allow subclasses to implement enable/disable semantics 99 if (!panelsEnabled()) return false; 100 101 // figure out which panel needs to be talked to here 102 if (event.getAction() == MotionEvent.ACTION_DOWN) { 103 final PanelView panel = selectPanelForTouch(event); 104 if (panel == null) { 105 // panel is not there, so we'll eat the gesture 106 if (DEBUG) LOG("PanelBar.onTouch: no panel for x=%d, bailing", event.getX()); 107 mTouchingPanel = null; 108 return true; 109 } 110 boolean enabled = panel.isEnabled(); 111 if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel, 112 (enabled ? "" : " (disabled)")); 113 if (!enabled) { 114 // panel is disabled, so we'll eat the gesture 115 mTouchingPanel = null; 116 return true; 117 } 118 startOpeningPanel(panel); 119 } 120 final boolean result = mTouchingPanel != null 121 ? mTouchingPanel.onTouchEvent(event) 122 : true; 123 return result; 124 } 125 126 // called from PanelView when self-expanding, too 127 public void startOpeningPanel(PanelView panel) { 128 if (DEBUG) LOG("startOpeningPanel: " + panel); 129 mTouchingPanel = panel; 130 mPanelHolder.setSelectedPanel(mTouchingPanel); 131 for (PanelView pv : mPanels) { 132 if (pv != panel) { 133 pv.collapse(); 134 } 135 } 136 } 137 138 public void panelExpansionChanged(PanelView panel, float frac) { 139 boolean fullyClosed = true; 140 PanelView fullyOpenedPanel = null; 141 if (DEBUG) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName()); 142 mPanelExpandedFractionSum = 0f; 143 for (PanelView pv : mPanels) { 144 final boolean visible = pv.getVisibility() == View.VISIBLE; 145 // adjust any other panels that may be partially visible 146 if (pv.getExpandedHeight() > 0f) { 147 if (mState == STATE_CLOSED) { 148 go(STATE_OPENING); 149 onPanelPeeked(); 150 } 151 fullyClosed = false; 152 final float thisFrac = pv.getExpandedFraction(); 153 mPanelExpandedFractionSum += (visible ? thisFrac : 0); 154 if (DEBUG) LOG("panelExpansionChanged: -> %s: f=%.1f", pv.getName(), thisFrac); 155 if (panel == pv) { 156 if (thisFrac == 1f) fullyOpenedPanel = panel; 157 } 158 } 159 if (pv.getExpandedHeight() > 0f) { 160 if (!visible) pv.setVisibility(View.VISIBLE); 161 } else { 162 if (visible) pv.setVisibility(View.GONE); 163 } 164 } 165 mPanelExpandedFractionSum /= mPanels.size(); 166 if (fullyOpenedPanel != null && !mTracking) { 167 go(STATE_OPEN); 168 onPanelFullyOpened(fullyOpenedPanel); 169 } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) { 170 go(STATE_CLOSED); 171 onAllPanelsCollapsed(); 172 } 173 174 if (DEBUG) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState, 175 (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":""); 176 } 177 178 public void collapseAllPanels(boolean animate) { 179 boolean waiting = false; 180 for (PanelView pv : mPanels) { 181 if (animate && !pv.isFullyCollapsed()) { 182 pv.collapse(); 183 waiting = true; 184 } else { 185 pv.setExpandedFraction(0); // just in case 186 pv.setVisibility(View.GONE); 187 } 188 } 189 if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting); 190 if (!waiting && mState != STATE_CLOSED) { 191 // it's possible that nothing animated, so we replicate the termination 192 // conditions of panelExpansionChanged here 193 go(STATE_CLOSED); 194 onAllPanelsCollapsed(); 195 } 196 } 197 198 public void onPanelPeeked() { 199 if (DEBUG) LOG("onPanelPeeked"); 200 } 201 202 public void onAllPanelsCollapsed() { 203 if (DEBUG) LOG("onAllPanelsCollapsed"); 204 } 205 206 public void onPanelFullyOpened(PanelView openPanel) { 207 if (DEBUG) LOG("onPanelFullyOpened"); 208 } 209 210 public void onTrackingStarted(PanelView panel) { 211 mTracking = true; 212 if (DEBUG && panel != mTouchingPanel) { 213 LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)", 214 panel, mTouchingPanel); 215 } 216 } 217 218 public void onTrackingStopped(PanelView panel) { 219 mTracking = false; 220 panelExpansionChanged(panel, panel.getExpandedFraction()); 221 } 222} 223