blob: 5c6c397229002f2d2b886e8d1ae39358a27e8ca4 [file] [log] [blame]
Mady Mellor3dff9e62019-02-05 18:12:53 -08001/*
2 * Copyright (C) 2019 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 */
16package com.android.systemui.bubbles;
17
18
Issei Suzukicac2a502019-04-16 16:52:50 +020019import static android.view.Display.INVALID_DISPLAY;
20
Mark Renouf9ba6cea2019-04-17 11:53:50 -040021import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
22
Lyn Han6c40fe72019-05-08 14:06:33 -070023import android.content.Context;
24import android.content.pm.ApplicationInfo;
25import android.content.pm.PackageManager;
Mark Renouf71a3af62019-04-08 15:02:54 -040026import android.os.UserHandle;
Mady Mellor3dff9e62019-02-05 18:12:53 -080027import android.view.LayoutInflater;
28
Mark Renouf9ba6cea2019-04-17 11:53:50 -040029import com.android.internal.annotations.VisibleForTesting;
Mady Mellor3dff9e62019-02-05 18:12:53 -080030import com.android.systemui.R;
31import com.android.systemui.statusbar.notification.collection.NotificationEntry;
32
Mark Renouf71a3af62019-04-08 15:02:54 -040033import java.util.Objects;
34
Mady Mellor3dff9e62019-02-05 18:12:53 -080035/**
36 * Encapsulates the data and UI elements of a bubble.
37 */
38class Bubble {
39
Mark Renouf71a3af62019-04-08 15:02:54 -040040 private static final boolean DEBUG = false;
41 private static final String TAG = "Bubble";
42
Mark Renouf85e0a902019-04-05 15:51:51 -040043 private final String mKey;
Mark Renouf71a3af62019-04-08 15:02:54 -040044 private final String mGroupId;
Lyn Han6c40fe72019-05-08 14:06:33 -070045 private String mAppName;
Mark Renouf85e0a902019-04-05 15:51:51 -040046 private final BubbleExpandedView.OnBubbleBlockedListener mListener;
47
48 private boolean mInflated;
Mady Mellor3dff9e62019-02-05 18:12:53 -080049 public NotificationEntry entry;
Mark Renouf71a3af62019-04-08 15:02:54 -040050 BubbleView iconView;
51 BubbleExpandedView expandedView;
Mark Renouf9ba6cea2019-04-17 11:53:50 -040052 private long mLastUpdated;
53 private long mLastAccessed;
Lyn Han6c40fe72019-05-08 14:06:33 -070054 private PackageManager mPm;
Mark Renouf71a3af62019-04-08 15:02:54 -040055
Mark Renoufba5ab512019-05-02 15:21:01 -040056 public static String groupId(NotificationEntry entry) {
Mark Renouf71a3af62019-04-08 15:02:54 -040057 UserHandle user = entry.notification.getUser();
Mark Renouf9ba6cea2019-04-17 11:53:50 -040058 return user.getIdentifier() + "|" + entry.notification.getPackageName();
59 }
60
61 /** Used in tests when no UI is required. */
62 @VisibleForTesting(visibility = PRIVATE)
Lyn Han6c40fe72019-05-08 14:06:33 -070063 Bubble(Context context, NotificationEntry e) {
64 this (context, e, null);
Mark Renouf71a3af62019-04-08 15:02:54 -040065 }
Mady Mellor3dff9e62019-02-05 18:12:53 -080066
Lyn Han6c40fe72019-05-08 14:06:33 -070067 Bubble(Context context, NotificationEntry e,
68 BubbleExpandedView.OnBubbleBlockedListener listener) {
Mark Renouf85e0a902019-04-05 15:51:51 -040069 entry = e;
70 mKey = e.key;
Mark Renouf9ba6cea2019-04-17 11:53:50 -040071 mLastUpdated = e.notification.getPostTime();
Mark Renouf71a3af62019-04-08 15:02:54 -040072 mGroupId = groupId(e);
Mark Renouf85e0a902019-04-05 15:51:51 -040073 mListener = listener;
Lyn Han6c40fe72019-05-08 14:06:33 -070074
75 mPm = context.getPackageManager();
76 ApplicationInfo info;
77 try {
78 info = mPm.getApplicationInfo(
79 entry.notification.getPackageName(),
80 PackageManager.MATCH_UNINSTALLED_PACKAGES
81 | PackageManager.MATCH_DISABLED_COMPONENTS
82 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
83 | PackageManager.MATCH_DIRECT_BOOT_AWARE);
84 if (info != null) {
85 mAppName = String.valueOf(mPm.getApplicationLabel(info));
86 }
87 } catch (PackageManager.NameNotFoundException unused) {
88 mAppName = entry.notification.getPackageName();
89 }
Mark Renouf85e0a902019-04-05 15:51:51 -040090 }
91
Mark Renouf85e0a902019-04-05 15:51:51 -040092 public String getKey() {
93 return mKey;
94 }
95
Mark Renouf71a3af62019-04-08 15:02:54 -040096 public String getGroupId() {
97 return mGroupId;
98 }
99
100 public String getPackageName() {
101 return entry.notification.getPackageName();
102 }
103
Lyn Han6c40fe72019-05-08 14:06:33 -0700104 public String getAppName() {
105 return mAppName;
106 }
107
Mark Renouf85e0a902019-04-05 15:51:51 -0400108 boolean isInflated() {
109 return mInflated;
110 }
111
Mark Renouf71a3af62019-04-08 15:02:54 -0400112 public void updateDotVisibility() {
113 if (iconView != null) {
Joshua Tsuji6549e702019-05-02 13:13:16 -0400114 iconView.updateDotVisibility(true /* animate */);
Mark Renouf71a3af62019-04-08 15:02:54 -0400115 }
116 }
117
Mark Renouf85e0a902019-04-05 15:51:51 -0400118 void inflate(LayoutInflater inflater, BubbleStackView stackView) {
119 if (mInflated) {
120 return;
121 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800122 iconView = (BubbleView) inflater.inflate(
123 R.layout.bubble_view, stackView, false /* attachToRoot */);
124 iconView.setNotif(entry);
125
126 expandedView = (BubbleExpandedView) inflater.inflate(
127 R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
Lyn Han6c40fe72019-05-08 14:06:33 -0700128 expandedView.setEntry(entry, stackView, mAppName);
Mark Renouf85e0a902019-04-05 15:51:51 -0400129 expandedView.setOnBlockedListener(mListener);
Lyn Han6c40fe72019-05-08 14:06:33 -0700130
Mark Renouf85e0a902019-04-05 15:51:51 -0400131 mInflated = true;
Mady Mellor3dff9e62019-02-05 18:12:53 -0800132 }
133
Issei Suzukicac2a502019-04-16 16:52:50 +0200134 /**
135 * Set visibility of bubble in the expanded state.
136 *
137 * @param visibility {@code true} if the expanded bubble should be visible on the screen.
138 *
139 * Note that this contents visibility doesn't affect visibility at {@link android.view.View},
140 * and setting {@code false} actually means rendering the expanded view in transparent.
141 */
142 void setContentVisibility(boolean visibility) {
143 if (expandedView != null) {
144 expandedView.setContentVisibility(visibility);
145 }
146 }
147
Mark Renouf71a3af62019-04-08 15:02:54 -0400148 void setDismissed() {
149 entry.setBubbleDismissed(true);
150 // TODO: move this somewhere where it can be guaranteed not to run until safe from flicker
151 if (expandedView != null) {
152 expandedView.cleanUpExpandedState();
153 }
154 }
155
Mark Renouf85e0a902019-04-05 15:51:51 -0400156 void setEntry(NotificationEntry entry) {
Mark Renouf71a3af62019-04-08 15:02:54 -0400157 this.entry = entry;
Mark Renouf9ba6cea2019-04-17 11:53:50 -0400158 mLastUpdated = entry.notification.getPostTime();
Mark Renouf85e0a902019-04-05 15:51:51 -0400159 if (mInflated) {
160 iconView.update(entry);
161 expandedView.update(entry);
162 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800163 }
Mark Renouf71a3af62019-04-08 15:02:54 -0400164
Mark Renoufba5ab512019-05-02 15:21:01 -0400165 /**
166 * @return the newer of {@link #getLastUpdateTime()} and {@link #getLastAccessTime()}
167 */
Mark Renouf9ba6cea2019-04-17 11:53:50 -0400168 public long getLastActivity() {
169 return Math.max(mLastUpdated, mLastAccessed);
170 }
171
172 /**
Mark Renoufba5ab512019-05-02 15:21:01 -0400173 * @return the timestamp in milliseconds of the most recent notification entry for this bubble
174 */
175 public long getLastUpdateTime() {
176 return mLastUpdated;
177 }
178
179 /**
180 * @return the timestamp in milliseconds when this bubble was last displayed in expanded state
181 */
182 public long getLastAccessTime() {
183 return mLastAccessed;
184 }
185
186 /**
Issei Suzukicac2a502019-04-16 16:52:50 +0200187 * @return the display id of the virtual display on which bubble contents is drawn.
188 */
189 int getDisplayId() {
190 return expandedView != null ? expandedView.getVirtualDisplayId() : INVALID_DISPLAY;
191 }
192
193 /**
Mark Renouf9ba6cea2019-04-17 11:53:50 -0400194 * Should be invoked whenever a Bubble is accessed (selected while expanded).
195 */
196 void markAsAccessedAt(long lastAccessedMillis) {
197 mLastAccessed = lastAccessedMillis;
198 entry.setShowInShadeWhenBubble(false);
199 }
200
201 /**
202 * @return whether bubble is from a notification associated with a foreground service.
203 */
204 public boolean isOngoing() {
205 return entry.isForegroundService();
206 }
207
208 @Override
209 public String toString() {
210 return "Bubble{" + mKey + '}';
211 }
212
Mark Renouf71a3af62019-04-08 15:02:54 -0400213 @Override
214 public boolean equals(Object o) {
215 if (this == o) return true;
216 if (!(o instanceof Bubble)) return false;
217 Bubble bubble = (Bubble) o;
218 return Objects.equals(mKey, bubble.mKey);
219 }
220
221 @Override
222 public int hashCode() {
223 return Objects.hash(mKey);
224 }
Mady Mellor3dff9e62019-02-05 18:12:53 -0800225}