blob: 28beb21dba4bf13adc2eac3315d00848eae8ff78 [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 Cinekfd3e2622016-01-12 16:02:42 -080028import com.android.systemui.statusbar.CrossFadeHelper;
Selim Cinek7d1c63e2016-04-21 15:26:10 -070029import com.android.systemui.statusbar.ExpandableNotificationRow;
Selim Cinek0ffbda62016-01-01 20:29:12 +010030import com.android.systemui.statusbar.TransformableView;
Selim Cinekfd3e2622016-01-12 16:02:42 -080031import com.android.systemui.statusbar.ViewTransformationHelper;
Selim Cinek65b2e7c2015-10-26 14:11:31 -070032
Jorim Jaggi4e857f42014-11-17 19:14:04 +010033/**
34 * Wraps a notification view inflated from a template.
35 */
Selim Cinek9c7712d2015-12-08 19:19:48 -080036public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
Jorim Jaggi4e857f42014-11-17 19:14:04 +010037
Selim Cinek9c7712d2015-12-08 19:19:48 -080038 private static final int mDarkProgressTint = 0xffffffff;
Jorim Jaggi4e857f42014-11-17 19:14:04 +010039
Jorim Jaggidacc9242014-12-08 19:21:26 +010040 protected ImageView mPicture;
Selim Cinek75fe38c2015-11-20 12:47:59 -080041 private ProgressBar mProgressBar;
Selim Cinek4ffd6362015-12-29 15:12:23 +010042 private TextView mTitle;
43 private TextView mText;
Selim Cineke62255c2017-09-28 18:23:23 -070044 protected View mActionsContainer;
Selim Cinek5d6ef8d2017-05-18 22:16:00 -070045 private View mReplyAction;
46 private Rect mTmpRect = new Rect();
Adrian Roos181385c2016-05-05 17:45:44 -040047
48 private int mContentHeight;
49 private int mMinHeightHint;
Jorim Jaggi92df1f22014-12-16 19:44:41 +010050
Adrian Roos7bcf6d32017-04-04 16:44:25 -070051 protected NotificationTemplateViewWrapper(Context ctx, View view,
52 ExpandableNotificationRow row) {
Selim Cinek7d1c63e2016-04-21 15:26:10 -070053 super(ctx, view, row);
Selim Cinekfd3e2622016-01-12 16:02:42 -080054 mTransformationHelper.setCustomTransformation(
55 new ViewTransformationHelper.CustomTransformation() {
56 @Override
57 public boolean transformTo(TransformState ownState,
Selim Cinek8f2f6a62016-02-23 19:56:31 -080058 TransformableView notification, final float transformationAmount) {
Selim Cinekfd3e2622016-01-12 16:02:42 -080059 if (!(notification instanceof HybridNotificationView)) {
60 return false;
61 }
62 TransformState otherState = notification.getCurrentState(
63 TRANSFORMING_VIEW_TITLE);
Selim Cinekb66685b2016-02-02 17:16:08 -080064 final View text = ownState.getTransformedView();
Selim Cinek8f2f6a62016-02-23 19:56:31 -080065 CrossFadeHelper.fadeOut(text, transformationAmount);
Selim Cinekfd3e2622016-01-12 16:02:42 -080066 if (otherState != null) {
Selim Cinek8f2f6a62016-02-23 19:56:31 -080067 ownState.transformViewVerticalTo(otherState, this,
68 transformationAmount);
Selim Cinekfd3e2622016-01-12 16:02:42 -080069 otherState.recycle();
70 }
71 return true;
72 }
73
74 @Override
Selim Cinek8f2f6a62016-02-23 19:56:31 -080075 public boolean customTransformTarget(TransformState ownState,
76 TransformState otherState) {
77 float endY = getTransformationY(ownState, otherState);
78 ownState.setTransformationEndY(endY);
79 return true;
80 }
81
82 @Override
Selim Cinekfd3e2622016-01-12 16:02:42 -080083 public boolean transformFrom(TransformState ownState,
Selim Cinek8f2f6a62016-02-23 19:56:31 -080084 TransformableView notification, float transformationAmount) {
Selim Cinekfd3e2622016-01-12 16:02:42 -080085 if (!(notification instanceof HybridNotificationView)) {
86 return false;
87 }
88 TransformState otherState = notification.getCurrentState(
89 TRANSFORMING_VIEW_TITLE);
Selim Cinekb66685b2016-02-02 17:16:08 -080090 final View text = ownState.getTransformedView();
Selim Cinek8f2f6a62016-02-23 19:56:31 -080091 CrossFadeHelper.fadeIn(text, transformationAmount);
Selim Cinekfd3e2622016-01-12 16:02:42 -080092 if (otherState != null) {
Selim Cinek8f2f6a62016-02-23 19:56:31 -080093 ownState.transformViewVerticalFrom(otherState, this,
94 transformationAmount);
Selim Cinekfd3e2622016-01-12 16:02:42 -080095 otherState.recycle();
96 }
97 return true;
98 }
Selim Cinek8f2f6a62016-02-23 19:56:31 -080099
100 @Override
101 public boolean initTransformation(TransformState ownState,
102 TransformState otherState) {
103 float startY = getTransformationY(ownState, otherState);
104 ownState.setTransformationStartY(startY);
105 return true;
106 }
107
108 private float getTransformationY(TransformState ownState,
109 TransformState otherState) {
110 int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
111 int[] ownStablePosition = ownState.getLaidOutLocationOnScreen();
112 return (otherStablePosition[1]
113 + otherState.getTransformedView().getHeight()
114 - ownStablePosition[1]) * 0.33f;
115 }
116
Selim Cinekfd3e2622016-01-12 16:02:42 -0800117 }, TRANSFORMING_VIEW_TEXT);
Jorim Jaggidacc9242014-12-08 19:21:26 +0100118 }
119
Selim Cinek4ffd6362015-12-29 15:12:23 +0100120 private void resolveTemplateViews(StatusBarNotification notification) {
Selim Cinek65b2e7c2015-10-26 14:11:31 -0700121 mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
Adrian Roos0aac04f2016-12-08 15:59:29 -0800122 if (mPicture != null) {
123 mPicture.setTag(ImageTransformState.ICON_TAG,
124 notification.getNotification().getLargeIcon());
125 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100126 mTitle = (TextView) mView.findViewById(com.android.internal.R.id.title);
127 mText = (TextView) mView.findViewById(com.android.internal.R.id.text);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800128 final View progress = mView.findViewById(com.android.internal.R.id.progress);
129 if (progress instanceof ProgressBar) {
130 mProgressBar = (ProgressBar) progress;
131 } else {
132 // It's still a viewstub
133 mProgressBar = null;
134 }
Adrian Roos181385c2016-05-05 17:45:44 -0400135 mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
Selim Cinek5d6ef8d2017-05-18 22:16:00 -0700136 mReplyAction = mView.findViewById(com.android.internal.R.id.reply_icon_action);
137 }
138
139 @Override
140 public boolean disallowSingleClick(float x, float y) {
141 if (mReplyAction != null && mReplyAction.getVisibility() == View.VISIBLE) {
142 if (isOnView(mReplyAction, x, y) || isOnView(mPicture, x, y)) {
143 return true;
144 }
145 }
146 return super.disallowSingleClick(x, y);
147 }
148
149 private boolean isOnView(View view, float x, float y) {
150 View searchView = (View) view.getParent();
151 while (searchView != null && !(searchView instanceof ExpandableNotificationRow)) {
152 searchView.getHitRect(mTmpRect);
153 x -= mTmpRect.left;
154 y -= mTmpRect.top;
155 searchView = (View) searchView.getParent();
156 }
157 view.getHitRect(mTmpRect);
158 return mTmpRect.contains((int) x,(int) y);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100159 }
160
161 @Override
Selim Cinek131f1a42017-06-05 17:50:19 -0700162 public void onContentUpdated(ExpandableNotificationRow row) {
Selim Cinek646d2052016-01-03 14:42:02 +0800163 // Reinspect the notification. Before the super call, because the super call also updates
164 // the transformation types and we need to have our values set by then.
Selim Cineka6ee4bd2017-09-20 22:52:29 +0000165 resolveTemplateViews(row.getStatusBarNotification());
Selim Cinek131f1a42017-06-05 17:50:19 -0700166 super.onContentUpdated(row);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100167 }
168
169 @Override
170 protected void updateInvertHelper() {
171 super.updateInvertHelper();
172 View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800173 if (mainColumn != null) {
Selim Cinek9c7712d2015-12-08 19:19:48 -0800174 mInvertHelper.addTarget(mainColumn);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800175 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100176 }
177
178 @Override
Selim Cinek4ffd6362015-12-29 15:12:23 +0100179 protected void updateTransformedTypes() {
180 // This also clears the existing types
181 super.updateTransformedTypes();
182 if (mTitle != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700183 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
184 mTitle);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100185 }
186 if (mText != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700187 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
188 mText);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100189 }
190 if (mPicture != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700191 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_IMAGE,
192 mPicture);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100193 }
194 if (mProgressBar != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700195 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_PROGRESS,
196 mProgressBar);
Selim Cinek4ffd6362015-12-29 15:12:23 +0100197 }
Jorim Jaggidacc9242014-12-08 19:21:26 +0100198 }
199
200 @Override
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100201 public void setDark(boolean dark, boolean fade, long delay) {
Selim Cinekb88b9842016-02-26 09:25:33 -0800202 if (dark == mDark && mDarkInitialized) {
Selim Cinek19ba7052016-01-27 20:04:27 -0800203 return;
204 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800205 super.setDark(dark, fade, delay);
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700206 setPictureDark(dark, fade, delay);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800207 setProgressBarDark(dark, fade, delay);
208 }
209
210 private void setProgressBarDark(boolean dark, boolean fade, long delay) {
211 if (mProgressBar != null) {
212 if (fade) {
213 fadeProgressDark(mProgressBar, dark, delay);
214 } else {
215 updateProgressDark(mProgressBar, dark);
216 }
217 }
218 }
219
220 private void fadeProgressDark(final ProgressBar target, final boolean dark, long delay) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700221 getDozer().startIntensityAnimation(animation -> {
222 float t = (float) animation.getAnimatedValue();
223 updateProgressDark(target, t);
Selim Cinek75fe38c2015-11-20 12:47:59 -0800224 }, dark, delay, null /* listener */);
225 }
226
227 private void updateProgressDark(ProgressBar target, float intensity) {
228 int color = interpolateColor(mColor, mDarkProgressTint, intensity);
229 target.getIndeterminateDrawable().mutate().setTint(color);
230 target.getProgressDrawable().mutate().setTint(color);
231 }
232
233 private void updateProgressDark(ProgressBar target, boolean dark) {
234 updateProgressDark(target, dark ? 1f : 0f);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100235 }
236
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700237 private void setPictureDark(boolean dark, boolean fade, long delay) {
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100238 if (mPicture != null) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -0700239 getDozer().setImageDark(mPicture, dark, fade, delay, true /* useGrayscale */);
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100240 }
241 }
242
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100243 private static int interpolateColor(int source, int target, float t) {
244 int aSource = Color.alpha(source);
245 int rSource = Color.red(source);
246 int gSource = Color.green(source);
247 int bSource = Color.blue(source);
248 int aTarget = Color.alpha(target);
249 int rTarget = Color.red(target);
250 int gTarget = Color.green(target);
251 int bTarget = Color.blue(target);
252 return Color.argb(
253 (int) (aSource * (1f - t) + aTarget * t),
254 (int) (rSource * (1f - t) + rTarget * t),
255 (int) (gSource * (1f - t) + gTarget * t),
256 (int) (bSource * (1f - t) + bTarget * t));
257 }
Adrian Roos181385c2016-05-05 17:45:44 -0400258
259 @Override
260 public void setContentHeight(int contentHeight, int minHeightHint) {
261 super.setContentHeight(contentHeight, minHeightHint);
262
263 mContentHeight = contentHeight;
264 mMinHeightHint = minHeightHint;
265 updateActionOffset();
266 }
267
Selim Cinek86bfcee2018-01-17 11:00:47 -0800268 @Override
269 public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) {
270 if (super.shouldClipToRounding(topRounded, bottomRounded)) {
271 return true;
272 }
273 return bottomRounded && mActionsContainer != null
274 && mActionsContainer.getVisibility() != View.GONE;
275 }
276
Adrian Roos181385c2016-05-05 17:45:44 -0400277 private void updateActionOffset() {
278 if (mActionsContainer != null) {
279 // We should never push the actions higher than they are in the headsup view.
280 int constrainedContentHeight = Math.max(mContentHeight, mMinHeightHint);
Selim Cinekaa9db1f2018-02-27 17:35:47 -0800281
282 // We also need to compensate for any header translation, since we're always at the end.
283 mActionsContainer.setTranslationY(constrainedContentHeight - mView.getHeight()
284 - getHeaderTranslation());
Adrian Roos181385c2016-05-05 17:45:44 -0400285 }
286 }
Jorim Jaggi4e857f42014-11-17 19:14:04 +0100287}