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:
Selim Cinek
2017-04-20 15:16:10 -07:00
parent 885b5f4466
commit 2630dc7ecf
11 changed files with 375 additions and 176 deletions

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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));
}
}

View File

@@ -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;

View File

@@ -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.");
}
}
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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());

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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();