Moved notification builder creation to the background
In preparation of future colorization work, the creation of the notification builder is moved to the background. Test: manual, add notifications, update them etc. Test: runtest systemui Bug: 36561228 Merged-In: Iaec5febf4d8d9da348d77e0d4f6f61b9746fae16 Change-Id: Iaec5febf4d8d9da348d77e0d4f6f61b9746fae16
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
|
||||
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -47,6 +47,7 @@ import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.util.NotificationColorUtil;
|
||||
@@ -61,7 +62,6 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
|
||||
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
|
||||
import com.android.systemui.statusbar.NotificationGuts.GutsContent;
|
||||
import com.android.systemui.statusbar.notification.HybridNotificationView;
|
||||
import com.android.systemui.statusbar.notification.InflationException;
|
||||
import com.android.systemui.statusbar.notification.NotificationInflater;
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
import com.android.systemui.statusbar.notification.VisualStabilityManager;
|
||||
@@ -314,14 +314,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
}
|
||||
}
|
||||
|
||||
public void updateNotification(NotificationData.Entry entry) throws InflationException {
|
||||
public void updateNotification(NotificationData.Entry entry) {
|
||||
mEntry = entry;
|
||||
mStatusBarNotification = entry.notification;
|
||||
mNotificationInflater.inflateNotificationViews();
|
||||
onNotificationUpdated();
|
||||
}
|
||||
|
||||
private void onNotificationUpdated() {
|
||||
public void onNotificationUpdated() {
|
||||
for (NotificationContentView l : mLayouts) {
|
||||
l.onNotificationUpdated(mEntry);
|
||||
}
|
||||
@@ -482,9 +481,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
boolean childInGroup = StatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
|
||||
mNotificationParent = childInGroup ? parent : null;
|
||||
mPrivateLayout.setIsChildInGroup(childInGroup);
|
||||
if (mNotificationInflater.setIsChildInGroup(childInGroup)) {
|
||||
onNotificationUpdated();
|
||||
}
|
||||
mNotificationInflater.setIsChildInGroup(childInGroup);
|
||||
resetBackgroundAlpha();
|
||||
updateBackgroundForGroupState();
|
||||
updateClickAndFocus();
|
||||
@@ -1111,14 +1108,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
mNotificationInflater.setRemoteViewClickHandler(remoteViewClickHandler);
|
||||
}
|
||||
|
||||
public void setInflateExceptionHandler(InflationExceptionHandler inflateExceptionHandler) {
|
||||
mNotificationInflater.setInflateExceptionHandler(inflateExceptionHandler);
|
||||
public void setInflationCallback(InflationCallback callback) {
|
||||
mNotificationInflater.setInflationCallback(callback);
|
||||
}
|
||||
|
||||
public void setNeedsRedaction(boolean needsRedaction) {
|
||||
mNotificationInflater.setRedactAmbient(needsRedaction);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public NotificationInflater getNotificationInflater() {
|
||||
return mNotificationInflater;
|
||||
}
|
||||
|
||||
public interface ExpansionLogger {
|
||||
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
@@ -32,6 +33,7 @@ import android.service.notification.NotificationListenerService.RankingMap;
|
||||
import android.service.notification.SnoozeCriterion;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RemoteViews;
|
||||
@@ -41,6 +43,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.util.NotificationColorUtil;
|
||||
import com.android.systemui.statusbar.notification.InflationException;
|
||||
import com.android.systemui.statusbar.notification.NotificationInflater;
|
||||
import com.android.systemui.statusbar.phone.NotificationGroupManager;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||
@@ -83,6 +86,7 @@ public class NotificationData {
|
||||
public List<SnoozeCriterion> snoozeCriteria;
|
||||
private int mCachedContrastColor = COLOR_INVALID;
|
||||
private int mCachedContrastColorIsFor = COLOR_INVALID;
|
||||
private ArraySet<AsyncTask> mRunningTasks = new ArraySet();
|
||||
|
||||
public Entry(StatusBarNotification n) {
|
||||
this.key = n.getKey();
|
||||
@@ -210,6 +214,19 @@ public class NotificationData {
|
||||
mCachedContrastColor = contrasted;
|
||||
return mCachedContrastColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort all existing inflation tasks
|
||||
*/
|
||||
public void abortInflation() {
|
||||
for (AsyncTask task : mRunningTasks) {
|
||||
task.cancel(true /* mayInterruptIfRunning */);
|
||||
}
|
||||
}
|
||||
|
||||
public void addInflationTask(AsyncTask asyncInflationTask) {
|
||||
mRunningTasks.add(asyncInflationTask);
|
||||
}
|
||||
}
|
||||
|
||||
private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
|
||||
@@ -302,12 +319,12 @@ public class NotificationData {
|
||||
return mEntries.get(key);
|
||||
}
|
||||
|
||||
public void add(Entry entry, RankingMap ranking) {
|
||||
public void add(Entry entry) {
|
||||
synchronized (mEntries) {
|
||||
mEntries.put(entry.notification.getKey(), entry);
|
||||
}
|
||||
mGroupManager.onEntryAdded(entry);
|
||||
updateRankingAndSort(ranking);
|
||||
filterAndSort();
|
||||
}
|
||||
|
||||
public Entry remove(String key, RankingMap ranking) {
|
||||
|
||||
@@ -18,11 +18,10 @@ package com.android.systemui.statusbar.notification;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -39,7 +38,8 @@ public class NotificationInflater {
|
||||
@VisibleForTesting
|
||||
static final int FLAG_REINFLATE_ALL = ~0;
|
||||
private static final int FLAG_REINFLATE_CONTENT_VIEW = 1<<0;
|
||||
private static final int FLAG_REINFLATE_EXPANDED_VIEW = 1<<1;
|
||||
@VisibleForTesting
|
||||
static final int FLAG_REINFLATE_EXPANDED_VIEW = 1<<1;
|
||||
private static final int FLAG_REINFLATE_HEADS_UP_VIEW = 1<<2;
|
||||
private static final int FLAG_REINFLATE_PUBLIC_VIEW = 1<<3;
|
||||
private static final int FLAG_REINFLATE_AMBIENT_VIEW = 1<<4;
|
||||
@@ -50,7 +50,7 @@ public class NotificationInflater {
|
||||
private boolean mUsesIncreasedHeadsUpHeight;
|
||||
private RemoteViews.OnClickHandler mRemoteViewClickHandler;
|
||||
private boolean mIsChildInGroup;
|
||||
private InflationExceptionHandler mInflateExceptionHandler;
|
||||
private InflationCallback mCallback;
|
||||
private boolean mRedactAmbient;
|
||||
|
||||
public NotificationInflater(ExpandableNotificationRow row) {
|
||||
@@ -66,21 +66,14 @@ public class NotificationInflater {
|
||||
*
|
||||
* @return whether the view was re-inflated
|
||||
*/
|
||||
public boolean setIsChildInGroup(boolean childInGroup) {
|
||||
public void setIsChildInGroup(boolean childInGroup) {
|
||||
if (childInGroup != mIsChildInGroup) {
|
||||
mIsChildInGroup = childInGroup;
|
||||
if (mIsLowPriority) {
|
||||
try {
|
||||
int flags = FLAG_REINFLATE_CONTENT_VIEW | FLAG_REINFLATE_EXPANDED_VIEW;
|
||||
inflateNotificationViews(flags);
|
||||
} catch (InflationException e) {
|
||||
mInflateExceptionHandler.handleInflationException(
|
||||
mRow.getStatusBarNotification(), e);
|
||||
}
|
||||
int flags = FLAG_REINFLATE_CONTENT_VIEW | FLAG_REINFLATE_EXPANDED_VIEW;
|
||||
inflateNotificationViews(flags);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} ;
|
||||
}
|
||||
|
||||
public void setUsesIncreasedHeight(boolean usesIncreasedHeight) {
|
||||
@@ -101,39 +94,29 @@ public class NotificationInflater {
|
||||
if (mRow.getEntry() == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
inflateNotificationViews(FLAG_REINFLATE_AMBIENT_VIEW);
|
||||
} catch (InflationException e) {
|
||||
mInflateExceptionHandler.handleInflationException(
|
||||
mRow.getStatusBarNotification(), e);
|
||||
}
|
||||
inflateNotificationViews(FLAG_REINFLATE_AMBIENT_VIEW);
|
||||
}
|
||||
}
|
||||
|
||||
public void inflateNotificationViews() throws InflationException {
|
||||
/**
|
||||
* Inflate all views of this notification on a background thread. This is asynchronous and will
|
||||
* notify the callback once it's finished.
|
||||
*/
|
||||
public void inflateNotificationViews() {
|
||||
inflateNotificationViews(FLAG_REINFLATE_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* reinflate all views for the specified flags
|
||||
* Reinflate all views for the specified flags on a background thread. This is asynchronous and
|
||||
* will notify the callback once it's finished.
|
||||
*
|
||||
* @param reInflateFlags flags which views should be reinflated. Use {@link #FLAG_REINFLATE_ALL}
|
||||
* to reinflate all of views.
|
||||
* @throws InflationException
|
||||
*/
|
||||
private void inflateNotificationViews(int reInflateFlags)
|
||||
throws InflationException {
|
||||
@VisibleForTesting
|
||||
void inflateNotificationViews(int reInflateFlags) {
|
||||
StatusBarNotification sbn = mRow.getEntry().notification;
|
||||
try {
|
||||
final Notification.Builder recoveredBuilder
|
||||
= Notification.Builder.recoverBuilder(mRow.getContext(), sbn.getNotification());
|
||||
Context packageContext = sbn.getPackageContext(mRow.getContext());
|
||||
inflateNotificationViews(reInflateFlags, recoveredBuilder, packageContext);
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
|
||||
Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
|
||||
throw new InflationException("Couldn't inflate contentViews");
|
||||
}
|
||||
new AsyncInflationTask(mRow.getContext(), sbn, reInflateFlags).execute();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -284,12 +267,13 @@ public class NotificationInflater {
|
||||
&& a.getLayoutId() == b.getLayoutId());
|
||||
}
|
||||
|
||||
public void setInflateExceptionHandler(InflationExceptionHandler inflateExceptionHandler) {
|
||||
mInflateExceptionHandler = inflateExceptionHandler;
|
||||
public void setInflationCallback(InflationCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
public interface InflationExceptionHandler {
|
||||
public interface InflationCallback {
|
||||
void handleInflationException(StatusBarNotification notification, InflationException e);
|
||||
void onAsyncInflationFinished(NotificationData.Entry entry);
|
||||
}
|
||||
|
||||
public void onDensityOrFontScaleChanged() {
|
||||
@@ -299,12 +283,67 @@ public class NotificationInflater {
|
||||
entry.cachedContentView = null;
|
||||
entry.cachedHeadsUpContentView = null;
|
||||
entry.cachedPublicContentView = null;
|
||||
try {
|
||||
inflateNotificationViews();
|
||||
} catch (InflationException e) {
|
||||
mInflateExceptionHandler.handleInflationException(
|
||||
mRow.getStatusBarNotification(), e);
|
||||
inflateNotificationViews();
|
||||
}
|
||||
|
||||
private class AsyncInflationTask extends AsyncTask<Void, Void, Notification.Builder> {
|
||||
|
||||
private final StatusBarNotification mSbn;
|
||||
private final Context mContext;
|
||||
private final int mReInflateFlags;
|
||||
private Context mPackageContext = null;
|
||||
private Exception mError;
|
||||
|
||||
private AsyncInflationTask(Context context, StatusBarNotification notification,
|
||||
int reInflateFlags) {
|
||||
mSbn = notification;
|
||||
mContext = context;
|
||||
mReInflateFlags = reInflateFlags;
|
||||
mRow.getEntry().addInflationTask(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Notification.Builder doInBackground(Void... params) {
|
||||
try {
|
||||
final Notification.Builder recoveredBuilder
|
||||
= Notification.Builder.recoverBuilder(mContext,
|
||||
mSbn.getNotification());
|
||||
mPackageContext = mSbn.getPackageContext(mContext);
|
||||
return recoveredBuilder;
|
||||
} catch (Exception e) {
|
||||
mError = e;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Notification.Builder builder) {
|
||||
if (mError == null) {
|
||||
finishInflation(mReInflateFlags, builder, mPackageContext);
|
||||
} else {
|
||||
handleError(mError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void finishInflation(int reinflationFlags, Notification.Builder builder,
|
||||
Context context) {
|
||||
try {
|
||||
inflateNotificationViews(reinflationFlags, builder, context);
|
||||
} catch (RuntimeException e){
|
||||
handleError(e);
|
||||
return;
|
||||
}
|
||||
mRow.onNotificationUpdated();
|
||||
mCallback.onAsyncInflationFinished(mRow.getEntry());
|
||||
}
|
||||
|
||||
private void handleError(Exception e) {
|
||||
StatusBarNotification sbn = mRow.getStatusBarNotification();
|
||||
final String ident = sbn.getPackageName() + "/0x"
|
||||
+ Integer.toHexString(sbn.getId());
|
||||
Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
|
||||
mCallback.handleInflationException(sbn,
|
||||
new InflationException("Couldn't inflate contentViews" + e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
|
||||
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
|
||||
import static android.app.StatusBarManager.windowStateToString;
|
||||
|
||||
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationExceptionHandler;
|
||||
import static com.android.systemui.statusbar.notification.NotificationInflater.InflationCallback;
|
||||
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
|
||||
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
|
||||
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
|
||||
@@ -257,7 +257,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
OnHeadsUpChangedListener, VisualStabilityManager.Callback, CommandQueue.Callbacks,
|
||||
ActivatableNotificationView.OnActivatedListener,
|
||||
ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
|
||||
ExpandableNotificationRow.OnExpandClickListener {
|
||||
ExpandableNotificationRow.OnExpandClickListener, InflationCallback {
|
||||
public static final boolean MULTIUSER_DEBUG = false;
|
||||
|
||||
public static final boolean ENABLE_REMOTE_INPUT =
|
||||
@@ -713,8 +713,8 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
|
||||
private NotificationIconAreaController mNotificationIconAreaController;
|
||||
private ConfigurationListener mConfigurationListener;
|
||||
private InflationExceptionHandler mInflationExceptionHandler = this::handleInflationException;
|
||||
private boolean mReinflateNotificationsOnUserSwitched;
|
||||
private HashMap<String, Entry> mPendingNotifications = new HashMap<>();
|
||||
|
||||
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
|
||||
final int N = array.size();
|
||||
@@ -1544,29 +1544,24 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
return new UserHandle(mCurrentUserId);
|
||||
}
|
||||
|
||||
public void addNotification(StatusBarNotification notification, RankingMap ranking,
|
||||
Entry oldEntry) throws InflationException {
|
||||
if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
|
||||
public void addNotification(StatusBarNotification notification, RankingMap ranking)
|
||||
throws InflationException {
|
||||
String key = notification.getKey();
|
||||
if (DEBUG) Log.d(TAG, "addNotification key=" + key);
|
||||
|
||||
mNotificationData.updateRanking(ranking);
|
||||
Entry shadeEntry = createNotificationViews(notification);
|
||||
boolean isHeadsUped = shouldPeek(shadeEntry);
|
||||
if (isHeadsUped) {
|
||||
mHeadsUpManager.showNotification(shadeEntry);
|
||||
// Mark as seen immediately
|
||||
setNotificationShown(notification);
|
||||
}
|
||||
|
||||
if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
|
||||
if (shouldSuppressFullScreenIntent(notification.getKey())) {
|
||||
if (shouldSuppressFullScreenIntent(key)) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
|
||||
Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + key);
|
||||
}
|
||||
} else if (mNotificationData.getImportance(notification.getKey())
|
||||
} else if (mNotificationData.getImportance(key)
|
||||
< NotificationManager.IMPORTANCE_HIGH) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "No Fullscreen intent: not important enough: "
|
||||
+ notification.getKey());
|
||||
+ key);
|
||||
}
|
||||
} else {
|
||||
// Stop screensaver if the notification has a full-screen intent.
|
||||
@@ -1578,7 +1573,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
|
||||
try {
|
||||
EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
|
||||
notification.getKey());
|
||||
key);
|
||||
notification.getNotification().fullScreenIntent.send();
|
||||
shadeEntry.notifyFullScreenIntentLaunched();
|
||||
mMetricsLogger.count("note_fullscreen", 1);
|
||||
@@ -1586,15 +1581,47 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
}
|
||||
}
|
||||
}
|
||||
addNotificationViews(shadeEntry, ranking);
|
||||
abortExistingInflation(key);
|
||||
mPendingNotifications.put(key, shadeEntry);
|
||||
}
|
||||
|
||||
private void abortExistingInflation(String key) {
|
||||
if (mPendingNotifications.containsKey(key)) {
|
||||
Entry entry = mPendingNotifications.get(key);
|
||||
entry.abortInflation();
|
||||
mPendingNotifications.remove(key);
|
||||
}
|
||||
Entry addedEntry = mNotificationData.get(key);
|
||||
if (addedEntry != null) {
|
||||
addedEntry.abortInflation();
|
||||
}
|
||||
}
|
||||
|
||||
private void addEntry(Entry shadeEntry) {
|
||||
boolean isHeadsUped = shouldPeek(shadeEntry);
|
||||
if (isHeadsUped) {
|
||||
mHeadsUpManager.showNotification(shadeEntry);
|
||||
// Mark as seen immediately
|
||||
setNotificationShown(shadeEntry.notification);
|
||||
}
|
||||
addNotificationViews(shadeEntry);
|
||||
// Recalculate the position of the sliding windows and the titles.
|
||||
setAreThereNotifications();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInflationException(StatusBarNotification notification, InflationException e) {
|
||||
handleNotificationError(notification, e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAsyncInflationFinished(Entry entry) {
|
||||
mPendingNotifications.remove(entry.key);
|
||||
if (mNotificationData.get(entry.key) == null) {
|
||||
addEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldSuppressFullScreenIntent(String key) {
|
||||
if (isDeviceInVrMode()) {
|
||||
return true;
|
||||
@@ -1614,6 +1641,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
|
||||
public void removeNotification(String key, RankingMap ranking) {
|
||||
boolean deferRemoval = false;
|
||||
abortExistingInflation(key);
|
||||
if (mHeadsUpManager.isHeadsUp(key)) {
|
||||
// A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
|
||||
// sending look longer than it takes.
|
||||
@@ -3295,6 +3323,14 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
+ " scroll " + mStackScroller.getScrollX()
|
||||
+ "," + mStackScroller.getScrollY());
|
||||
}
|
||||
pw.print(" mPendingNotifications=");
|
||||
if (mPendingNotifications.size() == 0) {
|
||||
pw.println("null");
|
||||
} else {
|
||||
for (Entry entry : mPendingNotifications.values()) {
|
||||
pw.println(entry.notification);
|
||||
}
|
||||
}
|
||||
|
||||
pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
|
||||
pw.print(" mStatusBarWindowState=");
|
||||
@@ -5531,7 +5567,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
public void run() {
|
||||
for (StatusBarNotification sbn : notifications) {
|
||||
try {
|
||||
addNotification(sbn, currentRanking, null /* oldEntry */);
|
||||
addNotification(sbn, currentRanking);
|
||||
} catch (InflationException e) {
|
||||
handleInflationException(sbn, e);
|
||||
}
|
||||
@@ -5574,7 +5610,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
if (isUpdate) {
|
||||
updateNotification(sbn, rankingMap);
|
||||
} else {
|
||||
addNotification(sbn, rankingMap, null /* oldEntry */);
|
||||
addNotification(sbn, rankingMap);
|
||||
}
|
||||
} catch (InflationException e) {
|
||||
handleInflationException(sbn, e);
|
||||
@@ -6132,8 +6168,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
}
|
||||
}
|
||||
|
||||
protected void inflateViews(Entry entry, ViewGroup parent) throws
|
||||
InflationException {
|
||||
protected void inflateViews(Entry entry, ViewGroup parent) {
|
||||
PackageManager pmUser = getPackageManagerForUser(mContext,
|
||||
entry.notification.getUser().getIdentifier());
|
||||
|
||||
@@ -6154,7 +6189,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
row.setRemoteInputController(mRemoteInputController);
|
||||
row.setOnExpandClickListener(this);
|
||||
row.setRemoteViewClickHandler(mOnClickHandler);
|
||||
row.setInflateExceptionHandler(mInflationExceptionHandler);
|
||||
row.setInflationCallback(this);
|
||||
|
||||
// Get the app name.
|
||||
// Note that Notification.Builder#bindHeaderAppName has similar logic
|
||||
@@ -6552,12 +6587,12 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
return entry;
|
||||
}
|
||||
|
||||
protected void addNotificationViews(Entry entry, RankingMap ranking) {
|
||||
protected void addNotificationViews(Entry entry) {
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
// Add the expanded view and icon.
|
||||
mNotificationData.add(entry, ranking);
|
||||
mNotificationData.add(entry);
|
||||
updateNotifications();
|
||||
}
|
||||
|
||||
@@ -6675,6 +6710,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
|
||||
|
||||
final String key = notification.getKey();
|
||||
abortExistingInflation(key);
|
||||
Entry entry = mNotificationData.get(key);
|
||||
if (entry == null) {
|
||||
return;
|
||||
|
||||
@@ -28,4 +28,10 @@ public class Assert {
|
||||
throw new IllegalStateException("should be called from the main thread.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void isNotMainThread() {
|
||||
if (Looper.getMainLooper().isCurrentThread()) {
|
||||
throw new IllegalStateException("should not be called from the main thread.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +43,13 @@ public class ExpandHelperTest extends SysuiTestCase {
|
||||
private ExpandHelper.Callback mCallback;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
public void setUp() throws Exception {
|
||||
Context context = getContext();
|
||||
mRow = new NotificationTestHelper(context).createRow();
|
||||
mCallback = mock(ExpandHelper.Callback.class);
|
||||
mExpandHelper = new ExpandHelper(context, mCallback, 10, 100);
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(
|
||||
() -> mExpandHelper = new ExpandHelper(context, mCallback, 10, 100));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -39,8 +39,7 @@ public class ExpandableNotificationRowTest {
|
||||
private NotificationTestHelper mNotificationTestHelper;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mNotificationTestHelper = new NotificationTestHelper(mContext);
|
||||
mGroup = mNotificationTestHelper.createGroup();
|
||||
|
||||
@@ -17,15 +17,18 @@
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.notification.InflationException;
|
||||
import com.android.systemui.statusbar.notification.NotificationInflaterTest;
|
||||
import com.android.systemui.statusbar.phone.NotificationGroupManager;
|
||||
|
||||
/**
|
||||
@@ -34,14 +37,18 @@ import com.android.systemui.statusbar.phone.NotificationGroupManager;
|
||||
public class NotificationTestHelper {
|
||||
|
||||
private final Context mContext;
|
||||
private final Instrumentation mInstrumentation;
|
||||
private int mId;
|
||||
private final NotificationGroupManager mGroupManager = new NotificationGroupManager();
|
||||
private ExpandableNotificationRow mRow;
|
||||
private InflationException mException;
|
||||
|
||||
public NotificationTestHelper(Context context) {
|
||||
mContext = context;
|
||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
}
|
||||
|
||||
public ExpandableNotificationRow createRow() {
|
||||
public ExpandableNotificationRow createRow() throws Exception {
|
||||
Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
|
||||
R.drawable.ic_person)
|
||||
.setCustomContentView(new RemoteViews(mContext.getPackageName(),
|
||||
@@ -56,12 +63,15 @@ public class NotificationTestHelper {
|
||||
return createRow(notification);
|
||||
}
|
||||
|
||||
public ExpandableNotificationRow createRow(Notification notification) {
|
||||
public ExpandableNotificationRow createRow(Notification notification) throws Exception {
|
||||
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
|
||||
mContext.LAYOUT_INFLATER_SERVICE);
|
||||
ExpandableNotificationRow row = (ExpandableNotificationRow) inflater.inflate(
|
||||
R.layout.status_bar_notification_row,
|
||||
null, false);
|
||||
mInstrumentation.runOnMainSync(() -> {
|
||||
mRow = (ExpandableNotificationRow) inflater.inflate(
|
||||
R.layout.status_bar_notification_row,
|
||||
null, false);
|
||||
});
|
||||
ExpandableNotificationRow row = mRow;
|
||||
row.setGroupManager(mGroupManager);
|
||||
UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
|
||||
StatusBarNotification sbn = new StatusBarNotification("com.android.systemui",
|
||||
@@ -69,16 +79,13 @@ public class NotificationTestHelper {
|
||||
2000, notification, mUser, null, System.currentTimeMillis());
|
||||
NotificationData.Entry entry = new NotificationData.Entry(sbn);
|
||||
entry.row = row;
|
||||
try {
|
||||
entry.createIcons(mContext, sbn);
|
||||
row.updateNotification(entry);
|
||||
} catch (InflationException e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
entry.createIcons(mContext, sbn);
|
||||
NotificationInflaterTest.runThenWaitForInflation(() -> row.updateNotification(entry),
|
||||
row.getNotificationInflater());
|
||||
return row;
|
||||
}
|
||||
|
||||
public ExpandableNotificationRow createGroup() {
|
||||
public ExpandableNotificationRow createGroup() throws Exception {
|
||||
ExpandableNotificationRow row = createRow();
|
||||
row.addChildNotification(createRow());
|
||||
row.addChildNotification(createRow());
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.NotificationInflater.FLAG_REINFLATE_ALL;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.NotificationData;
|
||||
import com.android.systemui.statusbar.NotificationTestHelper;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.function.Function;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NotificationInflaterTest {
|
||||
|
||||
private Context mContext;
|
||||
private NotificationInflater mNotificationInflater;
|
||||
private Notification.Builder mBuilder;
|
||||
private ExpandableNotificationRow mRow;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mBuilder = new Notification.Builder(mContext).setSmallIcon(
|
||||
R.drawable.ic_person)
|
||||
.setContentTitle("Title")
|
||||
.setContentText("Text")
|
||||
.setStyle(new Notification.BigTextStyle().bigText("big text"));
|
||||
ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow(
|
||||
mBuilder.build());
|
||||
mRow = spy(row);
|
||||
mNotificationInflater = new NotificationInflater(mRow);
|
||||
mNotificationInflater.setInflationCallback(new NotificationInflater.InflationCallback() {
|
||||
@Override
|
||||
public void handleInflationException(StatusBarNotification notification,
|
||||
InflationException e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAsyncInflationFinished(NotificationData.Entry entry) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncreasedHeadsUpBeingUsed() {
|
||||
mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
|
||||
Notification.Builder builder = spy(mBuilder);
|
||||
mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
|
||||
verify(builder).createHeadsUpContentView(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncreasedHeightBeingUsed() {
|
||||
mNotificationInflater.setUsesIncreasedHeight(true);
|
||||
Notification.Builder builder = spy(mBuilder);
|
||||
mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
|
||||
verify(builder).createContentView(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInflationCallsUpdated() throws Exception {
|
||||
runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
|
||||
mNotificationInflater);
|
||||
verify(mRow).onNotificationUpdated();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInflationCallsOnlyRightMethod() throws Exception {
|
||||
mRow.getPrivateLayout().removeAllViews();
|
||||
mRow.getEntry().cachedBigContentView = null;
|
||||
runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(
|
||||
NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW), mNotificationInflater);
|
||||
Assert.assertTrue(mRow.getPrivateLayout().getChildCount() == 1);
|
||||
Assert.assertTrue(mRow.getPrivateLayout().getChildAt(0)
|
||||
== mRow.getPrivateLayout().getExpandedChild());
|
||||
verify(mRow).onNotificationUpdated();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInflationThrowsErrorDoesntCallUpdated() throws Exception {
|
||||
mRow.getPrivateLayout().removeAllViews();
|
||||
mRow.getStatusBarNotification().getNotification().contentView
|
||||
= new RemoteViews(mContext.getPackageName(), R.layout.status_bar);;
|
||||
runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
|
||||
true /* expectingException */, mNotificationInflater);
|
||||
Assert.assertTrue(mRow.getPrivateLayout().getChildCount() == 0);
|
||||
verify(mRow, times(0)).onNotificationUpdated();
|
||||
}
|
||||
|
||||
public static void runThenWaitForInflation(Runnable block,
|
||||
NotificationInflater inflater) throws Exception {
|
||||
runThenWaitForInflation(block, false /* expectingException */, inflater);
|
||||
}
|
||||
|
||||
private static void runThenWaitForInflation(Runnable block, boolean expectingException,
|
||||
NotificationInflater inflater) throws Exception {
|
||||
com.android.systemui.util.Assert.isNotMainThread();
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
final ExceptionHolder exceptionHolder = new ExceptionHolder();
|
||||
inflater.setInflationCallback(new NotificationInflater.InflationCallback() {
|
||||
@Override
|
||||
public void handleInflationException(StatusBarNotification notification,
|
||||
InflationException e) {
|
||||
if (!expectingException) {
|
||||
exceptionHolder.setException(e);
|
||||
}
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAsyncInflationFinished(NotificationData.Entry entry) {
|
||||
if (expectingException) {
|
||||
exceptionHolder.setException(new RuntimeException(
|
||||
"Inflation finished even though there should be an error"));
|
||||
}
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
});
|
||||
block.run();
|
||||
countDownLatch.await(5, java.util.concurrent.TimeUnit.SECONDS);
|
||||
if (exceptionHolder.mException != null) {
|
||||
throw exceptionHolder.mException;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExceptionHolder {
|
||||
private Exception mException;
|
||||
|
||||
public void setException(Exception exception) {
|
||||
mException = exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.NotificationInflater.FLAG_REINFLATE_ALL;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.annotation.UiThreadTest;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.NotificationTestHelper;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NotificationinflaterTest {
|
||||
|
||||
private Context mContext;
|
||||
private NotificationInflater mNotificationInflater;
|
||||
private Notification.Builder mBuilder;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mBuilder = new Notification.Builder(mContext).setSmallIcon(
|
||||
R.drawable.ic_person)
|
||||
.setContentTitle("Title")
|
||||
.setContentText("Text");
|
||||
ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow(
|
||||
mBuilder.build());
|
||||
mNotificationInflater = new NotificationInflater(row);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncreasedHeadsUpBeingUsed() {
|
||||
mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
|
||||
Notification.Builder builder = spy(mBuilder);
|
||||
mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
|
||||
verify(builder).createHeadsUpContentView(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncreasedHeightBeingUsed() {
|
||||
mNotificationInflater.setUsesIncreasedHeight(true);
|
||||
Notification.Builder builder = spy(mBuilder);
|
||||
mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
|
||||
verify(builder).createContentView(true);
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,7 @@ public class NotificationChildrenContainerTest {
|
||||
private NotificationTestHelper mNotificationTestHelper;
|
||||
|
||||
@Before
|
||||
@UiThreadTest
|
||||
public void setUp() {
|
||||
public void setUp() throws Exception {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mNotificationTestHelper = new NotificationTestHelper(mContext);
|
||||
mGroup = mNotificationTestHelper.createGroup();
|
||||
|
||||
Reference in New Issue
Block a user