blob: e20be2b719396a5585789f83a175c69b168b34ce [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.app.AppOpsManager;
Selim Cinek414ad332017-02-24 19:06:12 -080022import android.app.Notification;
Selim Cinek9c7712d2015-12-08 19:19:48 -080023import android.content.Context;
Adrian Roos75524412016-06-21 11:56:57 -070024import android.util.ArraySet;
Selim Cinek9c7712d2015-12-08 19:19:48 -080025import android.view.NotificationHeaderView;
26import android.view.View;
Selim Cinek0ffbda62016-01-01 20:29:12 +010027import android.view.ViewGroup;
Selim Cinek5be6f332017-01-19 11:54:04 -080028import android.view.animation.Interpolator;
29import android.view.animation.PathInterpolator;
Selim Cinek9c7712d2015-12-08 19:19:48 -080030import android.widget.ImageView;
Selim Cinek6743c0b2017-01-18 18:24:01 -080031import android.widget.TextView;
Selim Cinek9c7712d2015-12-08 19:19:48 -080032
Selim Cinek79d98632020-03-24 19:16:02 -070033import com.android.internal.widget.CachingIconView;
Selim Cinek69e76f92017-04-05 17:06:02 -070034import com.android.internal.widget.NotificationExpandButton;
Selim Cinek5be6f332017-01-19 11:54:04 -080035import com.android.systemui.Interpolators;
Anthony Chen0f6e96c2017-04-07 15:48:17 -070036import com.android.systemui.R;
Gus Prevasab336792018-11-14 13:52:20 -050037import com.android.systemui.statusbar.TransformableView;
38import com.android.systemui.statusbar.ViewTransformationHelper;
Rohan Shah20790b82018-07-02 17:21:04 -070039import com.android.systemui.statusbar.notification.CustomInterpolatorTransformation;
40import com.android.systemui.statusbar.notification.ImageTransformState;
Gus Prevas51425312018-11-15 15:16:14 -050041import com.android.systemui.statusbar.notification.NotificationUtils;
Rohan Shah20790b82018-07-02 17:21:04 -070042import com.android.systemui.statusbar.notification.TransformState;
43import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Selim Cinek9c7712d2015-12-08 19:19:48 -080044
Selim Cinek0ffbda62016-01-01 20:29:12 +010045import java.util.Stack;
Selim Cinek9c7712d2015-12-08 19:19:48 -080046
47/**
48 * Wraps a notification header view.
49 */
50public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
51
Selim Cinek5be6f332017-01-19 11:54:04 -080052 private static final Interpolator LOW_PRIORITY_HEADER_CLOSE
53 = new PathInterpolator(0.4f, 0f, 0.7f, 1f);
Selim Cinek9c7712d2015-12-08 19:19:48 -080054
Selim Cinek4ffd6362015-12-29 15:12:23 +010055 protected final ViewTransformationHelper mTransformationHelper;
56
Selim Cinek9c7712d2015-12-08 19:19:48 -080057 protected int mColor;
Selim Cinek9c7712d2015-12-08 19:19:48 -080058
Selim Cinek79d98632020-03-24 19:16:02 -070059 private CachingIconView mIcon;
Selim Cinek69e76f92017-04-05 17:06:02 -070060 private NotificationExpandButton mExpandButton;
Selim Cinek4b259a12019-05-09 19:10:51 -070061 protected NotificationHeaderView mNotificationHeader;
Selim Cinek6743c0b2017-01-18 18:24:01 -080062 private TextView mHeaderText;
63 private ImageView mWorkProfileImage;
Selim Cinek4237e822020-03-31 17:22:28 -070064 private View mCameraIcon;
65 private View mMicIcon;
66 private View mOverlayIcon;
67 private View mAppOps;
Selim Cineka2b1d372020-03-31 17:54:19 -070068 private View mAudiblyAlertedIcon;
Selim Cinek20d1ee22020-02-03 16:04:26 -050069
Selim Cinek6743c0b2017-01-18 18:24:01 -080070 private boolean mIsLowPriority;
Selim Cinek414ad332017-02-24 19:06:12 -080071 private boolean mTransformLowPriorityTitle;
Anthony Chen0f6e96c2017-04-07 15:48:17 -070072 private boolean mShowExpandButtonAtEnd;
Selim Cinek9c7712d2015-12-08 19:19:48 -080073
Selim Cinek7d1c63e2016-04-21 15:26:10 -070074 protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
Adrian Roos7bcf6d32017-04-04 16:44:25 -070075 super(ctx, view, row);
Anthony Chen0f6e96c2017-04-07 15:48:17 -070076 mShowExpandButtonAtEnd = ctx.getResources().getBoolean(
Gus Prevas51425312018-11-15 15:16:14 -050077 R.bool.config_showNotificationExpandButtonAtEnd)
78 || NotificationUtils.useNewInterruptionModel(ctx);
Selim Cinek4ffd6362015-12-29 15:12:23 +010079 mTransformationHelper = new ViewTransformationHelper();
Selim Cinek5be6f332017-01-19 11:54:04 -080080
81 // we want to avoid that the header clashes with the other text when transforming
82 // low-priority
83 mTransformationHelper.setCustomTransformation(
84 new CustomInterpolatorTransformation(TRANSFORMING_VIEW_TITLE) {
85
86 @Override
87 public Interpolator getCustomInterpolator(int interpolationType,
88 boolean isFrom) {
89 boolean isLowPriority = mView instanceof NotificationHeaderView;
90 if (interpolationType == TRANSFORM_Y) {
91 if (isLowPriority && !isFrom
92 || !isLowPriority && isFrom) {
93 return Interpolators.LINEAR_OUT_SLOW_IN;
94 } else {
95 return LOW_PRIORITY_HEADER_CLOSE;
96 }
97 }
98 return null;
99 }
100
101 @Override
102 protected boolean hasCustomTransformation() {
Selim Cinek414ad332017-02-24 19:06:12 -0800103 return mIsLowPriority && mTransformLowPriorityTitle;
Selim Cinek5be6f332017-01-19 11:54:04 -0800104 }
105 }, TRANSFORMING_VIEW_TITLE);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800106 resolveHeaderViews();
Julia Reynoldsb5867452018-02-28 16:31:35 -0500107 addAppOpsOnClickListener(row);
Selim Cinek9c7712d2015-12-08 19:19:48 -0800108 }
109
110 protected void resolveHeaderViews() {
Selim Cinek69e76f92017-04-05 17:06:02 -0700111 mIcon = mView.findViewById(com.android.internal.R.id.icon);
112 mHeaderText = mView.findViewById(com.android.internal.R.id.header_text);
113 mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
Selim Cinek69e76f92017-04-05 17:06:02 -0700114 mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
Selim Cinek69e76f92017-04-05 17:06:02 -0700115 mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
Selim Cinek4237e822020-03-31 17:22:28 -0700116 mCameraIcon = mView.findViewById(com.android.internal.R.id.camera);
117 mMicIcon = mView.findViewById(com.android.internal.R.id.mic);
118 mOverlayIcon = mView.findViewById(com.android.internal.R.id.overlay);
119 mAppOps = mView.findViewById(com.android.internal.R.id.app_ops);
Selim Cineka2b1d372020-03-31 17:54:19 -0700120 mAudiblyAlertedIcon = mView.findViewById(com.android.internal.R.id.alerted_icon);
Selim Cinek20d1ee22020-02-03 16:04:26 -0500121 if (mNotificationHeader != null) {
122 mNotificationHeader.setShowExpandButtonAtEnd(mShowExpandButtonAtEnd);
123 mColor = mNotificationHeader.getOriginalIconColor();
124 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800125 }
126
Julia Reynoldsb5867452018-02-28 16:31:35 -0500127 private void addAppOpsOnClickListener(ExpandableNotificationRow row) {
Selim Cinek4237e822020-03-31 17:22:28 -0700128 View.OnClickListener listener = row.getAppOpsOnClickListener();
Selim Cinek20d1ee22020-02-03 16:04:26 -0500129 if (mNotificationHeader != null) {
Selim Cinek4237e822020-03-31 17:22:28 -0700130 mNotificationHeader.setAppOpsOnClickListener(listener);
131 }
Selim Cinek78c87312020-04-03 12:30:03 -0700132 if (mAppOps != null) {
133 mAppOps.setOnClickListener(listener);
134 }
Selim Cinek4237e822020-03-31 17:22:28 -0700135 }
136
137 /**
138 * Shows or hides 'app op in use' icons based on app usage.
139 */
140 @Override
141 public void showAppOpsIcons(ArraySet<Integer> appOps) {
142 if (appOps == null) {
143 return;
144 }
145 if (mOverlayIcon != null) {
146 mOverlayIcon.setVisibility(appOps.contains(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
147 ? View.VISIBLE : View.GONE);
148 }
149 if (mCameraIcon != null) {
150 mCameraIcon.setVisibility(appOps.contains(AppOpsManager.OP_CAMERA)
151 ? View.VISIBLE : View.GONE);
152 }
153 if (mMicIcon != null) {
154 mMicIcon.setVisibility(appOps.contains(AppOpsManager.OP_RECORD_AUDIO)
155 ? View.VISIBLE : View.GONE);
Selim Cinek20d1ee22020-02-03 16:04:26 -0500156 }
Julia Reynoldsb5867452018-02-28 16:31:35 -0500157 }
158
Selim Cinek9c7712d2015-12-08 19:19:48 -0800159 @Override
Selim Cinek131f1a42017-06-05 17:50:19 -0700160 public void onContentUpdated(ExpandableNotificationRow row) {
161 super.onContentUpdated(row);
Selim Cinek792eb062020-04-08 12:36:43 -0700162 mIsLowPriority = row.getEntry().isAmbient();
Selim Cinek414ad332017-02-24 19:06:12 -0800163 mTransformLowPriorityTitle = !row.isChildInGroup() && !row.isSummaryWithChildren();
Adrian Roos75524412016-06-21 11:56:57 -0700164 ArraySet<View> previousViews = mTransformationHelper.getAllTransformingViews();
165
Selim Cinek9c7712d2015-12-08 19:19:48 -0800166 // Reinspect the notification.
167 resolveHeaderViews();
Selim Cinek4ffd6362015-12-29 15:12:23 +0100168 updateTransformedTypes();
Selim Cinek646d2052016-01-03 14:42:02 +0800169 addRemainingTransformTypes();
Selim Cinek0ffbda62016-01-01 20:29:12 +0100170 updateCropToPaddingForImageViews();
Ned Burns1c2b85a42019-11-14 15:37:03 -0500171 Notification notification = row.getEntry().getSbn().getNotification();
Selim Cinek414ad332017-02-24 19:06:12 -0800172 mIcon.setTag(ImageTransformState.ICON_TAG, notification.getSmallIcon());
Adrian Roos75524412016-06-21 11:56:57 -0700173
174 // We need to reset all views that are no longer transforming in case a view was previously
175 // transformed, but now we decided to transform its container instead.
176 ArraySet<View> currentViews = mTransformationHelper.getAllTransformingViews();
177 for (int i = 0; i < previousViews.size(); i++) {
178 View view = previousViews.valueAt(i);
179 if (!currentViews.contains(view)) {
180 mTransformationHelper.resetTransformedView(view);
181 }
182 }
Selim Cinek0ffbda62016-01-01 20:29:12 +0100183 }
184
185 /**
Selim Cinek646d2052016-01-03 14:42:02 +0800186 * Adds the remaining TransformTypes to the TransformHelper. This is done to make sure that each
187 * child is faded automatically and doesn't have to be manually added.
188 * The keys used for the views are the ids.
189 */
190 private void addRemainingTransformTypes() {
191 mTransformationHelper.addRemainingTransformTypes(mView);
192 }
193
194 /**
Selim Cinek0ffbda62016-01-01 20:29:12 +0100195 * Since we are deactivating the clipping when transforming the ImageViews don't get clipped
196 * anymore during these transitions. We can avoid that by using
197 * {@link ImageView#setCropToPadding(boolean)} on all ImageViews.
198 */
199 private void updateCropToPaddingForImageViews() {
200 Stack<View> stack = new Stack<>();
201 stack.push(mView);
202 while (!stack.isEmpty()) {
203 View child = stack.pop();
204 if (child instanceof ImageView) {
205 ((ImageView) child).setCropToPadding(true);
206 } else if (child instanceof ViewGroup){
207 ViewGroup group = (ViewGroup) child;
208 for (int i = 0; i < group.getChildCount(); i++) {
209 stack.push(group.getChildAt(i));
210 }
211 }
212 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100213 }
214
Selim Cinek4ffd6362015-12-29 15:12:23 +0100215 protected void updateTransformedTypes() {
216 mTransformationHelper.reset();
Selim Cinek20d1ee22020-02-03 16:04:26 -0500217 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ICON,
218 mIcon);
Selim Cinekecf248f2020-03-20 16:17:21 -0700219 mTransformationHelper.addViewTransformingToSimilar(mWorkProfileImage);
Selim Cinek20d1ee22020-02-03 16:04:26 -0500220 if (mIsLowPriority && mHeaderText != null) {
Selim Cinek6743c0b2017-01-18 18:24:01 -0800221 mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
222 mHeaderText);
223 }
Selim Cinek4237e822020-03-31 17:22:28 -0700224 if (mCameraIcon != null) {
225 mTransformationHelper.addViewTransformingToSimilar(mCameraIcon);
226 }
227 if (mMicIcon != null) {
228 mTransformationHelper.addViewTransformingToSimilar(mMicIcon);
229 }
230 if (mOverlayIcon != null) {
231 mTransformationHelper.addViewTransformingToSimilar(mOverlayIcon);
232 }
Selim Cineka2b1d372020-03-31 17:54:19 -0700233 if (mAudiblyAlertedIcon != null) {
234 mTransformationHelper.addViewTransformingToSimilar(mAudiblyAlertedIcon);
235 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800236 }
237
238 @Override
Selim Cinek9c7712d2015-12-08 19:19:48 -0800239 public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
240 mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
Selim Cinek20d1ee22020-02-03 16:04:26 -0500241 if (mNotificationHeader != null) {
242 mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
243 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800244 }
245
Selim Cinek9c7712d2015-12-08 19:19:48 -0800246 @Override
Selim Cineka2b1d372020-03-31 17:54:19 -0700247 public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) {
248 if (mAudiblyAlertedIcon != null) {
249 mAudiblyAlertedIcon.setVisibility(audiblyAlerted ? View.VISIBLE : View.GONE);
250 }
251 }
252
253 @Override
Selim Cinek9c7712d2015-12-08 19:19:48 -0800254 public NotificationHeaderView getNotificationHeader() {
255 return mNotificationHeader;
256 }
Selim Cinek4ffd6362015-12-29 15:12:23 +0100257
258 @Override
Selim Cinek79d98632020-03-24 19:16:02 -0700259 public int getOriginalIconColor() {
260 return mIcon.getOriginalIconColor();
261 }
262
263 @Override
264 public View getShelfTransformationTarget() {
265 return mIcon;
266 }
267
268 @Override
Selim Cinek9ed6e042020-03-26 15:45:51 -0700269 public void setShelfIconVisible(boolean visible) {
270 super.setShelfIconVisible(visible);
271 mIcon.setForceHidden(visible);
Selim Cinek79d98632020-03-24 19:16:02 -0700272 }
273
274 @Override
Selim Cinek4ffd6362015-12-29 15:12:23 +0100275 public TransformState getCurrentState(int fadingView) {
276 return mTransformationHelper.getCurrentState(fadingView);
277 }
278
279 @Override
280 public void transformTo(TransformableView notification, Runnable endRunnable) {
281 mTransformationHelper.transformTo(notification, endRunnable);
282 }
283
284 @Override
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800285 public void transformTo(TransformableView notification, float transformationAmount) {
286 mTransformationHelper.transformTo(notification, transformationAmount);
287 }
288
289 @Override
Selim Cinek4ffd6362015-12-29 15:12:23 +0100290 public void transformFrom(TransformableView notification) {
291 mTransformationHelper.transformFrom(notification);
292 }
293
294 @Override
Selim Cinek8f2f6a62016-02-23 19:56:31 -0800295 public void transformFrom(TransformableView notification, float transformationAmount) {
296 mTransformationHelper.transformFrom(notification, transformationAmount);
297 }
298
299 @Override
Selim Cinek414ad332017-02-24 19:06:12 -0800300 public void setIsChildInGroup(boolean isChildInGroup) {
301 super.setIsChildInGroup(isChildInGroup);
302 mTransformLowPriorityTitle = !isChildInGroup;
303 }
304
305 @Override
Selim Cinek4ffd6362015-12-29 15:12:23 +0100306 public void setVisible(boolean visible) {
307 super.setVisible(visible);
308 mTransformationHelper.setVisible(visible);
309 }
Selim Cinek9c7712d2015-12-08 19:19:48 -0800310}