PanelBar.java revision 173bae2c674b2bc25cf376cbb4e150bd86703049
108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerpackage com.android.systemui.statusbar.phone;
208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport java.util.ArrayList;
408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.content.Context;
608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.util.AttributeSet;
708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.util.Slog;
808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.view.MotionEvent;
9173bae2c674b2bc25cf376cbb4e150bd86703049Daniel Sandlerimport android.view.View;
1008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerimport android.widget.FrameLayout;
1108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
1208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandlerpublic class PanelBar extends FrameLayout {
13bf4aa9d5bc34df144afcab45e8045d34a0ac090aDaniel Sandler    public static final boolean DEBUG = false;
14198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    public static final String TAG = PanelBar.class.getSimpleName();
1508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public static final void LOG(String fmt, Object... args) {
1608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        if (!DEBUG) return;
1708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        Slog.v(TAG, String.format(fmt, args));
1808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
1908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
20198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    public static final int STATE_CLOSED = 0;
21198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    public static final int STATE_OPENING = 1;
22198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    public static final int STATE_OPEN = 2;
23198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler
2408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    private PanelHolder mPanelHolder;
2508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    private ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
268e72c9e19cfb0b6c1463fa841f1dd02be8f3b4e1Daniel Sandler    protected PanelView mTouchingPanel;
27978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    private int mState = STATE_CLOSED;
28978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    private boolean mTracking;
29978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler
30198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    public void go(int state) {
31978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        LOG("go state: %d -> %d", mState, state);
32978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        mState = state;
33978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    }
3408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
3508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public PanelBar(Context context, AttributeSet attrs) {
3608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        super(context, attrs);
3708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
3808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
3908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    @Override
4008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    protected void onFinishInflate() {
4108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        super.onFinishInflate();
4208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
4308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
4408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void addPanel(PanelView pv) {
4508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        mPanels.add(pv);
4608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        pv.setBar(this);
4708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
4808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
4908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void setPanelHolder(PanelHolder ph) {
5008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        if (ph == null) {
5108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            Slog.e(TAG, "setPanelHolder: null PanelHolder", new Throwable());
5208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            return;
5308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        }
5408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        ph.setBar(this);
5508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        mPanelHolder = ph;
5608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        final int N = ph.getChildCount();
5708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        for (int i=0; i<N; i++) {
5808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            final PanelView v = (PanelView) ph.getChildAt(i);
5908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            if (v != null) {
6008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler                addPanel(v);
6108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            }
6208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        }
6308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
6408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
6508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public float getBarHeight() {
6608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        return getMeasuredHeight();
6708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
6808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
69cf591db04914d8ceadd982451b325bd8c4817086Daniel Sandler    public PanelView selectPanelForTouchX(float x) {
70cf591db04914d8ceadd982451b325bd8c4817086Daniel Sandler        final int N = mPanels.size();
71cf591db04914d8ceadd982451b325bd8c4817086Daniel Sandler        return mPanels.get((int)(N * x / getMeasuredWidth()));
72cf591db04914d8ceadd982451b325bd8c4817086Daniel Sandler    }
73cf591db04914d8ceadd982451b325bd8c4817086Daniel Sandler
745050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler    public boolean panelsEnabled() {
751e8feef1faca7d2f14bf459691dbe724c8cf5c88Daniel Sandler        return true;
761e8feef1faca7d2f14bf459691dbe724c8cf5c88Daniel Sandler    }
771e8feef1faca7d2f14bf459691dbe724c8cf5c88Daniel Sandler
7808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    @Override
7908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public boolean onTouchEvent(MotionEvent event) {
801e8feef1faca7d2f14bf459691dbe724c8cf5c88Daniel Sandler        // Allow subclasses to implement enable/disable semantics
815050813f15a1d39d49cb8eca5a3aa6df43c4d450Daniel Sandler        if (!panelsEnabled()) return false;
821e8feef1faca7d2f14bf459691dbe724c8cf5c88Daniel Sandler
8308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        // figure out which panel needs to be talked to here
8408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        if (event.getAction() == MotionEvent.ACTION_DOWN) {
85198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler            final PanelView panel = selectPanelForTouchX(event.getX());
86198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler            LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s", mState, panel);
87198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler            startOpeningPanel(panel);
8808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        }
8908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        final boolean result = mTouchingPanel.getHandle().dispatchTouchEvent(event);
9008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        return result;
9108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
9208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
93198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    // called from PanelView when self-expanding, too
94198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    public void startOpeningPanel(PanelView panel) {
95198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler        LOG("startOpeningPanel: " + panel);
96198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler        mTouchingPanel = panel;
97198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler        mPanelHolder.setSelectedPanel(mTouchingPanel);
98198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler    }
99198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler
10008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void panelExpansionChanged(PanelView panel, float frac) {
10108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        boolean fullyClosed = true;
1028e72c9e19cfb0b6c1463fa841f1dd02be8f3b4e1Daniel Sandler        PanelView fullyOpenedPanel = null;
103978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
10408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        for (PanelView pv : mPanels) {
105173bae2c674b2bc25cf376cbb4e150bd86703049Daniel Sandler            final boolean visible = pv.getVisibility() == View.VISIBLE;
106978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler            // adjust any other panels that may be partially visible
10708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            if (pv.getExpandedHeight() > 0f) {
108198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler                if (mState == STATE_CLOSED) {
109198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler                    go(STATE_OPENING);
110198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler                    onPanelPeeked();
111198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler                }
11208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler                fullyClosed = false;
11308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler                final float thisFrac = pv.getExpandedFraction();
114978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler                LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
11508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler                if (panel == pv) {
1168e72c9e19cfb0b6c1463fa841f1dd02be8f3b4e1Daniel Sandler                    if (thisFrac == 1f) fullyOpenedPanel = panel;
11708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler                } else {
11808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler                    pv.setExpandedFraction(1f-frac);
11908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler                }
12008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            }
121173bae2c674b2bc25cf376cbb4e150bd86703049Daniel Sandler            if (pv.getExpandedHeight() > 0f) {
122173bae2c674b2bc25cf376cbb4e150bd86703049Daniel Sandler                if (!visible) pv.setVisibility(View.VISIBLE);
123173bae2c674b2bc25cf376cbb4e150bd86703049Daniel Sandler            } else {
124173bae2c674b2bc25cf376cbb4e150bd86703049Daniel Sandler                if (visible) pv.setVisibility(View.GONE);
125173bae2c674b2bc25cf376cbb4e150bd86703049Daniel Sandler            }
12608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        }
127978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        if (fullyOpenedPanel != null && !mTracking) {
128978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler            go(STATE_OPEN);
129978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler            onPanelFullyOpened(fullyOpenedPanel);
130198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler        } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) {
131978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler            go(STATE_CLOSED);
132978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler            onAllPanelsCollapsed();
133978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        }
13408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
135978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
1368e72c9e19cfb0b6c1463fa841f1dd02be8f3b4e1Daniel Sandler                (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
13708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
13808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
13908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void collapseAllPanels(boolean animate) {
140198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler        boolean waiting = false;
14108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        for (PanelView pv : mPanels) {
142198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler            if (animate && !pv.isFullyCollapsed()) {
143198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler                pv.collapse();
144198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler                waiting = true;
14508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            } else {
14608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler                pv.setExpandedFraction(0); // just in case
14708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler            }
148173bae2c674b2bc25cf376cbb4e150bd86703049Daniel Sandler            pv.setVisibility(View.GONE);
14908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        }
150198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler        if (!waiting) {
151198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler            // it's possible that nothing animated, so we replicate the termination
152198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler            // conditions of panelExpansionChanged here
153198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler            go(STATE_CLOSED);
154198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler            onAllPanelsCollapsed();
155198a0306e5b0ef6b02d61e299a4b4ab4c1c2cdc8Daniel Sandler        }
15608d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
15708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
15808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void onPanelPeeked() {
15908d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        LOG("onPanelPeeked");
16008d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
16108d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
16208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    public void onAllPanelsCollapsed() {
16308d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        LOG("onAllPanelsCollapsed");
16408d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
16508d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler
1668e72c9e19cfb0b6c1463fa841f1dd02be8f3b4e1Daniel Sandler    public void onPanelFullyOpened(PanelView openPanel) {
16708d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler        LOG("onPanelFullyOpened");
16808d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler    }
169978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler
170978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    public void onTrackingStarted(PanelView panel) {
171978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        mTracking = true;
172978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        if (panel != mTouchingPanel) {
173978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler            LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)",
174978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler                    panel, mTouchingPanel);
175978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        }
176978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    }
177978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler
178978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    public void onTrackingStopped(PanelView panel) {
179978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        mTracking = false;
180978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler        panelExpansionChanged(panel, panel.getExpandedFraction());
181978f853d189c1857190b4a2e200c7a283e31ca14Daniel Sandler    }
18208d05e3d1d6ade6924266296033981a96b47d5fbDaniel Sandler}
183