/*
|
* 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.bubbles;
|
|
|
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
|
import android.content.Context;
|
import android.content.pm.ApplicationInfo;
|
import android.content.pm.PackageManager;
|
import android.os.UserHandle;
|
import android.view.LayoutInflater;
|
|
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.systemui.R;
|
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
|
|
import java.util.Objects;
|
|
/**
|
* Encapsulates the data and UI elements of a bubble.
|
*/
|
class Bubble {
|
|
private static final boolean DEBUG = false;
|
private static final String TAG = "Bubble";
|
|
private final String mKey;
|
private final String mGroupId;
|
private String mAppName;
|
private final BubbleExpandedView.OnBubbleBlockedListener mListener;
|
|
private boolean mInflated;
|
public NotificationEntry entry;
|
BubbleView iconView;
|
BubbleExpandedView expandedView;
|
private long mLastUpdated;
|
private long mLastAccessed;
|
private PackageManager mPm;
|
|
public static String groupId(NotificationEntry entry) {
|
UserHandle user = entry.notification.getUser();
|
return user.getIdentifier() + "|" + entry.notification.getPackageName();
|
}
|
|
/** Used in tests when no UI is required. */
|
@VisibleForTesting(visibility = PRIVATE)
|
Bubble(Context context, NotificationEntry e) {
|
this (context, e, null);
|
}
|
|
Bubble(Context context, NotificationEntry e,
|
BubbleExpandedView.OnBubbleBlockedListener listener) {
|
entry = e;
|
mKey = e.key;
|
mLastUpdated = e.notification.getPostTime();
|
mGroupId = groupId(e);
|
mListener = listener;
|
|
mPm = context.getPackageManager();
|
ApplicationInfo info;
|
try {
|
info = mPm.getApplicationInfo(
|
entry.notification.getPackageName(),
|
PackageManager.MATCH_UNINSTALLED_PACKAGES
|
| PackageManager.MATCH_DISABLED_COMPONENTS
|
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
|
| PackageManager.MATCH_DIRECT_BOOT_AWARE);
|
if (info != null) {
|
mAppName = String.valueOf(mPm.getApplicationLabel(info));
|
}
|
} catch (PackageManager.NameNotFoundException unused) {
|
mAppName = entry.notification.getPackageName();
|
}
|
}
|
|
public String getKey() {
|
return mKey;
|
}
|
|
public String getGroupId() {
|
return mGroupId;
|
}
|
|
public String getPackageName() {
|
return entry.notification.getPackageName();
|
}
|
|
public String getAppName() {
|
return mAppName;
|
}
|
|
boolean isInflated() {
|
return mInflated;
|
}
|
|
public void updateDotVisibility() {
|
if (iconView != null) {
|
iconView.updateDotVisibility(true /* animate */);
|
}
|
}
|
|
void inflate(LayoutInflater inflater, BubbleStackView stackView) {
|
if (mInflated) {
|
return;
|
}
|
iconView = (BubbleView) inflater.inflate(
|
R.layout.bubble_view, stackView, false /* attachToRoot */);
|
iconView.setNotif(entry);
|
|
expandedView = (BubbleExpandedView) inflater.inflate(
|
R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
|
expandedView.setEntry(entry, stackView, mAppName);
|
expandedView.setOnBlockedListener(mListener);
|
|
mInflated = true;
|
}
|
|
void setDismissed() {
|
entry.setBubbleDismissed(true);
|
// TODO: move this somewhere where it can be guaranteed not to run until safe from flicker
|
if (expandedView != null) {
|
expandedView.cleanUpExpandedState();
|
}
|
}
|
|
void setEntry(NotificationEntry entry) {
|
this.entry = entry;
|
mLastUpdated = entry.notification.getPostTime();
|
if (mInflated) {
|
iconView.update(entry);
|
expandedView.update(entry);
|
}
|
}
|
|
/**
|
* @return the newer of {@link #getLastUpdateTime()} and {@link #getLastAccessTime()}
|
*/
|
public long getLastActivity() {
|
return Math.max(mLastUpdated, mLastAccessed);
|
}
|
|
/**
|
* @return the timestamp in milliseconds of the most recent notification entry for this bubble
|
*/
|
public long getLastUpdateTime() {
|
return mLastUpdated;
|
}
|
|
/**
|
* @return the timestamp in milliseconds when this bubble was last displayed in expanded state
|
*/
|
public long getLastAccessTime() {
|
return mLastAccessed;
|
}
|
|
/**
|
* Should be invoked whenever a Bubble is accessed (selected while expanded).
|
*/
|
void markAsAccessedAt(long lastAccessedMillis) {
|
mLastAccessed = lastAccessedMillis;
|
entry.setShowInShadeWhenBubble(false);
|
}
|
|
/**
|
* @return whether bubble is from a notification associated with a foreground service.
|
*/
|
public boolean isOngoing() {
|
return entry.isForegroundService();
|
}
|
|
@Override
|
public String toString() {
|
return "Bubble{" + mKey + '}';
|
}
|
|
@Override
|
public boolean equals(Object o) {
|
if (this == o) return true;
|
if (!(o instanceof Bubble)) return false;
|
Bubble bubble = (Bubble) o;
|
return Objects.equals(mKey, bubble.mKey);
|
}
|
|
@Override
|
public int hashCode() {
|
return Objects.hash(mKey);
|
}
|
}
|