Add tests for setOnCheckedChangePendingIntent
Bug: 179245670
Test: atest
Change-Id: I07450c7ec5644ba64df577c48235e3beaaf83855
diff --git a/tests/tests/appwidget/res/layout/remoteviews_adapter_item.xml b/tests/tests/appwidget/res/layout/remoteviews_adapter_item.xml
index ec621da..d9dbe8a 100644
--- a/tests/tests/appwidget/res/layout/remoteviews_adapter_item.xml
+++ b/tests/tests/appwidget/res/layout/remoteviews_adapter_item.xml
@@ -13,11 +13,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<TextView
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/item"
- android:layout_width="120dp"
- android:layout_height="120dp"
- android:gravity="center"
- android:textStyle="bold"
- android:textSize="44sp" />
+ android:id="@+id/root"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <Switch
+ android:id="@+id/toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+ <TextView
+ android:id="@+id/item"
+ android:layout_width="120dp"
+ android:layout_height="120dp"
+ android:gravity="center"
+ android:textStyle="bold"
+ android:textSize="44sp" />
+</LinearLayout>
+
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/CollectionAppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/CollectionAppWidgetTest.java
index 2bc4e47..925fa69 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/CollectionAppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/CollectionAppWidgetTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -40,7 +41,9 @@
import android.os.Bundle;
import android.platform.test.annotations.AppModeFull;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.AbsListView;
+import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
@@ -64,6 +67,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Predicate;
/**
* Test AppWidgets which host collection widgets.
@@ -164,7 +168,9 @@
extras.putString(BlockingBroadcastReceiver.KEY_PARAM, COUNTRY_LIST[position]);
Intent fillInIntent = new Intent();
fillInIntent.putExtras(extras);
- remoteViews.setOnClickFillInIntent(R.id.item, fillInIntent);
+ remoteViews.setOnClickFillInIntent(R.id.root, fillInIntent);
+ remoteViews.setOnCheckedChangeResponse(
+ R.id.toggle, RemoteViews.RemoteResponse.fromFillInIntent(fillInIntent));
if (position == 0) {
factoryCountDownLatch.countDown();
@@ -339,6 +345,82 @@
verifyItemClickIntents(3);
}
+ /**
+ * Verifies that setting the item at {@code index} to {@code newChecked} sends a broadcast with
+ * the proper country and checked extras filled in.
+ *
+ * @param index the index to test
+ * @param newChecked the new checked state, which must be different from the current value
+ */
+ private void verifyItemCheckedChangeIntents(int index, boolean newChecked) throws Throwable {
+ BlockingBroadcastReceiver receiver = new BlockingBroadcastReceiver();
+ mActivityRule.runOnUiThread(() -> receiver.register(BROADCAST_ACTION));
+
+ mStackView = (StackView) mAppWidgetHostView.findViewById(R.id.remoteViews_stack);
+ PollingCheck.waitFor(() -> mStackView.getCurrentView() != null);
+
+ mActivityRule.runOnUiThread(
+ () -> {
+ ViewGroup currentView = (ViewGroup) mStackView.getCurrentView();
+ CompoundButton toggle =
+ findFirstMatchingView(currentView, v -> v instanceof CompoundButton);
+ if (newChecked) {
+ assertFalse(toggle.isChecked());
+ } else {
+ assertTrue(toggle.isChecked());
+ }
+ toggle.setChecked(newChecked);
+ });
+ assertEquals(COUNTRY_LIST[index],
+ receiver.getParam(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ if (newChecked) {
+ assertTrue(receiver.result.getBooleanExtra(RemoteViews.EXTRA_CHECKED, false));
+ } else {
+ assertFalse(receiver.result.getBooleanExtra(RemoteViews.EXTRA_CHECKED, true));
+ }
+ }
+
+ @Test
+ public void testSetOnCheckedChangePendingIntent() throws Throwable {
+ if (!mHasAppWidgets) {
+ return;
+ }
+
+ // Toggle the view twice to get the true and false broadcasts.
+ verifyItemCheckedChangeIntents(0, true);
+ verifyItemCheckedChangeIntents(0, false);
+ verifyItemCheckedChangeIntents(0, true);
+
+ // Switch to another child
+ verifySetDisplayedChild(2);
+ verifyItemCheckedChangeIntents(2, true);
+
+ // And one more
+ verifyShowCommand(CollectionAppWidgetProvider.KEY_SHOW_NEXT, 3);
+ verifyItemCheckedChangeIntents(3, true);
+ }
+
+ // Casting type for convenience. Test will fail either way if it's wrong.
+ @SuppressWarnings("unchecked")
+ private static <T extends View> T findFirstMatchingView(View view, Predicate<View> predicate) {
+ if (predicate.test(view)) {
+ return (T) view;
+ }
+ if ((!(view instanceof ViewGroup))) {
+ return null;
+ }
+
+ ViewGroup viewGroup = (ViewGroup) view;
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ View result = findFirstMatchingView(viewGroup.getChildAt(i), predicate);
+ if (result != null) {
+ return (T) result;
+ }
+ }
+
+ return null;
+ }
+
private class ListScrollListener implements AbsListView.OnScrollListener {
private CountDownLatch mLatchToNotify;
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index d7d7438..a3d6bf7 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -30,8 +30,10 @@
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -50,6 +52,7 @@
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Chronometer;
+import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.FrameLayout;
@@ -719,6 +722,48 @@
}
@Test
+ public void testSetOnCheckedChangePendingIntent() throws Throwable {
+ String action = "my-checked-change-action";
+ MockBroadcastReceiver receiver = new MockBroadcastReceiver();
+ mContext.registerReceiver(receiver, new IntentFilter(action));
+
+ Intent intent = new Intent(action).setPackage(mContext.getPackageName());
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ mRemoteViews.setOnCheckedChangeResponse(R.id.remoteView_checkBox,
+ RemoteViews.RemoteResponse.fromPendingIntent(pendingIntent));
+
+ // View being checked to true should launch the intent with the extra set to true.
+ CompoundButton view = mResult.findViewById(R.id.remoteView_checkBox);
+ mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+ mActivityRule.runOnUiThread(() -> view.setChecked(true));
+ mInstrumentation.waitForIdleSync();
+ assertNotNull(receiver.mIntent);
+ assertTrue(receiver.mIntent.getBooleanExtra(RemoteViews.EXTRA_CHECKED, false));
+
+ // Changing the checked state from a RemoteViews action should not launch the intent.
+ receiver.mIntent = null;
+ mRemoteViews.setCompoundButtonChecked(R.id.remoteView_checkBox, false);
+ mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+ mInstrumentation.waitForIdleSync();
+ assertFalse(view.isChecked());
+ assertNull(receiver.mIntent);
+
+ // View being checked to false should launch the intent with the extra set to false.
+ receiver.mIntent = null;
+ mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
+ mActivityRule.runOnUiThread(() -> view.setChecked(true));
+ mActivityRule.runOnUiThread(() -> view.setChecked(false));
+ mInstrumentation.waitForIdleSync();
+ assertNotNull(receiver.mIntent);
+ assertFalse(receiver.mIntent.getBooleanExtra(RemoteViews.EXTRA_CHECKED, true));
+ }
+
+ @Test
public void testSetLong() throws Throwable {
long base1 = 50;
long base2 = -50;
@@ -1189,4 +1234,14 @@
}
}
}
+
+ private static final class MockBroadcastReceiver extends BroadcastReceiver {
+
+ Intent mIntent;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mIntent = intent;
+ }
+ }
}