ExpandableNotificationRow.java revision 1685e634fb0b14033bd436af8d7174436699ffec
151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren/*
251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * Copyright (C) 2013 The Android Open Source Project
351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren *
451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * Licensed under the Apache License, Version 2.0 (the "License");
551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * you may not use this file except in compliance with the License.
651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * You may obtain a copy of the License at
751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren *
851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren *      http://www.apache.org/licenses/LICENSE-2.0
951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren *
1051c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * Unless required by applicable law or agreed to in writing, software
1151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * distributed under the License is distributed on an "AS IS" BASIS,
1251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * See the License for the specific language governing permissions and
1451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren * limitations under the License.
1551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren */
1651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
1751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wrenpackage com.android.systemui.statusbar;
1851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
1951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wrenimport android.content.Context;
2051c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wrenimport android.util.AttributeSet;
21a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandlerimport android.view.View;
2251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wrenimport android.view.ViewGroup;
2351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wrenimport android.widget.FrameLayout;
2451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
251685e634fb0b14033bd436af8d7174436699ffecSelim Cinekimport com.android.internal.widget.SizeAdaptiveLayout;
26a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandlerimport com.android.systemui.R;
27a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler
2851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wrenpublic class ExpandableNotificationRow extends FrameLayout {
291685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private int mRowMinHeight;
301685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private int mRowMaxHeight;
3151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
321685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** Does this row contain layouts that can adapt to row expansion */
3351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    private boolean mExpandable;
341685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** Has the user actively changed the expansion state of this row */
351685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private boolean mHasUserChangedExpansion;
361685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
3751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    private boolean mUserExpanded;
381685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** Is the user touching this row */
3951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    private boolean mUserLocked;
401685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** Are we showing the "public" version */
41a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler    private boolean mShowingPublic;
4251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
431685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
441685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Is this notification expanded by the system. The expansion state can be overridden by the
451685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * user expansion.
461685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
471685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private boolean mIsSystemExpanded;
481685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private SizeAdaptiveLayout mPublicLayout;
491685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private SizeAdaptiveLayout mPrivateLayout;
501685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private int mMaxExpandHeight;
511685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private boolean mMaxHeightNeedsUpdate;
521685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
5351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
5451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        super(context, attrs);
5551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
5651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
571685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    @Override
581685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    protected void onFinishInflate() {
591685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        super.onFinishInflate();
601685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic);
611685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded);
6251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
6351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
641685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
651685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mRowMinHeight = rowMinHeight;
661685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mRowMaxHeight = rowMaxHeight;
671685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mMaxHeightNeedsUpdate = true;
6851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
6951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
7051c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public boolean isExpandable() {
7151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        return mExpandable;
7251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
7351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
7451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public void setExpandable(boolean expandable) {
7551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        mExpandable = expandable;
7651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
7751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
781685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
791685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @return whether the user has changed the expansion state
801685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
811685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public boolean hasUserChangedExpansion() {
821685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        return mHasUserChangedExpansion;
831685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
841685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
8551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public boolean isUserExpanded() {
8651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        return mUserExpanded;
8751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
8851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
891685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
901685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Set this notification to be expanded by the user
911685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     *
921685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @param userExpanded whether the user wants this notification to be expanded
931685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
9451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public void setUserExpanded(boolean userExpanded) {
951685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mHasUserChangedExpansion = true;
9651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        mUserExpanded = userExpanded;
9751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
9851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
9951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public boolean isUserLocked() {
10051c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        return mUserLocked;
10151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
10251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
10351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public void setUserLocked(boolean userLocked) {
10451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        mUserLocked = userLocked;
10551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
10651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
1071685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1081685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @return has the system set this notification to be expanded
1091685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
1101685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public boolean isSystemExpanded() {
1111685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        return mIsSystemExpanded;
1121685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1131685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1141685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1151685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Set this notification to be expanded by the system.
1161685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     *
1171685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @param expand whether the system wants this notification to be expanded.
1181685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
1191685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public void setSystemExpanded(boolean expand) {
1201685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mIsSystemExpanded = expand;
1211685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        applyExpansionToLayout(expand);
1221685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1231685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1241685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1251685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Apply an expansion state to the layout.
1261685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     *
1271685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @param expand should the layout be in the expanded state
1281685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
1291685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public void applyExpansionToLayout(boolean expand) {
13051c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        ViewGroup.LayoutParams lp = getLayoutParams();
13151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        if (expand && mExpandable) {
13251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren            lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
13351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        } else {
1341685e634fb0b14033bd436af8d7174436699ffecSelim Cinek            lp.height = mRowMinHeight;
13551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        }
13651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        setLayoutParams(lp);
13751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
138a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler
1391685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1401685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * If {@link #isExpanded()} then this is the greatest possible height this view can
1411685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * get and otherwise it is {@link #mRowMinHeight}.
1421685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     *
1431685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @return the maximum allowed expansion height of this view.
1441685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
1451685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public int getMaximumAllowedExpandHeight() {
1461685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        boolean inExpansionState = isExpanded();
1471685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        if (!inExpansionState) {
1481685e634fb0b14033bd436af8d7174436699ffecSelim Cinek            // not expanded, so we return the collapsed size
1491685e634fb0b14033bd436af8d7174436699ffecSelim Cinek            return mRowMinHeight;
1501685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        }
1511685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1521685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        return mShowingPublic ? mRowMinHeight : getMaxExpandHeight();
1531685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1541685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1551685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1561685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1571685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private void updateMaxExpandHeight() {
1581685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        ViewGroup.LayoutParams lp = getLayoutParams();
1591685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        int oldHeight = lp.height;
1601685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
1611685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        setLayoutParams(lp);
1621685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        measure(View.MeasureSpec.makeMeasureSpec(getMeasuredWidth(), View.MeasureSpec.EXACTLY),
1631685e634fb0b14033bd436af8d7174436699ffecSelim Cinek                View.MeasureSpec.makeMeasureSpec(mRowMaxHeight, View.MeasureSpec.AT_MOST));
1641685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        lp.height = oldHeight;
1651685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        setLayoutParams(lp);
1661685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mMaxExpandHeight = getMeasuredHeight();
1671685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1681685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1691685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1701685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Check whether the view state is currently expanded. This is given by the system in {@link
1711685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * #setSystemExpanded(boolean)} and can be overridden by user expansion or
1721685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
1731685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * view can differ from this state, if layout params are modified from outside.
1741685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     *
1751685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @return whether the view state is currently expanded.
1761685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
1771685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private boolean isExpanded() {
1781685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        return !hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded();
1791685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1801685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1811685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    @Override
1821685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1831685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        super.onLayout(changed, left, top, right, bottom);
1841685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mMaxHeightNeedsUpdate = true;
1851685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1861685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
187a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler    public void setShowingPublic(boolean show) {
188a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler        mShowingPublic = show;
189a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler
190a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler        // bail out if no public version
1911685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        if (mPublicLayout.getChildCount() == 0) return;
192a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler
193a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler        // TODO: animation?
1941685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
1951685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
1961685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1971685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1981685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public int getMaxExpandHeight() {
1991685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        if (mMaxHeightNeedsUpdate) {
2001685e634fb0b14033bd436af8d7174436699ffecSelim Cinek            updateMaxExpandHeight();
2011685e634fb0b14033bd436af8d7174436699ffecSelim Cinek            mMaxHeightNeedsUpdate = false;
2021685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        }
2031685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        return mMaxExpandHeight;
204a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler    }
20551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren}
206