OSDN Git Service

Merge "Reset the notification expanded states on screen off" into lmp-dev
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / statusbar / ExpandableNotificationRow.java
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
17 package com.android.systemui.statusbar;
18
19 import android.content.Context;
20 import android.util.AttributeSet;
21 import android.view.View;
22 import android.view.accessibility.AccessibilityEvent;
23
24 import com.android.systemui.R;
25
26 public 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     private boolean mSensitive;
41     private boolean mShowingPublicInitialized;
42     private boolean mShowingPublicForIntrinsicHeight;
43
44     /**
45      * Is this notification expanded by the system. The expansion state can be overridden by the
46      * user expansion.
47      */
48     private boolean mIsSystemExpanded;
49
50     /**
51      * Whether the notification expansion is disabled. This is the case on Keyguard.
52      */
53     private boolean mExpansionDisabled;
54
55     private NotificationContentView mPublicLayout;
56     private NotificationContentView mPrivateLayout;
57     private int mMaxExpandHeight;
58     private View mVetoButton;
59     private boolean mClearable;
60     private ExpansionLogger mLogger;
61     private String mLoggingKey;
62     private boolean mWasReset;
63
64     public interface ExpansionLogger {
65         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
66     }
67
68     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
69         super(context, attrs);
70     }
71
72     /**
73      * Resets this view so it can be re-used for an updated notification.
74      */
75     @Override
76     public void reset() {
77         super.reset();
78         mRowMinHeight = 0;
79         final boolean wasExpanded = isExpanded();
80         mRowMaxHeight = 0;
81         mExpandable = false;
82         mHasUserChangedExpansion = false;
83         mUserLocked = false;
84         mShowingPublic = false;
85         mSensitive = false;
86         mShowingPublicInitialized = false;
87         mIsSystemExpanded = false;
88         mExpansionDisabled = false;
89         mPublicLayout.reset();
90         mPrivateLayout.reset();
91         mMaxExpandHeight = 0;
92         mWasReset = true;
93         logExpansionEvent(false, wasExpanded);
94     }
95
96     @Override
97     protected void onFinishInflate() {
98         super.onFinishInflate();
99         mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
100         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
101         mVetoButton = findViewById(R.id.veto);
102     }
103
104     @Override
105     public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
106         if (super.onRequestSendAccessibilityEvent(child, event)) {
107             // Add a record for the entire layout since its content is somehow small.
108             // The event comes from a leaf view that is interacted with.
109             AccessibilityEvent record = AccessibilityEvent.obtain();
110             onInitializeAccessibilityEvent(record);
111             dispatchPopulateAccessibilityEvent(record);
112             event.appendRecord(record);
113             return true;
114         }
115         return false;
116     }
117
118     public void setHeightRange(int rowMinHeight, int rowMaxHeight) {
119         mRowMinHeight = rowMinHeight;
120         mRowMaxHeight = rowMaxHeight;
121     }
122
123     public boolean isExpandable() {
124         return mExpandable;
125     }
126
127     public void setExpandable(boolean expandable) {
128         mExpandable = expandable;
129     }
130
131     /**
132      * @return whether the user has changed the expansion state
133      */
134     public boolean hasUserChangedExpansion() {
135         return mHasUserChangedExpansion;
136     }
137
138     public boolean isUserExpanded() {
139         return mUserExpanded;
140     }
141
142     /**
143      * Set this notification to be expanded by the user
144      *
145      * @param userExpanded whether the user wants this notification to be expanded
146      */
147     public void setUserExpanded(boolean userExpanded) {
148         if (userExpanded && !mExpandable) return;
149         final boolean wasExpanded = isExpanded();
150         mHasUserChangedExpansion = true;
151         mUserExpanded = userExpanded;
152         logExpansionEvent(true, wasExpanded);
153     }
154
155     public void resetUserExpansion() {
156         mHasUserChangedExpansion = false;
157         mUserExpanded = false;
158     }
159
160     public boolean isUserLocked() {
161         return mUserLocked;
162     }
163
164     public void setUserLocked(boolean userLocked) {
165         mUserLocked = userLocked;
166     }
167
168     /**
169      * @return has the system set this notification to be expanded
170      */
171     public boolean isSystemExpanded() {
172         return mIsSystemExpanded;
173     }
174
175     /**
176      * Set this notification to be expanded by the system.
177      *
178      * @param expand whether the system wants this notification to be expanded.
179      */
180     public void setSystemExpanded(boolean expand) {
181         final boolean wasExpanded = isExpanded();
182         mIsSystemExpanded = expand;
183         notifyHeightChanged();
184         logExpansionEvent(false, wasExpanded);
185     }
186
187     /**
188      * @param expansionDisabled whether to prevent notification expansion
189      */
190     public void setExpansionDisabled(boolean expansionDisabled) {
191         final boolean wasExpanded = isExpanded();
192         mExpansionDisabled = expansionDisabled;
193         logExpansionEvent(false, wasExpanded);
194         notifyHeightChanged();
195     }
196
197     /**
198      * @return Can the underlying notification be cleared?
199      */
200     public boolean isClearable() {
201         return mClearable;
202     }
203
204     /**
205      * Set whether the notification can be cleared.
206      *
207      * @param clearable
208      */
209     public void setClearable(boolean clearable) {
210         mClearable = clearable;
211         updateVetoButton();
212     }
213
214     /**
215      * Apply an expansion state to the layout.
216      */
217     public void applyExpansionToLayout() {
218         boolean expand = isExpanded();
219         if (expand && mExpandable) {
220             setActualHeight(mMaxExpandHeight);
221         } else {
222             setActualHeight(mRowMinHeight);
223         }
224     }
225
226     @Override
227     public int getIntrinsicHeight() {
228         if (isUserLocked()) {
229             return getActualHeight();
230         }
231         boolean inExpansionState = isExpanded();
232         if (!inExpansionState) {
233             // not expanded, so we return the collapsed size
234             return mRowMinHeight;
235         }
236
237         return mShowingPublicForIntrinsicHeight ? mRowMinHeight : getMaxExpandHeight();
238     }
239
240     /**
241      * Check whether the view state is currently expanded. This is given by the system in {@link
242      * #setSystemExpanded(boolean)} and can be overridden by user expansion or
243      * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this
244      * view can differ from this state, if layout params are modified from outside.
245      *
246      * @return whether the view state is currently expanded.
247      */
248     private boolean isExpanded() {
249         return !mExpansionDisabled
250                 && (!hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded());
251     }
252
253     @Override
254     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
255         super.onLayout(changed, left, top, right, bottom);
256         boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
257         mMaxExpandHeight = mPrivateLayout.getMaxHeight();
258         if (updateExpandHeight) {
259             applyExpansionToLayout();
260         }
261         mWasReset = false;
262     }
263
264     public void setSensitive(boolean sensitive) {
265         mSensitive = sensitive;
266     }
267
268     public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
269         mShowingPublicForIntrinsicHeight = mSensitive && hideSensitive;
270     }
271
272     public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
273             long duration) {
274         boolean oldShowingPublic = mShowingPublic;
275         mShowingPublic = mSensitive && hideSensitive;
276         if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
277             return;
278         }
279
280         // bail out if no public version
281         if (mPublicLayout.getChildCount() == 0) return;
282
283         if (!animated) {
284             mPublicLayout.animate().cancel();
285             mPrivateLayout.animate().cancel();
286             mPublicLayout.setAlpha(1f);
287             mPrivateLayout.setAlpha(1f);
288             mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
289             mPrivateLayout.setVisibility(mShowingPublic ? View.INVISIBLE : View.VISIBLE);
290         } else {
291             animateShowingPublic(delay, duration);
292         }
293
294         updateVetoButton();
295         mShowingPublicInitialized = true;
296     }
297
298     private void animateShowingPublic(long delay, long duration) {
299         final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
300         View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
301         source.setVisibility(View.VISIBLE);
302         target.setVisibility(View.VISIBLE);
303         target.setAlpha(0f);
304         source.animate().cancel();
305         target.animate().cancel();
306         source.animate()
307                 .alpha(0f)
308                 .withLayer()
309                 .setStartDelay(delay)
310                 .setDuration(duration)
311                 .withEndAction(new Runnable() {
312                     @Override
313                     public void run() {
314                         source.setVisibility(View.INVISIBLE);
315                     }
316                 });
317         target.animate()
318                 .alpha(1f)
319                 .withLayer()
320                 .setStartDelay(delay)
321                 .setDuration(duration);
322     }
323
324     private void updateVetoButton() {
325         // public versions cannot be dismissed
326         mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE);
327     }
328
329     public int getMaxExpandHeight() {
330         return mShowingPublicForIntrinsicHeight ? mRowMinHeight : mMaxExpandHeight;
331     }
332
333     @Override
334     public boolean isContentExpandable() {
335         NotificationContentView showingLayout = getShowingLayout();
336         return showingLayout.isContentExpandable();
337     }
338
339     @Override
340     public void setActualHeight(int height, boolean notifyListeners) {
341         mPrivateLayout.setActualHeight(height);
342         mPublicLayout.setActualHeight(height);
343         invalidate();
344         super.setActualHeight(height, notifyListeners);
345     }
346
347     @Override
348     public int getMaxHeight() {
349         NotificationContentView showingLayout = getShowingLayout();
350         return showingLayout.getMaxHeight();
351     }
352
353     @Override
354     public int getMinHeight() {
355         NotificationContentView showingLayout = getShowingLayout();
356         return showingLayout.getMinHeight();
357     }
358
359     @Override
360     public void setClipTopAmount(int clipTopAmount) {
361         super.setClipTopAmount(clipTopAmount);
362         mPrivateLayout.setClipTopAmount(clipTopAmount);
363         mPublicLayout.setClipTopAmount(clipTopAmount);
364     }
365
366     public void notifyContentUpdated() {
367         mPublicLayout.notifyContentUpdated();
368         mPrivateLayout.notifyContentUpdated();
369     }
370
371     public boolean isShowingLayoutLayouted() {
372         NotificationContentView showingLayout = getShowingLayout();
373         return showingLayout.getWidth() != 0;
374     }
375
376     private NotificationContentView getShowingLayout() {
377         return mShowingPublic ? mPublicLayout : mPrivateLayout;
378     }
379
380     public void setExpansionLogger(ExpansionLogger logger, String key) {
381         mLogger = logger;
382         mLoggingKey = key;
383     }
384
385
386     private void logExpansionEvent(boolean userAction, boolean wasExpanded) {
387         final boolean nowExpanded = isExpanded();
388         if (wasExpanded != nowExpanded && mLogger != null) {
389             mLogger.logNotificationExpansion(mLoggingKey, userAction, nowExpanded) ;
390         }
391     }
392 }