blob: d49f1685e34a6b10127bda9c5eb2d4caeec1b4ec [file] [log] [blame]
Mady Mellor87d79452017-01-10 11:52:52 -08001/*
2 * Copyright (C) 2017 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;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -050018
Gus Prevas9abc5062018-10-31 16:11:04 -040019import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
Gus Prevas9abc5062018-10-31 16:11:04 -040020import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds8728d002019-04-19 15:46:13 -040021import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
Julia Reynolds3aedded2017-03-31 14:42:09 -040022
Julia Reynolds437cdb12018-01-03 12:27:24 -050023import android.animation.Animator;
24import android.animation.AnimatorListenerAdapter;
25import android.animation.AnimatorSet;
26import android.animation.ObjectAnimator;
Gus Prevas9abc5062018-10-31 16:11:04 -040027import android.annotation.IntDef;
Rohan Shahca0447e2018-03-30 15:18:27 -070028import android.annotation.Nullable;
Mady Mellor87d79452017-01-10 11:52:52 -080029import android.app.INotificationManager;
Julia Reynolds3aedded2017-03-31 14:42:09 -040030import android.app.Notification;
Mady Mellor87d79452017-01-10 11:52:52 -080031import android.app.NotificationChannel;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -050032import android.app.NotificationChannelGroup;
Mady Mellor87d79452017-01-10 11:52:52 -080033import android.content.Context;
Julia Reynolds3aedded2017-03-31 14:42:09 -040034import android.content.Intent;
35import android.content.pm.ActivityInfo;
Mady Mellor87d79452017-01-10 11:52:52 -080036import android.content.pm.ApplicationInfo;
Mady Mellor87d79452017-01-10 11:52:52 -080037import android.content.pm.PackageManager;
Julia Reynolds3aedded2017-03-31 14:42:09 -040038import android.content.pm.ResolveInfo;
Mady Mellor87d79452017-01-10 11:52:52 -080039import android.graphics.drawable.Drawable;
William Brockman75cf66a2018-12-21 13:25:01 -050040import android.metrics.LogMaker;
Rohan Shahca0447e2018-03-30 15:18:27 -070041import android.os.Handler;
Mady Mellor87d79452017-01-10 11:52:52 -080042import android.os.RemoteException;
Julia Reynolds4d1dd792019-04-29 11:48:29 -040043import android.provider.Settings;
Julia Reynolds3aedded2017-03-31 14:42:09 -040044import android.service.notification.StatusBarNotification;
45import android.text.TextUtils;
Julia Reynolds4d1dd792019-04-29 11:48:29 -040046import android.transition.AutoTransition;
47import android.transition.TransitionManager;
Mady Mellor87d79452017-01-10 11:52:52 -080048import android.util.AttributeSet;
Rohan Shahca0447e2018-03-30 15:18:27 -070049import android.util.Log;
Mady Mellor87d79452017-01-10 11:52:52 -080050import android.view.View;
Julia Reynoldse0341482018-03-08 14:42:50 -050051import android.view.ViewGroup;
Geoffrey Pitschd94e7882017-04-06 09:52:11 -040052import android.view.accessibility.AccessibilityEvent;
Mady Mellor87d79452017-01-10 11:52:52 -080053import android.widget.ImageView;
54import android.widget.LinearLayout;
Mady Mellor87d79452017-01-10 11:52:52 -080055import android.widget.TextView;
56
Rohan Shah524cf7b2018-03-15 14:40:02 -070057import com.android.internal.annotations.VisibleForTesting;
Mady Mellor87d79452017-01-10 11:52:52 -080058import com.android.internal.logging.MetricsLogger;
59import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Rohan Shah524cf7b2018-03-15 14:40:02 -070060import com.android.systemui.Dependency;
Julia Reynolds437cdb12018-01-03 12:27:24 -050061import com.android.systemui.Interpolators;
Mady Mellor87d79452017-01-10 11:52:52 -080062import com.android.systemui.R;
Rohan Shah20790b82018-07-02 17:21:04 -070063import com.android.systemui.statusbar.notification.logging.NotificationCounters;
Mady Mellor87d79452017-01-10 11:52:52 -080064
Geoffrey Pitschd0856f02017-02-16 10:51:18 -050065import java.util.List;
Mady Mellor87d79452017-01-10 11:52:52 -080066
67/**
Rohan Shahda5dcdd2018-04-27 17:21:50 -070068 * The guts of a notification revealed when performing a long press. This also houses the blocking
69 * helper affordance that allows a user to keep/stop notifications after swiping one away.
Mady Mellor87d79452017-01-10 11:52:52 -080070 */
Mady Mellor95d743c2017-01-10 12:05:27 -080071public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
Mady Mellor87d79452017-01-10 11:52:52 -080072 private static final String TAG = "InfoGuts";
73
Gus Prevas894d9152018-11-12 13:51:40 -050074 @IntDef(prefix = { "ACTION_" }, value = {
75 ACTION_NONE,
76 ACTION_UNDO,
77 ACTION_TOGGLE_SILENT,
78 ACTION_BLOCK,
Gus Prevas9abc5062018-10-31 16:11:04 -040079 })
Gus Prevas894d9152018-11-12 13:51:40 -050080 public @interface NotificationInfoAction {
81 }
Gus Prevas9abc5062018-10-31 16:11:04 -040082
Gus Prevas894d9152018-11-12 13:51:40 -050083 public static final int ACTION_NONE = 0;
Nadia Benbernoub66516c2019-03-06 11:01:53 -050084 static final int ACTION_UNDO = 1;
Julia Reynolds52a27372019-04-03 11:00:17 -040085 // standard controls
Nadia Benbernoub66516c2019-03-06 11:01:53 -050086 static final int ACTION_TOGGLE_SILENT = 2;
Julia Reynolds52a27372019-04-03 11:00:17 -040087 // unused
Nadia Benbernoub66516c2019-03-06 11:01:53 -050088 static final int ACTION_BLOCK = 3;
Julia Reynolds52a27372019-04-03 11:00:17 -040089 // blocking helper
Nadia Benbernoub66516c2019-03-06 11:01:53 -050090 static final int ACTION_DELIVER_SILENTLY = 4;
Julia Reynolds52a27372019-04-03 11:00:17 -040091 // standard controls
Nadia Benbernoub66516c2019-03-06 11:01:53 -050092 private static final int ACTION_ALERT = 5;
Gus Prevas9abc5062018-10-31 16:11:04 -040093
Julia Reynolds4d1dd792019-04-29 11:48:29 -040094 private static final int BUTTON_ANIM_TIME_MS = 200;
95
Mady Mellor87d79452017-01-10 11:52:52 -080096 private INotificationManager mINotificationManager;
Julia Reynolds437cdb12018-01-03 12:27:24 -050097 private PackageManager mPm;
Rohan Shahda5dcdd2018-04-27 17:21:50 -070098 private MetricsLogger mMetricsLogger;
Julia Reynolds437cdb12018-01-03 12:27:24 -050099
Rohan Shahca0447e2018-03-30 15:18:27 -0700100 private String mPackageName;
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400101 private String mAppName;
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500102 private int mAppUid;
Julia Reynolds268647a2018-10-25 16:54:27 -0400103 private String mDelegatePkg;
Rohan Shahca0447e2018-03-30 15:18:27 -0700104 private int mNumUniqueChannelsInRow;
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500105 private NotificationChannel mSingleNotificationChannel;
Gus Prevas9abc5062018-10-31 16:11:04 -0400106 private int mStartingChannelImportance;
Gus Prevascaed15c2019-01-18 14:19:51 -0500107 private boolean mWasShownHighPriority;
Julia Reynolds8728d002019-04-19 15:46:13 -0400108 private boolean mShowOnLockscreen;
109 private boolean mShowInStatusBar;
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400110 private boolean mPressedApply;
111
Gus Prevascaed15c2019-01-18 14:19:51 -0500112 /**
113 * The last importance level chosen by the user. Null if the user has not chosen an importance
114 * level; non-null once the user takes an action which indicates an explicit preference.
115 */
116 @Nullable private Integer mChosenImportance;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500117 private boolean mIsSingleDefaultChannel;
Rohan Shah63411fc2018-03-28 19:05:52 -0700118 private boolean mIsNonblockable;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500119 private StatusBarNotification mSbn;
120 private AnimatorSet mExpandAnimation;
Julia Reynolds35765d82018-08-17 11:39:19 -0400121 private boolean mIsDeviceProvisioned;
Mady Mellor87d79452017-01-10 11:52:52 -0800122
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400123 private CheckSaveListener mCheckSaveListener;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500124 private OnSettingsClickListener mOnSettingsClickListener;
Julia Reynolds3aedded2017-03-31 14:42:09 -0400125 private OnAppSettingsClickListener mAppSettingsClickListener;
Mady Mellor95d743c2017-01-10 12:05:27 -0800126 private NotificationGuts mGutsContainer;
Julia Reynolds8728d002019-04-19 15:46:13 -0400127 private Drawable mSelectedBackground;
128 private Drawable mUnselectedBackground;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700129
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700130 /** Whether this view is being shown as part of the blocking helper. */
Rohan Shah524cf7b2018-03-15 14:40:02 -0700131 private boolean mIsForBlockingHelper;
Mady Mellor87d79452017-01-10 11:52:52 -0800132
Rohan Shahdd588c72018-05-09 20:32:15 -0700133 /**
134 * String that describes how the user exit or quit out of this view, also used as a counter tag.
135 */
136 private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700137
Julia Reynolds52a27372019-04-03 11:00:17 -0400138 // used by standard ui
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500139 private OnClickListener mOnAlert = v -> {
140 mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
141 mChosenImportance = IMPORTANCE_DEFAULT;
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400142 setImportanceSummary(ACTION_ALERT, true);
Julia Reynolds52a27372019-04-03 11:00:17 -0400143 updateButtons(ACTION_ALERT);
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500144 };
145
Julia Reynolds52a27372019-04-03 11:00:17 -0400146 // used by standard ui
147 private OnClickListener mOnSilent = v -> {
148 mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
149 mChosenImportance = IMPORTANCE_LOW;
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400150 setImportanceSummary(ACTION_TOGGLE_SILENT, true);
Julia Reynolds52a27372019-04-03 11:00:17 -0400151 updateButtons(ACTION_TOGGLE_SILENT);
152 };
153
154 // used by standard ui
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500155 private OnClickListener mOnDismissSettings = v -> {
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400156 mPressedApply = true;
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500157 closeControls(v);
Nadia Benbernou3b4a93a2019-02-06 16:16:47 -0500158 };
159
Julia Reynolds52a27372019-04-03 11:00:17 -0400160 // used by blocking helper
161 private OnClickListener mOnKeepShowing = v -> {
162 mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
163 closeControls(v);
164 mMetricsLogger.write(getLogMaker().setCategory(
165 MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
166 .setType(MetricsEvent.TYPE_ACTION)
167 .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
168 };
169
170 // used by blocking helper
Nadia Benbernou3b4a93a2019-02-06 16:16:47 -0500171 private OnClickListener mOnDeliverSilently = v -> {
172 handleSaveImportance(
173 ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
Nadia Benbernou3b4a93a2019-02-06 16:16:47 -0500174 };
175
176 private void handleSaveImportance(int action, int metricsSubtype) {
Gus Prevas533836a2018-09-24 17:15:32 -0400177 Runnable saveImportance = () -> {
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500178 saveImportanceAndExitReason(action);
Will Brockmana399f022019-01-30 10:59:36 -0500179 if (mIsForBlockingHelper) {
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500180 swapContent(action, true /* animate */);
Will Brockmana399f022019-01-30 10:59:36 -0500181 mMetricsLogger.write(getLogMaker()
182 .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
183 .setType(MetricsEvent.TYPE_ACTION)
Nadia Benbernou3b4a93a2019-02-06 16:16:47 -0500184 .setSubtype(metricsSubtype));
Will Brockmana399f022019-01-30 10:59:36 -0500185 }
Gus Prevas533836a2018-09-24 17:15:32 -0400186 };
187 if (mCheckSaveListener != null) {
188 mCheckSaveListener.checkSave(saveImportance, mSbn);
189 } else {
190 saveImportance.run();
191 }
Nadia Benbernou3b4a93a2019-02-06 16:16:47 -0500192 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500193
194 private OnClickListener mOnUndo = v -> {
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700195 // Reset exit counter that we'll log and record an undo event separately (not an exit event)
Rohan Shahdd588c72018-05-09 20:32:15 -0700196 mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
Will Brockmana399f022019-01-30 10:59:36 -0500197 if (mIsForBlockingHelper) {
198 logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
199 mMetricsLogger.write(getLogMaker().setCategory(
200 MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
201 .setType(MetricsEvent.TYPE_DISMISS)
202 .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
203 } else {
Julia Reynolds52a27372019-04-03 11:00:17 -0400204 // TODO: this can't happen?
Will Brockmana399f022019-01-30 10:59:36 -0500205 mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
206 }
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500207 saveImportanceAndExitReason(ACTION_UNDO);
Gus Prevas894d9152018-11-12 13:51:40 -0500208 swapContent(ACTION_UNDO, true /* animate */);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500209 };
210
Mady Mellor87d79452017-01-10 11:52:52 -0800211 public NotificationInfo(Context context, AttributeSet attrs) {
212 super(context, attrs);
213 }
214
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400215 // Specify a CheckSaveListener to override when/if the user's changes are committed.
216 public interface CheckSaveListener {
217 // Invoked when importance has changed and the NotificationInfo wants to try to save it.
218 // Listener should run saveImportance unless the change should be canceled.
Eliot Courtney47098cb2017-10-18 17:30:30 +0900219 void checkSave(Runnable saveImportance, StatusBarNotification sbn);
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400220 }
221
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500222 public interface OnSettingsClickListener {
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500223 void onClick(View v, NotificationChannel channel, int appUid);
Mady Mellor87d79452017-01-10 11:52:52 -0800224 }
225
Julia Reynolds3aedded2017-03-31 14:42:09 -0400226 public interface OnAppSettingsClickListener {
227 void onClick(View v, Intent intent);
228 }
229
Rohan Shah524cf7b2018-03-15 14:40:02 -0700230 @VisibleForTesting
231 void bindNotification(
232 final PackageManager pm,
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500233 final INotificationManager iNotificationManager,
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500234 final String pkg,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500235 final NotificationChannel notificationChannel,
Rohan Shahca0447e2018-03-30 15:18:27 -0700236 final int numUniqueChannelsInRow,
Julia Reynolds3aedded2017-03-31 14:42:09 -0400237 final StatusBarNotification sbn,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500238 final CheckSaveListener checkSaveListener,
239 final OnSettingsClickListener onSettingsClick,
240 final OnAppSettingsClickListener onAppSettingsClick,
Julia Reynolds35765d82018-08-17 11:39:19 -0400241 boolean isDeviceProvisioned,
Gus Prevas9abc5062018-10-31 16:11:04 -0400242 boolean isNonblockable,
Gus Prevascaed15c2019-01-18 14:19:51 -0500243 int importance,
244 boolean wasShownHighPriority)
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500245 throws RemoteException {
Rohan Shahca0447e2018-03-30 15:18:27 -0700246 bindNotification(pm, iNotificationManager, pkg, notificationChannel,
247 numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
Julia Reynolds35765d82018-08-17 11:39:19 -0400248 onAppSettingsClick, isDeviceProvisioned, isNonblockable,
Julia Reynolds52a27372019-04-03 11:00:17 -0400249 false /* isBlockingHelper */,
Gus Prevascaed15c2019-01-18 14:19:51 -0500250 importance, wasShownHighPriority);
Julia Reynolds0ef7d842018-01-24 17:50:31 -0500251 }
252
Rohan Shah524cf7b2018-03-15 14:40:02 -0700253 public void bindNotification(
254 PackageManager pm,
255 INotificationManager iNotificationManager,
256 String pkg,
257 NotificationChannel notificationChannel,
Rohan Shahca0447e2018-03-30 15:18:27 -0700258 int numUniqueChannelsInRow,
Rohan Shah524cf7b2018-03-15 14:40:02 -0700259 StatusBarNotification sbn,
260 CheckSaveListener checkSaveListener,
261 OnSettingsClickListener onSettingsClick,
262 OnAppSettingsClickListener onAppSettingsClick,
Julia Reynolds35765d82018-08-17 11:39:19 -0400263 boolean isDeviceProvisioned,
Rohan Shah63411fc2018-03-28 19:05:52 -0700264 boolean isNonblockable,
Rohan Shah524cf7b2018-03-15 14:40:02 -0700265 boolean isForBlockingHelper,
Gus Prevascaed15c2019-01-18 14:19:51 -0500266 int importance,
267 boolean wasShownHighPriority)
Rohan Shah524cf7b2018-03-15 14:40:02 -0700268 throws RemoteException {
Mady Mellor87d79452017-01-10 11:52:52 -0800269 mINotificationManager = iNotificationManager;
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700270 mMetricsLogger = Dependency.get(MetricsLogger.class);
Rohan Shahca0447e2018-03-30 15:18:27 -0700271 mPackageName = pkg;
272 mNumUniqueChannelsInRow = numUniqueChannelsInRow;
Julia Reynolds3aedded2017-03-31 14:42:09 -0400273 mSbn = sbn;
274 mPm = pm;
275 mAppSettingsClickListener = onAppSettingsClick;
Rohan Shahca0447e2018-03-30 15:18:27 -0700276 mAppName = mPackageName;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500277 mCheckSaveListener = checkSaveListener;
278 mOnSettingsClickListener = onSettingsClick;
279 mSingleNotificationChannel = notificationChannel;
Gus Prevascaed15c2019-01-18 14:19:51 -0500280 mStartingChannelImportance = mSingleNotificationChannel.getImportance();
281 mWasShownHighPriority = wasShownHighPriority;
Rohan Shah63411fc2018-03-28 19:05:52 -0700282 mIsNonblockable = isNonblockable;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700283 mIsForBlockingHelper = isForBlockingHelper;
Rohan Shahdbd64e72018-03-28 14:46:50 -0700284 mAppUid = mSbn.getUid();
Julia Reynolds268647a2018-10-25 16:54:27 -0400285 mDelegatePkg = mSbn.getOpPkg();
Julia Reynolds35765d82018-08-17 11:39:19 -0400286 mIsDeviceProvisioned = isDeviceProvisioned;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500287
Julia Reynolds8728d002019-04-19 15:46:13 -0400288 mSelectedBackground = mContext.getDrawable(R.drawable.button_border_selected);
289 mUnselectedBackground = mContext.getDrawable(R.drawable.button_border_unselected);
Julia Reynolds52a27372019-04-03 11:00:17 -0400290
Julia Reynolds437cdb12018-01-03 12:27:24 -0500291 int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400292 pkg, mAppUid, false /* includeDeleted */);
Rohan Shahca0447e2018-03-30 15:18:27 -0700293 if (mNumUniqueChannelsInRow == 0) {
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400294 throw new IllegalArgumentException("bindNotification requires at least one channel");
295 } else {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500296 // Special behavior for the Default channel if no other channels have been defined.
Rohan Shahca0447e2018-03-30 15:18:27 -0700297 mIsSingleDefaultChannel = mNumUniqueChannelsInRow == 1
Rohan Shahdbd64e72018-03-28 14:46:50 -0700298 && mSingleNotificationChannel.getId().equals(
299 NotificationChannel.DEFAULT_CHANNEL_ID)
300 && numTotalChannels == 1;
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400301 }
302
Julia Reynolds8728d002019-04-19 15:46:13 -0400303 mShowInStatusBar = !mINotificationManager.shouldHideSilentStatusIcons(
304 mContext.getPackageName());
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400305 mShowOnLockscreen = Settings.Secure.getInt(mContext.getContentResolver(),
306 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0) == 1;
Julia Reynolds8728d002019-04-19 15:46:13 -0400307
Julia Reynolds437cdb12018-01-03 12:27:24 -0500308 bindHeader();
Julia Reynolds52a27372019-04-03 11:00:17 -0400309 bindChannelDetails();
310
311 if (mIsForBlockingHelper) {
312 bindBlockingHelper();
313 } else {
314 bindInlineControls();
315 }
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200316
Will Brockmana399f022019-01-30 10:59:36 -0500317 mMetricsLogger.write(notificationControlsLogMaker());
Julia Reynolds437cdb12018-01-03 12:27:24 -0500318 }
319
Julia Reynolds52a27372019-04-03 11:00:17 -0400320 private void bindBlockingHelper() {
321 findViewById(R.id.inline_controls).setVisibility(GONE);
322 findViewById(R.id.blocking_helper).setVisibility(VISIBLE);
323
324 findViewById(R.id.undo).setOnClickListener(mOnUndo);
325
326 View turnOffButton = findViewById(R.id.blocking_helper_turn_off_notifications);
327 turnOffButton.setOnClickListener(getSettingsOnClickListener());
328 turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() ? VISIBLE : GONE);
329
330 TextView keepShowing = findViewById(R.id.keep_showing);
331 keepShowing.setOnClickListener(mOnKeepShowing);
332
333 View deliverSilently = findViewById(R.id.deliver_silently);
334 deliverSilently.setOnClickListener(mOnDeliverSilently);
335 }
336
337 private void bindInlineControls() {
338 findViewById(R.id.inline_controls).setVisibility(VISIBLE);
339 findViewById(R.id.blocking_helper).setVisibility(GONE);
340
341 if (mIsNonblockable) {
342 findViewById(R.id.non_configurable_text).setVisibility(VISIBLE);
343 findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
344 findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
Julia Reynolds8728d002019-04-19 15:46:13 -0400345 ((TextView) findViewById(R.id.done)).setText(R.string.inline_done_button);
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400346 findViewById(R.id.turn_off_notifications).setVisibility(GONE);
Julia Reynolds52a27372019-04-03 11:00:17 -0400347 } else if (mNumUniqueChannelsInRow > 1) {
348 findViewById(R.id.non_configurable_text).setVisibility(GONE);
349 findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
350 findViewById(R.id.non_configurable_multichannel_text).setVisibility(VISIBLE);
351 } else {
352 findViewById(R.id.non_configurable_text).setVisibility(GONE);
353 findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
354 findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
355 }
356
357 View turnOffButton = findViewById(R.id.turn_off_notifications);
358 turnOffButton.setOnClickListener(getSettingsOnClickListener());
359 turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() && !mIsNonblockable
360 ? VISIBLE : GONE);
361
362 View done = findViewById(R.id.done);
363 done.setOnClickListener(mOnDismissSettings);
364
365
Julia Reynolds8728d002019-04-19 15:46:13 -0400366 View silent = findViewById(R.id.silence);
367 View alert = findViewById(R.id.alert);
Julia Reynolds52a27372019-04-03 11:00:17 -0400368 silent.setOnClickListener(mOnSilent);
369 alert.setOnClickListener(mOnAlert);
370
371 if (mWasShownHighPriority) {
372 updateButtons(ACTION_ALERT);
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400373 setImportanceSummary(ACTION_ALERT, false);
Julia Reynolds52a27372019-04-03 11:00:17 -0400374 } else {
375 updateButtons(ACTION_TOGGLE_SILENT);
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400376 setImportanceSummary(ACTION_TOGGLE_SILENT, false);
Julia Reynolds52a27372019-04-03 11:00:17 -0400377 }
378 }
379
380 private void bindHeader() {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500381 // Package name
382 Drawable pkgicon = null;
383 ApplicationInfo info;
384 try {
Rohan Shahca0447e2018-03-30 15:18:27 -0700385 info = mPm.getApplicationInfo(
386 mPackageName,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500387 PackageManager.MATCH_UNINSTALLED_PACKAGES
388 | PackageManager.MATCH_DISABLED_COMPONENTS
389 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
390 | PackageManager.MATCH_DIRECT_BOOT_AWARE);
391 if (info != null) {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500392 mAppName = String.valueOf(mPm.getApplicationLabel(info));
393 pkgicon = mPm.getApplicationIcon(info);
Geoffrey Pitschee8c81e2017-03-23 11:38:56 -0400394 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500395 } catch (PackageManager.NameNotFoundException e) {
396 // app is gone, just show package name and generic icon
397 pkgicon = mPm.getDefaultActivityIcon();
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500398 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500399 ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400400 ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
Mady Mellor87d79452017-01-10 11:52:52 -0800401
Julia Reynolds268647a2018-10-25 16:54:27 -0400402 // Delegate
403 bindDelegate();
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000404
Julia Reynolds52a27372019-04-03 11:00:17 -0400405 // Set up app settings link (i.e. Customize)
406 View settingsLinkView = findViewById(R.id.app_settings);
407 Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName,
408 mSingleNotificationChannel,
409 mSbn.getId(), mSbn.getTag());
410 if (settingsIntent != null
411 && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
412 settingsLinkView.setVisibility(VISIBLE);
413 settingsLinkView.setOnClickListener((View view) -> {
414 mAppSettingsClickListener.onClick(view, settingsIntent);
415 });
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000416 } else {
Julia Reynolds52a27372019-04-03 11:00:17 -0400417 settingsLinkView.setVisibility(View.GONE);
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000418 }
Julia Reynolds52a27372019-04-03 11:00:17 -0400419
420 // System Settings button.
421 final View settingsButton = findViewById(R.id.info);
422 settingsButton.setOnClickListener(getSettingsOnClickListener());
423 settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE);
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000424 }
425
Julia Reynolds52a27372019-04-03 11:00:17 -0400426 private OnClickListener getSettingsOnClickListener() {
427 if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
428 final int appUidF = mAppUid;
429 return ((View view) -> {
430 logBlockingHelperCounter(
431 NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
432 mOnSettingsClickListener.onClick(view,
433 mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
434 appUidF);
435 });
436 }
437 return null;
438 }
439
440 private void bindChannelDetails() throws RemoteException {
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000441 bindName();
Julia Reynolds268647a2018-10-25 16:54:27 -0400442 bindGroup();
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000443 }
444
445 private void bindName() {
446 final TextView channelName = findViewById(R.id.channel_name);
447 if (mIsSingleDefaultChannel || mNumUniqueChannelsInRow > 1) {
448 channelName.setVisibility(View.GONE);
449 } else {
450 channelName.setText(mSingleNotificationChannel.getName());
451 }
Julia Reynoldsac98aea2018-10-25 16:54:27 -0400452 }
453
Julia Reynolds268647a2018-10-25 16:54:27 -0400454 private void bindDelegate() {
455 TextView delegateView = findViewById(R.id.delegate_name);
456 TextView dividerView = findViewById(R.id.pkg_divider);
457
458 CharSequence delegatePkg = null;
459 if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
460 // this notification was posted by a delegate!
Julia Reynolds268647a2018-10-25 16:54:27 -0400461 delegateView.setVisibility(View.VISIBLE);
462 dividerView.setVisibility(View.VISIBLE);
463 } else {
464 delegateView.setVisibility(View.GONE);
465 dividerView.setVisibility(View.GONE);
466 }
467 }
468
469 private void bindGroup() throws RemoteException {
470 // Set group information if this channel has an associated group.
471 CharSequence groupName = null;
472 if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
473 final NotificationChannelGroup notificationChannelGroup =
474 mINotificationManager.getNotificationChannelGroupForPackage(
475 mSingleNotificationChannel.getGroup(), mPackageName, mAppUid);
476 if (notificationChannelGroup != null) {
477 groupName = notificationChannelGroup.getName();
478 }
479 }
480 TextView groupNameView = findViewById(R.id.group_name);
Julia Reynolds268647a2018-10-25 16:54:27 -0400481 if (groupName != null) {
482 groupNameView.setText(groupName);
483 groupNameView.setVisibility(View.VISIBLE);
Julia Reynolds268647a2018-10-25 16:54:27 -0400484 } else {
485 groupNameView.setVisibility(View.GONE);
Julia Reynolds268647a2018-10-25 16:54:27 -0400486 }
487 }
488
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500489
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700490 @VisibleForTesting
491 void logBlockingHelperCounter(String counterTag) {
492 if (mIsForBlockingHelper) {
493 mMetricsLogger.count(counterTag, 1);
494 }
495 }
496
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500497 private void saveImportance() {
Gus Prevas894d9152018-11-12 13:51:40 -0500498 if (!mIsNonblockable
499 || mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) {
Gus Prevascaed15c2019-01-18 14:19:51 -0500500 if (mChosenImportance == null) {
501 mChosenImportance = mStartingChannelImportance;
502 }
Gus Prevas533836a2018-09-24 17:15:32 -0400503 updateImportance();
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500504 }
Rohan Shahca0447e2018-03-30 15:18:27 -0700505 }
506
507 /**
508 * Commits the updated importance values on the background thread.
509 */
510 private void updateImportance() {
Gus Prevascaed15c2019-01-18 14:19:51 -0500511 if (mChosenImportance != null) {
512 mMetricsLogger.write(importanceChangeLogMaker());
Rohan Shahca0447e2018-03-30 15:18:27 -0700513
Julia Reynolds8728d002019-04-19 15:46:13 -0400514 int newImportance = mChosenImportance;
515 if (mStartingChannelImportance != IMPORTANCE_UNSPECIFIED) {
516 if ((mWasShownHighPriority && mChosenImportance >= IMPORTANCE_DEFAULT)
517 || (!mWasShownHighPriority && mChosenImportance < IMPORTANCE_DEFAULT)) {
518 newImportance = mStartingChannelImportance;
519 }
520 }
521
Gus Prevascaed15c2019-01-18 14:19:51 -0500522 Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
523 bgHandler.post(
524 new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
525 mNumUniqueChannelsInRow == 1 ? mSingleNotificationChannel : null,
Julia Reynolds8728d002019-04-19 15:46:13 -0400526 mStartingChannelImportance, newImportance));
Gus Prevascaed15c2019-01-18 14:19:51 -0500527 }
Mady Mellor87d79452017-01-10 11:52:52 -0800528 }
529
Julia Reynolds52a27372019-04-03 11:00:17 -0400530 private void updateButtons(int blockState) {
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400531 View silence = findViewById(R.id.silence);
532 View alert = findViewById(R.id.alert);
Julia Reynolds8728d002019-04-19 15:46:13 -0400533 TextView done = findViewById(R.id.done);
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500534 switch (blockState) {
Julia Reynolds52a27372019-04-03 11:00:17 -0400535 case ACTION_TOGGLE_SILENT:
Julia Reynolds8728d002019-04-19 15:46:13 -0400536 updateButtons(silence, alert);
537 if (mWasShownHighPriority) {
538 done.setText(R.string.inline_ok_button);
539 } else {
540 done.setText(R.string.inline_done_button);
541 }
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500542 break;
543 case ACTION_ALERT:
Julia Reynolds8728d002019-04-19 15:46:13 -0400544 updateButtons(alert, silence);
545 if (mWasShownHighPriority) {
546 done.setText(R.string.inline_done_button);
547 } else {
548 done.setText(R.string.inline_ok_button);
549 }
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500550 break;
551 }
552 }
553
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400554 private void updateButtons(View selected, View unselected) {
Julia Reynolds8728d002019-04-19 15:46:13 -0400555 selected.setBackground(mSelectedBackground);
556 selected.setSelected(true);
Julia Reynolds8728d002019-04-19 15:46:13 -0400557 unselected.setBackground(mUnselectedBackground);
558 unselected.setSelected(false);
Julia Reynolds8728d002019-04-19 15:46:13 -0400559 }
560
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400561 void setImportanceSummary(int blockState, boolean userTriggered) {
562 if (userTriggered) {
563 AutoTransition transition = new AutoTransition();
564 transition.setDuration(BUTTON_ANIM_TIME_MS);
565 TransitionManager.beginDelayedTransition(this, transition);
566 }
Julia Reynolds8728d002019-04-19 15:46:13 -0400567 if (blockState == ACTION_ALERT) {
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400568 TextView view = findViewById(R.id.alert_summary);
569 view.setVisibility(VISIBLE);
570 findViewById(R.id.silence_summary).setVisibility(GONE);
Julia Reynolds8728d002019-04-19 15:46:13 -0400571 view.setText(R.string.notification_channel_summary_default);
572 } else {
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400573 TextView view = findViewById(R.id.silence_summary);
574 view.setVisibility(VISIBLE);
575 findViewById(R.id.alert_summary).setVisibility(GONE);
Julia Reynolds8728d002019-04-19 15:46:13 -0400576 if (mShowInStatusBar) {
577 if (mShowOnLockscreen) {
578 view.setText(R.string.notification_channel_summary_low_status_lock);
579 } else {
580 view.setText(R.string.notification_channel_summary_low_status);
581 }
582 } else if (mShowOnLockscreen) {
583 view.setText(R.string.notification_channel_summary_low_lock);
584 } else {
585 view.setText(R.string.notification_channel_summary_low);
586 }
587 }
588 }
589
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500590 private void saveImportanceAndExitReason(@NotificationInfoAction int action) {
591 switch (action) {
592 case ACTION_UNDO:
593 mChosenImportance = mStartingChannelImportance;
594 break;
595 case ACTION_DELIVER_SILENTLY:
596 mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
Julia Reynolds8728d002019-04-19 15:46:13 -0400597 mChosenImportance = mWasShownHighPriority
598 ? IMPORTANCE_LOW : mStartingChannelImportance;
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500599 break;
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500600 default:
601 throw new IllegalArgumentException();
602 }
603 }
604
Julia Reynolds52a27372019-04-03 11:00:17 -0400605 // only used for blocking helper
Gus Prevas894d9152018-11-12 13:51:40 -0500606 private void swapContent(@NotificationInfoAction int action, boolean animate) {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500607 if (mExpandAnimation != null) {
608 mExpandAnimation.cancel();
609 }
Mady Mellor87d79452017-01-10 11:52:52 -0800610
Julia Reynolds52a27372019-04-03 11:00:17 -0400611 View blockingHelper = findViewById(R.id.blocking_helper);
Julia Reynoldse0341482018-03-08 14:42:50 -0500612 ViewGroup confirmation = findViewById(R.id.confirmation);
613 TextView confirmationText = findViewById(R.id.confirmation_text);
Julia Reynoldse0341482018-03-08 14:42:50 -0500614
Nadia Benbernoub66516c2019-03-06 11:01:53 -0500615 saveImportanceAndExitReason(action);
616
Gus Prevas9abc5062018-10-31 16:11:04 -0400617 switch (action) {
Gus Prevas894d9152018-11-12 13:51:40 -0500618 case ACTION_UNDO:
Gus Prevas9abc5062018-10-31 16:11:04 -0400619 break;
Nadia Benbernou3b4a93a2019-02-06 16:16:47 -0500620 case ACTION_DELIVER_SILENTLY:
Nadia Benbernou3b4a93a2019-02-06 16:16:47 -0500621 confirmationText.setText(R.string.notification_channel_silenced);
622 break;
Gus Prevas9abc5062018-10-31 16:11:04 -0400623 default:
624 throw new IllegalArgumentException();
Julia Reynolds437cdb12018-01-03 12:27:24 -0500625 }
626
Gus Prevas894d9152018-11-12 13:51:40 -0500627 boolean isUndo = action == ACTION_UNDO;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500628
Julia Reynolds52a27372019-04-03 11:00:17 -0400629 blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
630 findViewById(R.id.channel_info).setVisibility(isUndo ? VISIBLE : GONE);
631 findViewById(R.id.header).setVisibility(isUndo ? VISIBLE : GONE);
Gus Prevas9abc5062018-10-31 16:11:04 -0400632 confirmation.setVisibility(isUndo ? GONE : VISIBLE);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500633
Gus Prevas894d9152018-11-12 13:51:40 -0500634 if (animate) {
Julia Reynolds52a27372019-04-03 11:00:17 -0400635 ObjectAnimator promptAnim = ObjectAnimator.ofFloat(blockingHelper, View.ALPHA,
636 blockingHelper.getAlpha(), isUndo ? 1f : 0f);
Gus Prevas894d9152018-11-12 13:51:40 -0500637 promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
638 ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
639 confirmation.getAlpha(), isUndo ? 0f : 1f);
640 confirmAnim.setInterpolator(isUndo ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500641
Gus Prevas894d9152018-11-12 13:51:40 -0500642 mExpandAnimation = new AnimatorSet();
643 mExpandAnimation.playTogether(promptAnim, confirmAnim);
644 mExpandAnimation.setDuration(150);
645 mExpandAnimation.addListener(new AnimatorListenerAdapter() {
646 boolean mCancelled = false;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500647
Gus Prevas894d9152018-11-12 13:51:40 -0500648 @Override
649 public void onAnimationCancel(Animator animation) {
650 mCancelled = true;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500651 }
Gus Prevas894d9152018-11-12 13:51:40 -0500652
653 @Override
654 public void onAnimationEnd(Animator animation) {
655 if (!mCancelled) {
Julia Reynolds52a27372019-04-03 11:00:17 -0400656 blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
Gus Prevas894d9152018-11-12 13:51:40 -0500657 confirmation.setVisibility(isUndo ? GONE : VISIBLE);
658 }
659 }
660 });
661 mExpandAnimation.start();
662 }
Rohan Shah142e2da2018-06-14 13:14:18 -0700663
664 // Since we're swapping/update the content, reset the timeout so the UI can't close
665 // immediately after the update.
666 if (mGutsContainer != null) {
667 mGutsContainer.resetFalsingCheck();
668 }
Mady Mellor87d79452017-01-10 11:52:52 -0800669 }
670
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400671 @Override
Gus Prevas9abc5062018-10-31 16:11:04 -0400672 public void onFinishedClosing() {
Gus Prevascaed15c2019-01-18 14:19:51 -0500673 if (mChosenImportance != null) {
674 mStartingChannelImportance = mChosenImportance;
Gus Prevas9abc5062018-10-31 16:11:04 -0400675 }
676 mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
677
Julia Reynolds52a27372019-04-03 11:00:17 -0400678 if (mIsForBlockingHelper) {
679 bindBlockingHelper();
680 } else {
681 bindInlineControls();
682 }
Will Brockmana399f022019-01-30 10:59:36 -0500683
684 mMetricsLogger.write(notificationControlsLogMaker().setType(MetricsEvent.TYPE_CLOSE));
Gus Prevas9abc5062018-10-31 16:11:04 -0400685 }
686
687 @Override
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400688 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
689 super.onInitializeAccessibilityEvent(event);
690 if (mGutsContainer != null &&
691 event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
692 if (mGutsContainer.isExposed()) {
693 event.getText().add(mContext.getString(
694 R.string.notification_channel_controls_opened_accessibility, mAppName));
695 } else {
696 event.getText().add(mContext.getString(
697 R.string.notification_channel_controls_closed_accessibility, mAppName));
698 }
699 }
700 }
701
Julia Reynolds3aedded2017-03-31 14:42:09 -0400702 private Intent getAppSettingsIntent(PackageManager pm, String packageName,
703 NotificationChannel channel, int id, String tag) {
704 Intent intent = new Intent(Intent.ACTION_MAIN)
705 .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
706 .setPackage(packageName);
707 final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
708 intent,
709 PackageManager.MATCH_DEFAULT_ONLY
710 );
711 if (resolveInfos == null || resolveInfos.size() == 0 || resolveInfos.get(0) == null) {
712 return null;
713 }
714 final ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
715 intent.setClassName(activityInfo.packageName, activityInfo.name);
716 if (channel != null) {
717 intent.putExtra(Notification.EXTRA_CHANNEL_ID, channel.getId());
718 }
719 intent.putExtra(Notification.EXTRA_NOTIFICATION_ID, id);
720 intent.putExtra(Notification.EXTRA_NOTIFICATION_TAG, tag);
721 return intent;
722 }
723
Rohan Shahca0447e2018-03-30 15:18:27 -0700724 /**
725 * Closes the controls and commits the updated importance values (indirectly). If this view is
726 * being used to show the blocking helper, this will immediately dismiss the blocking helper and
727 * commit the updated importance.
728 *
729 * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
Julia Reynolds52a27372019-04-03 11:00:17 -0400730 * user does not have the ability to undo the action anymore. See
731 * {@link #swapContent(boolean, boolean)} for where undo is handled.
Rohan Shahca0447e2018-03-30 15:18:27 -0700732 */
Rohan Shah524cf7b2018-03-15 14:40:02 -0700733 @VisibleForTesting
734 void closeControls(View v) {
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700735 int[] parentLoc = new int[2];
736 int[] targetLoc = new int[2];
737 mGutsContainer.getLocationOnScreen(parentLoc);
738 v.getLocationOnScreen(targetLoc);
739 final int centerX = v.getWidth() / 2;
740 final int centerY = v.getHeight() / 2;
741 final int x = targetLoc[0] - parentLoc[0] + centerX;
742 final int y = targetLoc[1] - parentLoc[1] + centerY;
743 mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500744 }
745
Mady Mellor87d79452017-01-10 11:52:52 -0800746 @Override
Mady Mellor95d743c2017-01-10 12:05:27 -0800747 public void setGutsParent(NotificationGuts guts) {
748 mGutsContainer = guts;
Mady Mellor87d79452017-01-10 11:52:52 -0800749 }
750
751 @Override
Mady Mellor434180c2017-02-13 11:29:42 -0800752 public boolean willBeRemoved() {
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400753 return false;
Mady Mellor434180c2017-02-13 11:29:42 -0800754 }
755
756 @Override
Lucas Dupin9b08c012018-05-16 19:53:32 -0700757 public boolean shouldBeSaved() {
Julia Reynolds4d1dd792019-04-29 11:48:29 -0400758 return mPressedApply;
Lucas Dupin9b08c012018-05-16 19:53:32 -0700759 }
760
761 @Override
Mady Mellor87d79452017-01-10 11:52:52 -0800762 public View getContentView() {
763 return this;
764 }
765
766 @Override
Mady Mellorc2dbe492017-03-30 13:22:03 -0700767 public boolean handleCloseControls(boolean save, boolean force) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500768 // Save regardless of the importance so we can lock the importance field if the user wants
769 // to keep getting notifications
770 if (save) {
Rohan Shahca0447e2018-03-30 15:18:27 -0700771 saveImportance();
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500772 }
Rohan Shahdd588c72018-05-09 20:32:15 -0700773 logBlockingHelperCounter(mExitReason);
Mady Mellor87d79452017-01-10 11:52:52 -0800774 return false;
775 }
Mady Mellore09fb702017-03-30 13:23:29 -0700776
777 @Override
778 public int getActualHeight() {
779 return getHeight();
780 }
Rohan Shahca0447e2018-03-30 15:18:27 -0700781
Gus Prevas533836a2018-09-24 17:15:32 -0400782 @VisibleForTesting
783 public boolean isAnimating() {
784 return mExpandAnimation != null && mExpandAnimation.isRunning();
785 }
786
Rohan Shahca0447e2018-03-30 15:18:27 -0700787 /**
788 * Runnable to either update the given channel (with a new importance value) or, if no channel
789 * is provided, update notifications enabled state for the package.
790 */
791 private static class UpdateImportanceRunnable implements Runnable {
792 private final INotificationManager mINotificationManager;
793 private final String mPackageName;
794 private final int mAppUid;
795 private final @Nullable NotificationChannel mChannelToUpdate;
796 private final int mCurrentImportance;
797 private final int mNewImportance;
798
799
800 public UpdateImportanceRunnable(INotificationManager notificationManager,
801 String packageName, int appUid, @Nullable NotificationChannel channelToUpdate,
802 int currentImportance, int newImportance) {
803 mINotificationManager = notificationManager;
804 mPackageName = packageName;
805 mAppUid = appUid;
806 mChannelToUpdate = channelToUpdate;
807 mCurrentImportance = currentImportance;
808 mNewImportance = newImportance;
809 }
810
811 @Override
812 public void run() {
813 try {
814 if (mChannelToUpdate != null) {
815 mChannelToUpdate.setImportance(mNewImportance);
816 mChannelToUpdate.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
817 mINotificationManager.updateNotificationChannelForPackage(
818 mPackageName, mAppUid, mChannelToUpdate);
819 } else {
820 // For notifications with more than one channel, update notification enabled
821 // state. If the importance was lowered, we disable notifications.
Rohan Shah590e1b22018-04-10 23:48:47 -0400822 mINotificationManager.setNotificationsEnabledWithImportanceLockForPackage(
Rohan Shahca0447e2018-03-30 15:18:27 -0700823 mPackageName, mAppUid, mNewImportance >= mCurrentImportance);
824 }
825 } catch (RemoteException e) {
826 Log.e(TAG, "Unable to update notification importance", e);
827 }
828 }
829 }
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200830
Will Brockmana399f022019-01-30 10:59:36 -0500831 /**
832 * Returns a LogMaker with all available notification information.
833 * Caller should set category, type, and maybe subtype, before passing it to mMetricsLogger.
834 * @return LogMaker
835 */
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200836 private LogMaker getLogMaker() {
Will Brockmana399f022019-01-30 10:59:36 -0500837 // The constructor requires a category, so also do it in the other branch for consistency.
838 return mSbn == null ? new LogMaker(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
839 : mSbn.getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER);
840 }
841
842 /**
843 * Returns an initialized LogMaker for logging importance changes.
844 * The caller may override the type before passing it to mMetricsLogger.
845 * @return LogMaker
846 */
847 private LogMaker importanceChangeLogMaker() {
848 Integer chosenImportance =
849 mChosenImportance != null ? mChosenImportance : mStartingChannelImportance;
850 return getLogMaker().setCategory(MetricsEvent.ACTION_SAVE_IMPORTANCE)
851 .setType(MetricsEvent.TYPE_ACTION)
852 .setSubtype(chosenImportance - mStartingChannelImportance);
853 }
854
855 /**
856 * Returns an initialized LogMaker for logging open/close of the info display.
857 * The caller may override the type before passing it to mMetricsLogger.
858 * @return LogMaker
859 */
860 private LogMaker notificationControlsLogMaker() {
861 return getLogMaker().setCategory(MetricsEvent.ACTION_NOTE_CONTROLS)
862 .setType(MetricsEvent.TYPE_OPEN)
863 .setSubtype(mIsForBlockingHelper ? MetricsEvent.BLOCKING_HELPER_DISPLAY
864 : MetricsEvent.BLOCKING_HELPER_UNKNOWN);
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200865 }
Mady Mellor87d79452017-01-10 11:52:52 -0800866}