summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java
blob: 9a7610ddd3540b9ee7f44887c4e9527b085404fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.statusbar.notification.interruption;

import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;

import android.util.ArrayMap;

import androidx.annotation.Nullable;
import androidx.core.os.CancellationSignal;

import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;

import java.util.Map;

import javax.inject.Inject;

/**
 * Wrapper around heads up view binding logic. {@link HeadsUpViewBinder} is responsible for
 * figuring out the right heads up inflation parameters and inflating/freeing the heads up
 * content view.
 *
 * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated.
 */
@SysUISingleton
public class HeadsUpViewBinder {
    private final RowContentBindStage mStage;
    private final NotificationMessagingUtil mNotificationMessagingUtil;
    private final Map<NotificationEntry, CancellationSignal> mOngoingBindCallbacks =
            new ArrayMap<>();
    private final HeadsUpViewBinderLogger mLogger;

    private NotificationPresenter mNotificationPresenter;

    @Inject
    HeadsUpViewBinder(
            NotificationMessagingUtil notificationMessagingUtil,
            RowContentBindStage bindStage, HeadsUpViewBinderLogger logger) {
        mNotificationMessagingUtil = notificationMessagingUtil;
        mStage = bindStage;
        mLogger = logger;
    }

    /**
     * Set notification presenter to determine parameters for heads up view inflation.
     */
    public void setPresenter(NotificationPresenter presenter) {
        mNotificationPresenter = presenter;
    }

    /**
     * Bind heads up view to the notification row.
     * @param callback callback after heads up view is bound
     */
    public void bindHeadsUpView(NotificationEntry entry, @Nullable BindCallback callback) {
        RowContentBindParams params = mStage.getStageParams(entry);
        final boolean isImportantMessage = mNotificationMessagingUtil.isImportantMessaging(
                entry.getSbn(), entry.getImportance());
        final boolean useIncreasedHeadsUp = isImportantMessage
                && !mNotificationPresenter.isPresenterFullyCollapsed();
        params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
        params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
        CancellationSignal signal = mStage.requestRebind(entry, en -> {
            mLogger.entryBoundSuccessfully(entry);
            en.getRow().setUsesIncreasedHeadsUpHeight(params.useIncreasedHeadsUpHeight());
            // requestRebing promises that if we called cancel before this callback would be
            // invoked, then we will not enter this callback, and because we always cancel before
            // adding to this map, we know this will remove the correct signal.
            mOngoingBindCallbacks.remove(entry);
            if (callback != null) {
                callback.onBindFinished(en);
            }
        });
        abortBindCallback(entry);
        mLogger.startBindingHun(entry);
        mOngoingBindCallbacks.put(entry, signal);
    }

    /**
     * Abort any callbacks waiting for heads up view binding to finish for a given notification.
     * @param entry notification with bind in progress
     */
    public void abortBindCallback(NotificationEntry entry) {
        CancellationSignal ongoingBindCallback = mOngoingBindCallbacks.remove(entry);
        if (ongoingBindCallback != null) {
            mLogger.currentOngoingBindingAborted(entry);
            ongoingBindCallback.cancel();
        }
    }

    /**
     * Unbind the heads up view from the notification row.
     */
    public void unbindHeadsUpView(NotificationEntry entry) {
        abortBindCallback(entry);

        // params may be null if the notification was already removed from the collection but we let
        // it stick around during a launch animation. In this case, the heads up view has already
        // been unbound, so we don't need to unbind it.
        // TODO(b/253081345): Change this back to getStageParams and remove null check.
        RowContentBindParams params = mStage.tryGetStageParams(entry);
        if (params == null) {
            mLogger.entryBindStageParamsNullOnUnbind(entry);
            return;
        }

        params.markContentViewsFreeable(FLAG_CONTENT_VIEW_HEADS_UP);
        mLogger.entryContentViewMarkedFreeable(entry);
        mStage.requestRebind(entry, e -> mLogger.entryUnbound(e));
    }
}