1 /*
2  * Copyright (C) 2014 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.notification;
18 
19 import android.content.Context;
20 import android.graphics.Color;
21 import android.graphics.drawable.ColorDrawable;
22 import android.graphics.drawable.Drawable;
23 import android.support.v4.graphics.ColorUtils;
24 import android.view.NotificationHeaderView;
25 import android.view.View;
26 
27 import com.android.systemui.statusbar.CrossFadeHelper;
28 import com.android.systemui.statusbar.ExpandableNotificationRow;
29 import com.android.systemui.statusbar.TransformableView;
30 
31 /**
32  * Wraps the actual notification content view; used to implement behaviors which are different for
33  * the individual templates and custom views.
34  */
35 public abstract class NotificationViewWrapper implements TransformableView {
36 
37     protected final View mView;
38     protected final ExpandableNotificationRow mRow;
39     private final NotificationDozeHelper mDozer;
40 
41     protected boolean mDark;
42     private int mBackgroundColor = 0;
43     protected boolean mShouldInvertDark;
44     protected boolean mDarkInitialized = false;
45 
wrap(Context ctx, View v, ExpandableNotificationRow row)46     public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
47         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
48             if ("bigPicture".equals(v.getTag())) {
49                 return new NotificationBigPictureTemplateViewWrapper(ctx, v, row);
50             } else if ("bigText".equals(v.getTag())) {
51                 return new NotificationBigTextTemplateViewWrapper(ctx, v, row);
52             } else if ("media".equals(v.getTag()) || "bigMediaNarrow".equals(v.getTag())) {
53                 return new NotificationMediaTemplateViewWrapper(ctx, v, row);
54             } else if ("messaging".equals(v.getTag())) {
55                 return new NotificationMessagingTemplateViewWrapper(ctx, v, row);
56             }
57             return new NotificationTemplateViewWrapper(ctx, v, row);
58         } else if (v instanceof NotificationHeaderView) {
59             return new NotificationHeaderViewWrapper(ctx, v, row);
60         } else {
61             return new NotificationCustomViewWrapper(ctx, v, row);
62         }
63     }
64 
NotificationViewWrapper(Context ctx, View view, ExpandableNotificationRow row)65     protected NotificationViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
66         mView = view;
67         mRow = row;
68         mDozer = createDozer(ctx);
69         onReinflated();
70     }
71 
createDozer(Context ctx)72     protected NotificationDozeHelper createDozer(Context ctx) {
73         return new NotificationDozeHelper();
74     }
75 
getDozer()76     protected NotificationDozeHelper getDozer() {
77         return mDozer;
78     }
79 
80     /**
81      * In dark mode, we draw as little as possible, assuming a black background.
82      *
83      * @param dark whether we should display ourselves in dark mode
84      * @param fade whether to animate the transition if the mode changes
85      * @param delay if fading, the delay of the animation
86      */
setDark(boolean dark, boolean fade, long delay)87     public void setDark(boolean dark, boolean fade, long delay) {
88         mDark = dark;
89         mDarkInitialized = true;
90     }
91 
92     /**
93      * Notifies this wrapper that the content of the view might have changed.
94      * @param row the row this wrapper is attached to
95      */
onContentUpdated(ExpandableNotificationRow row)96     public void onContentUpdated(ExpandableNotificationRow row) {
97         mDarkInitialized = false;
98     }
99 
onReinflated()100     public void onReinflated() {
101         if (shouldClearBackgroundOnReapply()) {
102             mBackgroundColor = 0;
103         }
104         Drawable background = mView.getBackground();
105         if (background instanceof ColorDrawable) {
106             mBackgroundColor = ((ColorDrawable) background).getColor();
107             mView.setBackground(null);
108         }
109         mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
110     }
111 
shouldClearBackgroundOnReapply()112     protected boolean shouldClearBackgroundOnReapply() {
113         return true;
114     }
115 
isColorLight(int backgroundColor)116     private boolean isColorLight(int backgroundColor) {
117         return Color.alpha(backgroundColor) == 0
118                 || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
119     }
120 
121     /**
122      * Update the appearance of the expand button.
123      *
124      * @param expandable should this view be expandable
125      * @param onClickListener the listener to invoke when the expand affordance is clicked on
126      */
updateExpandability(boolean expandable, View.OnClickListener onClickListener)127     public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {}
128 
129     /**
130      * @return the notification header if it exists
131      */
getNotificationHeader()132     public NotificationHeaderView getNotificationHeader() {
133         return null;
134     }
135 
136     @Override
getCurrentState(int fadingView)137     public TransformState getCurrentState(int fadingView) {
138         return null;
139     }
140 
141     @Override
transformTo(TransformableView notification, Runnable endRunnable)142     public void transformTo(TransformableView notification, Runnable endRunnable) {
143         // By default we are fading out completely
144         CrossFadeHelper.fadeOut(mView, endRunnable);
145     }
146 
147     @Override
transformTo(TransformableView notification, float transformationAmount)148     public void transformTo(TransformableView notification, float transformationAmount) {
149         CrossFadeHelper.fadeOut(mView, transformationAmount);
150     }
151 
152     @Override
transformFrom(TransformableView notification)153     public void transformFrom(TransformableView notification) {
154         // By default we are fading in completely
155         CrossFadeHelper.fadeIn(mView);
156     }
157 
158     @Override
transformFrom(TransformableView notification, float transformationAmount)159     public void transformFrom(TransformableView notification, float transformationAmount) {
160         CrossFadeHelper.fadeIn(mView, transformationAmount);
161     }
162 
163     @Override
setVisible(boolean visible)164     public void setVisible(boolean visible) {
165         mView.animate().cancel();
166         mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
167     }
168 
getCustomBackgroundColor()169     public int getCustomBackgroundColor() {
170         // Parent notifications should always use the normal background color
171         return mRow.isSummaryWithChildren() ? 0 : mBackgroundColor;
172     }
173 
setLegacy(boolean legacy)174     public void setLegacy(boolean legacy) {
175     }
176 
setContentHeight(int contentHeight, int minHeightHint)177     public void setContentHeight(int contentHeight, int minHeightHint) {
178     }
179 
setRemoteInputVisible(boolean visible)180     public void setRemoteInputVisible(boolean visible) {
181     }
182 
setIsChildInGroup(boolean isChildInGroup)183     public void setIsChildInGroup(boolean isChildInGroup) {
184     }
185 
isDimmable()186     public boolean isDimmable() {
187         return true;
188     }
189 }
190