blob: d3e5af8c729eaf6537ec3046975a9d0e5343feb1 [file] [log] [blame]
Gus Prevas8ba88a82018-12-18 11:13:44 -05001/*
2 * Copyright (C) 2018 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
Ned Burnsc5864672019-02-20 12:57:29 -050017package com.android.systemui.statusbar.notification.collection;
Gus Prevas8ba88a82018-12-18 11:13:44 -050018
19import static com.android.internal.util.Preconditions.checkNotNull;
20import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
Ned Burns1a5e22f2019-02-14 15:11:52 -050021import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
22import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_HEADS_UP;
Gus Prevas8ba88a82018-12-18 11:13:44 -050023
24import android.annotation.Nullable;
25import android.content.Context;
26import android.content.pm.ApplicationInfo;
27import android.content.pm.PackageManager;
28import android.os.Build;
Gus Prevas8ba88a82018-12-18 11:13:44 -050029import android.service.notification.StatusBarNotification;
30import android.util.Log;
31import android.view.ViewGroup;
32
Gus Prevas8ba88a82018-12-18 11:13:44 -050033import com.android.internal.util.NotificationMessagingUtil;
34import com.android.systemui.Dependency;
35import com.android.systemui.R;
36import com.android.systemui.UiOffloadThread;
37import com.android.systemui.statusbar.NotificationLockscreenUserManager;
38import com.android.systemui.statusbar.NotificationPresenter;
39import com.android.systemui.statusbar.NotificationRemoteInputManager;
40import com.android.systemui.statusbar.NotificationUiAdjustment;
Ned Burnsc5864672019-02-20 12:57:29 -050041import com.android.systemui.statusbar.notification.InflationException;
42import com.android.systemui.statusbar.notification.NotificationClicker;
43import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
Tony Mak202f25d2019-01-07 14:40:39 +000044import com.android.systemui.statusbar.notification.logging.NotificationLogger;
Gus Prevas8ba88a82018-12-18 11:13:44 -050045import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Ned Burns1a5e22f2019-02-14 15:11:52 -050046import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
Gus Prevas8ba88a82018-12-18 11:13:44 -050047import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
Gus Prevas8ba88a82018-12-18 11:13:44 -050048import com.android.systemui.statusbar.notification.row.RowInflaterTask;
49import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
50import com.android.systemui.statusbar.phone.NotificationGroupManager;
51import com.android.systemui.statusbar.phone.StatusBar;
52import com.android.systemui.statusbar.policy.HeadsUpManager;
53
Gus Prevas8ba88a82018-12-18 11:13:44 -050054/** Handles inflating and updating views for notifications. */
Ned Burnsc5864672019-02-20 12:57:29 -050055public class NotificationRowBinderImpl implements NotificationRowBinder {
Gus Prevas8ba88a82018-12-18 11:13:44 -050056
57 private static final String TAG = "NotificationViewManager";
58
59 private final NotificationGroupManager mGroupManager =
60 Dependency.get(NotificationGroupManager.class);
61 private final NotificationGutsManager mGutsManager =
62 Dependency.get(NotificationGutsManager.class);
63 private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
Gus Prevasec9e1f02018-12-18 15:28:12 -050064 private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
65 Dependency.get(NotificationInterruptionStateProvider.class);
Gus Prevas8ba88a82018-12-18 11:13:44 -050066
67 private final Context mContext;
Gus Prevas8ba88a82018-12-18 11:13:44 -050068 private final NotificationMessagingUtil mMessagingUtil;
69 private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
70 this::logNotificationExpansion;
Gus Prevas59ec2ff2018-12-28 16:20:28 -050071 private final boolean mAllowLongPress;
Gus Prevas8ba88a82018-12-18 11:13:44 -050072
73 private NotificationRemoteInputManager mRemoteInputManager;
74 private NotificationPresenter mPresenter;
75 private NotificationListContainer mListContainer;
76 private HeadsUpManager mHeadsUpManager;
Ned Burns1a5e22f2019-02-14 15:11:52 -050077 private NotificationContentInflater.InflationCallback mInflationCallback;
Gus Prevas8ba88a82018-12-18 11:13:44 -050078 private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
79 private BindRowCallback mBindRowCallback;
80 private NotificationClicker mNotificationClicker;
Tony Mak202f25d2019-01-07 14:40:39 +000081 private final NotificationLogger mNotificationLogger = Dependency.get(NotificationLogger.class);
Gus Prevas8ba88a82018-12-18 11:13:44 -050082
Ned Burnsc5864672019-02-20 12:57:29 -050083 public NotificationRowBinderImpl(Context context, boolean allowLongPress) {
Gus Prevas8ba88a82018-12-18 11:13:44 -050084 mContext = context;
85 mMessagingUtil = new NotificationMessagingUtil(context);
Gus Prevas59ec2ff2018-12-28 16:20:28 -050086 mAllowLongPress = allowLongPress;
Gus Prevas8ba88a82018-12-18 11:13:44 -050087 }
88
89 private NotificationRemoteInputManager getRemoteInputManager() {
90 if (mRemoteInputManager == null) {
91 mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
92 }
93 return mRemoteInputManager;
94 }
95
96 /**
97 * Sets up late-bound dependencies for this component.
98 */
99 public void setUpWithPresenter(NotificationPresenter presenter,
100 NotificationListContainer listContainer,
101 HeadsUpManager headsUpManager,
Ned Burns1a5e22f2019-02-14 15:11:52 -0500102 NotificationContentInflater.InflationCallback inflationCallback,
Gus Prevas8ba88a82018-12-18 11:13:44 -0500103 BindRowCallback bindRowCallback) {
104 mPresenter = presenter;
105 mListContainer = listContainer;
106 mHeadsUpManager = headsUpManager;
107 mInflationCallback = inflationCallback;
108 mBindRowCallback = bindRowCallback;
109 mOnAppOpsClickListener = mGutsManager::openGuts;
110 }
111
112 public void setNotificationClicker(NotificationClicker clicker) {
113 mNotificationClicker = clicker;
114 }
115
Gus Prevas8ba88a82018-12-18 11:13:44 -0500116 /**
117 * Inflates the views for the given entry (possibly asynchronously).
118 */
Ned Burnsc5864672019-02-20 12:57:29 -0500119 @Override
Gus Prevas86928bb2019-01-04 16:46:13 -0500120 public void inflateViews(
Ned Burnsf81c4c42019-01-07 14:10:43 -0500121 NotificationEntry entry,
Ned Burnsf529ec22019-02-12 19:33:50 -0500122 Runnable onDismissRunnable)
Gus Prevas86928bb2019-01-04 16:46:13 -0500123 throws InflationException {
Gus Prevas8ba88a82018-12-18 11:13:44 -0500124 ViewGroup parent = mListContainer.getViewParentForNotification(entry);
125 PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
126 entry.notification.getUser().getIdentifier());
127
128 final StatusBarNotification sbn = entry.notification;
129 if (entry.rowExists()) {
Gus Prevas86928bb2019-01-04 16:46:13 -0500130 entry.updateIcons(mContext, sbn);
Gus Prevas8ba88a82018-12-18 11:13:44 -0500131 entry.reset();
Ned Burnsf529ec22019-02-12 19:33:50 -0500132 updateNotification(entry, pmUser, sbn, entry.getRow());
Gus Prevas8ba88a82018-12-18 11:13:44 -0500133 } else {
Gus Prevas86928bb2019-01-04 16:46:13 -0500134 entry.createIcons(mContext, sbn);
Gus Prevas8ba88a82018-12-18 11:13:44 -0500135 new RowInflaterTask().inflate(mContext, parent, entry,
136 row -> {
137 bindRow(entry, pmUser, sbn, row, onDismissRunnable);
Ned Burnsf529ec22019-02-12 19:33:50 -0500138 updateNotification(entry, pmUser, sbn, row);
Gus Prevas8ba88a82018-12-18 11:13:44 -0500139 });
140 }
141 }
142
Ned Burnsf81c4c42019-01-07 14:10:43 -0500143 private void bindRow(NotificationEntry entry, PackageManager pmUser,
Gus Prevas8ba88a82018-12-18 11:13:44 -0500144 StatusBarNotification sbn, ExpandableNotificationRow row,
145 Runnable onDismissRunnable) {
146 row.setExpansionLogger(mExpansionLogger, entry.notification.getKey());
147 row.setGroupManager(mGroupManager);
148 row.setHeadsUpManager(mHeadsUpManager);
149 row.setOnExpandClickListener(mPresenter);
150 row.setInflationCallback(mInflationCallback);
Gus Prevas59ec2ff2018-12-28 16:20:28 -0500151 if (mAllowLongPress) {
152 row.setLongPressListener(mGutsManager::openGuts);
153 }
Gus Prevas8ba88a82018-12-18 11:13:44 -0500154 mListContainer.bindRow(row);
155 getRemoteInputManager().bindRow(row);
156
157 // Get the app name.
158 // Note that Notification.Builder#bindHeaderAppName has similar logic
159 // but since this field is used in the guts, it must be accurate.
160 // Therefore we will only show the application label, or, failing that, the
161 // package name. No substitutions.
162 final String pkg = sbn.getPackageName();
163 String appname = pkg;
164 try {
165 final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
166 PackageManager.MATCH_UNINSTALLED_PACKAGES
167 | PackageManager.MATCH_DISABLED_COMPONENTS);
168 if (info != null) {
169 appname = String.valueOf(pmUser.getApplicationLabel(info));
170 }
171 } catch (PackageManager.NameNotFoundException e) {
172 // Do nothing
173 }
174 row.setAppName(appname);
175 row.setOnDismissRunnable(onDismissRunnable);
176 row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
177 if (ENABLE_REMOTE_INPUT) {
178 row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
179 }
180
181 row.setAppOpsOnClickListener(mOnAppOpsClickListener);
182
183 mBindRowCallback.onBindRow(entry, pmUser, sbn, row);
184 }
185
186 /**
187 * Updates the views bound to an entry when the entry's ranking changes, either in-place or by
188 * reinflating them.
189 */
Ned Burnsc5864672019-02-20 12:57:29 -0500190 @Override
Gus Prevas8ba88a82018-12-18 11:13:44 -0500191 public void onNotificationRankingUpdated(
Ned Burnsf81c4c42019-01-07 14:10:43 -0500192 NotificationEntry entry,
Gus Prevas8ba88a82018-12-18 11:13:44 -0500193 @Nullable Integer oldImportance,
194 NotificationUiAdjustment oldAdjustment,
Ned Burnsf529ec22019-02-12 19:33:50 -0500195 NotificationUiAdjustment newAdjustment) {
Gus Prevas8ba88a82018-12-18 11:13:44 -0500196 if (NotificationUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) {
197 if (entry.rowExists()) {
198 entry.reset();
199 PackageManager pmUser = StatusBar.getPackageManagerForUser(
200 mContext,
201 entry.notification.getUser().getIdentifier());
Ned Burnsf529ec22019-02-12 19:33:50 -0500202 updateNotification(entry, pmUser, entry.notification, entry.getRow());
Gus Prevas8ba88a82018-12-18 11:13:44 -0500203 } else {
204 // Once the RowInflaterTask is done, it will pick up the updated entry, so
205 // no-op here.
206 }
207 } else {
208 if (oldImportance != null && entry.importance != oldImportance) {
209 if (entry.rowExists()) {
210 entry.getRow().onNotificationRankingUpdated();
211 }
212 }
213 }
214 }
215
216 //TODO: This method associates a row with an entry, but eventually needs to not do that
217 private void updateNotification(
Ned Burnsf81c4c42019-01-07 14:10:43 -0500218 NotificationEntry entry,
Gus Prevas8ba88a82018-12-18 11:13:44 -0500219 PackageManager pmUser,
220 StatusBarNotification sbn,
Ned Burnsf529ec22019-02-12 19:33:50 -0500221 ExpandableNotificationRow row) {
Ned Burnsa13b6f12019-02-11 20:42:58 -0500222 row.setIsLowPriority(entry.ambient);
Gus Prevas8ba88a82018-12-18 11:13:44 -0500223
224 // Extract target SDK version.
225 try {
226 ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
227 entry.targetSdk = info.targetSdkVersion;
228 } catch (PackageManager.NameNotFoundException ex) {
229 Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
230 }
231 row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
232 && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
233
234 // TODO: should updates to the entry be happening somewhere else?
235 entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
236 entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
237
238 entry.setRow(row);
239 row.setOnActivatedListener(mPresenter);
240
241 boolean useIncreasedCollapsedHeight =
242 mMessagingUtil.isImportantMessaging(sbn, entry.importance);
243 boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight
244 && !mPresenter.isPresenterFullyCollapsed();
245 row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
246 row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
247 row.setEntry(entry);
248
Gus Prevasec9e1f02018-12-18 15:28:12 -0500249 if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
Gus Prevas8ba88a82018-12-18 11:13:44 -0500250 row.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP, true /* shouldInflate */);
251 }
Gus Prevasec9e1f02018-12-18 15:28:12 -0500252 if (mNotificationInterruptionStateProvider.shouldPulse(entry)) {
Gus Prevas8ba88a82018-12-18 11:13:44 -0500253 row.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, true /* shouldInflate */);
254 }
255 row.setNeedsRedaction(
256 Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry));
257 row.inflateViews();
Mark Renouffec45da2019-03-13 13:24:27 -0400258
259 // bind the click event to the content area
260 checkNotNull(mNotificationClicker).register(row, sbn);
Gus Prevas8ba88a82018-12-18 11:13:44 -0500261 }
262
Gus Prevas8ba88a82018-12-18 11:13:44 -0500263 private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
Ned Burnsc5864672019-02-20 12:57:29 -0500264 mNotificationLogger.onExpansionChanged(key, userAction, expanded);
Gus Prevas8ba88a82018-12-18 11:13:44 -0500265 }
266
267 /** Callback for when a row is bound to an entry. */
268 public interface BindRowCallback {
269 /**
270 * Called when a new notification and row is created.
271 *
272 * @param entry entry for the notification
273 * @param pmUser package manager for user
274 * @param sbn notification
275 * @param row row for the notification
276 */
Ned Burnsf81c4c42019-01-07 14:10:43 -0500277 void onBindRow(NotificationEntry entry, PackageManager pmUser,
Gus Prevas8ba88a82018-12-18 11:13:44 -0500278 StatusBarNotification sbn, ExpandableNotificationRow row);
279 }
280}