blob: 7ac066277c860e9ef7722e545f6d66558e3b9652 [file] [log] [blame]
Selim Cinek9c7712d2015-12-08 19:19:48 -08001/*
2 * Copyright (C) 2015 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
Rohan Shah20790b82018-07-02 17:21:04 -070017package com.android.systemui.statusbar.notification.row.wrapper;
Selim Cinek9c7712d2015-12-08 19:19:48 -080018
Gus Prevasab336792018-11-14 13:52:20 -050019import static com.android.systemui.statusbar.notification.TransformState.TRANSFORM_Y;
Selim Cinek82b33a22018-05-04 18:05:33 -070020
Selim Cinek4237e822020-03-31 17:22:28 -070021import android.annotation.NonNull;
22import android.app.AppOpsManager;
Selim Cinek414ad332017-02-24 19:06:12 -080023import android.app.Notification;
Selim Cinek9c7712d2015-12-08 19:19:48 -080024import android.content.Context;
Adrian Roos75524412016-06-21 11:56:57 -070025import android.util.ArraySet;
Selim Cinek9c7712d2015-12-08 19:19:48 -080026import android.view.NotificationHeaderView;
27import android.view.View;
Selim Cinek0ffbda62016-01-01 20:29:12 +010028import android.view.ViewGroup;
Selim Cinek5be6f332017-01-19 11:54:04 -080029import android.view.animation.Interpolator;
30import android.view.animation.PathInterpolator;
Selim Cinek9c7712d2015-12-08 19:19:48 -080031import android.widget.ImageView;
Selim Cinek6743c0b2017-01-18 18:24:01 -080032import android.widget.TextView;
Selim Cinek9c7712d2015-12-08 19:19:48 -080033
Selim Cinek79d98632020-03-24 19:16:02 -070034import com.android.internal.widget.CachingIconView;
Selim Cinek69e76f92017-04-05 17:06:02 -070035import com.android.internal.widget.NotificationExpandButton;
Selim Cinek5be6f332017-01-19 11:54:04 -080036import com.android.systemui.Interpolators;
Anthony Chen0f6e96c2017-04-07 15:48:17 -070037import com.android.systemui.R;
Gus Prevasab336792018-11-14 13:52:20 -050038import com.android.systemui.statusbar.TransformableView;
39import com.android.systemui.statusbar.ViewTransformationHelper;
Rohan Shah20790b82018-07-02 17:21:04 -070040import com.android.systemui.statusbar.notification.CustomInterpolatorTransformation;
41import com.android.systemui.statusbar.notification.ImageTransformState;
Gus Prevas51425312018-11-15 15:16:14 -050042import com.android.systemui.statusbar.notification.NotificationUtils;
Rohan Shah20790b82018-07-02 17:21:04 -070043import com.android.systemui.statusbar.notification.TransformState;
44import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Selim Cinek9c7712d2015-12-08 19:19:48 -080045
Selim Cinek0ffbda62016-01-01 20:29:12 +010046import java.util.Stack;
Selim Cinek9c7712d2015-12-08 19:19:48 -080047
48/**
49 * Wraps a notification header view.
50 */
51public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
52
Selim Cinek5be6f332017-01-19 11:54:04 -080053 private static final Interpolator LOW_PRIORITY_HEADER_CLOSE
54 = new PathInterpolator(0.4f, 0f, 0.7f, 1f);
Selim Cinek9c7712d2015-12-08 19:19:48 -080055
Selim Cinek4ffd6362015-12-29 15:12:23 +010056 protected final ViewTransformationHelper mTransformationHelper;
57
Selim Cinek9c7712d2015-12-08 19:19:48 -080058 protected int mColor;
Selim Cinek9c7712d2015-12-08 19:19:48 -080059
Selim Cinek79d98632020-03-24 19:16:02 -070060 private CachingIconView mIcon;
Selim Cinek69e76f92017-04-05 17:06:02 -070061 private NotificationExpandButton mExpandButton;
Selim Cinek4b259a12019-05-09 19:10:51 -070062 protected NotificationHeaderView mNotificationHeader;
Selim Cinek6743c0b2017-01-18 18:24:01 -080063 private TextView mHeaderText;
64 private ImageView mWorkProfileImage;
Selim Cinek4237e822020-03-31 17:22:28 -070065 private View mCameraIcon;
66 private View mMicIcon;
67 private View mOverlayIcon;
68 private View mAppOps;
Selim Cineka2b1d372020-03-31 17:54:19 -070069 private View mAudiblyAlertedIcon;
Selim Cinek20d1ee22020-02-03 16:04:26 -050070
Selim Cinek6743c0b2017-01-18 18:24:01 -080071 private boolean mIsLowPriority;
Selim Cinek414ad332017-02-24 19:06:12 -080072 private boolean mTransformLowPriorityTitle;
Anthony Chen0f6e96c2017-04-07 15:48:17 -070073 private boolean mShowExpandButtonAtEnd;
Selim Cinek9c7712d2015-12-08 19:19:48 -080074
Selim Cinek7d1c63e2016-04-21 15:26:10 -070075 protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -070076 super(ctx, view, row);
Anthony Chen0f6e96c2017-04-07 15:48:17 -070077 mShowExpandButtonAtEnd = ctx.getResources().getBoolean(
Gus Prevas51425312018-11-15 15:16:14 -050078 R.bool.config_showNotificationExpandButtonAtEnd)
79 || NotificationUtils.useNewInterruptionModel(ctx);
Selim Cinek4ffd6362015-12-29 15:12:23 +010080 mTransformationHelper = new ViewTransformationHelper();
Selim Cinek5be6f332017-01-19 11:54:04 -080081
82 // we want to avoid that the header clashes with the other text when transforming
83 // low-priority
84 mTransformationHelper.setCustomTransformation(
85 new CustomInterpolatorTransformation(TRANSFORMING_VIEW_TITLE) {
86
87 @Override
88 public Interpolator getCustomInterpolator(int interpolationType,
89 boolean isFrom) {
90 boolean isLowPriority = mView instanceof NotificationHeaderView;
91 if (interpolationType == TRANSFORM_Y) {
92 if (isLowPriority && !isFrom
93 || !isLowPriority && isFrom) {
94 return Interpolators.LINEAR_OUT_SLOW_IN;
95 } else {
96 return LOW_PRIORITY_HEADER_CLOSE;
97 }
98 }
99 return null;
100 }
101
102 @Override
103 protected boolean hasCustomTransformation() {
Selim Cinek414ad332017-02-24 19:06:12 -0800104 return mIsLowPriority && mTransformLowPriorityTitle;
Selim Cinek5be6f332017-01-19 11:54:04 -0800105 }
106 }, TRANSFORMING_VIEW_TITLE);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800107 resolveHeaderViews();
Julia Reynoldsb5867452018-02-28 16:31:35 -0500108 addAppOpsOnClickListener(row);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800109 }
110
111 protected void resolveHeaderViews() {
Selim Cinek69e76f92017-04-05 17:06:02 -0700112 mIcon = mView.findViewById(com.android.internal.R.id.icon);
113 mHeaderText = mView.findViewById(com.android.internal.R.id.header_text);
114 mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
Selim Cinek69e76f92017-04-05 17:06:02 -0700115 mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
Selim Cinek69e76f92017-04-05 17:06:02 -0700116 mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
Selim Cinek4237e822020-03-31 17:22:28 -0700117 mCameraIcon = mView.findViewById(com.android.internal.R.id.camera);
118 mMicIcon = mView.findViewById(com.android.internal.R.id.mic);
119 mOverlayIcon = mView.findViewById(com.android.internal.R.id.overlay);
120 mAppOps = mView.findViewById(com.android.internal.R.id.app_ops);
Selim Cineka2b1d372020-03-31 17:54:19 -0700121 mAudiblyAlertedIcon = mView.findViewById(com.android.internal.R.id.alerted_icon);
Selim Cinek20d1ee22020-02-03 16:04:26 -0500122 if (mNotificationHeader != null) {
123 mNotificationHeader.setShowExpandButtonAtEnd(mShowExpandButtonAtEnd);
124 mColor = mNotificationHeader.getOriginalIconColor();
125 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800126 }
127
Julia Reynoldsb5867452018-02-28 16:31:35 -0500128 private void addAppOpsOnClickListener(ExpandableNotificationRow row) {
Selim Cinek4237e822020-03-31 17:22:28 -0700129 View.OnClickListener listener = row.getAppOpsOnClickListener();
Selim Cinek20d1ee22020-02-03 16:04:26 -0500130 if (mNotificationHeader != null) {
Selim Cinek4237e822020-03-31 17:22:28 -0700131 mNotificationHeader.setAppOpsOnClickListener(listener);
132 }
Selim Cinek78c87312020-04-03 12:30:03 -0700133 if (mAppOps != null) {
134 mAppOps.setOnClickListener(listener);
135 }
136 if (mCameraIcon != null) {
137 mCameraIcon.setOnClickListener(listener);
138 }
139 if (mMicIcon != null) {
140 mMicIcon.setOnClickListener(listener);
141 }
142 if (mOverlayIcon != null) {
143 mOverlayIcon.setOnClickListener(listener);
144 }
Selim Cinek4237e822020-03-31 17:22:28 -0700145 }
146
147 /**
148 * Shows or hides 'app op in use' icons based on app usage.
149 */
150 @Override
151 public void showAppOpsIcons(ArraySet<Integer> appOps) {
152 if (appOps == null) {
153 return;
154 }
155 if (mOverlayIcon != null) {
156 mOverlayIcon.setVisibility(appOps.contains(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
157 ? View.VISIBLE : View.GONE);
158 }
159 if (mCameraIcon != null) {
160 mCameraIcon.setVisibility(appOps.contains(AppOpsManager.OP_CAMERA)
161 ? View.VISIBLE : View.GONE);
162 }
163 if (mMicIcon != null) {
164 mMicIcon.setVisibility(appOps.contains(AppOpsManager.OP_RECORD_AUDIO)
165 ? View.VISIBLE : View.GONE);
Selim Cinek20d1ee22020-02-03 16:04:26 -0500166 }
Julia Reynoldsb5867452018-02-28 16:31:35 -0500167 }
168
Selim Cinek9c7712d2015-12-08 19:19:48 -0800169 @Override
Selim Cinek131f1a42017-06-05 17:50:19 -0700170 public void onContentUpdated(ExpandableNotificationRow row) {
171 super.onContentUpdated(row);
Selim Cinek792eb062020-04-08 12:36:43 -0700172 mIsLowPriority = row.getEntry().isAmbient();
Selim Cinek414ad332017-02-24 19:06:12 -0800173 mTransformLowPriorityTitle = !row.isChildInGroup() && !row.isSummaryWithChildren();
Adrian Roos75524412016-06-21 11:56:57 -0700174 ArraySet<View> previousViews = mTransformationHelper.getAllTransformingViews();
175
Selim Cinek9c7712d2015-12-08 19:19:48 -0800176 // Reinspect the notification.
177 resolveHeaderViews();
Selim Cinek4ffd6362015-12-29 15:12:23 +0100178 updateTransformedTypes();
Selim Cinek646d2052016-01-03 14:42:02 +0800179 addRemainingTransformTypes();
Selim Cinek0ffbda62016-01-01 20:29:12 +0100180 updateCropToPaddingForImageViews();
Ned Burns1c2b85a42019-11-14 15:37:03 -0500181 Notification notification = row.getEntry().getSbn().getNotification();
Selim Cinek414ad332017-02-24 19:06:12 -0800182 mIcon.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
Adrian Roos75524412016-06-21 11:56:57 -0700183
184 // We need to reset all views that are no longer transforming in case a view was previously
185 // transformed, but now we decided to transform its container instead.
186 ArraySet<View> currentViews = mTransformationHelper.getAllTransformingViews();
187 for (int i = 0; i < previousViews.size(); i++) {
188 View view = previousViews.valueAt(i);
189 if (!currentViews.contains(view)) {
190 mTransformationHelper.resetTransformedView(view);
191 }
192 }
Selim Cinek0ffbda62016-01-01 20:29:12 +0100193 }
194
195 /**
Selim Cinek646d2052016-01-03 14:42:02 +0800196 * Adds the remaining TransformTypes to the TransformHelper. This is done to make sure that each
197 * child is faded automatically and doesn't have to be manually added.
198 * The keys used for the views are the ids.
199 */
200 private void addRemainingTransformTypes() {
201 mTransformationHelper.addRemainingTransformTypes(mView);
202 }
203
204 /**
Selim Cinek0ffbda62016-01-01 20:29:12 +0100205 * Since we are deactivating the clipping when transforming the ImageViews don't get clipped
206 * anymore during these transitions. We can avoid that by using
207 * {@link ImageView#setCropToPadding(boolean)} on all ImageViews.
208 */
209 private void updateCropToPaddingForImageViews() {
210 Stack<View> stack = new Stack<>();
211 stack.push(mView);
212 while (!stack.isEmpty()) {
213 View child = stack.pop();
214 if (child instanceof ImageView) {
215 ((ImageView) child).setCropToPadding(true);
216 } else if (child instanceof ViewGroup){
217 ViewGroup group = (ViewGroup) child;
218 for (int i = 0; i < group.getChildCount(); i++) {
219 stack.push(group.getChildAt(i));
220 }
221 }
222 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100223 }
224
Selim Cinek4ffd6362015-12-29 15:12:23 +0100225 protected void updateTransformedTypes() {
226 mTransformationHelper.reset();
Selim Cinek20d1ee22020-02-03 16:04:26 -0500227 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ICON,
228 mIcon);
Selim Cinekecf248f2020-03-20 16:17:21 -0700229 mTransformationHelper.addViewTransformingToSimilar(mWorkProfileImage);
Selim Cinek20d1ee22020-02-03 16:04:26 -0500230 if (mIsLowPriority && mHeaderText != null) {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800231 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
232 mHeaderText);
233 }
Selim Cinek4237e822020-03-31 17:22:28 -0700234 if (mCameraIcon != null) {
235 mTransformationHelper.addViewTransformingToSimilar(mCameraIcon);
236 }
237 if (mMicIcon != null) {
238 mTransformationHelper.addViewTransformingToSimilar(mMicIcon);
239 }
240 if (mOverlayIcon != null) {
241 mTransformationHelper.addViewTransformingToSimilar(mOverlayIcon);
242 }
Selim Cineka2b1d372020-03-31 17:54:19 -0700243 if (mAudiblyAlertedIcon != null) {
244 mTransformationHelper.addViewTransformingToSimilar(mAudiblyAlertedIcon);
245 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800246 }
247
248 @Override
Selim Cinek9c7712d2015-12-08 19:19:48 -0800249 public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
250 mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
Selim Cinek20d1ee22020-02-03 16:04:26 -0500251 if (mNotificationHeader != null) {
252 mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
253 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800254 }
255
Selim Cinek9c7712d2015-12-08 19:19:48 -0800256 @Override
Selim Cineka2b1d372020-03-31 17:54:19 -0700257 public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) {
258 if (mAudiblyAlertedIcon != null) {
259 mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE);
260 }
261 }
262
263 @Override
Selim Cinek9c7712d2015-12-08 19:19:48 -0800264 public NotificationHeaderView getNotificationHeader() {
265 return mNotificationHeader;
266 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100267
268 @Override
Selim Cinek79d98632020-03-24 19:16:02 -0700269 public int getOriginalIconColor() {
270 return mIcon.getOriginalIconColor();
271 }
272
273 @Override
274 public View getShelfTransformationTarget() {
275 return mIcon;
276 }
277
278 @Override
Selim Cinek9ed6e042020-03-26 15:45:51 -0700279 public void setShelfIconVisible(boolean visible) {
280 super.setShelfIconVisible(visible);
281 mIcon.setForceHidden(visible);
Selim Cinek79d98632020-03-24 19:16:02 -0700282 }
283
284 @Override
Selim Cinek4ffd6362015-12-29 15:12:23 +0100285 public TransformState getCurrentState(int fadingView) {
286 return mTransformationHelper.getCurrentState(fadingView);
287 }
288
289 @Override
290 public void transformTo(TransformableView notification, Runnable endRunnable) {
291 mTransformationHelper.transformTo(notification, endRunnable);
292 }
293
294 @Override
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800295 public void transformTo(TransformableView notification, float transformationAmount) {
296 mTransformationHelper.transformTo(notification, transformationAmount);
297 }
298
299 @Override
Selim Cinek4ffd6362015-12-29 15:12:23 +0100300 public void transformFrom(TransformableView notification) {
301 mTransformationHelper.transformFrom(notification);
302 }
303
304 @Override
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800305 public void transformFrom(TransformableView notification, float transformationAmount) {
306 mTransformationHelper.transformFrom(notification, transformationAmount);
307 }
308
309 @Override
Selim Cinek414ad332017-02-24 19:06:12 -0800310 public void setIsChildInGroup(boolean isChildInGroup) {
311 super.setIsChildInGroup(isChildInGroup);
312 mTransformLowPriorityTitle = !isChildInGroup;
313 }
314
315 @Override
Selim Cinek4ffd6362015-12-29 15:12:23 +0100316 public void setVisible(boolean visible) {
317 super.setVisible(visible);
318 mTransformationHelper.setVisible(visible);
319 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800320}