ExpandableNotificationRow.java revision dce3c4cca5d4df4cc49c1a9f0537e2fecdbc45d2
1/*
2 * Copyright (C) 2013 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
17package com.android.systemui.statusbar;
18
19import android.content.Context;
20import android.util.AttributeSet;
21import android.view.View;
22import android.view.accessibility.AccessibilityEvent;
23
24import com.android.systemui.R;
25
26public class ExpandableNotificationRow extends ActivatableNotificationView {
27    private int mRowMinHeight;
28    private int mRowMaxHeight;
29
30    /** Does this row contain layouts that can adapt to row expansion */
31    private boolean mExpandable;
32    /** Has the user actively changed the expansion state of this row */
33    private boolean mHasUserChangedExpansion;
34    /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */
35    private boolean mUserExpanded;
36    /** Is the user touching this row */
37    private boolean mUserLocked;
38    /** Are we showing the "public" version */
39    private boolean mShowingPublic;
40
41    /**
42     * Is this notification expanded by the system. The expansion state can be overridden by the
43     * user expansion.
44     */
45    private boolean mIsSystemExpanded;
46
47    /**
48     * Whether the notification expansion is disabled. This is the case on Keyguard.
49     */
50    private boolean mExpansionDisabled;
51
52    private NotificationContentView mPublicLayout;
53    private NotificationContentView mPrivateLayout;
54    private int mMaxExpandHeight;
55    private NotificationActivator mActivator;
56
57    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
58        super(context, attrs);
59    }
60
61    @Override
62    protected void onFinishInflate() {
63        super.onFinishInflate();
64        mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
65        mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
66
67        mActivator = new NotificationActivator(this);
68    }
69
70    @Override
71    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
72        if (super.onRequestSendAccessibilityEvent(child, event)) {
73            // Add a record for the entire layout since its content is somehow small.
74            // The event comes from a leaf view that is interacted with.
75            AccessibilityEvent record = AccessibilityEvent.obtain();
76            onInitializeAccessibilityEvent(record);
77            dispatchPopulateAccessibilityEvent(record);
78            event.appendRecord(record);
79            return true;
80        }
81        return false;
82    }
83
84    public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
85        mRowMinHeight = rowMinHeight;
86        mRowMaxHeight = rowMaxHeight;
87    }
88
89    public boolean isExpandable() {
90        return mExpandable;
91    }
92
93    public void setExpandable(boolean expandable) {
94        mExpandable = expandable;
95    }
96
97    /**
98     * @return whether the user has changed the expansion state
99     */
100    public boolean hasUserChangedExpansion() {
101        return mHasUserChangedExpansion;
102    }
103
104    public boolean isUserExpanded() {
105        return mUserExpanded;
106    }
107
108    /**
109     * Set this notification to be expanded by the user
110     *
111     * @param userExpanded whether the user wants this notification to be expanded
112     */
113    public void setUserExpanded(boolean userExpanded) {
114        mHasUserChangedExpansion = true;
115        mUserExpanded = userExpanded;
116    }
117
118    public boolean isUserLocked() {
119        return mUserLocked;
120    }
121
122    public void setUserLocked(boolean userLocked) {
123        mUserLocked = userLocked;
124    }
125
126    /**
127     * @return has the system set this notification to be expanded
128     */
129    public boolean isSystemExpanded() {
130        return mIsSystemExpanded;
131    }
132
133    /**
134     * Set this notification to be expanded by the system.
135     *
136     * @param expand whether the system wants this notification to be expanded.
137     */
138    public void setSystemExpanded(boolean expand) {
139        mIsSystemExpanded = expand;
140        applyExpansionToLayout();
141    }
142
143    /**
144     * @param expansionDisabled whether to prevent notification expansion
145     */
146    public void setExpansionDisabled(boolean expansionDisabled) {
147        mExpansionDisabled = expansionDisabled;
148        applyExpansionToLayout();
149    }
150
151    /**
152     * Apply an expansion state to the layout.
153     */
154    public void applyExpansionToLayout() {
155        boolean expand = isExpanded();
156        if (expand && mExpandable) {
157            setActualHeight(mMaxExpandHeight);
158        } else {
159            setActualHeight(mRowMinHeight);
160        }
161    }
162
163    /**
164     * If {@link #isExpanded()} then this is the greatest possible height this view can
165     * get and otherwise it is {@link #mRowMinHeight}.
166     *
167     * @return the maximum allowed expansion height of this view.
168     */
169    public int getMaximumAllowedExpandHeight() {
170        if (isUserLocked()) {
171            return getActualHeight();
172        }
173        boolean inExpansionState = isExpanded();
174        if (!inExpansionState) {
175            // not expanded, so we return the collapsed size
176            return mRowMinHeight;
177        }
178
179        return mShowingPublic ? mRowMinHeight : getMaxExpandHeight();
180    }
181
182    /**
183     * Check whether the view state is currently expanded. This is given by the system in {@link
184     * #setSystemExpanded(boolean)} and can be overridden by user expansion or
185     * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
186     * view can differ from this state, if layout params are modified from outside.
187     *
188     * @return whether the view state is currently expanded.
189     */
190    private boolean isExpanded() {
191        return !mExpansionDisabled
192                && (!hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded());
193    }
194
195    @Override
196    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
197        super.onLayout(changed, left, top, right, bottom);
198        boolean updateExpandHeight = mMaxExpandHeight == 0;
199        mMaxExpandHeight = mPrivateLayout.getMaxHeight();
200        if (updateExpandHeight) {
201            applyExpansionToLayout();
202        }
203    }
204
205    public void setShowingPublic(boolean show) {
206        mShowingPublic = show;
207
208        // bail out if no public version
209        if (mPublicLayout.getChildCount() == 0) return;
210
211        // TODO: animation?
212        mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
213        mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
214    }
215
216    /**
217     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
218     */
219    public void setDimmed(boolean dimmed) {
220        super.setDimmed(dimmed);
221        mActivator.setDimmed(dimmed);
222    }
223
224    public int getMaxExpandHeight() {
225        return mMaxExpandHeight;
226    }
227
228    public NotificationActivator getActivator() {
229        return mActivator;
230    }
231
232    /**
233     * @return the potential height this view could expand in addition.
234     */
235    public int getExpandPotential() {
236        return getMaximumAllowedExpandHeight() - getActualHeight();
237    }
238
239    @Override
240    public void setActualHeight(int height) {
241        mPrivateLayout.setActualHeight(height);
242        invalidate();
243        super.setActualHeight(height);
244    }
245
246    @Override
247    public int getMaxHeight() {
248        return mPrivateLayout.getMaxHeight();
249    }
250
251    @Override
252    public void setClipTopAmount(int clipTopAmount) {
253        super.setClipTopAmount(clipTopAmount);
254        mPrivateLayout.setClipTopAmount(clipTopAmount);
255    }
256
257    public void notifyContentUpdated() {
258        mPrivateLayout.notifyContentUpdated();
259    }
260}
261