ExpandableNotificationRow.java revision 863834bd96bdebcf21f4c4a7d8285d4858c061e4
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 boolean mIsBelowSpeedBump;
56    private View mVetoButton;
57
58    public ExpandableNotificationRow(Context context, AttributeSet attrs) {
59        super(context, attrs);
60    }
61
62    @Override
63    protected void onFinishInflate() {
64        super.onFinishInflate();
65        mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
66        mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
67        mVetoButton = findViewById(R.id.veto);
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        notifyHeightChanged();
141    }
142
143    /**
144     * @param expansionDisabled whether to prevent notification expansion
145     */
146    public void setExpansionDisabled(boolean expansionDisabled) {
147        mExpansionDisabled = expansionDisabled;
148        notifyHeightChanged();
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    @Override
164    public int getIntrinsicHeight() {
165        if (isUserLocked()) {
166            return getActualHeight();
167        }
168        boolean inExpansionState = isExpanded();
169        if (!inExpansionState) {
170            // not expanded, so we return the collapsed size
171            return mRowMinHeight;
172        }
173
174        return mShowingPublic ? mRowMinHeight : getMaxExpandHeight();
175    }
176
177    /**
178     * Check whether the view state is currently expanded. This is given by the system in {@link
179     * #setSystemExpanded(boolean)} and can be overridden by user expansion or
180     * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
181     * view can differ from this state, if layout params are modified from outside.
182     *
183     * @return whether the view state is currently expanded.
184     */
185    private boolean isExpanded() {
186        return !mExpansionDisabled
187                && (!hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded());
188    }
189
190    @Override
191    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
192        super.onLayout(changed, left, top, right, bottom);
193        boolean updateExpandHeight = mMaxExpandHeight == 0;
194        mMaxExpandHeight = mPrivateLayout.getMaxHeight();
195        if (updateExpandHeight) {
196            applyExpansionToLayout();
197        }
198    }
199
200    public void setShowingPublic(boolean show) {
201        mShowingPublic = show;
202
203        // bail out if no public version
204        if (mPublicLayout.getChildCount() == 0) return;
205
206        // TODO: animation?
207        mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
208        mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
209    }
210
211    public int getMaxExpandHeight() {
212        return mMaxExpandHeight;
213    }
214
215    /**
216     * @return the potential height this view could expand in addition.
217     */
218    public int getExpandPotential() {
219        return getIntrinsicHeight() - getActualHeight();
220    }
221
222    @Override
223    public boolean isContentExpandable() {
224        return mPrivateLayout.isContentExpandable();
225    }
226
227    @Override
228    public void setActualHeight(int height, boolean notifyListeners) {
229        mPrivateLayout.setActualHeight(height);
230        invalidate();
231        super.setActualHeight(height, notifyListeners);
232    }
233
234    @Override
235    public int getMaxHeight() {
236        return mPrivateLayout.getMaxHeight();
237    }
238
239    @Override
240    public int getMinHeight() {
241        return mPrivateLayout.getMinHeight();
242    }
243
244    @Override
245    public void setClipTopAmount(int clipTopAmount) {
246        super.setClipTopAmount(clipTopAmount);
247        mPrivateLayout.setClipTopAmount(clipTopAmount);
248    }
249
250    public boolean isBelowSpeedBump() {
251        return mIsBelowSpeedBump;
252    }
253
254    public void setIsBelowSpeedBump(boolean isBelow) {
255        this.mIsBelowSpeedBump = isBelow;
256    }
257
258    public void notifyContentUpdated() {
259        mPrivateLayout.notifyContentUpdated();
260    }
261
262    @Override
263    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
264        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
265        int newHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
266        mVetoButton.measure(widthMeasureSpec, newHeightSpec);
267    }
268}
269