Home | History | Annotate | Download | only in phone
      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 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         Log.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             Log.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()) {
    100             if (event.getAction() == MotionEvent.ACTION_DOWN) {
    101                 Log.v(TAG, String.format("onTouch: all panels disabled, ignoring touch at (%d,%d)",
    102                         (int) event.getX(), (int) event.getY()));
    103             }
    104             return false;
    105         }
    106 
    107         // figure out which panel needs to be talked to here
    108         if (event.getAction() == MotionEvent.ACTION_DOWN) {
    109             final PanelView panel = selectPanelForTouch(event);
    110             if (panel == null) {
    111                 // panel is not there, so we'll eat the gesture
    112                 Log.v(TAG, String.format("onTouch: no panel for touch at (%d,%d)",
    113                         (int) event.getX(), (int) event.getY()));
    114                 mTouchingPanel = null;
    115                 return true;
    116             }
    117             boolean enabled = panel.isEnabled();
    118             if (DEBUG) LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
    119                     (enabled ? "" : " (disabled)"));
    120             if (!enabled) {
    121                 // panel is disabled, so we'll eat the gesture
    122                 Log.v(TAG, String.format(
    123                         "onTouch: panel (%s) is disabled, ignoring touch at (%d,%d)",
    124                         panel, (int) event.getX(), (int) event.getY()));
    125                 mTouchingPanel = null;
    126                 return true;
    127             }
    128             startOpeningPanel(panel);
    129         }
    130         final boolean result = mTouchingPanel != null
    131                 ? mTouchingPanel.onTouchEvent(event)
    132                 : true;
    133         return result;
    134     }
    135 
    136     // called from PanelView when self-expanding, too
    137     public void startOpeningPanel(PanelView panel) {
    138         if (DEBUG) LOG("startOpeningPanel: " + panel);
    139         mTouchingPanel = panel;
    140         mPanelHolder.setSelectedPanel(mTouchingPanel);
    141         for (PanelView pv : mPanels) {
    142             if (pv != panel) {
    143                 pv.collapse();
    144             }
    145         }
    146     }
    147 
    148     public void panelExpansionChanged(PanelView panel, float frac) {
    149         boolean fullyClosed = true;
    150         PanelView fullyOpenedPanel = null;
    151         if (DEBUG) LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
    152         mPanelExpandedFractionSum = 0f;
    153         for (PanelView pv : mPanels) {
    154             final boolean visible = pv.getVisibility() == View.VISIBLE;
    155             // adjust any other panels that may be partially visible
    156             if (pv.getExpandedHeight() > 0f) {
    157                 if (mState == STATE_CLOSED) {
    158                     go(STATE_OPENING);
    159                     onPanelPeeked();
    160                 }
    161                 fullyClosed = false;
    162                 final float thisFrac = pv.getExpandedFraction();
    163                 mPanelExpandedFractionSum += (visible ? thisFrac : 0);
    164                 if (DEBUG) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
    165                 if (panel == pv) {
    166                     if (thisFrac == 1f) fullyOpenedPanel = panel;
    167                 }
    168             }
    169             if (pv.getExpandedHeight() > 0f) {
    170                 if (!visible) pv.setVisibility(View.VISIBLE);
    171             } else {
    172                 if (visible) pv.setVisibility(View.GONE);
    173             }
    174         }
    175         mPanelExpandedFractionSum /= mPanels.size();
    176         if (fullyOpenedPanel != null && !mTracking) {
    177             go(STATE_OPEN);
    178             onPanelFullyOpened(fullyOpenedPanel);
    179         } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) {
    180             go(STATE_CLOSED);
    181             onAllPanelsCollapsed();
    182         }
    183 
    184         if (DEBUG) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
    185                 (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
    186     }
    187 
    188     public void collapseAllPanels(boolean animate) {
    189         boolean waiting = false;
    190         for (PanelView pv : mPanels) {
    191             if (animate && !pv.isFullyCollapsed()) {
    192                 pv.collapse();
    193                 waiting = true;
    194             } else {
    195                 pv.setExpandedFraction(0); // just in case
    196                 pv.setVisibility(View.GONE);
    197                 pv.cancelPeek();
    198             }
    199         }
    200         if (DEBUG) LOG("collapseAllPanels: animate=%s waiting=%s", animate, waiting);
    201         if (!waiting && mState != STATE_CLOSED) {
    202             // it's possible that nothing animated, so we replicate the termination
    203             // conditions of panelExpansionChanged here
    204             go(STATE_CLOSED);
    205             onAllPanelsCollapsed();
    206         }
    207     }
    208 
    209     public void onPanelPeeked() {
    210         if (DEBUG) LOG("onPanelPeeked");
    211     }
    212 
    213     public void onAllPanelsCollapsed() {
    214         if (DEBUG) LOG("onAllPanelsCollapsed");
    215     }
    216 
    217     public void onPanelFullyOpened(PanelView openPanel) {
    218         if (DEBUG) LOG("onPanelFullyOpened");
    219     }
    220 
    221     public void onTrackingStarted(PanelView panel) {
    222         mTracking = true;
    223         if (DEBUG && panel != mTouchingPanel) {
    224             LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)",
    225                     panel, mTouchingPanel);
    226         }
    227     }
    228 
    229     public void onTrackingStopped(PanelView panel) {
    230         mTracking = false;
    231         panelExpansionChanged(panel, panel.getExpandedFraction());
    232     }
    233 }
    234