blob: 3fa02c3d0f6809db28e827907617189400cfa9d7 [file] [log] [blame]
Selim Cinek1a48bab2017-02-17 19:38:40 -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
17package com.android.systemui.statusbar.notification;
18
19import android.app.Notification;
20import android.content.Context;
21import android.service.notification.StatusBarNotification;
22import android.util.Log;
23import android.view.View;
24import android.widget.RemoteViews;
25
26import com.android.systemui.statusbar.ExpandableNotificationRow;
27import com.android.systemui.statusbar.NotificationContentView;
28import com.android.systemui.statusbar.NotificationData;
29import com.android.systemui.statusbar.phone.StatusBar;
30
31import java.util.Objects;
32
33/**
34 * A utility that inflates the right kind of contentView based on the state
35 */
36public class NotificationInflater {
37
38 private final ExpandableNotificationRow mRow;
39 private boolean mIsLowPriority;
40 private boolean mUsesIncreasedHeight;
41 private boolean mUsesIncreasedHeadsUpHeight;
42 private RemoteViews.OnClickHandler mRemoteViewClickHandler;
43
44 public NotificationInflater(ExpandableNotificationRow row) {
45 mRow = row;
46 }
47
48 public void setIsLowPriority(boolean isLowPriority) {
49 mIsLowPriority = isLowPriority;
50 }
51
52 public void setUsesIncreasedHeight(boolean usesIncreasedHeight) {
53 mUsesIncreasedHeight = usesIncreasedHeight;
54 }
55
56 public void setUsesIncreasedHeadsUpHeight(boolean usesIncreasedHeight) {
57 mUsesIncreasedHeadsUpHeight = usesIncreasedHeight;
58 }
59
60 public void setRemoteViewClickHandler(RemoteViews.OnClickHandler remoteViewClickHandler) {
61 mRemoteViewClickHandler = remoteViewClickHandler;
62 }
63
64 public void inflateNotificationViews() throws InflationException {
65 NotificationData.Entry entry = mRow.getEntry();
66 StatusBarNotification sbn = entry.notification;
67 Context context = mRow.getContext();
68 NotificationContentView privateLayout = mRow.getPrivateLayout();
69 try {
70 final Notification.Builder recoveredBuilder
71 = Notification.Builder.recoverBuilder(context, sbn.getNotification());
72
73 final RemoteViews newContentView = createContentView(recoveredBuilder,
74 mIsLowPriority, mUsesIncreasedHeadsUpHeight);
75 if (!compareRemoteViews(newContentView, entry.cachedContentView)) {
76 View contentViewLocal = newContentView.apply(
77 sbn.getPackageContext(context),
78 privateLayout,
79 mRemoteViewClickHandler);
80 contentViewLocal.setIsRootNamespace(true);
81 privateLayout.setContractedChild(contentViewLocal);
82 } else {
83 newContentView.reapply(sbn.getPackageContext(context),
84 privateLayout.getContractedChild(),
85 mRemoteViewClickHandler);
86 }
87 entry.cachedContentView = newContentView;
88
89 final RemoteViews newBigContentView = createBigContentView(
90 recoveredBuilder, mIsLowPriority);
91 if (newBigContentView != null) {
92 if (!compareRemoteViews(newBigContentView, entry.cachedBigContentView)) {
93 View bigContentViewLocal = newBigContentView.apply(
94 sbn.getPackageContext(context),
95 privateLayout,
96 mRemoteViewClickHandler);
97 bigContentViewLocal.setIsRootNamespace(true);
98 privateLayout.setExpandedChild(bigContentViewLocal);
99 } else {
100 newBigContentView.reapply(sbn.getPackageContext(context),
101 privateLayout.getExpandedChild(),
102 mRemoteViewClickHandler);
103 }
104 } else if (entry.cachedBigContentView != null) {
105 privateLayout.setExpandedChild(null);
106 }
107 entry.cachedBigContentView = newBigContentView;
108
109 final RemoteViews newHeadsUpContentView =
110 recoveredBuilder.createHeadsUpContentView(mUsesIncreasedHeight);
111 if (newHeadsUpContentView != null) {
112 if (!compareRemoteViews(newHeadsUpContentView, entry.cachedHeadsUpContentView)) {
113 View headsUpContentViewLocal = newHeadsUpContentView.apply(
114 sbn.getPackageContext(context),
115 privateLayout,
116 mRemoteViewClickHandler);
117 headsUpContentViewLocal.setIsRootNamespace(true);
118 privateLayout.setHeadsUpChild(headsUpContentViewLocal);
119 } else {
120 newHeadsUpContentView.reapply(sbn.getPackageContext(context),
121 privateLayout.getHeadsUpChild(),
122 mRemoteViewClickHandler);
123 }
124 } else if (entry.cachedHeadsUpContentView != null) {
125 privateLayout.setHeadsUpChild(null);
126 }
127 entry.cachedHeadsUpContentView = newHeadsUpContentView;
128
129 NotificationContentView publicLayout = mRow.getPublicLayout();
130 final RemoteViews newPublicNotification
131 = recoveredBuilder.makePublicContentView();
132 if (!compareRemoteViews(newPublicNotification, entry.cachedPublicContentView)) {
133 View publicContentView = newPublicNotification.apply(
134 sbn.getPackageContext(context),
135 publicLayout,
136 mRemoteViewClickHandler);
137 publicContentView.setIsRootNamespace(true);
138 publicLayout.setContractedChild(publicContentView);
139 } else {
140 newPublicNotification.reapply(sbn.getPackageContext(context),
141 publicLayout.getContractedChild(),
142 mRemoteViewClickHandler);
143 }
144 entry.cachedPublicContentView = newPublicNotification;
145
146 final RemoteViews newAmbientNotification
147 = recoveredBuilder.makeAmbientNotification();
148 if (!compareRemoteViews(newAmbientNotification, entry.cachedAmbientContentView)) {
149 View ambientContentView = newAmbientNotification.apply(
150 sbn.getPackageContext(context),
151 privateLayout,
152 mRemoteViewClickHandler);
153 ambientContentView.setIsRootNamespace(true);
154 privateLayout.setAmbientChild(ambientContentView);
155 } else {
156 newAmbientNotification.reapply(sbn.getPackageContext(context),
157 privateLayout.getAmbientChild(),
158 mRemoteViewClickHandler);
159 }
160 entry.cachedAmbientContentView = newAmbientNotification;
161
162 mRow.setExpandable(newBigContentView != null);
163
164 } catch (RuntimeException e) {
165 final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
166 Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
167 throw new InflationException("Couldn't inflate contentViews");
168 }
169 }
170
171 private RemoteViews createBigContentView(Notification.Builder builder,
172 boolean isLowPriority) {
173 RemoteViews bigContentView = builder.createBigContentView();
174 if (bigContentView != null) {
175 return bigContentView;
176 }
177 if (isLowPriority) {
178 RemoteViews contentView = builder.createContentView();
179 Notification.Builder.makeHeaderExpanded(contentView);
180 return contentView;
181 }
182 return null;
183 }
184
185 private RemoteViews createContentView(Notification.Builder builder,
186 boolean isLowPriority, boolean useLarge) {
187 if (isLowPriority) {
188 return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
189 }
190 return builder.createContentView(useLarge);
191 }
192
193 // Returns true if the RemoteViews are the same.
194 private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
195 return (a == null && b == null) ||
196 (a != null && b != null
197 && b.getPackage() != null
198 && a.getPackage() != null
199 && a.getPackage().equals(b.getPackage())
200 && a.getLayoutId() == b.getLayoutId());
201 }
202 public void onDensityOrFontScaleChanged() {
203 NotificationData.Entry entry = mRow.getEntry();
204 entry.cachedAmbientContentView = null;
205 entry.cachedBigContentView = null;
206 entry.cachedContentView = null;
207 entry.cachedHeadsUpContentView = null;
208 entry.cachedPublicContentView = null;
209 try {
210 inflateNotificationViews();
211 } catch (InflationException e) {
212 mInflateExceptionHandler.handleInflationException(
213 mRow.getStatusBarNotification(), e);
214 }
215 }
216
217}