1 /* 2 * Copyright (C) 2020 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 17 package com.android.systemui.statusbar.notification.interruption; 18 19 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; 20 21 import android.util.ArrayMap; 22 23 import androidx.annotation.Nullable; 24 import androidx.core.os.CancellationSignal; 25 26 import com.android.internal.util.NotificationMessagingUtil; 27 import com.android.systemui.dagger.SysUISingleton; 28 import com.android.systemui.statusbar.NotificationPresenter; 29 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 30 import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator; 31 import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback; 32 import com.android.systemui.statusbar.notification.row.RowContentBindParams; 33 import com.android.systemui.statusbar.notification.row.RowContentBindStage; 34 35 import java.util.Map; 36 37 import javax.inject.Inject; 38 39 /** 40 * Wrapper around heads up view binding logic. {@link HeadsUpViewBinder} is responsible for 41 * figuring out the right heads up inflation parameters and inflating/freeing the heads up 42 * content view. 43 * 44 * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated. 45 */ 46 @SysUISingleton 47 public class HeadsUpViewBinder { 48 private final RowContentBindStage mStage; 49 private final NotificationMessagingUtil mNotificationMessagingUtil; 50 private final Map<NotificationEntry, CancellationSignal> mOngoingBindCallbacks = 51 new ArrayMap<>(); 52 private final HeadsUpViewBinderLogger mLogger; 53 54 private NotificationPresenter mNotificationPresenter; 55 56 @Inject HeadsUpViewBinder( NotificationMessagingUtil notificationMessagingUtil, RowContentBindStage bindStage, HeadsUpViewBinderLogger logger)57 HeadsUpViewBinder( 58 NotificationMessagingUtil notificationMessagingUtil, 59 RowContentBindStage bindStage, HeadsUpViewBinderLogger logger) { 60 mNotificationMessagingUtil = notificationMessagingUtil; 61 mStage = bindStage; 62 mLogger = logger; 63 } 64 65 /** 66 * Set notification presenter to determine parameters for heads up view inflation. 67 */ setPresenter(NotificationPresenter presenter)68 public void setPresenter(NotificationPresenter presenter) { 69 mNotificationPresenter = presenter; 70 } 71 72 /** 73 * Bind heads up view to the notification row. 74 * @param callback callback after heads up view is bound 75 */ bindHeadsUpView(NotificationEntry entry, @Nullable BindCallback callback)76 public void bindHeadsUpView(NotificationEntry entry, @Nullable BindCallback callback) { 77 RowContentBindParams params = mStage.getStageParams(entry); 78 final boolean isImportantMessage = mNotificationMessagingUtil.isImportantMessaging( 79 entry.getSbn(), entry.getImportance()); 80 final boolean useIncreasedHeadsUp = isImportantMessage 81 && !mNotificationPresenter.isPresenterFullyCollapsed(); 82 params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp); 83 params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP); 84 CancellationSignal signal = mStage.requestRebind(entry, en -> { 85 mLogger.entryBoundSuccessfully(entry); 86 en.getRow().setUsesIncreasedHeadsUpHeight(params.useIncreasedHeadsUpHeight()); 87 // requestRebing promises that if we called cancel before this callback would be 88 // invoked, then we will not enter this callback, and because we always cancel before 89 // adding to this map, we know this will remove the correct signal. 90 mOngoingBindCallbacks.remove(entry); 91 if (callback != null) { 92 callback.onBindFinished(en); 93 } 94 }); 95 abortBindCallback(entry); 96 mLogger.startBindingHun(entry); 97 mOngoingBindCallbacks.put(entry, signal); 98 } 99 100 /** 101 * Abort any callbacks waiting for heads up view binding to finish for a given notification. 102 * @param entry notification with bind in progress 103 */ abortBindCallback(NotificationEntry entry)104 public void abortBindCallback(NotificationEntry entry) { 105 CancellationSignal ongoingBindCallback = mOngoingBindCallbacks.remove(entry); 106 if (ongoingBindCallback != null) { 107 mLogger.currentOngoingBindingAborted(entry); 108 ongoingBindCallback.cancel(); 109 } 110 } 111 112 /** 113 * Unbind the heads up view from the notification row. 114 */ unbindHeadsUpView(NotificationEntry entry)115 public void unbindHeadsUpView(NotificationEntry entry) { 116 abortBindCallback(entry); 117 118 // params may be null if the notification was already removed from the collection but we let 119 // it stick around during a launch animation. In this case, the heads up view has already 120 // been unbound, so we don't need to unbind it. 121 // TODO(b/253081345): Change this back to getStageParams and remove null check. 122 RowContentBindParams params = mStage.tryGetStageParams(entry); 123 if (params == null) { 124 mLogger.entryBindStageParamsNullOnUnbind(entry); 125 return; 126 } 127 128 params.markContentViewsFreeable(FLAG_CONTENT_VIEW_HEADS_UP); 129 mLogger.entryContentViewMarkedFreeable(entry); 130 mStage.requestRebind(entry, e -> mLogger.entryUnbound(e)); 131 } 132 } 133