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