blob: 5f7b638dc872b0a11c29d012bb2c45fbf8703d7a [file] [log] [blame]
Jorim Jaggi4e857f42014-11-17 19:14:04 +01001/*
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
Selim Cinek0ffbda62016-01-01 20:29:12 +010017package com.android.systemui.statusbar.notification;
Jorim Jaggi4e857f42014-11-17 19:14:04 +010018
Jorim Jaggi4e857f42014-11-17 19:14:04 +010019import android.content.Context;
20import android.graphics.Color;
Selim Cinek5d6ef8d2017-05-18 22:16:00 -070021import android.graphics.Rect;
Selim Cinek4ffd6362015-12-29 15:12:23 +010022import android.service.notification.StatusBarNotification;
Jorim Jaggi4e857f42014-11-17 19:14:04 +010023import android.view.View;
Jorim Jaggi4e857f42014-11-17 19:14:04 +010024import android.widget.ImageView;
Selim Cinek75fe38c2015-11-20 12:47:59 -080025import android.widget.ProgressBar;
Selim Cinek4ffd6362015-12-29 15:12:23 +010026import android.widget.TextView;
27
Selim Cinek396caca2018-04-10 17:46:46 -070028import com.android.internal.widget.NotificationActionListLayout;
Selim Cinekfd3e2622016-01-12 16:02:42 -080029import com.android.systemui.statusbar.CrossFadeHelper;
Selim Cinek7d1c63e2016-04-21 15:26:10 -070030import com.android.systemui.statusbar.ExpandableNotificationRow;
Selim Cinek0ffbda62016-01-01 20:29:12 +010031import com.android.systemui.statusbar.TransformableView;
Selim Cinekfd3e2622016-01-12 16:02:42 -080032import com.android.systemui.statusbar.ViewTransformationHelper;
Selim Cinek65b2e7c2015-10-26 14:11:31 -070033
Jorim Jaggi4e857f42014-11-17 19:14:04 +010034/**
35 * Wraps a notification view inflated from a template.
36 */
Selim Cinek9c7712d2015-12-08 19:19:48 -080037public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
Jorim Jaggi4e857f42014-11-17 19:14:04 +010038
Selim Cinek9c7712d2015-12-08 19:19:48 -080039 private static final int mDarkProgressTint = 0xffffffff;
Jorim Jaggi4e857f42014-11-17 19:14:04 +010040
Jorim Jaggidacc9242014-12-08 19:21:26 +010041 protected ImageView mPicture;
Selim Cinek75fe38c2015-11-20 12:47:59 -080042 private ProgressBar mProgressBar;
Selim Cinek4ffd6362015-12-29 15:12:23 +010043 private TextView mTitle;
44 private TextView mText;
Selim Cineke62255c2017-09-28 18:23:23 -070045 protected View mActionsContainer;
Selim Cinek5d6ef8d2017-05-18 22:16:00 -070046 private View mReplyAction;
47 private Rect mTmpRect = new Rect();
Adrian Roos181385c2016-05-05 17:45:44 -040048
49 private int mContentHeight;
50 private int mMinHeightHint;
Selim Cinek396caca2018-04-10 17:46:46 -070051 private NotificationActionListLayout mActions;
Jorim Jaggi92df1f22014-12-16 19:44:41 +010052
Adrian Roos7bcf6d32017-04-04 16:44:25 -070053 protected NotificationTemplateViewWrapper(Context ctx, View view,
54 ExpandableNotificationRow row) {
Selim Cinek7d1c63e2016-04-21 15:26:10 -070055 super(ctx, view, row);
Selim Cinekfd3e2622016-01-12 16:02:42 -080056 mTransformationHelper.setCustomTransformation(
57 new ViewTransformationHelper.CustomTransformation() {
58 @Override
59 public boolean transformTo(TransformState ownState,
Selim Cinek8f2f6a62016-02-23 19:56:31 -080060 TransformableView notification, final float transformationAmount) {
Selim Cinekfd3e2622016-01-12 16:02:42 -080061 if (!(notification instanceof HybridNotificationView)) {
62 return false;
63 }
64 TransformState otherState = notification.getCurrentState(
65 TRANSFORMING_VIEW_TITLE);
Selim Cinekb66685b2016-02-02 17:16:08 -080066 final View text = ownState.getTransformedView();
Selim Cinek8f2f6a62016-02-23 19:56:31 -080067 CrossFadeHelper.fadeOut(text, transformationAmount);
Selim Cinekfd3e2622016-01-12 16:02:42 -080068 if (otherState != null) {
Selim Cinek8f2f6a62016-02-23 19:56:31 -080069 ownState.transformViewVerticalTo(otherState, this,
70 transformationAmount);
Selim Cinekfd3e2622016-01-12 16:02:42 -080071 otherState.recycle();
72 }
73 return true;
74 }
75
76 @Override
Selim Cinek8f2f6a62016-02-23 19:56:31 -080077 public boolean customTransformTarget(TransformState ownState,
78 TransformState otherState) {
79 float endY = getTransformationY(ownState, otherState);
80 ownState.setTransformationEndY(endY);
81 return true;
82 }
83
84 @Override
Selim Cinekfd3e2622016-01-12 16:02:42 -080085 public boolean transformFrom(TransformState ownState,
Selim Cinek8f2f6a62016-02-23 19:56:31 -080086 TransformableView notification, float transformationAmount) {
Selim Cinekfd3e2622016-01-12 16:02:42 -080087 if (!(notification instanceof HybridNotificationView)) {
88 return false;
89 }
90 TransformState otherState = notification.getCurrentState(
91 TRANSFORMING_VIEW_TITLE);
Selim Cinekb66685b2016-02-02 17:16:08 -080092 final View text = ownState.getTransformedView();
Selim Cinek8f2f6a62016-02-23 19:56:31 -080093 CrossFadeHelper.fadeIn(text, transformationAmount);
Selim Cinekfd3e2622016-01-12 16:02:42 -080094 if (otherState != null) {
Selim Cinek8f2f6a62016-02-23 19:56:31 -080095 ownState.transformViewVerticalFrom(otherState, this,
96 transformationAmount);
Selim Cinekfd3e2622016-01-12 16:02:42 -080097 otherState.recycle();
98 }
99 return true;
100 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800101
102 @Override
103 public boolean initTransformation(TransformState ownState,
104 TransformState otherState) {
105 float startY = getTransformationY(ownState, otherState);
106 ownState.setTransformationStartY(startY);
107 return true;
108 }
109
110 private float getTransformationY(TransformState ownState,
111 TransformState otherState) {
112 int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
113 int[] ownStablePosition = ownState.getLaidOutLocationOnScreen();
114 return (otherStablePosition[1]
115 + otherState.getTransformedView().getHeight()
116 - ownStablePosition[1]) * 0.33f;
117 }
118
Selim Cinekfd3e2622016-01-12 16:02:42 -0800119 }, TRANSFORMING_VIEW_TEXT);
Jorim Jaggidacc9242014-12-08 19:21:26 +0100120 }
121
Selim Cinek4ffd6362015-12-29 15:12:23 +0100122 private void resolveTemplateViews(StatusBarNotification notification) {
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700123 mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
Adrian Roos0aac04f2016-12-08 15:59:29 -0800124 if (mPicture != null) {
125 mPicture.setTag(ImageTransformState.ICON_TAG,
126 notification.getNotification().getLargeIcon());
127 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100128 mTitle = (TextView) mView.findViewById(com.android.internal.R.id.title);
129 mText = (TextView) mView.findViewById(com.android.internal.R.id.text);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800130 final View progress = mView.findViewById(com.android.internal.R.id.progress);
131 if (progress instanceof ProgressBar) {
132 mProgressBar = (ProgressBar) progress;
133 } else {
134 // It's still a viewstub
135 mProgressBar = null;
136 }
Adrian Roos181385c2016-05-05 17:45:44 -0400137 mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
Selim Cinek396caca2018-04-10 17:46:46 -0700138 mActions = mView.findViewById(com.android.internal.R.id.actions);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -0700139 mReplyAction = mView.findViewById(com.android.internal.R.id.reply_icon_action);
140 }
141
142 @Override
143 public boolean disallowSingleClick(float x, float y) {
144 if (mReplyAction != null && mReplyAction.getVisibility() == View.VISIBLE) {
145 if (isOnView(mReplyAction, x, y) || isOnView(mPicture, x, y)) {
146 return true;
147 }
148 }
149 return super.disallowSingleClick(x, y);
150 }
151
152 private boolean isOnView(View view, float x, float y) {
153 View searchView = (View) view.getParent();
154 while (searchView != null && !(searchView instanceof ExpandableNotificationRow)) {
155 searchView.getHitRect(mTmpRect);
156 x -= mTmpRect.left;
157 y -= mTmpRect.top;
158 searchView = (View) searchView.getParent();
159 }
160 view.getHitRect(mTmpRect);
161 return mTmpRect.contains((int) x,(int) y);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100162 }
163
164 @Override
Selim Cinek131f1a42017-06-05 17:50:19 -0700165 public void onContentUpdated(ExpandableNotificationRow row) {
Selim Cinek646d2052016-01-03 14:42:02 +0800166 // Reinspect the notification. Before the super call, because the super call also updates
167 // the transformation types and we need to have our values set by then.
Selim Cineka6ee4bd2017-09-20 22:52:29 +0000168 resolveTemplateViews(row.getStatusBarNotification());
Selim Cinek131f1a42017-06-05 17:50:19 -0700169 super.onContentUpdated(row);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100170 }
171
172 @Override
173 protected void updateInvertHelper() {
174 super.updateInvertHelper();
175 View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800176 if (mainColumn != null) {
Selim Cinek9c7712d2015-12-08 19:19:48 -0800177 mInvertHelper.addTarget(mainColumn);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800178 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100179 }
180
181 @Override
Selim Cinek4ffd6362015-12-29 15:12:23 +0100182 protected void updateTransformedTypes() {
183 // This also clears the existing types
184 super.updateTransformedTypes();
185 if (mTitle != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700186 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
187 mTitle);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100188 }
189 if (mText != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700190 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
191 mText);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100192 }
193 if (mPicture != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700194 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_IMAGE,
195 mPicture);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100196 }
197 if (mProgressBar != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700198 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_PROGRESS,
199 mProgressBar);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100200 }
Jorim Jaggidacc9242014-12-08 19:21:26 +0100201 }
202
203 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100204 public void setDark(boolean dark, boolean fade, long delay) {
Selim Cinekb88b9842016-02-26 09:25:33 -0800205 if (dark == mDark && mDarkInitialized) {
Selim Cinek19ba7052016-01-27 20:04:27 -0800206 return;
207 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800208 super.setDark(dark, fade, delay);
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700209 setPictureDark(dark, fade, delay);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800210 setProgressBarDark(dark, fade, delay);
211 }
212
213 private void setProgressBarDark(boolean dark, boolean fade, long delay) {
214 if (mProgressBar != null) {
215 if (fade) {
216 fadeProgressDark(mProgressBar, dark, delay);
217 } else {
218 updateProgressDark(mProgressBar, dark);
219 }
220 }
221 }
222
223 private void fadeProgressDark(final ProgressBar target, final boolean dark, long delay) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700224 getDozer().startIntensityAnimation(animation -> {
225 float t = (float) animation.getAnimatedValue();
226 updateProgressDark(target, t);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800227 }, dark, delay, null /* listener */);
228 }
229
230 private void updateProgressDark(ProgressBar target, float intensity) {
231 int color = interpolateColor(mColor, mDarkProgressTint, intensity);
232 target.getIndeterminateDrawable().mutate().setTint(color);
233 target.getProgressDrawable().mutate().setTint(color);
234 }
235
236 private void updateProgressDark(ProgressBar target, boolean dark) {
237 updateProgressDark(target, dark ? 1f : 0f);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100238 }
239
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700240 private void setPictureDark(boolean dark, boolean fade, long delay) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100241 if (mPicture != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700242 getDozer().setImageDark(mPicture, dark, fade, delay, true /* useGrayscale */);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100243 }
244 }
245
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100246 private static int interpolateColor(int source, int target, float t) {
247 int aSource = Color.alpha(source);
248 int rSource = Color.red(source);
249 int gSource = Color.green(source);
250 int bSource = Color.blue(source);
251 int aTarget = Color.alpha(target);
252 int rTarget = Color.red(target);
253 int gTarget = Color.green(target);
254 int bTarget = Color.blue(target);
255 return Color.argb(
256 (int) (aSource * (1f - t) + aTarget * t),
257 (int) (rSource * (1f - t) + rTarget * t),
258 (int) (gSource * (1f - t) + gTarget * t),
259 (int) (bSource * (1f - t) + bTarget * t));
260 }
Adrian Roos181385c2016-05-05 17:45:44 -0400261
262 @Override
263 public void setContentHeight(int contentHeight, int minHeightHint) {
264 super.setContentHeight(contentHeight, minHeightHint);
265
266 mContentHeight = contentHeight;
267 mMinHeightHint = minHeightHint;
268 updateActionOffset();
269 }
270
Selim Cinek86bfcee2018-01-17 11:00:47 -0800271 @Override
272 public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) {
273 if (super.shouldClipToRounding(topRounded, bottomRounded)) {
274 return true;
275 }
276 return bottomRounded && mActionsContainer != null
277 && mActionsContainer.getVisibility() != View.GONE;
278 }
279
Adrian Roos181385c2016-05-05 17:45:44 -0400280 private void updateActionOffset() {
281 if (mActionsContainer != null) {
282 // We should never push the actions higher than they are in the headsup view.
283 int constrainedContentHeight = Math.max(mContentHeight, mMinHeightHint);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800284
285 // We also need to compensate for any header translation, since we're always at the end.
286 mActionsContainer.setTranslationY(constrainedContentHeight - mView.getHeight()
287 - getHeaderTranslation());
Adrian Roos181385c2016-05-05 17:45:44 -0400288 }
289 }
Selim Cinek396caca2018-04-10 17:46:46 -0700290
291 @Override
292 public int getExtraMeasureHeight() {
293 int extra = 0;
294 if (mActions != null) {
295 extra = mActions.getExtraMeasureHeight();
296 }
297 return extra + super.getExtraMeasureHeight();
298 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100299}