blob: 148cdea92052064500f4312e05d72be17615af2e [file] [log] [blame]
/*
* Copyright (C) 2019 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;
import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_CONTRACTED;
import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_EXPANDED;
import static com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
/**
* Controller that binds/unbinds views content views on notification group children.
*
* We currently only show a limited number of notification children even if more exist, so we
* can save memory by freeing content views when they're not visible and binding them again when
* they get close to being visible.
*
* Eventually, when {@link NotifPipeline} takes over as the new notification pipeline, we'll have
* more control over which notifications even make it to inflation in the first place and be able
* to enforce this at an earlier stage at the level of the {@link ExpandableNotificationRow}, but
* for now, we're just doing it at the level of content views.
*/
public class DynamicChildBindController {
private final RowContentBindStage mStage;
private final int mChildBindCutoff;
@Inject
public DynamicChildBindController(RowContentBindStage stage) {
this(stage, CHILD_BIND_CUTOFF);
}
/**
* @param childBindCutoff the cutoff where we no longer bother having content views bound
*/
DynamicChildBindController(
RowContentBindStage stage,
int childBindCutoff) {
mStage = stage;
mChildBindCutoff = childBindCutoff;
}
/**
* Update the child content views, unbinding content views on children that won't be visible
* and binding content views on children that will be visible eventually.
*
* @param groupNotifs map of notification summaries to their children
*/
public void updateChildContentViews(
Map<NotificationEntry, List<NotificationEntry>> groupNotifs) {
for (NotificationEntry entry : groupNotifs.keySet()) {
List<NotificationEntry> children = groupNotifs.get(entry);
for (int j = 0; j < children.size(); j++) {
NotificationEntry childEntry = children.get(j);
if (j >= mChildBindCutoff) {
if (hasChildContent(childEntry)) {
freeChildContent(childEntry);
}
} else {
if (!hasChildContent(childEntry)) {
bindChildContent(childEntry);
}
}
}
}
}
private boolean hasChildContent(NotificationEntry entry) {
ExpandableNotificationRow row = entry.getRow();
return row.getPrivateLayout().getContractedChild() != null
|| row.getPrivateLayout().getExpandedChild() != null;
}
private void freeChildContent(NotificationEntry entry) {
RowContentBindParams params = mStage.getStageParams(entry);
params.markContentViewsFreeable(FLAG_CONTENT_VIEW_CONTRACTED);
params.markContentViewsFreeable(FLAG_CONTENT_VIEW_EXPANDED);
mStage.requestRebind(entry, null);
}
private void bindChildContent(NotificationEntry entry) {
RowContentBindParams params = mStage.getStageParams(entry);
params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
params.requireContentViews(FLAG_CONTENT_VIEW_EXPANDED);
mStage.requestRebind(entry, null);
}
/**
* How big the buffer of extra views we keep around to be ready to show when we do need to
* dynamically inflate.
*/
private static final int EXTRA_VIEW_BUFFER_COUNT = 1;
private static final int CHILD_BIND_CUTOFF =
NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED + EXTRA_VIEW_BUFFER_COUNT;
}