Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt +106 −171 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.CancellationSignal import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper.RunWithLooper import android.util.TypedValue import android.util.TypedValue.COMPLEX_UNIT_SP import android.view.View import android.view.ViewGroup import android.widget.RemoteViews Loading @@ -34,6 +35,10 @@ import com.android.systemui.res.R import com.android.systemui.statusbar.notification.ConversationNotificationProcessor import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag import com.android.systemui.statusbar.notification.row.shared.HeadsUpStatusBarModel Loading @@ -43,7 +48,6 @@ import com.android.systemui.statusbar.notification.row.shared.NotificationRowCon import com.android.systemui.statusbar.policy.InflatedSmartReplyState import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder import com.android.systemui.statusbar.policy.SmartReplyStateInflater import com.android.systemui.util.concurrency.mockExecutorHandler import java.util.concurrent.CountDownLatch import java.util.concurrent.Executor import java.util.concurrent.TimeUnit Loading @@ -65,20 +69,24 @@ import org.mockito.kotlin.whenever @RunWithLooper @EnableFlags(NotificationRowContentBinderRefactor.FLAG_NAME) class NotificationRowContentBinderImplTest : SysuiTestCase() { private lateinit var mNotificationInflater: NotificationRowContentBinderImpl private lateinit var mBuilder: Notification.Builder private lateinit var mRow: ExpandableNotificationRow private lateinit var mHelper: NotificationTestHelper private var mCache: NotifRemoteViewCache = mock() private var mConversationNotificationProcessor: ConversationNotificationProcessor = mock() private var mInflatedSmartReplyState: InflatedSmartReplyState = mock() private var mInflatedSmartReplies: InflatedSmartReplyViewHolder = mock() private var mNotifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider = mock() private var mHeadsUpStyleProvider: HeadsUpStyleProvider = mock() private var mNotifLayoutInflaterFactory: NotifLayoutInflaterFactory = mock() private val mSmartReplyStateInflater: SmartReplyStateInflater = private lateinit var notificationInflater: NotificationRowContentBinderImpl private lateinit var builder: Notification.Builder private lateinit var row: ExpandableNotificationRow private lateinit var testHelper: NotificationTestHelper private val cache: NotifRemoteViewCache = mock() private val layoutInflaterFactoryProvider = object : NotifLayoutInflaterFactory.Provider { override fun provide( row: ExpandableNotificationRow, layoutType: Int ): NotifLayoutInflaterFactory = mock() } private val smartReplyStateInflater: SmartReplyStateInflater = object : SmartReplyStateInflater { private val inflatedSmartReplyState: InflatedSmartReplyState = mock() private val inflatedSmartReplies: InflatedSmartReplyViewHolder = mock() override fun inflateSmartReplyViewHolder( sysuiContext: Context, notifPackageContext: Context, Loading @@ -86,37 +94,34 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { existingSmartReplyState: InflatedSmartReplyState?, newSmartReplyState: InflatedSmartReplyState ): InflatedSmartReplyViewHolder { return mInflatedSmartReplies return inflatedSmartReplies } override fun inflateSmartReplyState(entry: NotificationEntry): InflatedSmartReplyState { return mInflatedSmartReplyState return inflatedSmartReplyState } } @Before fun setUp() { allowTestableLooperAsMainThread() mBuilder = builder = Notification.Builder(mContext, "no-id") .setSmallIcon(R.drawable.ic_person) .setContentTitle("Title") .setContentText("Text") .setStyle(Notification.BigTextStyle().bigText("big text")) mHelper = NotificationTestHelper(mContext, mDependency) val row = mHelper.createRow(mBuilder.build()) mRow = spy(row) whenever(mNotifLayoutInflaterFactoryProvider.provide(any(), any())) .thenReturn(mNotifLayoutInflaterFactory) mNotificationInflater = testHelper = NotificationTestHelper(mContext, mDependency) row = spy(testHelper.createRow(builder.build())) notificationInflater = NotificationRowContentBinderImpl( mCache, cache, mock(), mConversationNotificationProcessor, mock<ConversationNotificationProcessor>(), mock(), mSmartReplyStateInflater, mNotifLayoutInflaterFactoryProvider, mHeadsUpStyleProvider, smartReplyStateInflater, layoutInflaterFactoryProvider, mock<HeadsUpStyleProvider>(), mock() ) } Loading @@ -125,16 +130,16 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { fun testIncreasedHeadsUpBeingUsed() { val params = BindParams() params.usesIncreasedHeadsUpHeight = true val builder = spy(mBuilder) mNotificationInflater.inflateNotificationViews( mRow.entry, mRow, val builder = spy(builder) notificationInflater.inflateNotificationViews( row.entry, row, params, true /* inflateSynchronously */, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, FLAG_CONTENT_VIEW_ALL, builder, mContext, mSmartReplyStateInflater smartReplyStateInflater ) verify(builder).createHeadsUpContentView(true) } Loading @@ -143,80 +148,68 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { fun testIncreasedHeightBeingUsed() { val params = BindParams() params.usesIncreasedHeight = true val builder = spy(mBuilder) mNotificationInflater.inflateNotificationViews( mRow.entry, mRow, val builder = spy(builder) notificationInflater.inflateNotificationViews( row.entry, row, params, true /* inflateSynchronously */, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, FLAG_CONTENT_VIEW_ALL, builder, mContext, mSmartReplyStateInflater smartReplyStateInflater ) verify(builder).createContentView(true) } @Test fun testInflationCallsUpdated() { inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, mRow ) verify(mRow).onNotificationUpdated() inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) verify(row).onNotificationUpdated() } @Test fun testInflationOnlyInflatesSetFlags() { inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP, mRow ) Assert.assertNotNull(mRow.privateLayout.headsUpChild) verify(mRow).onNotificationUpdated() inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_HEADS_UP, row) Assert.assertNotNull(row.privateLayout.headsUpChild) verify(row).onNotificationUpdated() } @Test fun testInflationThrowsErrorDoesntCallUpdated() { mRow.privateLayout.removeAllViews() mRow.entry.sbn.notification.contentView = row.privateLayout.removeAllViews() row.entry.sbn.notification.contentView = RemoteViews(mContext.packageName, R.layout.status_bar) inflateAndWait( true /* expectingException */, mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, mRow notificationInflater, FLAG_CONTENT_VIEW_ALL, row ) Assert.assertTrue(mRow.privateLayout.childCount == 0) verify(mRow, times(0)).onNotificationUpdated() Assert.assertTrue(row.privateLayout.childCount == 0) verify(row, times(0)).onNotificationUpdated() } @Test fun testAsyncTaskRemoved() { mRow.entry.abortTask() inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, mRow ) verify(mRow).onNotificationUpdated() row.entry.abortTask() inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) verify(row).onNotificationUpdated() } @Test fun testRemovedNotInflated() { mRow.setRemoved() mNotificationInflater.setInflateSynchronously(true) mNotificationInflater.bindContent( mRow.entry, mRow, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, row.setRemoved() notificationInflater.setInflateSynchronously(true) notificationInflater.bindContent( row.entry, row, FLAG_CONTENT_VIEW_ALL, BindParams(), false /* forceInflate */, null /* callback */ ) Assert.assertNull(mRow.entry.runningTask) Assert.assertNull(row.entry.runningTask) } @Test Loading @@ -235,11 +228,11 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { inflateSynchronously = false, isMinimized = false, result = result, reInflateFlags = NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED, reInflateFlags = FLAG_CONTENT_VIEW_EXPANDED, inflationId = 0, remoteViewCache = mock(), entry = mRow.entry, row = mRow, entry = row.entry, row = row, isNewView = true, /* isNewView */ remoteViewClickHandler = { _, _, _ -> true }, callback = Loading @@ -253,7 +246,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { countDownLatch.countDown() } }, parentLayout = mRow.privateLayout, parentLayout = row.privateLayout, existingView = null, existingWrapper = null, runningInflations = HashMap(), Loading @@ -275,13 +268,13 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @Test fun doesntReapplyDisallowedRemoteView() { mBuilder.setStyle(Notification.MediaStyle()) val mediaView = mBuilder.createContentView() mBuilder.setStyle(Notification.DecoratedCustomViewStyle()) mBuilder.setCustomContentView( builder.setStyle(Notification.MediaStyle()) val mediaView = builder.createContentView() builder.setStyle(Notification.DecoratedCustomViewStyle()) builder.setCustomContentView( RemoteViews(context.packageName, com.android.systemui.tests.R.layout.custom_view_dark) ) val decoratedMediaView = mBuilder.createContentView() val decoratedMediaView = builder.createContentView() Assert.assertFalse( "The decorated media style doesn't allow a view to be reapplied!", NotificationRowContentBinderImpl.canReapplyRemoteView(mediaView, decoratedMediaView) Loading @@ -292,112 +285,65 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @Ignore("b/345418902") fun testUsesSameViewWhenCachedPossibleToReuse() { // GIVEN a cached view. val contractedRemoteView = mBuilder.createContentView() whenever( mCache.hasCachedView( mRow.entry, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED ) ) .thenReturn(true) whenever( mCache.getCachedView( mRow.entry, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED ) ) val contractedRemoteView = builder.createContentView() whenever(cache.hasCachedView(row.entry, FLAG_CONTENT_VIEW_CONTRACTED)).thenReturn(true) whenever(cache.getCachedView(row.entry, FLAG_CONTENT_VIEW_CONTRACTED)) .thenReturn(contractedRemoteView) // GIVEN existing bound view with same layout id. val view = contractedRemoteView.apply(mContext, null /* parent */) mRow.privateLayout.setContractedChild(view) row.privateLayout.setContractedChild(view) // WHEN inflater inflates inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, mRow ) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, row) // THEN the view should be re-used Assert.assertEquals( "Binder inflated a new view even though the old one was cached and usable.", view, mRow.privateLayout.contractedChild row.privateLayout.contractedChild ) } @Test fun testInflatesNewViewWhenCachedNotPossibleToReuse() { // GIVEN a cached remote view. val contractedRemoteView = mBuilder.createHeadsUpContentView() whenever( mCache.hasCachedView( mRow.entry, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED ) ) .thenReturn(true) whenever( mCache.getCachedView( mRow.entry, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED ) ) val contractedRemoteView = builder.createHeadsUpContentView() whenever(cache.hasCachedView(row.entry, FLAG_CONTENT_VIEW_CONTRACTED)).thenReturn(true) whenever(cache.getCachedView(row.entry, FLAG_CONTENT_VIEW_CONTRACTED)) .thenReturn(contractedRemoteView) // GIVEN existing bound view with different layout id. val view: View = TextView(mContext) mRow.privateLayout.setContractedChild(view) row.privateLayout.setContractedChild(view) // WHEN inflater inflates inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, mRow ) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, row) // THEN the view should be a new view Assert.assertNotEquals( "Binder (somehow) used the same view when inflating.", view, mRow.privateLayout.contractedChild row.privateLayout.contractedChild ) } @Test fun testInflationCachesCreatedRemoteView() { // WHEN inflater inflates inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, mRow ) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, row) // THEN inflater informs cache of the new remote view verify(mCache) .putCachedView( eq(mRow.entry), eq(NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED), any() ) verify(cache).putCachedView(eq(row.entry), eq(FLAG_CONTENT_VIEW_CONTRACTED), any()) } @Test fun testUnbindRemovesCachedRemoteView() { // WHEN inflated unbinds content mNotificationInflater.unbindContent( mRow.entry, mRow, NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP ) notificationInflater.unbindContent(row.entry, row, FLAG_CONTENT_VIEW_HEADS_UP) // THEN inflated informs cache to remove remote view verify(mCache) .removeCachedView( eq(mRow.entry), eq(NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP) ) verify(cache).removeCachedView(eq(row.entry), eq(FLAG_CONTENT_VIEW_HEADS_UP)) } @Test Loading Loading @@ -453,46 +399,36 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { whenever(view.measuredHeight) .thenReturn( TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, COMPLEX_UNIT_SP, measuredHeightDp, mContext.resources.displayMetrics ) .toInt() ) mRow.entry.targetSdk = targetSdk mRow.entry.sbn.notification.contentView = contentView return NotificationRowContentBinderImpl.isValidView(view, mRow.entry, mContext.resources) row.entry.targetSdk = targetSdk row.entry.sbn.notification.contentView = contentView return NotificationRowContentBinderImpl.isValidView(view, row.entry, mContext.resources) } @Test fun testInvalidNotificationDoesNotInvokeCallback() { mRow.privateLayout.removeAllViews() mRow.entry.sbn.notification.contentView = row.privateLayout.removeAllViews() row.entry.sbn.notification.contentView = RemoteViews( mContext.packageName, com.android.systemui.tests.R.layout.invalid_notification_height ) inflateAndWait( true, mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, mRow ) Assert.assertEquals(0, mRow.privateLayout.childCount.toLong()) verify(mRow, times(0)).onNotificationUpdated() inflateAndWait(true, notificationInflater, FLAG_CONTENT_VIEW_ALL, row) Assert.assertEquals(0, row.privateLayout.childCount.toLong()) verify(row, times(0)).onNotificationUpdated() } private class ExceptionHolder { var mException: Exception? = null fun setException(exception: Exception?) { mException = exception } var exception: Exception? = null } private class AsyncFailRemoteView(packageName: String?, layoutId: Int) : RemoteViews(packageName, layoutId) { var mHandler = mockExecutorHandler { p0 -> p0.run() } override fun apply(context: Context, parent: ViewGroup): View { return super.apply(context, parent) Loading @@ -505,7 +441,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { listener: OnViewAppliedListener, handler: InteractionHandler? ): CancellationSignal { mHandler.post { listener.onError(RuntimeException("Failed to inflate async")) } executor.execute { listener.onError(RuntimeException("Failed to inflate async")) } return CancellationSignal() } Loading Loading @@ -541,18 +477,17 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { object : InflationCallback { override fun handleInflationException(entry: NotificationEntry, e: Exception) { if (!expectingException) { exceptionHolder.setException(e) exceptionHolder.exception = e } countDownLatch.countDown() } override fun onAsyncInflationFinished(entry: NotificationEntry) { if (expectingException) { exceptionHolder.setException( exceptionHolder.exception = RuntimeException( "Inflation finished even though there should be an error" ) ) } countDownLatch.countDown() } Loading @@ -566,7 +501,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { callback /* callback */ ) Assert.assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS)) exceptionHolder.mException?.let { throw it } exceptionHolder.exception?.let { throw it } } } } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt +106 −171 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.CancellationSignal import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper.RunWithLooper import android.util.TypedValue import android.util.TypedValue.COMPLEX_UNIT_SP import android.view.View import android.view.ViewGroup import android.widget.RemoteViews Loading @@ -34,6 +35,10 @@ import com.android.systemui.res.R import com.android.systemui.statusbar.notification.ConversationNotificationProcessor import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag import com.android.systemui.statusbar.notification.row.shared.HeadsUpStatusBarModel Loading @@ -43,7 +48,6 @@ import com.android.systemui.statusbar.notification.row.shared.NotificationRowCon import com.android.systemui.statusbar.policy.InflatedSmartReplyState import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder import com.android.systemui.statusbar.policy.SmartReplyStateInflater import com.android.systemui.util.concurrency.mockExecutorHandler import java.util.concurrent.CountDownLatch import java.util.concurrent.Executor import java.util.concurrent.TimeUnit Loading @@ -65,20 +69,24 @@ import org.mockito.kotlin.whenever @RunWithLooper @EnableFlags(NotificationRowContentBinderRefactor.FLAG_NAME) class NotificationRowContentBinderImplTest : SysuiTestCase() { private lateinit var mNotificationInflater: NotificationRowContentBinderImpl private lateinit var mBuilder: Notification.Builder private lateinit var mRow: ExpandableNotificationRow private lateinit var mHelper: NotificationTestHelper private var mCache: NotifRemoteViewCache = mock() private var mConversationNotificationProcessor: ConversationNotificationProcessor = mock() private var mInflatedSmartReplyState: InflatedSmartReplyState = mock() private var mInflatedSmartReplies: InflatedSmartReplyViewHolder = mock() private var mNotifLayoutInflaterFactoryProvider: NotifLayoutInflaterFactory.Provider = mock() private var mHeadsUpStyleProvider: HeadsUpStyleProvider = mock() private var mNotifLayoutInflaterFactory: NotifLayoutInflaterFactory = mock() private val mSmartReplyStateInflater: SmartReplyStateInflater = private lateinit var notificationInflater: NotificationRowContentBinderImpl private lateinit var builder: Notification.Builder private lateinit var row: ExpandableNotificationRow private lateinit var testHelper: NotificationTestHelper private val cache: NotifRemoteViewCache = mock() private val layoutInflaterFactoryProvider = object : NotifLayoutInflaterFactory.Provider { override fun provide( row: ExpandableNotificationRow, layoutType: Int ): NotifLayoutInflaterFactory = mock() } private val smartReplyStateInflater: SmartReplyStateInflater = object : SmartReplyStateInflater { private val inflatedSmartReplyState: InflatedSmartReplyState = mock() private val inflatedSmartReplies: InflatedSmartReplyViewHolder = mock() override fun inflateSmartReplyViewHolder( sysuiContext: Context, notifPackageContext: Context, Loading @@ -86,37 +94,34 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { existingSmartReplyState: InflatedSmartReplyState?, newSmartReplyState: InflatedSmartReplyState ): InflatedSmartReplyViewHolder { return mInflatedSmartReplies return inflatedSmartReplies } override fun inflateSmartReplyState(entry: NotificationEntry): InflatedSmartReplyState { return mInflatedSmartReplyState return inflatedSmartReplyState } } @Before fun setUp() { allowTestableLooperAsMainThread() mBuilder = builder = Notification.Builder(mContext, "no-id") .setSmallIcon(R.drawable.ic_person) .setContentTitle("Title") .setContentText("Text") .setStyle(Notification.BigTextStyle().bigText("big text")) mHelper = NotificationTestHelper(mContext, mDependency) val row = mHelper.createRow(mBuilder.build()) mRow = spy(row) whenever(mNotifLayoutInflaterFactoryProvider.provide(any(), any())) .thenReturn(mNotifLayoutInflaterFactory) mNotificationInflater = testHelper = NotificationTestHelper(mContext, mDependency) row = spy(testHelper.createRow(builder.build())) notificationInflater = NotificationRowContentBinderImpl( mCache, cache, mock(), mConversationNotificationProcessor, mock<ConversationNotificationProcessor>(), mock(), mSmartReplyStateInflater, mNotifLayoutInflaterFactoryProvider, mHeadsUpStyleProvider, smartReplyStateInflater, layoutInflaterFactoryProvider, mock<HeadsUpStyleProvider>(), mock() ) } Loading @@ -125,16 +130,16 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { fun testIncreasedHeadsUpBeingUsed() { val params = BindParams() params.usesIncreasedHeadsUpHeight = true val builder = spy(mBuilder) mNotificationInflater.inflateNotificationViews( mRow.entry, mRow, val builder = spy(builder) notificationInflater.inflateNotificationViews( row.entry, row, params, true /* inflateSynchronously */, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, FLAG_CONTENT_VIEW_ALL, builder, mContext, mSmartReplyStateInflater smartReplyStateInflater ) verify(builder).createHeadsUpContentView(true) } Loading @@ -143,80 +148,68 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { fun testIncreasedHeightBeingUsed() { val params = BindParams() params.usesIncreasedHeight = true val builder = spy(mBuilder) mNotificationInflater.inflateNotificationViews( mRow.entry, mRow, val builder = spy(builder) notificationInflater.inflateNotificationViews( row.entry, row, params, true /* inflateSynchronously */, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, FLAG_CONTENT_VIEW_ALL, builder, mContext, mSmartReplyStateInflater smartReplyStateInflater ) verify(builder).createContentView(true) } @Test fun testInflationCallsUpdated() { inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, mRow ) verify(mRow).onNotificationUpdated() inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) verify(row).onNotificationUpdated() } @Test fun testInflationOnlyInflatesSetFlags() { inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP, mRow ) Assert.assertNotNull(mRow.privateLayout.headsUpChild) verify(mRow).onNotificationUpdated() inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_HEADS_UP, row) Assert.assertNotNull(row.privateLayout.headsUpChild) verify(row).onNotificationUpdated() } @Test fun testInflationThrowsErrorDoesntCallUpdated() { mRow.privateLayout.removeAllViews() mRow.entry.sbn.notification.contentView = row.privateLayout.removeAllViews() row.entry.sbn.notification.contentView = RemoteViews(mContext.packageName, R.layout.status_bar) inflateAndWait( true /* expectingException */, mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, mRow notificationInflater, FLAG_CONTENT_VIEW_ALL, row ) Assert.assertTrue(mRow.privateLayout.childCount == 0) verify(mRow, times(0)).onNotificationUpdated() Assert.assertTrue(row.privateLayout.childCount == 0) verify(row, times(0)).onNotificationUpdated() } @Test fun testAsyncTaskRemoved() { mRow.entry.abortTask() inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, mRow ) verify(mRow).onNotificationUpdated() row.entry.abortTask() inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_ALL, row) verify(row).onNotificationUpdated() } @Test fun testRemovedNotInflated() { mRow.setRemoved() mNotificationInflater.setInflateSynchronously(true) mNotificationInflater.bindContent( mRow.entry, mRow, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, row.setRemoved() notificationInflater.setInflateSynchronously(true) notificationInflater.bindContent( row.entry, row, FLAG_CONTENT_VIEW_ALL, BindParams(), false /* forceInflate */, null /* callback */ ) Assert.assertNull(mRow.entry.runningTask) Assert.assertNull(row.entry.runningTask) } @Test Loading @@ -235,11 +228,11 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { inflateSynchronously = false, isMinimized = false, result = result, reInflateFlags = NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED, reInflateFlags = FLAG_CONTENT_VIEW_EXPANDED, inflationId = 0, remoteViewCache = mock(), entry = mRow.entry, row = mRow, entry = row.entry, row = row, isNewView = true, /* isNewView */ remoteViewClickHandler = { _, _, _ -> true }, callback = Loading @@ -253,7 +246,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { countDownLatch.countDown() } }, parentLayout = mRow.privateLayout, parentLayout = row.privateLayout, existingView = null, existingWrapper = null, runningInflations = HashMap(), Loading @@ -275,13 +268,13 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @Test fun doesntReapplyDisallowedRemoteView() { mBuilder.setStyle(Notification.MediaStyle()) val mediaView = mBuilder.createContentView() mBuilder.setStyle(Notification.DecoratedCustomViewStyle()) mBuilder.setCustomContentView( builder.setStyle(Notification.MediaStyle()) val mediaView = builder.createContentView() builder.setStyle(Notification.DecoratedCustomViewStyle()) builder.setCustomContentView( RemoteViews(context.packageName, com.android.systemui.tests.R.layout.custom_view_dark) ) val decoratedMediaView = mBuilder.createContentView() val decoratedMediaView = builder.createContentView() Assert.assertFalse( "The decorated media style doesn't allow a view to be reapplied!", NotificationRowContentBinderImpl.canReapplyRemoteView(mediaView, decoratedMediaView) Loading @@ -292,112 +285,65 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { @Ignore("b/345418902") fun testUsesSameViewWhenCachedPossibleToReuse() { // GIVEN a cached view. val contractedRemoteView = mBuilder.createContentView() whenever( mCache.hasCachedView( mRow.entry, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED ) ) .thenReturn(true) whenever( mCache.getCachedView( mRow.entry, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED ) ) val contractedRemoteView = builder.createContentView() whenever(cache.hasCachedView(row.entry, FLAG_CONTENT_VIEW_CONTRACTED)).thenReturn(true) whenever(cache.getCachedView(row.entry, FLAG_CONTENT_VIEW_CONTRACTED)) .thenReturn(contractedRemoteView) // GIVEN existing bound view with same layout id. val view = contractedRemoteView.apply(mContext, null /* parent */) mRow.privateLayout.setContractedChild(view) row.privateLayout.setContractedChild(view) // WHEN inflater inflates inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, mRow ) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, row) // THEN the view should be re-used Assert.assertEquals( "Binder inflated a new view even though the old one was cached and usable.", view, mRow.privateLayout.contractedChild row.privateLayout.contractedChild ) } @Test fun testInflatesNewViewWhenCachedNotPossibleToReuse() { // GIVEN a cached remote view. val contractedRemoteView = mBuilder.createHeadsUpContentView() whenever( mCache.hasCachedView( mRow.entry, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED ) ) .thenReturn(true) whenever( mCache.getCachedView( mRow.entry, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED ) ) val contractedRemoteView = builder.createHeadsUpContentView() whenever(cache.hasCachedView(row.entry, FLAG_CONTENT_VIEW_CONTRACTED)).thenReturn(true) whenever(cache.getCachedView(row.entry, FLAG_CONTENT_VIEW_CONTRACTED)) .thenReturn(contractedRemoteView) // GIVEN existing bound view with different layout id. val view: View = TextView(mContext) mRow.privateLayout.setContractedChild(view) row.privateLayout.setContractedChild(view) // WHEN inflater inflates inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, mRow ) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, row) // THEN the view should be a new view Assert.assertNotEquals( "Binder (somehow) used the same view when inflating.", view, mRow.privateLayout.contractedChild row.privateLayout.contractedChild ) } @Test fun testInflationCachesCreatedRemoteView() { // WHEN inflater inflates inflateAndWait( mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED, mRow ) inflateAndWait(notificationInflater, FLAG_CONTENT_VIEW_CONTRACTED, row) // THEN inflater informs cache of the new remote view verify(mCache) .putCachedView( eq(mRow.entry), eq(NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED), any() ) verify(cache).putCachedView(eq(row.entry), eq(FLAG_CONTENT_VIEW_CONTRACTED), any()) } @Test fun testUnbindRemovesCachedRemoteView() { // WHEN inflated unbinds content mNotificationInflater.unbindContent( mRow.entry, mRow, NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP ) notificationInflater.unbindContent(row.entry, row, FLAG_CONTENT_VIEW_HEADS_UP) // THEN inflated informs cache to remove remote view verify(mCache) .removeCachedView( eq(mRow.entry), eq(NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP) ) verify(cache).removeCachedView(eq(row.entry), eq(FLAG_CONTENT_VIEW_HEADS_UP)) } @Test Loading Loading @@ -453,46 +399,36 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { whenever(view.measuredHeight) .thenReturn( TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, COMPLEX_UNIT_SP, measuredHeightDp, mContext.resources.displayMetrics ) .toInt() ) mRow.entry.targetSdk = targetSdk mRow.entry.sbn.notification.contentView = contentView return NotificationRowContentBinderImpl.isValidView(view, mRow.entry, mContext.resources) row.entry.targetSdk = targetSdk row.entry.sbn.notification.contentView = contentView return NotificationRowContentBinderImpl.isValidView(view, row.entry, mContext.resources) } @Test fun testInvalidNotificationDoesNotInvokeCallback() { mRow.privateLayout.removeAllViews() mRow.entry.sbn.notification.contentView = row.privateLayout.removeAllViews() row.entry.sbn.notification.contentView = RemoteViews( mContext.packageName, com.android.systemui.tests.R.layout.invalid_notification_height ) inflateAndWait( true, mNotificationInflater, NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL, mRow ) Assert.assertEquals(0, mRow.privateLayout.childCount.toLong()) verify(mRow, times(0)).onNotificationUpdated() inflateAndWait(true, notificationInflater, FLAG_CONTENT_VIEW_ALL, row) Assert.assertEquals(0, row.privateLayout.childCount.toLong()) verify(row, times(0)).onNotificationUpdated() } private class ExceptionHolder { var mException: Exception? = null fun setException(exception: Exception?) { mException = exception } var exception: Exception? = null } private class AsyncFailRemoteView(packageName: String?, layoutId: Int) : RemoteViews(packageName, layoutId) { var mHandler = mockExecutorHandler { p0 -> p0.run() } override fun apply(context: Context, parent: ViewGroup): View { return super.apply(context, parent) Loading @@ -505,7 +441,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { listener: OnViewAppliedListener, handler: InteractionHandler? ): CancellationSignal { mHandler.post { listener.onError(RuntimeException("Failed to inflate async")) } executor.execute { listener.onError(RuntimeException("Failed to inflate async")) } return CancellationSignal() } Loading Loading @@ -541,18 +477,17 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { object : InflationCallback { override fun handleInflationException(entry: NotificationEntry, e: Exception) { if (!expectingException) { exceptionHolder.setException(e) exceptionHolder.exception = e } countDownLatch.countDown() } override fun onAsyncInflationFinished(entry: NotificationEntry) { if (expectingException) { exceptionHolder.setException( exceptionHolder.exception = RuntimeException( "Inflation finished even though there should be an error" ) ) } countDownLatch.countDown() } Loading @@ -566,7 +501,7 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { callback /* callback */ ) Assert.assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS)) exceptionHolder.mException?.let { throw it } exceptionHolder.exception?.let { throw it } } } }