17da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos/*
27da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * Copyright (C) 2016 The Android Open Source Project
37da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos *
47da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * Licensed under the Apache License, Version 2.0 (the "License");
57da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * you may not use this file except in compliance with the License.
67da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * You may obtain a copy of the License at
77da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos *
87da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos *      http://www.apache.org/licenses/LICENSE-2.0
97da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos *
107da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * Unless required by applicable law or agreed to in writing, software
117da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * distributed under the License is distributed on an "AS IS" BASIS,
127da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * See the License for the specific language governing permissions and
147da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * limitations under the License
157da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos */
167da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
178376f9eaa0bd41a9c7ce7ada4cb7c2cda28ef64cKirill Grouchnikovpackage android.widget;
187da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1956333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyalimport static org.junit.Assert.assertEquals;
2056333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyalimport static org.junit.Assert.assertSame;
2156333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyalimport static org.junit.Assert.assertTrue;
2256333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal
235b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyalimport android.app.PendingIntent;
247da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roosimport android.content.Context;
255b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyalimport android.content.Intent;
267da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roosimport android.graphics.Bitmap;
277da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roosimport android.graphics.drawable.BitmapDrawable;
287da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roosimport android.graphics.drawable.Drawable;
297b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyalimport android.os.AsyncTask;
30fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roosimport android.os.Binder;
315d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyalimport android.os.Parcel;
327da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roosimport android.support.test.InstrumentationRegistry;
337da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roosimport android.support.test.filters.SmallTest;
347da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roosimport android.support.test.runner.AndroidJUnit4;
358376f9eaa0bd41a9c7ce7ada4cb7c2cda28ef64cKirill Grouchnikovimport android.view.View;
367b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyalimport android.view.ViewGroup;
377da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
387da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roosimport com.android.frameworks.coretests.R;
397da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
408376f9eaa0bd41a9c7ce7ada4cb7c2cda28ef64cKirill Grouchnikovimport org.junit.Before;
418376f9eaa0bd41a9c7ce7ada4cb7c2cda28ef64cKirill Grouchnikovimport org.junit.Rule;
428376f9eaa0bd41a9c7ce7ada4cb7c2cda28ef64cKirill Grouchnikovimport org.junit.Test;
438376f9eaa0bd41a9c7ce7ada4cb7c2cda28ef64cKirill Grouchnikovimport org.junit.rules.ExpectedException;
448376f9eaa0bd41a9c7ce7ada4cb7c2cda28ef64cKirill Grouchnikovimport org.junit.runner.RunWith;
458376f9eaa0bd41a9c7ce7ada4cb7c2cda28ef64cKirill Grouchnikov
467b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyalimport java.util.ArrayList;
477b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyalimport java.util.Arrays;
487b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyalimport java.util.concurrent.CountDownLatch;
497b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
507da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos/**
517da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos * Tests for RemoteViews.
527da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos */
537da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos@RunWith(AndroidJUnit4.class)
547da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos@SmallTest
557da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roospublic class RemoteViewsTest {
567da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
575d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    // This can point to any other package which exists on the device.
585d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    private static final String OTHER_PACKAGE = "com.android.systemui";
595d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal
607da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    @Rule
617da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    public final ExpectedException exception = ExpectedException.none();
627da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
637da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    private Context mContext;
647da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    private String mPackage;
657da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    private LinearLayout mContainer;
667da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
677da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    @Before
687da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    public void setup() {
697da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        mContext = InstrumentationRegistry.getContext();
704d10db7fdd1dc86684f31ec582872072fb02c350Adrian Roos        mPackage = mContext.getPackageName();
717da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        mContainer = new LinearLayout(mContext);
727da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    }
737da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
747da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    @Test
757da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    public void clone_doesNotCopyBitmap() {
767da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
777da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
787da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
797da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        original.setImageViewBitmap(R.id.image, bitmap);
807da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews clone = original.clone();
817da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        View inflated = clone.apply(mContext, mContainer);
827da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
837da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        Drawable drawable = ((ImageView) inflated.findViewById(R.id.image)).getDrawable();
847da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        assertSame(bitmap, ((BitmapDrawable)drawable).getBitmap());
857da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    }
867da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
877da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    @Test
887da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    public void clone_originalCanStillBeApplied() {
897da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
907da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
917da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews clone = original.clone();
927da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
937da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        clone.apply(mContext, mContainer);
947da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    }
957da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
967da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    @Test
977da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    public void clone_clones() {
987da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
997da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1007da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews clone = original.clone();
1017da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        original.setTextViewText(R.id.text, "test");
1027da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        View inflated = clone.apply(mContext, mContainer);
1037da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1047da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        TextView textView = (TextView) inflated.findViewById(R.id.text);
1057da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        assertEquals("", textView.getText());
1067da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    }
1077da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1087da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    @Test
1097da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    public void clone_child_fails() {
1107da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
1117da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews child = new RemoteViews(mPackage, R.layout.remote_views_test);
1127da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1137da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        original.addView(R.id.layout, child);
1147da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1157da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        exception.expect(IllegalStateException.class);
1167da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews clone = child.clone();
1177da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    }
1187da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1197da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    @Test
1207da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    public void clone_repeatedly() {
1217da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
1227da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1237da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        original.clone();
1247da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        original.clone();
1257da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1267da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        original.apply(mContext, mContainer);
1277da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    }
1287da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1297da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    @Test
1307da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    public void clone_chained() {
1317da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
1327da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1337da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        RemoteViews clone = original.clone().clone();
1347da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1357da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos        clone.apply(mContext, mContainer);
1367da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos    }
1377da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos
1385d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    @Test
1395d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    public void parcelSize_nestedViews() {
1405d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);
1415d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        // We don't care about the actual layout id.
1425d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        RemoteViews child = new RemoteViews(mPackage, 33);
1435d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        int expectedSize = getParcelSize(original) + getParcelSize(child);
1445d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        original.addView(R.id.layout, child);
1455d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal
1465d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        // The application info will get written only once.
1475d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        assertTrue(getParcelSize(original) < expectedSize);
1485d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        assertEquals(getParcelSize(original), getParcelSize(original.clone()));
1495d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal
1505d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        original = new RemoteViews(mPackage, R.layout.remote_views_test);
1515d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        child = new RemoteViews(OTHER_PACKAGE, 33);
1525d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        expectedSize = getParcelSize(original) + getParcelSize(child);
1535d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        original.addView(R.id.layout, child);
1545d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal
1555d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        // Both the views will get written completely along with an additional view operation
1565d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        assertTrue(getParcelSize(original) > expectedSize);
1575d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        assertEquals(getParcelSize(original), getParcelSize(original.clone()));
1585d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    }
1595d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal
1605d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    @Test
1615d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    public void parcelSize_differentOrientation() {
1625d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        RemoteViews landscape = new RemoteViews(mPackage, R.layout.remote_views_test);
1635d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        RemoteViews portrait = new RemoteViews(mPackage, 33);
1645d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal
1655d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        // The application info will get written only once.
1665d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        RemoteViews views = new RemoteViews(landscape, portrait);
1675d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        assertTrue(getParcelSize(views) < (getParcelSize(landscape) + getParcelSize(portrait)));
1685d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        assertEquals(getParcelSize(views), getParcelSize(views.clone()));
1695d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    }
1705d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal
1715d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    private int getParcelSize(RemoteViews view) {
1725d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        Parcel parcel = Parcel.obtain();
1735d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        view.writeToParcel(parcel, 0);
1745d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        int size = parcel.dataSize();
1755d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        parcel.recycle();
1765d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal        return size;
1775d8bcdf6a575aa9e6eadb17e90ea21f5e4fc9c6bSunny Goyal    }
1787b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
1797b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    @Test
1807b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    public void asyncApply_fail() throws Exception {
1817b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_test_bad_1);
1827b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        ViewAppliedListener listener = new ViewAppliedListener();
1837b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
1847b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
185692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        exception.expect(Exception.class);
186692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        listener.waitAndGetView();
1877b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
1887b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
1897b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    @Test
1907b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    public void asyncApply() throws Exception {
1917b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
1927b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.setTextViewText(R.id.text, "Dummy");
1937b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
1947b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        View syncView = views.apply(mContext, mContainer);
1957b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
1967b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        ViewAppliedListener listener = new ViewAppliedListener();
1977b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
1987b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        View asyncView = listener.waitAndGetView();
1997b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2007b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        verifyViewTree(syncView, asyncView, "Dummy");
2017b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
2027b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2037b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    @Test
2047b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    public void asyncApply_viewStub() throws Exception {
2057b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_viewstub);
2067b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.setInt(R.id.viewStub, "setLayoutResource", R.layout.remote_views_text);
2077b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        // This will cause the view to be inflated
2087b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.setViewVisibility(R.id.viewStub, View.INVISIBLE);
2097b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.setTextViewText(R.id.stub_inflated, "Dummy");
2107b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2117b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        View syncView = views.apply(mContext, mContainer);
2127b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2137b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        ViewAppliedListener listener = new ViewAppliedListener();
2147b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
2157b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        View asyncView = listener.waitAndGetView();
2167b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2177b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        verifyViewTree(syncView, asyncView, "Dummy");
2187b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
2197b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2207b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    @Test
2217b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    public void asyncApply_nestedViews() throws Exception {
2227b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_host);
2237b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.removeAllViews(R.id.container);
2247b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.addView(R.id.container, createViewChained(1, "row1-c1", "row1-c2", "row1-c3"));
2257b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.addView(R.id.container, createViewChained(5, "row2-c1", "row2-c2"));
2267b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.addView(R.id.container, createViewChained(2, "row3-c1", "row3-c2"));
2277b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2287b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        View syncView = views.apply(mContext, mContainer);
2297b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2307b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        ViewAppliedListener listener = new ViewAppliedListener();
2317b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
2327b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        View asyncView = listener.waitAndGetView();
2337b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2347b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        verifyViewTree(syncView, asyncView,
2357b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal                "row1-c1", "row1-c2", "row1-c3", "row2-c1", "row2-c2", "row3-c1", "row3-c2");
2367b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
2377b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2387b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    @Test
2397b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    public void asyncApply_viewstub_nestedViews() throws Exception {
2407b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        RemoteViews viewstub = new RemoteViews(mPackage, R.layout.remote_views_viewstub);
2417b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        viewstub.setInt(R.id.viewStub, "setLayoutResource", R.layout.remote_view_host);
2427b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        // This will cause the view to be inflated
2437b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        viewstub.setViewVisibility(R.id.viewStub, View.INVISIBLE);
2447b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        viewstub.addView(R.id.stub_inflated, createViewChained(1, "row1-c1", "row1-c2", "row1-c3"));
2457b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2467b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_view_host);
2477b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.removeAllViews(R.id.container);
2487b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.addView(R.id.container, viewstub);
2497b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.addView(R.id.container, createViewChained(5, "row2-c1", "row2-c2"));
2507b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2517b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        View syncView = views.apply(mContext, mContainer);
2527b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2537b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        ViewAppliedListener listener = new ViewAppliedListener();
2547b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
2557b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        View asyncView = listener.waitAndGetView();
2567b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2577b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        verifyViewTree(syncView, asyncView, "row1-c1", "row1-c2", "row1-c3", "row2-c1", "row2-c2");
2587b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
2597b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2607b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    private RemoteViews createViewChained(int depth, String... texts) {
2617b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        RemoteViews result = new RemoteViews(mPackage, R.layout.remote_view_host);
2627b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2637b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        // Create depth
2647b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        RemoteViews parent = result;
2657b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        while(depth > 0) {
2667b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            depth--;
2677b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            RemoteViews child = new RemoteViews(mPackage, R.layout.remote_view_host);
2687b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            parent.addView(R.id.container, child);
2697b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            parent = child;
2707b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        }
2717b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2727b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        // Add texts
2737b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        for (String text : texts) {
2747b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            RemoteViews child = new RemoteViews(mPackage, R.layout.remote_views_text);
2757b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            child.setTextViewText(R.id.text, text);
2767b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            parent.addView(R.id.container, child);
2777b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        }
2787b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        return result;
2797b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
2807b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2817b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    private void verifyViewTree(View v1, View v2, String... texts) {
2827b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        ArrayList<String> expectedTexts = new ArrayList<>(Arrays.asList(texts));
2837b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        verifyViewTreeRecur(v1, v2, expectedTexts);
2847b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        // Verify that all expected texts were found
2857b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        assertEquals(0, expectedTexts.size());
2867b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
2877b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2887b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    private void verifyViewTreeRecur(View v1, View v2, ArrayList<String> expectedTexts) {
2897b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        assertEquals(v1.getClass(), v2.getClass());
2907b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
2917b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        if (v1 instanceof TextView) {
2927b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            String text = ((TextView) v1).getText().toString();
2937b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            assertEquals(text, ((TextView) v2).getText().toString());
2947b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            // Verify that the text was one of the expected texts and remove it from the list
2957b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            assertTrue(expectedTexts.remove(text));
2967b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        } else if (v1 instanceof ViewGroup) {
2977b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            ViewGroup vg1 = (ViewGroup) v1;
2987b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            ViewGroup vg2 = (ViewGroup) v2;
2997b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            assertEquals(vg1.getChildCount(), vg2.getChildCount());
3007b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            for (int i = vg1.getChildCount() - 1; i >= 0; i--) {
3017b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal                verifyViewTreeRecur(vg1.getChildAt(i), vg2.getChildAt(i), expectedTexts);
3027b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            }
3037b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        }
3047b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
3057b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
3067b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    private class ViewAppliedListener implements RemoteViews.OnViewAppliedListener {
3077b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
3087b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        private final CountDownLatch mLatch = new CountDownLatch(1);
3097b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        private View mView;
3107b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        private Exception mError;
3117b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
3127b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        @Override
3137b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        public void onViewApplied(View v) {
3147b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            mView = v;
3157b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            mLatch.countDown();
3167b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        }
3177b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
3187b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        @Override
3197b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        public void onError(Exception e) {
3207b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            mError = e;
3217b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            mLatch.countDown();
3227b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        }
3237b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
3247b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        public View waitAndGetView() throws Exception {
3257b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            mLatch.await();
3267b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal
3277b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            if (mError != null) {
3287b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal                throw new Exception(mError);
3297b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            }
3307b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal            return mView;
3317b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal        }
3327b0e2c7659c5abd9e452cc71a6dbe0fee1d8b12fSunny Goyal    }
333692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal
334692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal    @Test
335692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal    public void nestedAddViews() {
336692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
337692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        for (int i = 0; i < 10; i++) {
338692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal            RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
339692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal            parent.addView(R.id.layout, views);
340692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal            views = parent;
341692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        }
34256333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        // Both clone and parcel/unparcel work,
343692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        views.clone();
34456333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        parcelAndRecreate(views);
345692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal
346692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        views = new RemoteViews(mPackage, R.layout.remote_views_test);
347692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        for (int i = 0; i < 11; i++) {
348692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal            RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
349692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal            parent.addView(R.id.layout, views);
350692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal            views = parent;
351692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        }
35256333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        // Clone works but parcel/unparcel fails
353692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        views.clone();
35456333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        exception.expect(IllegalArgumentException.class);
35556333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        parcelAndRecreate(views);
356692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal    }
357692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal
358692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal    @Test
359692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal    public void nestedLandscapeViews() {
360692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
361692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        for (int i = 0; i < 10; i++) {
362692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal            views = new RemoteViews(views,
363692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal                    new RemoteViews(mPackage, R.layout.remote_views_test));
364692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        }
36556333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        // Both clone and parcel/unparcel work,
366692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        views.clone();
36756333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        parcelAndRecreate(views);
368692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal
369692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        views = new RemoteViews(mPackage, R.layout.remote_views_test);
370692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        for (int i = 0; i < 11; i++) {
37156333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal            views = new RemoteViews(views,
37256333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal                    new RemoteViews(mPackage, R.layout.remote_views_test));
373692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        }
37456333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        // Clone works but parcel/unparcel fails
375692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal        views.clone();
37656333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        exception.expect(IllegalArgumentException.class);
37756333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        parcelAndRecreate(views);
37856333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal    }
37956333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal
380fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos    private RemoteViews parcelAndRecreate(RemoteViews views) {
381fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        return parcelAndRecreateWithPendingIntentCookie(views, null);
382fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos    }
383fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos
384fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos    private RemoteViews parcelAndRecreateWithPendingIntentCookie(RemoteViews views, Object cookie) {
38556333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal        Parcel p = Parcel.obtain();
386fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        try {
387fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            views.writeToParcel(p, 0);
388fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            p.setDataPosition(0);
389fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos
390fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            if (cookie != null) {
391fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos                p.setClassCookie(PendingIntent.class, cookie);
392fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            }
39356333a872af40ecde7f71192c77393afc0afb1f3Sunny Goyal
394fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            return RemoteViews.CREATOR.createFromParcel(p);
395fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        } finally {
396fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            p.recycle();
397fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        }
398692f8c9324cc491d0778666830e6584a2d5ee7acSunny Goyal    }
3995b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal
4005b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal    @Test
4015b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal    public void copyWithBinders() throws Exception {
4025b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
4035b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal        for (int i = 1; i < 10; i++) {
4045b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal            PendingIntent pi = PendingIntent.getBroadcast(mContext, 0,
4055b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal                    new Intent("android.widget.RemoteViewsTest_" + i), PendingIntent.FLAG_ONE_SHOT);
4065b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal            views.setOnClickPendingIntent(i, pi);
4075b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal        }
4085b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal        try {
4095b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal            new RemoteViews(views);
4105b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal        } catch (Throwable t) {
4115b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal            throw new Exception(t);
4125b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal        }
4135b7689f287d3e5afc477ab58cdf9a62242789bd2Sunny Goyal    }
414fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos
415fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos    @Test
416fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos    public void copy_keepsPendingIntentWhitelistToken() throws Exception {
417fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        Binder whitelistToken = new Binder();
418fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos
419fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
420fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0,
421fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos                new Intent("test"), PendingIntent.FLAG_ONE_SHOT);
422fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        views.setOnClickPendingIntent(1, pi);
423fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        RemoteViews withCookie = parcelAndRecreateWithPendingIntentCookie(views, whitelistToken);
424fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos
425fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        RemoteViews cloned = new RemoteViews(withCookie);
426fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos
427fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        PendingIntent found = extractAnyPendingIntent(cloned);
428fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        assertEquals(whitelistToken, found.getWhitelistToken());
429fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos    }
430fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos
431fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos    private PendingIntent extractAnyPendingIntent(RemoteViews cloned) {
432fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        PendingIntent[] found = new PendingIntent[1];
433fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        Parcel p = Parcel.obtain();
434fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        try {
435fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            PendingIntent.setOnMarshaledListener((intent, parcel, flags) -> {
436fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos                if (parcel == p) {
437fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos                    found[0] = intent;
438fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos                }
439fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            });
440fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            cloned.writeToParcel(p, 0);
441fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        } finally {
442fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            p.recycle();
443fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos            PendingIntent.setOnMarshaledListener(null);
444fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        }
445fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos        return found[0];
446fb92184ebc7da516b8cb59932e1be6421879fa0aAdrian Roos    }
4477da889d81d2ff4c1704dc0a64389947fb30de5d8Adrian Roos}
448