12630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek/*
22630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * Copyright (C) 2017 The Android Open Source Project
32630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek *
42630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * Licensed under the Apache License, Version 2.0 (the "License");
52630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * you may not use this file except in compliance with the License.
62630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * You may obtain a copy of the License at
72630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek *
82630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek *      http://www.apache.org/licenses/LICENSE-2.0
92630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek *
102630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * Unless required by applicable law or agreed to in writing, software
112630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * distributed under the License is distributed on an "AS IS" BASIS,
122630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * See the License for the specific language governing permissions and
142630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek * limitations under the License
152630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek */
162630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
172630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekpackage com.android.systemui.statusbar.notification;
182630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
192630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport static com.android.systemui.statusbar.notification.NotificationInflater.FLAG_REINFLATE_ALL;
202630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
212630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport static org.mockito.Mockito.spy;
222630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport static org.mockito.Mockito.times;
232630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport static org.mockito.Mockito.verify;
242630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
252630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport android.app.Notification;
262630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport android.content.Context;
27d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinekimport android.os.CancellationSignal;
28d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinekimport android.os.Handler;
29d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinekimport android.os.Looper;
302630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport android.service.notification.StatusBarNotification;
3101d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinekimport android.support.test.annotation.UiThreadTest;
3270950def80d1aa5938c104e125635e0d42933ba7Geoffrey Pitschimport android.support.test.filters.FlakyTest;
332630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport android.support.test.filters.SmallTest;
342630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport android.support.test.runner.AndroidJUnit4;
35d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinekimport android.view.View;
36d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinekimport android.view.ViewGroup;
372630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport android.widget.RemoteViews;
382630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
392630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport com.android.systemui.R;
40fba8faf5c5f58f115fa3c099da9ef0953b484147Jason Monkimport com.android.systemui.SysuiTestCase;
412630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport com.android.systemui.statusbar.ExpandableNotificationRow;
42b05395f53c1241eb1925008f1864e8d5c8455371Jason Monkimport com.android.systemui.statusbar.InflationTask;
432630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport com.android.systemui.statusbar.NotificationData;
442630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport com.android.systemui.statusbar.NotificationTestHelper;
452630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
462630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport org.junit.Assert;
472630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport org.junit.Before;
48351a321371c307e92ee73ea6d179de41518d1ef3Geoffrey Pitschimport org.junit.Ignore;
492630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport org.junit.Test;
502630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport org.junit.runner.RunWith;
512630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
52d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinekimport java.util.HashMap;
532630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinekimport java.util.concurrent.CountDownLatch;
54d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinekimport java.util.concurrent.Executor;
552630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
562630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek@SmallTest
572630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek@RunWith(AndroidJUnit4.class)
5870950def80d1aa5938c104e125635e0d42933ba7Geoffrey Pitsch@FlakyTest
59fba8faf5c5f58f115fa3c099da9ef0953b484147Jason Monkpublic class NotificationInflaterTest extends SysuiTestCase {
602630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
612630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    private NotificationInflater mNotificationInflater;
622630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    private Notification.Builder mBuilder;
632630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    private ExpandableNotificationRow mRow;
642630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
652630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    @Before
662630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    public void setUp() throws Exception {
672630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mBuilder = new Notification.Builder(mContext).setSmallIcon(
682630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                R.drawable.ic_person)
692630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                .setContentTitle("Title")
702630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                .setContentText("Text")
712630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                .setStyle(new Notification.BigTextStyle().bigText("big text"));
722630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        ExpandableNotificationRow row = new NotificationTestHelper(mContext).createRow(
732630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                mBuilder.build());
742630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mRow = spy(row);
752630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mNotificationInflater = new NotificationInflater(mRow);
762630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mNotificationInflater.setInflationCallback(new NotificationInflater.InflationCallback() {
772630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            @Override
782630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            public void handleInflationException(StatusBarNotification notification,
7901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek                    Exception e) {
802630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            }
812630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
822630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            @Override
832630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            public void onAsyncInflationFinished(NotificationData.Entry entry) {
842630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            }
852630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        });
862630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
872630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
882630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    @Test
8901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek    @UiThreadTest
902630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    public void testIncreasedHeadsUpBeingUsed() {
912630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
922630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        Notification.Builder builder = spy(mBuilder);
932630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
942630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        verify(builder).createHeadsUpContentView(true);
952630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
962630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
972630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    @Test
9801d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek    @UiThreadTest
992630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    public void testIncreasedHeightBeingUsed() {
1002630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mNotificationInflater.setUsesIncreasedHeight(true);
1012630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        Notification.Builder builder = spy(mBuilder);
1022630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mNotificationInflater.inflateNotificationViews(FLAG_REINFLATE_ALL, builder, mContext);
1032630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        verify(builder).createContentView(true);
1042630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
1052630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
1062630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    @Test
1072630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    public void testInflationCallsUpdated() throws Exception {
1082630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
1092630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                mNotificationInflater);
1102630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        verify(mRow).onNotificationUpdated();
1112630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
1122630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
1132630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    @Test
1142630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    public void testInflationCallsOnlyRightMethod() throws Exception {
1152630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mRow.getPrivateLayout().removeAllViews();
1162630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mRow.getEntry().cachedBigContentView = null;
1172630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(
1182630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW), mNotificationInflater);
1192630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        Assert.assertTrue(mRow.getPrivateLayout().getChildCount() == 1);
1202630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        Assert.assertTrue(mRow.getPrivateLayout().getChildAt(0)
1212630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                == mRow.getPrivateLayout().getExpandedChild());
1222630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        verify(mRow).onNotificationUpdated();
1232630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
1242630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
1252630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    @Test
1262630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    public void testInflationThrowsErrorDoesntCallUpdated() throws Exception {
1272630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mRow.getPrivateLayout().removeAllViews();
1282630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        mRow.getStatusBarNotification().getNotification().contentView
129dc1231c3b9fd72790f767a605136e3f05a2af3e2Selim Cinek                = new RemoteViews(mContext.getPackageName(), R.layout.status_bar);
1302630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
1312630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                true /* expectingException */, mNotificationInflater);
1322630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        Assert.assertTrue(mRow.getPrivateLayout().getChildCount() == 0);
1332630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        verify(mRow, times(0)).onNotificationUpdated();
1342630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
1352630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
136dc1231c3b9fd72790f767a605136e3f05a2af3e2Selim Cinek    @Test
137dc1231c3b9fd72790f767a605136e3f05a2af3e2Selim Cinek    public void testAsyncTaskRemoved() throws Exception {
1380f66a4cc16ec1a927c90ac559c73c80ddcb5ee71Selim Cinek        mRow.getEntry().abortTask();
139dc1231c3b9fd72790f767a605136e3f05a2af3e2Selim Cinek        runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
140dc1231c3b9fd72790f767a605136e3f05a2af3e2Selim Cinek                mNotificationInflater);
14167ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        verify(mRow).onNotificationUpdated();
14267ff248168fb77dadd81886df134cbfe048a6001Selim Cinek    }
14367ff248168fb77dadd81886df134cbfe048a6001Selim Cinek
14467ff248168fb77dadd81886df134cbfe048a6001Selim Cinek    @Test
14567ff248168fb77dadd81886df134cbfe048a6001Selim Cinek    public void testRemovedNotInflated() throws Exception {
14667ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        mRow.setRemoved();
14767ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        mNotificationInflater.inflateNotificationViews();
14867ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        Assert.assertNull(mRow.getEntry().getRunningTask());
14967ff248168fb77dadd81886df134cbfe048a6001Selim Cinek    }
15067ff248168fb77dadd81886df134cbfe048a6001Selim Cinek
151d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek    @Test
152b05395f53c1241eb1925008f1864e8d5c8455371Jason Monk    @Ignore
153d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek    public void testInflationIsRetriedIfAsyncFails() throws Exception {
154d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        NotificationInflater.InflationProgress result =
155d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                new NotificationInflater.InflationProgress();
156d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        result.packageContext = mContext;
157d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        CountDownLatch countDownLatch = new CountDownLatch(1);
158d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        NotificationInflater.applyRemoteView(result,
159d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                NotificationInflater.FLAG_REINFLATE_EXPANDED_VIEW, 0, mRow,
160d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                false /* redactAmbient */, true /* isNewView */, new RemoteViews.OnClickHandler(),
161d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                new NotificationInflater.InflationCallback() {
162d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    @Override
163d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    public void handleInflationException(StatusBarNotification notification,
164d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                            Exception e) {
165d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                        countDownLatch.countDown();
166d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                        throw new RuntimeException("No Exception expected");
167d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    }
168d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek
169d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    @Override
170d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    public void onAsyncInflationFinished(NotificationData.Entry entry) {
171d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                        countDownLatch.countDown();
172d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    }
173d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                }, mRow.getEntry(), mRow.getPrivateLayout(), null, null, new HashMap<>(),
174d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                new NotificationInflater.ApplyCallback() {
175d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    @Override
176d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    public void setResultView(View v) {
177d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    }
178d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek
179d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    @Override
180d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    public RemoteViews getRemoteView() {
181d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                        return new AsyncFailRemoteView(mContext.getPackageName(),
182d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                                R.layout.custom_view_dark);
183d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                    }
184d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                });
185d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        countDownLatch.await();
186d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek    }
18767ff248168fb77dadd81886df134cbfe048a6001Selim Cinek
18821f336614c41bf872f02aebb5c40c2ec78f61870Selim Cinek    /* Cancelling requires us to be on the UI thread otherwise we might have a race */
18967ff248168fb77dadd81886df134cbfe048a6001Selim Cinek    @Test
19021f336614c41bf872f02aebb5c40c2ec78f61870Selim Cinek    @UiThreadTest
19167ff248168fb77dadd81886df134cbfe048a6001Selim Cinek    public void testSupersedesExistingTask() throws Exception {
19267ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        mNotificationInflater.inflateNotificationViews();
19367ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        mNotificationInflater.setIsLowPriority(true);
19467ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        mNotificationInflater.setIsChildInGroup(true);
19567ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        InflationTask runningTask = mRow.getEntry().getRunningTask();
19667ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        NotificationInflater.AsyncInflationTask asyncInflationTask =
19767ff248168fb77dadd81886df134cbfe048a6001Selim Cinek                (NotificationInflater.AsyncInflationTask) runningTask;
19867ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        Assert.assertSame("Successive inflations don't inherit the previous flags!",
19967ff248168fb77dadd81886df134cbfe048a6001Selim Cinek                asyncInflationTask.getReInflateFlags(),
20067ff248168fb77dadd81886df134cbfe048a6001Selim Cinek                NotificationInflater.FLAG_REINFLATE_ALL);
20167ff248168fb77dadd81886df134cbfe048a6001Selim Cinek        runningTask.abort();
202dc1231c3b9fd72790f767a605136e3f05a2af3e2Selim Cinek    }
203dc1231c3b9fd72790f767a605136e3f05a2af3e2Selim Cinek
204fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek    @Test
205fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek    public void doesntReapplyDisallowedRemoteView() throws Exception {
206fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek        mBuilder.setStyle(new Notification.MediaStyle());
207fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek        RemoteViews mediaView = mBuilder.createContentView();
208fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek        mBuilder.setStyle(new Notification.DecoratedCustomViewStyle());
209fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek        mBuilder.setCustomContentView(new RemoteViews(getContext().getPackageName(),
210fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek                R.layout.custom_view_dark));
211fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek        RemoteViews decoratedMediaView = mBuilder.createContentView();
212fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek        Assert.assertFalse("The decorated media style doesn't allow a view to be reapplied!",
213fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek                NotificationInflater.canReapplyRemoteView(mediaView, decoratedMediaView));
214fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek    }
215fc8073c4b606e18366660cea5cbe570c9bef5a51Selim Cinek
2162630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    public static void runThenWaitForInflation(Runnable block,
2172630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            NotificationInflater inflater) throws Exception {
2182630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        runThenWaitForInflation(block, false /* expectingException */, inflater);
2192630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
2202630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
2212630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    private static void runThenWaitForInflation(Runnable block, boolean expectingException,
2222630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            NotificationInflater inflater) throws Exception {
2232630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        com.android.systemui.util.Assert.isNotMainThread();
2242630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        CountDownLatch countDownLatch = new CountDownLatch(1);
2252630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        final ExceptionHolder exceptionHolder = new ExceptionHolder();
2262630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        inflater.setInflationCallback(new NotificationInflater.InflationCallback() {
2272630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            @Override
2282630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            public void handleInflationException(StatusBarNotification notification,
22901d3da63cef1f82db182c6995264bf3ea3371dccSelim Cinek                    Exception e) {
2302630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                if (!expectingException) {
2312630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                    exceptionHolder.setException(e);
2322630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                }
2332630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                countDownLatch.countDown();
2342630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            }
2352630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
2362630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            @Override
2372630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            public void onAsyncInflationFinished(NotificationData.Entry entry) {
2382630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                if (expectingException) {
2392630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                    exceptionHolder.setException(new RuntimeException(
2402630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                            "Inflation finished even though there should be an error"));
2412630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                }
2422630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek                countDownLatch.countDown();
2432630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            }
2442630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        });
2452630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        block.run();
246454a5fc4bb5cb9d5242cf88d53cee5d811f02a3aSelim Cinek        countDownLatch.await();
2472630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        if (exceptionHolder.mException != null) {
2482630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            throw exceptionHolder.mException;
2492630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        }
2502630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
2512630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
2522630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    private static class ExceptionHolder {
2532630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        private Exception mException;
2542630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek
2552630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        public void setException(Exception exception) {
2562630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek            mException = exception;
2572630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek        }
2582630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek    }
259d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek
260d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek    private class AsyncFailRemoteView extends RemoteViews {
261d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        Handler mHandler = new Handler(Looper.getMainLooper());
262d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek
263d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        public AsyncFailRemoteView(String packageName, int layoutId) {
264d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek            super(packageName, layoutId);
265d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        }
266d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek
267d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        @Override
268d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        public View apply(Context context, ViewGroup parent) {
269d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek            return super.apply(context, parent);
270d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        }
271d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek
272d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        @Override
273d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
274d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                OnViewAppliedListener listener, OnClickHandler handler) {
275d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek            mHandler.post(() -> listener.onError(new RuntimeException("Failed to inflate async")));
276d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek            return new CancellationSignal();
277d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        }
278d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek
279d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        @Override
280d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
281d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek                OnViewAppliedListener listener) {
282d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek            return applyAsync(context, parent, executor, listener, null);
283d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek        }
284d246bed148f5505bd65627027dfe27313b03fd4cSelim Cinek    }
2852630dc7ecf16a965321cfc615104f372cd2b0e96Selim Cinek}
286