ExpandableNotificationRow.java revision d2319fbe6a53ac4c38ca02e4d8e32da86ed0994b
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;
22fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggiimport android.view.accessibility.AccessibilityEvent;
2351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
24a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandlerimport com.android.systemui.R;
25a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler
264222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggipublic class ExpandableNotificationRow extends ActivatableNotificationView {
271685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private int mRowMinHeight;
281685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private int mRowMaxHeight;
2951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
301685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** Does this row contain layouts that can adapt to row expansion */
3151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    private boolean mExpandable;
321685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** Has the user actively changed the expansion state of this row */
331685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private boolean mHasUserChangedExpansion;
341685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
3551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    private boolean mUserExpanded;
361685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** Is the user touching this row */
3751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    private boolean mUserLocked;
381685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /** Are we showing the "public" version */
39a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler    private boolean mShowingPublic;
40ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    private boolean mSensitive;
41ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    private boolean mShowingPublicInitialized;
42ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    private boolean mShowingPublicForIntrinsicHeight;
4351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
441685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
451685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Is this notification expanded by the system. The expansion state can be overridden by the
461685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * user expansion.
471685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
481685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private boolean mIsSystemExpanded;
49dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi
50dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi    /**
51dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi     * Whether the notification expansion is disabled. This is the case on Keyguard.
52dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi     */
53dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi    private boolean mExpansionDisabled;
54dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi
55be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    private NotificationContentView mPublicLayout;
56be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    private NotificationContentView mPrivateLayout;
571685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private int mMaxExpandHeight;
58863834bd96bdebcf21f4c4a7d8285d4858c061e4Selim Cinek    private View mVetoButton;
590d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    private boolean mClearable;
6078403d79739605511ea88b653564d81d7bf4bbbaChris Wren    private ExpansionLogger mLogger;
6178403d79739605511ea88b653564d81d7bf4bbbaChris Wren    private String mLoggingKey;
62a5e211b1f2a8d055b369dadc464dc5d5bc3dd9c1Selim Cinek    private boolean mWasReset;
6378403d79739605511ea88b653564d81d7bf4bbbaChris Wren
6478403d79739605511ea88b653564d81d7bf4bbbaChris Wren    public interface ExpansionLogger {
6578403d79739605511ea88b653564d81d7bf4bbbaChris Wren        public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
6678403d79739605511ea88b653564d81d7bf4bbbaChris Wren    }
671685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
6851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
6951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        super(context, attrs);
7051c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
7151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
72a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer    /**
73a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer     * Resets this view so it can be re-used for an updated notification.
74a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer     */
7522f2ee567dd1b1a42432251229bcb2f05c1c4700Christoph Studer    @Override
76a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer    public void reset() {
7722f2ee567dd1b1a42432251229bcb2f05c1c4700Christoph Studer        super.reset();
78a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mRowMinHeight = 0;
7978403d79739605511ea88b653564d81d7bf4bbbaChris Wren        final boolean wasExpanded = isExpanded();
80a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mRowMaxHeight = 0;
81a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mExpandable = false;
82a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mHasUserChangedExpansion = false;
83a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mUserLocked = false;
84a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mShowingPublic = false;
85ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        mSensitive = false;
86ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        mShowingPublicInitialized = false;
87a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mIsSystemExpanded = false;
88a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mExpansionDisabled = false;
89a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mPublicLayout.reset();
90a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mPrivateLayout.reset();
9131094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        resetHeight();
9231094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        logExpansionEvent(false, wasExpanded);
9331094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek    }
9431094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek
9531094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek    public void resetHeight() {
96a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        mMaxExpandHeight = 0;
97a5e211b1f2a8d055b369dadc464dc5d5bc3dd9c1Selim Cinek        mWasReset = true;
9831094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        onHeightReset();
99a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer    }
100a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer
101251957d76e57eb6e5f8068b37346144e10e586a4Jorim Jaggi    @Override
102251957d76e57eb6e5f8068b37346144e10e586a4Jorim Jaggi    protected void onFinishInflate() {
103251957d76e57eb6e5f8068b37346144e10e586a4Jorim Jaggi        super.onFinishInflate();
104be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
105be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
106863834bd96bdebcf21f4c4a7d8285d4858c061e4Selim Cinek        mVetoButton = findViewById(R.id.veto);
107fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi    }
108fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi
109fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi    @Override
110fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
111fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi        if (super.onRequestSendAccessibilityEvent(child, event)) {
112fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi            // Add a record for the entire layout since its content is somehow small.
113fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi            // The event comes from a leaf view that is interacted with.
114fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi            AccessibilityEvent record = AccessibilityEvent.obtain();
115fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi            onInitializeAccessibilityEvent(record);
116fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi            dispatchPopulateAccessibilityEvent(record);
117fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi            event.appendRecord(record);
118fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi            return true;
119fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi        }
120fe40f7d13bfc1faa35c9a131ce4be5104cb8f6b9Jorim Jaggi        return false;
121c5dc0d0cce373fbf292e13633c114a431d747167Jorim Jaggi    }
12251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
123e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock    @Override
124e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock    public void setDark(boolean dark, boolean fade) {
125e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock        super.setDark(dark, fade);
126e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock        final NotificationContentView showing = getShowingLayout();
127e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock        if (showing != null) {
128e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock            showing.setDark(dark, fade);
129e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock        }
130e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock    }
131e15452bb49d2531eee3086acb4763dd125f8053aJohn Spurlock
1321685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
1331685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mRowMinHeight = rowMinHeight;
1341685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mRowMaxHeight = rowMaxHeight;
13551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
13651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
13751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public boolean isExpandable() {
13851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        return mExpandable;
13951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
14051c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
14151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public void setExpandable(boolean expandable) {
14251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        mExpandable = expandable;
14351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
14451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
1451685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1461685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @return whether the user has changed the expansion state
1471685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
1481685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public boolean hasUserChangedExpansion() {
1491685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        return mHasUserChangedExpansion;
1501685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1511685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
15251c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public boolean isUserExpanded() {
15351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        return mUserExpanded;
15451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
15551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
1561685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1571685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Set this notification to be expanded by the user
1581685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     *
1591685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @param userExpanded whether the user wants this notification to be expanded
1601685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
16151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public void setUserExpanded(boolean userExpanded) {
162a7fe63190cc3f95af1830886edd80acef0c334e3Christoph Studer        if (userExpanded && !mExpandable) return;
16378403d79739605511ea88b653564d81d7bf4bbbaChris Wren        final boolean wasExpanded = isExpanded();
1641685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        mHasUserChangedExpansion = true;
16551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        mUserExpanded = userExpanded;
16678403d79739605511ea88b653564d81d7bf4bbbaChris Wren        logExpansionEvent(true, wasExpanded);
16751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
16851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
169ccd14fbcfe613eae71f0e00c39f38e5125749389Selim Cinek    public void resetUserExpansion() {
170ccd14fbcfe613eae71f0e00c39f38e5125749389Selim Cinek        mHasUserChangedExpansion = false;
171ccd14fbcfe613eae71f0e00c39f38e5125749389Selim Cinek        mUserExpanded = false;
172ccd14fbcfe613eae71f0e00c39f38e5125749389Selim Cinek    }
173ccd14fbcfe613eae71f0e00c39f38e5125749389Selim Cinek
17451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public boolean isUserLocked() {
17551c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        return mUserLocked;
17651c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
17751c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
17851c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    public void setUserLocked(boolean userLocked) {
17951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        mUserLocked = userLocked;
18051c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
18151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren
1821685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1831685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @return has the system set this notification to be expanded
1841685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
1851685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public boolean isSystemExpanded() {
1861685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        return mIsSystemExpanded;
1871685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
1881685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
1891685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
1901685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Set this notification to be expanded by the system.
1911685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     *
1921685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @param expand whether the system wants this notification to be expanded.
1931685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
1941685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public void setSystemExpanded(boolean expand) {
19531094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        if (expand != mIsSystemExpanded) {
19631094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            final boolean wasExpanded = isExpanded();
19731094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            mIsSystemExpanded = expand;
19831094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            notifyHeightChanged();
19931094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            logExpansionEvent(false, wasExpanded);
20031094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        }
201dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi    }
202dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi
203dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi    /**
204dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi     * @param expansionDisabled whether to prevent notification expansion
205dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi     */
206dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi    public void setExpansionDisabled(boolean expansionDisabled) {
20731094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        if (expansionDisabled != mExpansionDisabled) {
20831094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            final boolean wasExpanded = isExpanded();
20931094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            mExpansionDisabled = expansionDisabled;
21031094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            logExpansionEvent(false, wasExpanded);
21131094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            if (wasExpanded != isExpanded()) {
21231094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek                notifyHeightChanged();
21331094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek            }
21431094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        }
2151685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
2161685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
2171685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
2180d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler     * @return Can the underlying notification be cleared?
2190d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler     */
2200d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    public boolean isClearable() {
2210d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler        return mClearable;
2220d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    }
2230d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler
2240d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    /**
2250d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler     * Set whether the notification can be cleared.
2260d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler     *
2270d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler     * @param clearable
2280d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler     */
2290d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    public void setClearable(boolean clearable) {
2300d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler        mClearable = clearable;
2310d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler        updateVetoButton();
2320d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    }
2330d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler
2340d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    /**
2351685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Apply an expansion state to the layout.
2361685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
237dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi    public void applyExpansionToLayout() {
238dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi        boolean expand = isExpanded();
23951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        if (expand && mExpandable) {
240be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            setActualHeight(mMaxExpandHeight);
24151c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        } else {
242be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            setActualHeight(mRowMinHeight);
24351c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren        }
24451c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren    }
245a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler
2469cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi    @Override
2479cbadd3c08a7d7dd3412743dd04aecb16c5a1595Jorim Jaggi    public int getIntrinsicHeight() {
248be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        if (isUserLocked()) {
249be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi            return getActualHeight();
250be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        }
2511685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        boolean inExpansionState = isExpanded();
2521685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        if (!inExpansionState) {
2531685e634fb0b14033bd436af8d7174436699ffecSelim Cinek            // not expanded, so we return the collapsed size
2541685e634fb0b14033bd436af8d7174436699ffecSelim Cinek            return mRowMinHeight;
2551685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        }
2561685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
257ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        return mShowingPublicForIntrinsicHeight ? mRowMinHeight : getMaxExpandHeight();
2581685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
2591685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
2601685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    /**
2611685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * Check whether the view state is currently expanded. This is given by the system in {@link
2621685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * #setSystemExpanded(boolean)} and can be overridden by user expansion or
2631685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
2641685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * view can differ from this state, if layout params are modified from outside.
2651685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     *
2661685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     * @return whether the view state is currently expanded.
2671685e634fb0b14033bd436af8d7174436699ffecSelim Cinek     */
2681685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    private boolean isExpanded() {
269dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi        return !mExpansionDisabled
270dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi                && (!hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded());
2711685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
2721685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
2731685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    @Override
2741685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
2751685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        super.onLayout(changed, left, top, right, bottom);
276a5e211b1f2a8d055b369dadc464dc5d5bc3dd9c1Selim Cinek        boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
277d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek        updateMaxExpandHeight();
278be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        if (updateExpandHeight) {
279dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2Jorim Jaggi            applyExpansionToLayout();
280be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        }
281a5e211b1f2a8d055b369dadc464dc5d5bc3dd9c1Selim Cinek        mWasReset = false;
2821685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    }
2831685e634fb0b14033bd436af8d7174436699ffecSelim Cinek
284d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek    private void updateMaxExpandHeight() {
285d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek        int intrinsicBefore = getIntrinsicHeight();
286d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek        mMaxExpandHeight = mPrivateLayout.getMaxHeight();
287d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek        if (intrinsicBefore != getIntrinsicHeight()) {
288d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek            notifyHeightChanged();
289d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek        }
290d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek    }
291d2319fbe6a53ac4c38ca02e4d8e32da86ed0994bSelim Cinek
292ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    public void setSensitive(boolean sensitive) {
293ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        mSensitive = sensitive;
294ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    }
295ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi
296ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
297ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        mShowingPublicForIntrinsicHeight = mSensitive && hideSensitive;
298ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    }
299ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi
300ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
301ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            long duration) {
302ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        boolean oldShowingPublic = mShowingPublic;
303ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        mShowingPublic = mSensitive && hideSensitive;
304ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
305ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            return;
306ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        }
307a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler
308a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler        // bail out if no public version
3091685e634fb0b14033bd436af8d7174436699ffecSelim Cinek        if (mPublicLayout.getChildCount() == 0) return;
310a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler
311ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        if (!animated) {
312ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            mPublicLayout.animate().cancel();
313ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            mPrivateLayout.animate().cancel();
314ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            mPublicLayout.setAlpha(1f);
315ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            mPrivateLayout.setAlpha(1f);
316ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
317ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            mPrivateLayout.setVisibility(mShowingPublic ? View.INVISIBLE : View.VISIBLE);
318ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        } else {
319ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi            animateShowingPublic(delay, duration);
320ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        }
3210d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler
3220d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler        updateVetoButton();
323ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        mShowingPublicInitialized = true;
324ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    }
325ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi
326ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi    private void animateShowingPublic(long delay, long duration) {
327ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
328ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
329ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        source.setVisibility(View.VISIBLE);
330ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        target.setVisibility(View.VISIBLE);
331ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        target.setAlpha(0f);
332ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        source.animate().cancel();
333ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        target.animate().cancel();
334ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        source.animate()
335ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .alpha(0f)
336ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .withLayer()
337ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .setStartDelay(delay)
338ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .setDuration(duration)
339ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .withEndAction(new Runnable() {
340ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                    @Override
341ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                    public void run() {
342ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                        source.setVisibility(View.INVISIBLE);
343ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                    }
344ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                });
345ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        target.animate()
346ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .alpha(1f)
347ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .withLayer()
348ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .setStartDelay(delay)
349ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi                .setDuration(duration);
3500d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    }
3510d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler
3520d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler    private void updateVetoButton() {
3530d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler        // public versions cannot be dismissed
3540d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655Dan Sandler        mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
355a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler    }
356251957d76e57eb6e5f8068b37346144e10e586a4Jorim Jaggi
3571685e634fb0b14033bd436af8d7174436699ffecSelim Cinek    public int getMaxExpandHeight() {
358ae44128776410abd11bd06ae700db9cc4606a773Jorim Jaggi        return mShowingPublicForIntrinsicHeight ? mRowMinHeight : mMaxExpandHeight;
359a5e0f415d351ad1a9c0ffde8d93df91a2384591fDan Sandler    }
360584a7aa62c54bcbd654a6696d4fbb56e124874e7Jorim Jaggi
361be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
3624222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    public boolean isContentExpandable() {
3632f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        NotificationContentView showingLayout = getShowingLayout();
3642f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        return showingLayout.isContentExpandable();
3654222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    }
3664222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi
3674222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    @Override
368d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi    public void setActualHeight(int height, boolean notifyListeners) {
369c9c00ae2fa5fb787e9f12705f8cd8de445ecde4bSelim Cinek        mPrivateLayout.setActualHeight(height);
3702f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        mPublicLayout.setActualHeight(height);
371be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        invalidate();
372d552d9d8e964c102e6832610be46cf2c041e8829Jorim Jaggi        super.setActualHeight(height, notifyListeners);
373be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
374be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
375be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
376be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public int getMaxHeight() {
3772f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        NotificationContentView showingLayout = getShowingLayout();
3782f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        return showingLayout.getMaxHeight();
379be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
380be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
381be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    @Override
3824222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    public int getMinHeight() {
3832f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        NotificationContentView showingLayout = getShowingLayout();
3842f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        return showingLayout.getMinHeight();
3854222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    }
3864222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi
3874222d9a7fb87d73e1443ec1a2de9782b05741af6Jorim Jaggi    @Override
388be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void setClipTopAmount(int clipTopAmount) {
389be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        super.setClipTopAmount(clipTopAmount);
390be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mPrivateLayout.setClipTopAmount(clipTopAmount);
3912f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        mPublicLayout.setClipTopAmount(clipTopAmount);
392be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    }
393be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi
394be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi    public void notifyContentUpdated() {
3952f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        mPublicLayout.notifyContentUpdated();
396be565dfc1c17b7ddafa9753851b8f82849fd3f42Jorim Jaggi        mPrivateLayout.notifyContentUpdated();
397343e6e258ab6a9f647eabebaed05ce3acafd2ff1Selim Cinek    }
3987d447726e2cb9fae80db417012039828daab8fe7Selim Cinek
39931094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek    public boolean isMaxExpandHeightInitialized() {
40031094df5c6e3cb3a4a4faacb091e35eea1f6a5deSelim Cinek        return mMaxExpandHeight != 0;
4017d447726e2cb9fae80db417012039828daab8fe7Selim Cinek    }
4022f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek
4032f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek    private NotificationContentView getShowingLayout() {
4042f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek        return mShowingPublic ? mPublicLayout : mPrivateLayout;
4052f0df8ae038dbb873bf2e11e1e13c75cf95b0198Selim Cinek    }
40678403d79739605511ea88b653564d81d7bf4bbbaChris Wren
40778403d79739605511ea88b653564d81d7bf4bbbaChris Wren    public void setExpansionLogger(ExpansionLogger logger, String key) {
40878403d79739605511ea88b653564d81d7bf4bbbaChris Wren        mLogger = logger;
40978403d79739605511ea88b653564d81d7bf4bbbaChris Wren        mLoggingKey = key;
41078403d79739605511ea88b653564d81d7bf4bbbaChris Wren    }
41178403d79739605511ea88b653564d81d7bf4bbbaChris Wren
41278403d79739605511ea88b653564d81d7bf4bbbaChris Wren
41378403d79739605511ea88b653564d81d7bf4bbbaChris Wren    private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
41478403d79739605511ea88b653564d81d7bf4bbbaChris Wren        final boolean nowExpanded = isExpanded();
41578403d79739605511ea88b653564d81d7bf4bbbaChris Wren        if (wasExpanded != nowExpanded && mLogger != null) {
41678403d79739605511ea88b653564d81d7bf4bbbaChris Wren            mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
41778403d79739605511ea88b653564d81d7bf4bbbaChris Wren        }
41878403d79739605511ea88b653564d81d7bf4bbbaChris Wren    }
41951c7510e493680b4aca1ed7695b35c52d2cd63ffChris Wren}
420