blob: 359bc6ec71d8cb94ebd0549786e2c78f716f930f [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;
20import static android.app.NotificationManager.IMPORTANCE_HIGH;
21import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynoldse0341482018-03-08 14:42:50 -050022import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds3aedded2017-03-31 14:42:09 -040023import static android.app.NotificationManager.IMPORTANCE_NONE;
24
Julia Reynolds437cdb12018-01-03 12:27:24 -050025import android.animation.Animator;
26import android.animation.AnimatorListenerAdapter;
27import android.animation.AnimatorSet;
28import android.animation.ObjectAnimator;
Gus Prevas9abc5062018-10-31 16:11:04 -040029import android.annotation.IntDef;
Rohan Shahca0447e2018-03-30 15:18:27 -070030import android.annotation.Nullable;
Mady Mellor87d79452017-01-10 11:52:52 -080031import android.app.INotificationManager;
Julia Reynolds3aedded2017-03-31 14:42:09 -040032import android.app.Notification;
Mady Mellor87d79452017-01-10 11:52:52 -080033import android.app.NotificationChannel;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -050034import android.app.NotificationChannelGroup;
Mady Mellor87d79452017-01-10 11:52:52 -080035import android.content.Context;
Julia Reynolds3aedded2017-03-31 14:42:09 -040036import android.content.Intent;
37import android.content.pm.ActivityInfo;
Mady Mellor87d79452017-01-10 11:52:52 -080038import android.content.pm.ApplicationInfo;
Mady Mellor87d79452017-01-10 11:52:52 -080039import android.content.pm.PackageManager;
Julia Reynolds3aedded2017-03-31 14:42:09 -040040import android.content.pm.ResolveInfo;
Mady Mellor87d79452017-01-10 11:52:52 -080041import android.graphics.drawable.Drawable;
William Brockman75cf66a2018-12-21 13:25:01 -050042import android.metrics.LogMaker;
Rohan Shahca0447e2018-03-30 15:18:27 -070043import android.os.Handler;
Mady Mellor87d79452017-01-10 11:52:52 -080044import android.os.RemoteException;
Julia Reynolds3aedded2017-03-31 14:42:09 -040045import android.service.notification.StatusBarNotification;
46import android.text.TextUtils;
Mady Mellor87d79452017-01-10 11:52:52 -080047import android.util.AttributeSet;
Rohan Shahca0447e2018-03-30 15:18:27 -070048import android.util.Log;
Mady Mellor87d79452017-01-10 11:52:52 -080049import android.view.View;
Julia Reynoldse0341482018-03-08 14:42:50 -050050import android.view.ViewGroup;
Geoffrey Pitschd94e7882017-04-06 09:52:11 -040051import android.view.accessibility.AccessibilityEvent;
Mady Mellor87d79452017-01-10 11:52:52 -080052import android.widget.ImageView;
53import android.widget.LinearLayout;
Mady Mellor87d79452017-01-10 11:52:52 -080054import android.widget.TextView;
55
Rohan Shah524cf7b2018-03-15 14:40:02 -070056import com.android.internal.annotations.VisibleForTesting;
Mady Mellor87d79452017-01-10 11:52:52 -080057import com.android.internal.logging.MetricsLogger;
58import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Rohan Shah524cf7b2018-03-15 14:40:02 -070059import com.android.systemui.Dependency;
Julia Reynolds437cdb12018-01-03 12:27:24 -050060import com.android.systemui.Interpolators;
Mady Mellor87d79452017-01-10 11:52:52 -080061import com.android.systemui.R;
Gus Prevas9abc5062018-10-31 16:11:04 -040062import com.android.systemui.statusbar.notification.NotificationUtils;
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;
84 public static final int ACTION_UNDO = 1;
85 public static final int ACTION_TOGGLE_SILENT = 2;
86 public static final int ACTION_BLOCK = 3;
Gus Prevas9abc5062018-10-31 16:11:04 -040087
Mady Mellor87d79452017-01-10 11:52:52 -080088 private INotificationManager mINotificationManager;
Julia Reynolds437cdb12018-01-03 12:27:24 -050089 private PackageManager mPm;
Rohan Shahda5dcdd2018-04-27 17:21:50 -070090 private MetricsLogger mMetricsLogger;
Julia Reynolds437cdb12018-01-03 12:27:24 -050091
Rohan Shahca0447e2018-03-30 15:18:27 -070092 private String mPackageName;
Geoffrey Pitschd94e7882017-04-06 09:52:11 -040093 private String mAppName;
Geoffrey Pitschd0856f02017-02-16 10:51:18 -050094 private int mAppUid;
Julia Reynolds268647a2018-10-25 16:54:27 -040095 private String mDelegatePkg;
Rohan Shahca0447e2018-03-30 15:18:27 -070096 private int mNumUniqueChannelsInRow;
Geoffrey Pitschd0856f02017-02-16 10:51:18 -050097 private NotificationChannel mSingleNotificationChannel;
Gus Prevas9abc5062018-10-31 16:11:04 -040098 private int mStartingChannelImportance;
Gus Prevascaed15c2019-01-18 14:19:51 -050099 private boolean mWasShownHighPriority;
100 /**
101 * The last importance level chosen by the user. Null if the user has not chosen an importance
102 * level; non-null once the user takes an action which indicates an explicit preference.
103 */
104 @Nullable private Integer mChosenImportance;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500105 private boolean mIsSingleDefaultChannel;
Rohan Shah63411fc2018-03-28 19:05:52 -0700106 private boolean mIsNonblockable;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500107 private StatusBarNotification mSbn;
108 private AnimatorSet mExpandAnimation;
Julia Reynoldse0341482018-03-08 14:42:50 -0500109 private boolean mIsForeground;
Julia Reynolds35765d82018-08-17 11:39:19 -0400110 private boolean mIsDeviceProvisioned;
Mady Mellor87d79452017-01-10 11:52:52 -0800111
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400112 private CheckSaveListener mCheckSaveListener;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500113 private OnSettingsClickListener mOnSettingsClickListener;
Julia Reynolds3aedded2017-03-31 14:42:09 -0400114 private OnAppSettingsClickListener mAppSettingsClickListener;
Mady Mellor95d743c2017-01-10 12:05:27 -0800115 private NotificationGuts mGutsContainer;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700116
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700117 /** Whether this view is being shown as part of the blocking helper. */
Rohan Shah524cf7b2018-03-15 14:40:02 -0700118 private boolean mIsForBlockingHelper;
Julia Reynolds0ef7d842018-01-24 17:50:31 -0500119 private boolean mNegativeUserSentiment;
Mady Mellor87d79452017-01-10 11:52:52 -0800120
Rohan Shahdd588c72018-05-09 20:32:15 -0700121 /**
122 * String that describes how the user exit or quit out of this view, also used as a counter tag.
123 */
124 private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700125
126 private OnClickListener mOnKeepShowing = v -> {
Rohan Shahdd588c72018-05-09 20:32:15 -0700127 mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700128 closeControls(v);
Eyal Poseneraea29ed2019-01-24 09:54:08 +0200129 mMetricsLogger.write(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
130 .setType(MetricsEvent.TYPE_ACTION)
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200131 .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700132 };
Julia Reynolds437cdb12018-01-03 12:27:24 -0500133
Gus Prevas9abc5062018-10-31 16:11:04 -0400134 private OnClickListener mOnToggleSilent = v -> {
135 Runnable saveImportance = () -> {
Gus Prevas894d9152018-11-12 13:51:40 -0500136 swapContent(ACTION_TOGGLE_SILENT, true /* animate */);
Eyal Poseneraea29ed2019-01-24 09:54:08 +0200137 mMetricsLogger.write(getLogMaker()
138 .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
139 .setType(MetricsEvent.TYPE_ACTION)
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200140 .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME));
Gus Prevas9abc5062018-10-31 16:11:04 -0400141 };
142 if (mCheckSaveListener != null) {
143 mCheckSaveListener.checkSave(saveImportance, mSbn);
144 } else {
145 saveImportance.run();
146 }
147 };
148
Rohan Shahca0447e2018-03-30 15:18:27 -0700149 private OnClickListener mOnStopOrMinimizeNotifications = v -> {
Gus Prevas533836a2018-09-24 17:15:32 -0400150 Runnable saveImportance = () -> {
Gus Prevas894d9152018-11-12 13:51:40 -0500151 swapContent(ACTION_BLOCK, true /* animate */);
Eyal Poseneraea29ed2019-01-24 09:54:08 +0200152 mMetricsLogger.write(getLogMaker()
153 .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
154 .setType(MetricsEvent.TYPE_ACTION)
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200155 .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED));
Gus Prevas533836a2018-09-24 17:15:32 -0400156 };
157 if (mCheckSaveListener != null) {
158 mCheckSaveListener.checkSave(saveImportance, mSbn);
159 } else {
160 saveImportance.run();
161 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500162 };
163
164 private OnClickListener mOnUndo = v -> {
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700165 // Reset exit counter that we'll log and record an undo event separately (not an exit event)
Rohan Shahdd588c72018-05-09 20:32:15 -0700166 mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700167 logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
William Brockman75cf66a2018-12-21 13:25:01 -0500168 mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
Gus Prevas894d9152018-11-12 13:51:40 -0500169 swapContent(ACTION_UNDO, true /* animate */);
Eyal Poseneraea29ed2019-01-24 09:54:08 +0200170 mMetricsLogger.write(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
171 .setType(MetricsEvent.TYPE_DISMISS)
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200172 .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
Julia Reynolds437cdb12018-01-03 12:27:24 -0500173 };
174
Mady Mellor87d79452017-01-10 11:52:52 -0800175 public NotificationInfo(Context context, AttributeSet attrs) {
176 super(context, attrs);
177 }
178
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400179 // Specify a CheckSaveListener to override when/if the user's changes are committed.
180 public interface CheckSaveListener {
181 // Invoked when importance has changed and the NotificationInfo wants to try to save it.
182 // Listener should run saveImportance unless the change should be canceled.
Eliot Courtney47098cb2017-10-18 17:30:30 +0900183 void checkSave(Runnable saveImportance, StatusBarNotification sbn);
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400184 }
185
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500186 public interface OnSettingsClickListener {
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500187 void onClick(View v, NotificationChannel channel, int appUid);
Mady Mellor87d79452017-01-10 11:52:52 -0800188 }
189
Julia Reynolds3aedded2017-03-31 14:42:09 -0400190 public interface OnAppSettingsClickListener {
191 void onClick(View v, Intent intent);
192 }
193
Rohan Shah524cf7b2018-03-15 14:40:02 -0700194 @VisibleForTesting
195 void bindNotification(
196 final PackageManager pm,
Jason Monk2a6ea9c2017-01-26 11:14:51 -0500197 final INotificationManager iNotificationManager,
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500198 final String pkg,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500199 final NotificationChannel notificationChannel,
Rohan Shahca0447e2018-03-30 15:18:27 -0700200 final int numUniqueChannelsInRow,
Julia Reynolds3aedded2017-03-31 14:42:09 -0400201 final StatusBarNotification sbn,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500202 final CheckSaveListener checkSaveListener,
203 final OnSettingsClickListener onSettingsClick,
204 final OnAppSettingsClickListener onAppSettingsClick,
Julia Reynolds35765d82018-08-17 11:39:19 -0400205 boolean isDeviceProvisioned,
Gus Prevas9abc5062018-10-31 16:11:04 -0400206 boolean isNonblockable,
Gus Prevascaed15c2019-01-18 14:19:51 -0500207 int importance,
208 boolean wasShownHighPriority)
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500209 throws RemoteException {
Rohan Shahca0447e2018-03-30 15:18:27 -0700210 bindNotification(pm, iNotificationManager, pkg, notificationChannel,
211 numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
Julia Reynolds35765d82018-08-17 11:39:19 -0400212 onAppSettingsClick, isDeviceProvisioned, isNonblockable,
Gus Prevas82ad0592018-11-28 14:27:40 -0500213 false /* isBlockingHelper */, false /* isUserSentimentNegative */,
Gus Prevascaed15c2019-01-18 14:19:51 -0500214 importance, wasShownHighPriority);
Julia Reynolds0ef7d842018-01-24 17:50:31 -0500215 }
216
Rohan Shah524cf7b2018-03-15 14:40:02 -0700217 public void bindNotification(
218 PackageManager pm,
219 INotificationManager iNotificationManager,
220 String pkg,
221 NotificationChannel notificationChannel,
Rohan Shahca0447e2018-03-30 15:18:27 -0700222 int numUniqueChannelsInRow,
Rohan Shah524cf7b2018-03-15 14:40:02 -0700223 StatusBarNotification sbn,
224 CheckSaveListener checkSaveListener,
225 OnSettingsClickListener onSettingsClick,
226 OnAppSettingsClickListener onAppSettingsClick,
Julia Reynolds35765d82018-08-17 11:39:19 -0400227 boolean isDeviceProvisioned,
Rohan Shah63411fc2018-03-28 19:05:52 -0700228 boolean isNonblockable,
Rohan Shah524cf7b2018-03-15 14:40:02 -0700229 boolean isForBlockingHelper,
Gus Prevas9abc5062018-10-31 16:11:04 -0400230 boolean isUserSentimentNegative,
Gus Prevascaed15c2019-01-18 14:19:51 -0500231 int importance,
232 boolean wasShownHighPriority)
Rohan Shah524cf7b2018-03-15 14:40:02 -0700233 throws RemoteException {
Mady Mellor87d79452017-01-10 11:52:52 -0800234 mINotificationManager = iNotificationManager;
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700235 mMetricsLogger = Dependency.get(MetricsLogger.class);
Rohan Shahca0447e2018-03-30 15:18:27 -0700236 mPackageName = pkg;
237 mNumUniqueChannelsInRow = numUniqueChannelsInRow;
Julia Reynolds3aedded2017-03-31 14:42:09 -0400238 mSbn = sbn;
239 mPm = pm;
240 mAppSettingsClickListener = onAppSettingsClick;
Rohan Shahca0447e2018-03-30 15:18:27 -0700241 mAppName = mPackageName;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500242 mCheckSaveListener = checkSaveListener;
243 mOnSettingsClickListener = onSettingsClick;
244 mSingleNotificationChannel = notificationChannel;
Gus Prevascaed15c2019-01-18 14:19:51 -0500245 mStartingChannelImportance = mSingleNotificationChannel.getImportance();
246 mWasShownHighPriority = wasShownHighPriority;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700247 mNegativeUserSentiment = isUserSentimentNegative;
Rohan Shah63411fc2018-03-28 19:05:52 -0700248 mIsNonblockable = isNonblockable;
Julia Reynoldse0341482018-03-08 14:42:50 -0500249 mIsForeground =
250 (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
Rohan Shah524cf7b2018-03-15 14:40:02 -0700251 mIsForBlockingHelper = isForBlockingHelper;
Rohan Shahdbd64e72018-03-28 14:46:50 -0700252 mAppUid = mSbn.getUid();
Julia Reynolds268647a2018-10-25 16:54:27 -0400253 mDelegatePkg = mSbn.getOpPkg();
Julia Reynolds35765d82018-08-17 11:39:19 -0400254 mIsDeviceProvisioned = isDeviceProvisioned;
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500255
Julia Reynolds437cdb12018-01-03 12:27:24 -0500256 int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400257 pkg, mAppUid, false /* includeDeleted */);
Rohan Shahca0447e2018-03-30 15:18:27 -0700258 if (mNumUniqueChannelsInRow == 0) {
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400259 throw new IllegalArgumentException("bindNotification requires at least one channel");
260 } else {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500261 // Special behavior for the Default channel if no other channels have been defined.
Rohan Shahca0447e2018-03-30 15:18:27 -0700262 mIsSingleDefaultChannel = mNumUniqueChannelsInRow == 1
Rohan Shahdbd64e72018-03-28 14:46:50 -0700263 && mSingleNotificationChannel.getId().equals(
264 NotificationChannel.DEFAULT_CHANNEL_ID)
265 && numTotalChannels == 1;
Geoffrey Pitschd034d292017-05-12 11:59:20 -0400266 }
267
Julia Reynolds437cdb12018-01-03 12:27:24 -0500268 bindHeader();
269 bindPrompt();
270 bindButtons();
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200271
Eyal Poseneraea29ed2019-01-24 09:54:08 +0200272 mMetricsLogger.write(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
273 .setType(MetricsEvent.TYPE_OPEN)
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200274 .setSubtype(MetricsEvent.BLOCKING_HELPER_DISPLAY));
Julia Reynolds437cdb12018-01-03 12:27:24 -0500275 }
276
277 private void bindHeader() throws RemoteException {
278 // Package name
279 Drawable pkgicon = null;
280 ApplicationInfo info;
281 try {
Rohan Shahca0447e2018-03-30 15:18:27 -0700282 info = mPm.getApplicationInfo(
283 mPackageName,
Julia Reynolds437cdb12018-01-03 12:27:24 -0500284 PackageManager.MATCH_UNINSTALLED_PACKAGES
285 | PackageManager.MATCH_DISABLED_COMPONENTS
286 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
287 | PackageManager.MATCH_DIRECT_BOOT_AWARE);
288 if (info != null) {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500289 mAppName = String.valueOf(mPm.getApplicationLabel(info));
290 pkgicon = mPm.getApplicationIcon(info);
Geoffrey Pitschee8c81e2017-03-23 11:38:56 -0400291 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500292 } catch (PackageManager.NameNotFoundException e) {
293 // app is gone, just show package name and generic icon
294 pkgicon = mPm.getDefaultActivityIcon();
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500295 }
Julia Reynolds437cdb12018-01-03 12:27:24 -0500296 ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400297 ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
Mady Mellor87d79452017-01-10 11:52:52 -0800298
Julia Reynolds268647a2018-10-25 16:54:27 -0400299 // Delegate
300 bindDelegate();
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000301
302 // Settings button.
303 final View settingsButton = findViewById(R.id.info);
304 if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
305 settingsButton.setVisibility(View.VISIBLE);
306 final int appUidF = mAppUid;
307 settingsButton.setOnClickListener(
308 (View view) -> {
309 logBlockingHelperCounter(
310 NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
311 mOnSettingsClickListener.onClick(view,
312 mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
313 appUidF);
314 });
315 } else {
316 settingsButton.setVisibility(View.GONE);
317 }
318 }
319
Julia Reynolds268647a2018-10-25 16:54:27 -0400320 private void bindPrompt() throws RemoteException {
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000321 final TextView blockPrompt = findViewById(R.id.block_prompt);
322 bindName();
Julia Reynolds268647a2018-10-25 16:54:27 -0400323 bindGroup();
Daniel Sandlerd0a52b62018-10-31 20:13:22 +0000324 if (mIsNonblockable) {
325 blockPrompt.setText(R.string.notification_unblockable_desc);
326 } else {
327 if (mNegativeUserSentiment) {
328 blockPrompt.setText(R.string.inline_blocking_helper);
329 } else if (mIsSingleDefaultChannel || mNumUniqueChannelsInRow > 1) {
330 blockPrompt.setText(R.string.inline_keep_showing_app);
331 } else {
332 blockPrompt.setText(R.string.inline_keep_showing);
333 }
334 }
335 }
336
337 private void bindName() {
338 final TextView channelName = findViewById(R.id.channel_name);
339 if (mIsSingleDefaultChannel || mNumUniqueChannelsInRow > 1) {
340 channelName.setVisibility(View.GONE);
341 } else {
342 channelName.setText(mSingleNotificationChannel.getName());
343 }
Julia Reynoldsac98aea2018-10-25 16:54:27 -0400344 }
345
Julia Reynolds268647a2018-10-25 16:54:27 -0400346 private void bindDelegate() {
347 TextView delegateView = findViewById(R.id.delegate_name);
348 TextView dividerView = findViewById(R.id.pkg_divider);
349
350 CharSequence delegatePkg = null;
351 if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
352 // this notification was posted by a delegate!
353 ApplicationInfo info;
354 try {
355 info = mPm.getApplicationInfo(
356 mDelegatePkg,
357 PackageManager.MATCH_UNINSTALLED_PACKAGES
358 | PackageManager.MATCH_DISABLED_COMPONENTS
359 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
360 | PackageManager.MATCH_DIRECT_BOOT_AWARE);
361 if (info != null) {
362 delegatePkg = String.valueOf(mPm.getApplicationLabel(info));
363 }
364 } catch (PackageManager.NameNotFoundException e) { }
365 }
366 if (delegatePkg != null) {
367 delegateView.setText(mContext.getResources().getString(
368 R.string.notification_delegate_header, delegatePkg));
369 delegateView.setVisibility(View.VISIBLE);
370 dividerView.setVisibility(View.VISIBLE);
371 } else {
372 delegateView.setVisibility(View.GONE);
373 dividerView.setVisibility(View.GONE);
374 }
375 }
376
377 private void bindGroup() throws RemoteException {
378 // Set group information if this channel has an associated group.
379 CharSequence groupName = null;
380 if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
381 final NotificationChannelGroup notificationChannelGroup =
382 mINotificationManager.getNotificationChannelGroupForPackage(
383 mSingleNotificationChannel.getGroup(), mPackageName, mAppUid);
384 if (notificationChannelGroup != null) {
385 groupName = notificationChannelGroup.getName();
386 }
387 }
388 TextView groupNameView = findViewById(R.id.group_name);
389 TextView groupDividerView = findViewById(R.id.pkg_group_divider);
390 if (groupName != null) {
391 groupNameView.setText(groupName);
392 groupNameView.setVisibility(View.VISIBLE);
393 groupDividerView.setVisibility(View.VISIBLE);
394 } else {
395 groupNameView.setVisibility(View.GONE);
396 groupDividerView.setVisibility(View.GONE);
397 }
398 }
399
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700400 @VisibleForTesting
401 void logBlockingHelperCounter(String counterTag) {
402 if (mIsForBlockingHelper) {
403 mMetricsLogger.count(counterTag, 1);
404 }
405 }
406
William Brockman75cf66a2018-12-21 13:25:01 -0500407 /**
408 * Returns an initialized LogMaker for logging importance changes.
409 * The caller may override the type (to DISMISS) before passing it to mMetricsLogger.
410 * @return new LogMaker
411 */
412 private LogMaker importanceChangeLogMaker() {
Gus Prevascaed15c2019-01-18 14:19:51 -0500413 Integer chosenImportance =
414 mChosenImportance != null ? mChosenImportance : mStartingChannelImportance;
William Brockman75cf66a2018-12-21 13:25:01 -0500415 return new LogMaker(MetricsEvent.ACTION_SAVE_IMPORTANCE)
416 .setType(MetricsEvent.TYPE_ACTION)
Gus Prevascaed15c2019-01-18 14:19:51 -0500417 .setSubtype(chosenImportance - mStartingChannelImportance);
William Brockman75cf66a2018-12-21 13:25:01 -0500418 }
419
Geoffrey Pitsch5278d3d2017-03-29 13:39:10 -0400420 private boolean hasImportanceChanged() {
Gus Prevas9abc5062018-10-31 16:11:04 -0400421 return mSingleNotificationChannel != null
Gus Prevascaed15c2019-01-18 14:19:51 -0500422 && mChosenImportance != null
423 && (mStartingChannelImportance != mChosenImportance
424 || (mWasShownHighPriority && mChosenImportance < IMPORTANCE_DEFAULT)
425 || (!mWasShownHighPriority && mChosenImportance >= IMPORTANCE_DEFAULT));
Mady Mellor87d79452017-01-10 11:52:52 -0800426 }
427
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500428 private void saveImportance() {
Gus Prevas894d9152018-11-12 13:51:40 -0500429 if (!mIsNonblockable
430 || mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) {
Gus Prevascaed15c2019-01-18 14:19:51 -0500431 if (mChosenImportance == null) {
432 mChosenImportance = mStartingChannelImportance;
433 }
Gus Prevas533836a2018-09-24 17:15:32 -0400434 updateImportance();
Geoffrey Pitschd0856f02017-02-16 10:51:18 -0500435 }
Rohan Shahca0447e2018-03-30 15:18:27 -0700436 }
437
438 /**
439 * Commits the updated importance values on the background thread.
440 */
441 private void updateImportance() {
Gus Prevascaed15c2019-01-18 14:19:51 -0500442 if (mChosenImportance != null) {
443 mMetricsLogger.write(importanceChangeLogMaker());
Rohan Shahca0447e2018-03-30 15:18:27 -0700444
Gus Prevascaed15c2019-01-18 14:19:51 -0500445 Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
446 bgHandler.post(
447 new UpdateImportanceRunnable(mINotificationManager, mPackageName, mAppUid,
448 mNumUniqueChannelsInRow == 1 ? mSingleNotificationChannel : null,
449 mStartingChannelImportance, mChosenImportance));
450 }
Mady Mellor87d79452017-01-10 11:52:52 -0800451 }
452
Julia Reynolds437cdb12018-01-03 12:27:24 -0500453 private void bindButtons() {
Rohan Shah524cf7b2018-03-15 14:40:02 -0700454 findViewById(R.id.undo).setOnClickListener(mOnUndo);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500455
Gus Prevas82ad0592018-11-28 14:27:40 -0500456 boolean showInterruptivenessSettings =
457 !mIsNonblockable
458 && !mIsForeground
459 && !mIsForBlockingHelper
460 && NotificationUtils.useNewInterruptionModel(mContext);
461 if (showInterruptivenessSettings) {
462 findViewById(R.id.block_or_minimize).setVisibility(GONE);
463 findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
464 View block = findViewById(R.id.int_block);
465 TextView silent = findViewById(R.id.int_silent);
466 TextView alert = findViewById(R.id.int_alert);
467
Gus Prevas82ad0592018-11-28 14:27:40 -0500468 block.setOnClickListener(mOnStopOrMinimizeNotifications);
Gus Prevascaed15c2019-01-18 14:19:51 -0500469 if (mWasShownHighPriority) {
Gus Prevas82ad0592018-11-28 14:27:40 -0500470 silent.setOnClickListener(mOnToggleSilent);
471 silent.setText(R.string.inline_silent_button_silent);
472 alert.setOnClickListener(mOnKeepShowing);
473 alert.setText(R.string.inline_silent_button_keep_alerting);
474 } else {
475 silent.setOnClickListener(mOnKeepShowing);
476 silent.setText(R.string.inline_silent_button_stay_silent);
477 alert.setOnClickListener(mOnToggleSilent);
478 alert.setText(R.string.inline_silent_button_alert);
479 }
Mady Mellor87d79452017-01-10 11:52:52 -0800480 } else {
Gus Prevas82ad0592018-11-28 14:27:40 -0500481 findViewById(R.id.block_or_minimize).setVisibility(VISIBLE);
482 findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
483 View block = findViewById(R.id.block);
484 TextView keep = findViewById(R.id.keep);
485 View minimize = findViewById(R.id.minimize);
486
487 block.setOnClickListener(mOnStopOrMinimizeNotifications);
488 keep.setOnClickListener(mOnKeepShowing);
489 minimize.setOnClickListener(mOnStopOrMinimizeNotifications);
490
491 if (mIsNonblockable) {
492 keep.setText(android.R.string.ok);
493 block.setVisibility(GONE);
494 minimize.setVisibility(GONE);
495 } else if (mIsForeground) {
496 block.setVisibility(GONE);
497 minimize.setVisibility(VISIBLE);
498 } else {
499 block.setVisibility(VISIBLE);
500 minimize.setVisibility(GONE);
501 }
502
503 // Set up app settings link (i.e. Customize)
504 TextView settingsLinkView = findViewById(R.id.app_settings);
505 Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName,
506 mSingleNotificationChannel,
507 mSbn.getId(), mSbn.getTag());
508 if (!mIsForBlockingHelper
509 && settingsIntent != null
510 && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
511 settingsLinkView.setVisibility(VISIBLE);
512 settingsLinkView.setText(mContext.getString(R.string.notification_app_settings));
513 settingsLinkView.setOnClickListener((View view) -> {
514 mAppSettingsClickListener.onClick(view, settingsIntent);
515 });
516 } else {
517 settingsLinkView.setVisibility(View.GONE);
518 }
Mady Mellor87d79452017-01-10 11:52:52 -0800519 }
520 }
521
Gus Prevas894d9152018-11-12 13:51:40 -0500522 private void swapContent(@NotificationInfoAction int action, boolean animate) {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500523 if (mExpandAnimation != null) {
524 mExpandAnimation.cancel();
525 }
Mady Mellor87d79452017-01-10 11:52:52 -0800526
Julia Reynoldse0341482018-03-08 14:42:50 -0500527 View prompt = findViewById(R.id.prompt);
528 ViewGroup confirmation = findViewById(R.id.confirmation);
529 TextView confirmationText = findViewById(R.id.confirmation_text);
530 View header = findViewById(R.id.header);
531
Gus Prevas9abc5062018-10-31 16:11:04 -0400532 switch (action) {
Gus Prevas894d9152018-11-12 13:51:40 -0500533 case ACTION_UNDO:
Gus Prevas9abc5062018-10-31 16:11:04 -0400534 mChosenImportance = mStartingChannelImportance;
535 break;
Gus Prevas894d9152018-11-12 13:51:40 -0500536 case ACTION_TOGGLE_SILENT:
537 mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
Gus Prevascaed15c2019-01-18 14:19:51 -0500538 if (mWasShownHighPriority) {
Gus Prevas9abc5062018-10-31 16:11:04 -0400539 mChosenImportance = IMPORTANCE_LOW;
540 confirmationText.setText(R.string.notification_channel_silenced);
541 } else {
542 mChosenImportance = IMPORTANCE_HIGH;
543 confirmationText.setText(R.string.notification_channel_unsilenced);
544 }
545 break;
Gus Prevas894d9152018-11-12 13:51:40 -0500546 case ACTION_BLOCK:
547 mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
Gus Prevas9abc5062018-10-31 16:11:04 -0400548 if (mIsForeground) {
549 mChosenImportance = IMPORTANCE_MIN;
550 confirmationText.setText(R.string.notification_channel_minimized);
551 } else {
552 mChosenImportance = IMPORTANCE_NONE;
553 confirmationText.setText(R.string.notification_channel_disabled);
554 }
555 break;
556 default:
557 throw new IllegalArgumentException();
Julia Reynolds437cdb12018-01-03 12:27:24 -0500558 }
559
Gus Prevas894d9152018-11-12 13:51:40 -0500560 boolean isUndo = action == ACTION_UNDO;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500561
Gus Prevas9abc5062018-10-31 16:11:04 -0400562 prompt.setVisibility(isUndo ? VISIBLE : GONE);
563 confirmation.setVisibility(isUndo ? GONE : VISIBLE);
564 header.setVisibility(isUndo ? VISIBLE : GONE);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500565
Gus Prevas894d9152018-11-12 13:51:40 -0500566 if (animate) {
567 ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
568 prompt.getAlpha(), isUndo ? 1f : 0f);
569 promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
570 ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
571 confirmation.getAlpha(), isUndo ? 0f : 1f);
572 confirmAnim.setInterpolator(isUndo ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500573
Gus Prevas894d9152018-11-12 13:51:40 -0500574 mExpandAnimation = new AnimatorSet();
575 mExpandAnimation.playTogether(promptAnim, confirmAnim);
576 mExpandAnimation.setDuration(150);
577 mExpandAnimation.addListener(new AnimatorListenerAdapter() {
578 boolean mCancelled = false;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500579
Gus Prevas894d9152018-11-12 13:51:40 -0500580 @Override
581 public void onAnimationCancel(Animator animation) {
582 mCancelled = true;
Julia Reynolds437cdb12018-01-03 12:27:24 -0500583 }
Gus Prevas894d9152018-11-12 13:51:40 -0500584
585 @Override
586 public void onAnimationEnd(Animator animation) {
587 if (!mCancelled) {
588 prompt.setVisibility(isUndo ? VISIBLE : GONE);
589 confirmation.setVisibility(isUndo ? GONE : VISIBLE);
590 }
591 }
592 });
593 mExpandAnimation.start();
594 }
Rohan Shah142e2da2018-06-14 13:14:18 -0700595
596 // Since we're swapping/update the content, reset the timeout so the UI can't close
597 // immediately after the update.
598 if (mGutsContainer != null) {
599 mGutsContainer.resetFalsingCheck();
600 }
Mady Mellor87d79452017-01-10 11:52:52 -0800601 }
602
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400603 @Override
Gus Prevas9abc5062018-10-31 16:11:04 -0400604 public void onFinishedClosing() {
Gus Prevascaed15c2019-01-18 14:19:51 -0500605 if (mChosenImportance != null) {
606 mStartingChannelImportance = mChosenImportance;
Gus Prevas9abc5062018-10-31 16:11:04 -0400607 }
608 mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
609
610 View prompt = findViewById(R.id.prompt);
611 ViewGroup confirmation = findViewById(R.id.confirmation);
612 View header = findViewById(R.id.header);
613 prompt.setVisibility(VISIBLE);
614 prompt.setAlpha(1f);
615 confirmation.setVisibility(GONE);
616 confirmation.setAlpha(1f);
617 header.setVisibility(VISIBLE);
618 header.setAlpha(1f);
Eyal Poseneraea29ed2019-01-24 09:54:08 +0200619 mMetricsLogger.write(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
620 .setType(MetricsEvent.TYPE_CLOSE));
Gus Prevas9abc5062018-10-31 16:11:04 -0400621 }
622
623 @Override
Geoffrey Pitschd94e7882017-04-06 09:52:11 -0400624 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
625 super.onInitializeAccessibilityEvent(event);
626 if (mGutsContainer != null &&
627 event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
628 if (mGutsContainer.isExposed()) {
629 event.getText().add(mContext.getString(
630 R.string.notification_channel_controls_opened_accessibility, mAppName));
631 } else {
632 event.getText().add(mContext.getString(
633 R.string.notification_channel_controls_closed_accessibility, mAppName));
634 }
635 }
636 }
637
Julia Reynolds3aedded2017-03-31 14:42:09 -0400638 private Intent getAppSettingsIntent(PackageManager pm, String packageName,
639 NotificationChannel channel, int id, String tag) {
640 Intent intent = new Intent(Intent.ACTION_MAIN)
641 .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
642 .setPackage(packageName);
643 final List<ResolveInfo> resolveInfos = pm.queryIntentActivities(
644 intent,
645 PackageManager.MATCH_DEFAULT_ONLY
646 );
647 if (resolveInfos == null || resolveInfos.size() == 0 || resolveInfos.get(0) == null) {
648 return null;
649 }
650 final ActivityInfo activityInfo = resolveInfos.get(0).activityInfo;
651 intent.setClassName(activityInfo.packageName, activityInfo.name);
652 if (channel != null) {
653 intent.putExtra(Notification.EXTRA_CHANNEL_ID, channel.getId());
654 }
655 intent.putExtra(Notification.EXTRA_NOTIFICATION_ID, id);
656 intent.putExtra(Notification.EXTRA_NOTIFICATION_TAG, tag);
657 return intent;
658 }
659
Rohan Shahca0447e2018-03-30 15:18:27 -0700660 /**
661 * Closes the controls and commits the updated importance values (indirectly). If this view is
662 * being used to show the blocking helper, this will immediately dismiss the blocking helper and
663 * commit the updated importance.
664 *
665 * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
666 * user does not have the ability to undo the action anymore. See {@link #swapContent(boolean)}
667 * for where undo is handled.
668 */
Rohan Shah524cf7b2018-03-15 14:40:02 -0700669 @VisibleForTesting
670 void closeControls(View v) {
Rohan Shahda5dcdd2018-04-27 17:21:50 -0700671 int[] parentLoc = new int[2];
672 int[] targetLoc = new int[2];
673 mGutsContainer.getLocationOnScreen(parentLoc);
674 v.getLocationOnScreen(targetLoc);
675 final int centerX = v.getWidth() / 2;
676 final int centerY = v.getHeight() / 2;
677 final int x = targetLoc[0] - parentLoc[0] + centerX;
678 final int y = targetLoc[1] - parentLoc[1] + centerY;
679 mGutsContainer.closeControls(x, y, true /* save */, false /* force */);
Julia Reynolds437cdb12018-01-03 12:27:24 -0500680 }
681
Mady Mellor87d79452017-01-10 11:52:52 -0800682 @Override
Mady Mellor95d743c2017-01-10 12:05:27 -0800683 public void setGutsParent(NotificationGuts guts) {
684 mGutsContainer = guts;
Mady Mellor87d79452017-01-10 11:52:52 -0800685 }
686
687 @Override
Mady Mellor434180c2017-02-13 11:29:42 -0800688 public boolean willBeRemoved() {
Julia Reynolds437cdb12018-01-03 12:27:24 -0500689 return hasImportanceChanged();
Mady Mellor434180c2017-02-13 11:29:42 -0800690 }
691
692 @Override
Lucas Dupin9b08c012018-05-16 19:53:32 -0700693 public boolean shouldBeSaved() {
694 return hasImportanceChanged();
695 }
696
697 @Override
Mady Mellor87d79452017-01-10 11:52:52 -0800698 public View getContentView() {
699 return this;
700 }
701
702 @Override
Mady Mellorc2dbe492017-03-30 13:22:03 -0700703 public boolean handleCloseControls(boolean save, boolean force) {
Julia Reynoldsc65656a2018-02-12 09:55:14 -0500704 // Save regardless of the importance so we can lock the importance field if the user wants
705 // to keep getting notifications
706 if (save) {
Rohan Shahca0447e2018-03-30 15:18:27 -0700707 saveImportance();
Geoffrey Pitschdf44b602017-02-03 13:31:50 -0500708 }
Rohan Shahdd588c72018-05-09 20:32:15 -0700709 logBlockingHelperCounter(mExitReason);
Mady Mellor87d79452017-01-10 11:52:52 -0800710 return false;
711 }
Mady Mellore09fb702017-03-30 13:23:29 -0700712
713 @Override
714 public int getActualHeight() {
715 return getHeight();
716 }
Rohan Shahca0447e2018-03-30 15:18:27 -0700717
Gus Prevas533836a2018-09-24 17:15:32 -0400718 @VisibleForTesting
719 public boolean isAnimating() {
720 return mExpandAnimation != null && mExpandAnimation.isRunning();
721 }
722
Rohan Shahca0447e2018-03-30 15:18:27 -0700723 /**
724 * Runnable to either update the given channel (with a new importance value) or, if no channel
725 * is provided, update notifications enabled state for the package.
726 */
727 private static class UpdateImportanceRunnable implements Runnable {
728 private final INotificationManager mINotificationManager;
729 private final String mPackageName;
730 private final int mAppUid;
731 private final @Nullable NotificationChannel mChannelToUpdate;
732 private final int mCurrentImportance;
733 private final int mNewImportance;
734
735
736 public UpdateImportanceRunnable(INotificationManager notificationManager,
737 String packageName, int appUid, @Nullable NotificationChannel channelToUpdate,
738 int currentImportance, int newImportance) {
739 mINotificationManager = notificationManager;
740 mPackageName = packageName;
741 mAppUid = appUid;
742 mChannelToUpdate = channelToUpdate;
743 mCurrentImportance = currentImportance;
744 mNewImportance = newImportance;
745 }
746
747 @Override
748 public void run() {
749 try {
750 if (mChannelToUpdate != null) {
751 mChannelToUpdate.setImportance(mNewImportance);
752 mChannelToUpdate.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
753 mINotificationManager.updateNotificationChannelForPackage(
754 mPackageName, mAppUid, mChannelToUpdate);
755 } else {
756 // For notifications with more than one channel, update notification enabled
757 // state. If the importance was lowered, we disable notifications.
Rohan Shah590e1b22018-04-10 23:48:47 -0400758 mINotificationManager.setNotificationsEnabledWithImportanceLockForPackage(
Rohan Shahca0447e2018-03-30 15:18:27 -0700759 mPackageName, mAppUid, mNewImportance >= mCurrentImportance);
760 }
761 } catch (RemoteException e) {
762 Log.e(TAG, "Unable to update notification importance", e);
763 }
764 }
765 }
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200766
767 private LogMaker getLogMaker() {
Eyal Poseneraea29ed2019-01-24 09:54:08 +0200768 return mSbn.getLogMaker();
Eyal Posenera9cf9c72018-12-18 16:23:54 +0200769 }
Mady Mellor87d79452017-01-10 11:52:52 -0800770}