1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.widget.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertSame;
24 import static org.junit.Assert.assertTrue;
25 
26 import android.app.Activity;
27 import android.app.Instrumentation;
28 import android.app.Instrumentation.ActivityMonitor;
29 import android.app.PendingIntent;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.res.ColorStateList;
33 import android.graphics.Bitmap;
34 import android.graphics.BitmapFactory;
35 import android.graphics.drawable.BitmapDrawable;
36 import android.graphics.drawable.Icon;
37 import android.net.Uri;
38 import android.os.Bundle;
39 import android.os.Parcel;
40 import android.text.TextUtils;
41 import android.util.TypedValue;
42 import android.view.View;
43 import android.view.ViewGroup;
44 import android.widget.AbsoluteLayout;
45 import android.widget.AnalogClock;
46 import android.widget.Button;
47 import android.widget.Chronometer;
48 import android.widget.DatePicker;
49 import android.widget.EditText;
50 import android.widget.FrameLayout;
51 import android.widget.GridLayout;
52 import android.widget.GridView;
53 import android.widget.ImageButton;
54 import android.widget.ImageView;
55 import android.widget.LinearLayout;
56 import android.widget.ListView;
57 import android.widget.NumberPicker;
58 import android.widget.ProgressBar;
59 import android.widget.RatingBar;
60 import android.widget.RelativeLayout;
61 import android.widget.RemoteViews;
62 import android.widget.RemoteViews.ActionException;
63 import android.widget.SeekBar;
64 import android.widget.StackView;
65 import android.widget.TextClock;
66 import android.widget.TextView;
67 import android.widget.ViewFlipper;
68 import android.widget.cts.util.TestUtils;
69 
70 import androidx.test.InstrumentationRegistry;
71 import androidx.test.annotation.UiThreadTest;
72 import androidx.test.filters.LargeTest;
73 import androidx.test.filters.MediumTest;
74 import androidx.test.rule.ActivityTestRule;
75 import androidx.test.runner.AndroidJUnit4;
76 
77 import com.android.compatibility.common.util.WidgetTestUtils;
78 
79 import org.junit.Before;
80 import org.junit.Rule;
81 import org.junit.Test;
82 import org.junit.rules.ExpectedException;
83 import org.junit.runner.RunWith;
84 
85 import java.io.File;
86 import java.io.FileOutputStream;
87 import java.io.IOException;
88 import java.io.InputStream;
89 import java.io.OutputStream;
90 
91 /**
92  * Test {@link RemoteViews}.
93  */
94 @MediumTest
95 @RunWith(AndroidJUnit4.class)
96 public class RemoteViewsTest {
97     private static final String PACKAGE_NAME = "android.widget.cts";
98 
99     private static final int INVALID_ID = -1;
100 
101     private static final long TEST_TIMEOUT = 5000;
102 
103     @Rule
104     public ActivityTestRule<RemoteViewsCtsActivity> mActivityRule =
105             new ActivityTestRule<>(RemoteViewsCtsActivity.class);
106 
107     @Rule
108     public ExpectedException mExpectedException = ExpectedException.none();
109 
110     private Instrumentation mInstrumentation;
111 
112     private Context mContext;
113 
114     private RemoteViews mRemoteViews;
115 
116     private View mResult;
117 
118     @UiThreadTest
119     @Before
setup()120     public void setup() {
121         mInstrumentation = InstrumentationRegistry.getInstrumentation();
122         mContext = mInstrumentation.getTargetContext();
123         mRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
124         mResult = mRemoteViews.apply(mContext, null);
125 
126         // Add our host view to the activity behind this test. This is similar to how launchers
127         // add widgets to the on-screen UI.
128         ViewGroup root = (ViewGroup) mActivityRule.getActivity().findViewById
129                 (R.id.remoteView_host);
130         FrameLayout.MarginLayoutParams lp = new FrameLayout.MarginLayoutParams(
131                 ViewGroup.LayoutParams.MATCH_PARENT,
132                 ViewGroup.LayoutParams.MATCH_PARENT);
133         mResult.setLayoutParams(lp);
134 
135         root.addView(mResult);
136     }
137 
138     @Test
testConstructor()139     public void testConstructor() {
140         new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
141 
142         new RemoteViews(Parcel.obtain());
143     }
144 
145     @Test
testGetPackage()146     public void testGetPackage() {
147         assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
148 
149         mRemoteViews = new RemoteViews(null, R.layout.remoteviews_good);
150         assertNull(mRemoteViews.getPackage());
151     }
152 
153     @Test
testGetLayoutId()154     public void testGetLayoutId() {
155         assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId());
156 
157         mRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
158         assertEquals(R.layout.listview_layout, mRemoteViews.getLayoutId());
159 
160         mRemoteViews = new RemoteViews(PACKAGE_NAME, INVALID_ID);
161         assertEquals(INVALID_ID, mRemoteViews.getLayoutId());
162 
163         mRemoteViews = new RemoteViews(PACKAGE_NAME, 0);
164         assertEquals(0, mRemoteViews.getLayoutId());
165     }
166 
167     @Test
testSetContentDescription()168     public void testSetContentDescription() throws Throwable {
169         View view = mResult.findViewById(R.id.remoteView_frame);
170 
171         assertNull(view.getContentDescription());
172 
173         CharSequence contentDescription = mContext.getString(R.string.remote_content_description);
174         mRemoteViews.setContentDescription(R.id.remoteView_frame, contentDescription);
175         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
176         assertTrue(TextUtils.equals(contentDescription, view.getContentDescription()));
177     }
178 
179     @Test
testSetViewVisibility()180     public void testSetViewVisibility() throws Throwable {
181         View view = mResult.findViewById(R.id.remoteView_chronometer);
182         assertEquals(View.VISIBLE, view.getVisibility());
183 
184         mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.INVISIBLE);
185         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
186         assertEquals(View.INVISIBLE, view.getVisibility());
187 
188         mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.GONE);
189         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
190         assertEquals(View.GONE, view.getVisibility());
191 
192         mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.VISIBLE);
193         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
194         assertEquals(View.VISIBLE, view.getVisibility());
195     }
196 
197     @Test
testSetTextViewText()198     public void testSetTextViewText() throws Throwable {
199         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
200         assertEquals("", textView.getText().toString());
201 
202         String expected = "This is content";
203         mRemoteViews.setTextViewText(R.id.remoteView_text, expected);
204         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
205         assertEquals(expected, textView.getText().toString());
206 
207         mRemoteViews.setTextViewText(R.id.remoteView_text, null);
208         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
209         assertEquals("", textView.getText().toString());
210 
211         mExpectedException.expect(ActionException.class);
212         mRemoteViews.setTextViewText(R.id.remoteView_absolute, "");
213         mRemoteViews.reapply(mContext, mResult);
214     }
215 
216     @Test
testSetTextViewTextSize()217     public void testSetTextViewTextSize() throws Throwable {
218         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
219 
220         mRemoteViews.setTextViewTextSize(R.id.remoteView_text, TypedValue.COMPLEX_UNIT_SP, 18);
221         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
222         assertEquals(mContext.getResources().getDisplayMetrics().scaledDensity * 18,
223                 textView.getTextSize(), 0.001f);
224 
225         mExpectedException.expect(Throwable.class);
226         mRemoteViews.setTextViewTextSize(R.id.remoteView_absolute, TypedValue.COMPLEX_UNIT_SP, 20);
227         mRemoteViews.reapply(mContext, mResult);
228     }
229 
230     @Test
testSetIcon()231     public void testSetIcon() throws Throwable {
232         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
233         assertNull(image.getDrawable());
234 
235         Icon iconBlack = Icon.createWithResource(mContext, R.drawable.icon_black);
236         mRemoteViews.setIcon(R.id.remoteView_image, "setImageIcon", iconBlack);
237         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
238         assertNotNull(image.getDrawable());
239         BitmapDrawable dBlack = (BitmapDrawable) mContext.getDrawable(R.drawable.icon_black);
240         WidgetTestUtils.assertEquals(dBlack.getBitmap(),
241                 ((BitmapDrawable) image.getDrawable()).getBitmap());
242     }
243 
244     @Test
testSetImageViewIcon()245     public void testSetImageViewIcon() throws Throwable {
246         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
247         assertNull(image.getDrawable());
248 
249         Icon iconBlue = Icon.createWithResource(mContext, R.drawable.icon_blue);
250         mRemoteViews.setImageViewIcon(R.id.remoteView_image, iconBlue);
251         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
252         assertNotNull(image.getDrawable());
253         BitmapDrawable dBlue = (BitmapDrawable) mContext.getDrawable(R.drawable.icon_blue);
254         WidgetTestUtils.assertEquals(dBlue.getBitmap(),
255                 ((BitmapDrawable) image.getDrawable()).getBitmap());
256 
257     }
258 
259     @Test
testSetImageViewResource()260     public void testSetImageViewResource() throws Throwable {
261         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
262         assertNull(image.getDrawable());
263 
264         mRemoteViews.setImageViewResource(R.id.remoteView_image, R.drawable.testimage);
265         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
266         assertNotNull(image.getDrawable());
267         BitmapDrawable d = (BitmapDrawable) mContext.getDrawable(R.drawable.testimage);
268         WidgetTestUtils.assertEquals(d.getBitmap(),
269                 ((BitmapDrawable) image.getDrawable()).getBitmap());
270 
271         mExpectedException.expect(ActionException.class);
272         mRemoteViews.setImageViewResource(R.id.remoteView_absolute, R.drawable.testimage);
273         mRemoteViews.reapply(mContext, mResult);
274     }
275 
276     @Test
testSetImageViewUri()277     public void testSetImageViewUri() throws Throwable {
278         String path = getTestImagePath();
279         File imageFile = new File(path);
280 
281         try {
282             createSampleImage(imageFile, R.raw.testimage);
283 
284             Uri uri = Uri.parse(path);
285             ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
286             assertNull(image.getDrawable());
287 
288             mRemoteViews.setImageViewUri(R.id.remoteView_image, uri);
289             mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
290 
291             Bitmap imageViewBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
292             Bitmap expectedBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
293                     mContext.getResources(), R.raw.testimage, imageViewBitmap.getConfig());
294             WidgetTestUtils.assertEquals(expectedBitmap, imageViewBitmap);
295         } finally {
296             imageFile.delete();
297         }
298     }
299 
300     /**
301      * Returns absolute file path of location where test image should be stored
302      */
getTestImagePath()303     private String getTestImagePath() {
304         return mContext.getFilesDir() + "/test.jpg";
305     }
306 
307     @Test
testSetChronometer()308     public void testSetChronometer() throws Throwable {
309         long base1 = 50;
310         long base2 = -50;
311         Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
312 
313         mRemoteViews.setChronometer(R.id.remoteView_chronometer, base1, "HH:MM:SS",
314                 false);
315         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
316         assertEquals(base1, chronometer.getBase());
317         assertEquals("HH:MM:SS", chronometer.getFormat());
318 
319         mRemoteViews.setChronometer(R.id.remoteView_chronometer, base2, "HH:MM:SS",
320                 false);
321         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
322         assertEquals(base2, chronometer.getBase());
323         assertEquals("HH:MM:SS", chronometer.getFormat());
324 
325         mRemoteViews.setChronometer(R.id.remoteView_chronometer, base1, "invalid",
326                 true);
327         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
328         assertEquals(base1, chronometer.getBase());
329         assertEquals("invalid", chronometer.getFormat());
330 
331         mExpectedException.expect(ActionException.class);
332         mRemoteViews.setChronometer(R.id.remoteView_absolute, base1, "invalid", true);
333         mRemoteViews.reapply(mContext, mResult);
334     }
335 
336     @Test
testSetChronometerCountDown()337     public void testSetChronometerCountDown() throws Throwable {
338         Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
339 
340         mRemoteViews.setChronometerCountDown(R.id.remoteView_chronometer, true);
341         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
342         assertTrue(chronometer.isCountDown());
343 
344         mRemoteViews.setChronometerCountDown(R.id.remoteView_chronometer, false);
345         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
346         assertFalse(chronometer.isCountDown());
347 
348         mExpectedException.expect(ActionException.class);
349         mRemoteViews.setChronometerCountDown(R.id.remoteView_absolute, true);
350         mRemoteViews.reapply(mContext, mResult);
351     }
352 
353     @Test
testSetProgressBar()354     public void testSetProgressBar() throws Throwable {
355         ProgressBar progress = (ProgressBar) mResult.findViewById(R.id.remoteView_progress);
356         assertEquals(100, progress.getMax());
357         assertEquals(0, progress.getProgress());
358         // the view uses style progressBarHorizontal, so the default is false
359         assertFalse(progress.isIndeterminate());
360 
361         mRemoteViews.setProgressBar(R.id.remoteView_progress, 80, 50, true);
362         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
363         // make the bar indeterminate will not affect max and progress
364         assertEquals(100, progress.getMax());
365         assertEquals(0, progress.getProgress());
366         assertTrue(progress.isIndeterminate());
367 
368         mRemoteViews.setProgressBar(R.id.remoteView_progress, 60, 50, false);
369         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
370         assertEquals(60, progress.getMax());
371         assertEquals(50, progress.getProgress());
372         assertFalse(progress.isIndeterminate());
373 
374         mExpectedException.expect(ActionException.class);
375         mRemoteViews.setProgressBar(R.id.remoteView_relative, 60, 50, false);
376         mRemoteViews.reapply(mContext, mResult);
377     }
378 
379     @Test
testApply()380     public void testApply() {
381         assertNotNull(mResult);
382         assertNotNull(mResult.findViewById(R.id.remoteViews_good));
383         assertNotNull(mResult.findViewById(R.id.remoteView_absolute));
384         assertNotNull(mResult.findViewById(R.id.remoteView_chronometer));
385         assertNotNull(mResult.findViewById(R.id.remoteView_frame));
386         assertNotNull(mResult.findViewById(R.id.remoteView_image));
387         assertNotNull(mResult.findViewById(R.id.remoteView_linear));
388         assertNotNull(mResult.findViewById(R.id.remoteView_progress));
389         assertNotNull(mResult.findViewById(R.id.remoteView_relative));
390         assertNotNull(mResult.findViewById(R.id.remoteView_text));
391     }
392 
393     @Test
testReapply()394     public void testReapply() throws Throwable {
395         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
396         assertNull(image.getDrawable());
397 
398         mRemoteViews.setImageViewResource(R.id.remoteView_image, R.drawable.testimage);
399         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, image));
400         assertNotNull(image.getDrawable());
401         BitmapDrawable d = (BitmapDrawable) mContext
402                 .getResources().getDrawable(R.drawable.testimage);
403         WidgetTestUtils.assertEquals(d.getBitmap(),
404                 ((BitmapDrawable) image.getDrawable()).getBitmap());
405     }
406 
407     @Test
testOnLoadClass()408     public void testOnLoadClass() {
409         mRemoteViews = new RemoteViews(Parcel.obtain());
410 
411         assertTrue(mRemoteViews.onLoadClass(AbsoluteLayout.class));
412         assertTrue(mRemoteViews.onLoadClass(AnalogClock.class));
413         assertTrue(mRemoteViews.onLoadClass(Button.class));
414         assertTrue(mRemoteViews.onLoadClass(Chronometer.class));
415         assertTrue(mRemoteViews.onLoadClass(FrameLayout.class));
416         assertTrue(mRemoteViews.onLoadClass(GridLayout.class));
417         assertTrue(mRemoteViews.onLoadClass(GridView.class));
418         assertTrue(mRemoteViews.onLoadClass(ImageButton.class));
419         assertTrue(mRemoteViews.onLoadClass(ImageView.class));
420         assertTrue(mRemoteViews.onLoadClass(LinearLayout.class));
421         assertTrue(mRemoteViews.onLoadClass(ListView.class));
422         assertTrue(mRemoteViews.onLoadClass(ProgressBar.class));
423         assertTrue(mRemoteViews.onLoadClass(RelativeLayout.class));
424         assertTrue(mRemoteViews.onLoadClass(StackView.class));
425         assertTrue(mRemoteViews.onLoadClass(TextClock.class));
426         assertTrue(mRemoteViews.onLoadClass(TextView.class));
427         assertTrue(mRemoteViews.onLoadClass(ViewFlipper.class));
428 
429         // those classes without annotation @RemoteView
430         assertFalse(mRemoteViews.onLoadClass(EditText.class));
431         assertFalse(mRemoteViews.onLoadClass(DatePicker.class));
432         assertFalse(mRemoteViews.onLoadClass(NumberPicker.class));
433         assertFalse(mRemoteViews.onLoadClass(RatingBar.class));
434         assertFalse(mRemoteViews.onLoadClass(SeekBar.class));
435     }
436 
437     @Test
testDescribeContents()438     public void testDescribeContents() {
439         mRemoteViews = new RemoteViews(Parcel.obtain());
440         mRemoteViews.describeContents();
441     }
442 
443     @Test
testWriteToParcel()444     public void testWriteToParcel() {
445         mRemoteViews.setTextViewText(R.id.remoteView_text, "This is content");
446         mRemoteViews.setViewVisibility(R.id.remoteView_frame, View.GONE);
447         Parcel p = Parcel.obtain();
448         mRemoteViews.writeToParcel(p, 0);
449         p.setDataPosition(0);
450 
451         // the package and layout are successfully written into parcel
452         mRemoteViews = RemoteViews.CREATOR.createFromParcel(p);
453         View result = mRemoteViews.apply(mContext, null);
454         assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
455         assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId());
456         assertEquals("This is content", ((TextView) result.findViewById(R.id.remoteView_text))
457                 .getText().toString());
458         assertEquals(View.GONE, result.findViewById(R.id.remoteView_frame).getVisibility());
459 
460         p = Parcel.obtain();
461 
462         // currently the flag is not used
463         mRemoteViews.writeToParcel(p, -1);
464 
465         p.recycle();
466 
467         RemoteViews[] remote = RemoteViews.CREATOR.newArray(1);
468         assertNotNull(remote);
469         assertEquals(1, remote.length);
470     }
471 
472     @Test(expected=NullPointerException.class)
testWriteNullToParcel()473     public void testWriteNullToParcel() {
474         mRemoteViews.writeToParcel(null, 0);
475     }
476 
477     @Test(expected=NegativeArraySizeException.class)
testCreateNegativeSizedArray()478     public void testCreateNegativeSizedArray() {
479         RemoteViews.CREATOR.newArray(-1);
480     }
481 
482     @Test
testSetImageViewBitmap()483     public void testSetImageViewBitmap() throws Throwable {
484         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
485         assertNull(image.getDrawable());
486 
487         Bitmap bitmap =
488                 BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage);
489         mRemoteViews.setImageViewBitmap(R.id.remoteView_image, bitmap);
490         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
491         assertNotNull(image.getDrawable());
492         WidgetTestUtils.assertEquals(bitmap, ((BitmapDrawable) image.getDrawable()).getBitmap());
493 
494         mExpectedException.expect(ActionException.class);
495         mRemoteViews.setImageViewBitmap(R.id.remoteView_absolute, bitmap);
496         mRemoteViews.reapply(mContext, mResult);
497     }
498 
499     @Test
testSetBitmap()500     public void testSetBitmap() throws Throwable {
501         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
502         assertNull(image.getDrawable());
503 
504         Bitmap bitmap =
505                 BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage);
506         mRemoteViews.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap);
507         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
508         assertNotNull(image.getDrawable());
509         WidgetTestUtils.assertEquals(bitmap, ((BitmapDrawable) image.getDrawable()).getBitmap());
510 
511         mExpectedException.expect(ActionException.class);
512         mRemoteViews.setBitmap(R.id.remoteView_absolute, "setImageBitmap", bitmap);
513         mRemoteViews.reapply(mContext, mResult);
514     }
515 
516     @Test
testSetBoolean()517     public void testSetBoolean() throws Throwable {
518         ProgressBar progress = (ProgressBar) mResult.findViewById(R.id.remoteView_progress);
519         // the view uses style progressBarHorizontal, so the default is false
520         assertFalse(progress.isIndeterminate());
521 
522         mRemoteViews.setBoolean(R.id.remoteView_progress, "setIndeterminate", true);
523         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
524         assertTrue(progress.isIndeterminate());
525 
526         mExpectedException.expect(ActionException.class);
527         mRemoteViews.setBoolean(R.id.remoteView_relative, "setIndeterminate", false);
528         mRemoteViews.reapply(mContext, mResult);
529     }
530 
531     @Test
testSetCharSequence()532     public void testSetCharSequence() throws Throwable {
533         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
534         assertEquals("", textView.getText().toString());
535 
536         String expected = "test setCharSequence";
537         mRemoteViews.setCharSequence(R.id.remoteView_text, "setText", expected);
538         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
539         assertEquals(expected, textView.getText().toString());
540 
541         mRemoteViews.setCharSequence(R.id.remoteView_text, "setText", null);
542         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
543         assertEquals("", textView.getText().toString());
544 
545         mExpectedException.expect(ActionException.class);
546         mRemoteViews.setCharSequence(R.id.remoteView_absolute, "setText", "");
547         mRemoteViews.reapply(mContext, mResult);
548     }
549 
550     @Test
testSetInt()551     public void testSetInt() throws Throwable {
552         View view = mResult.findViewById(R.id.remoteView_chronometer);
553         assertEquals(View.VISIBLE, view.getVisibility());
554 
555         mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.INVISIBLE);
556         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
557         assertEquals(View.INVISIBLE, view.getVisibility());
558 
559         mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.GONE);
560         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
561         assertEquals(View.GONE, view.getVisibility());
562 
563         mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.VISIBLE);
564         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
565         assertEquals(View.VISIBLE, view.getVisibility());
566     }
567 
568     @Test
testSetString()569     public void testSetString() throws Throwable {
570         String format = "HH:MM:SS";
571         Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
572         assertNull(chronometer.getFormat());
573 
574         mRemoteViews.setString(R.id.remoteView_chronometer, "setFormat", format);
575         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
576         assertEquals(format, chronometer.getFormat());
577 
578         mExpectedException.expect(ActionException.class);
579         mRemoteViews.setString(R.id.remoteView_image, "setFormat", format);
580         mRemoteViews.reapply(mContext, mResult);
581     }
582 
583     @Test
testSetUri()584     public void testSetUri() throws Throwable {
585         String path = getTestImagePath();
586         File imagefile = new File(path);
587 
588         try {
589             createSampleImage(imagefile, R.raw.testimage);
590 
591             Uri uri = Uri.parse(path);
592             ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
593             assertNull(image.getDrawable());
594 
595             mRemoteViews.setUri(R.id.remoteView_image, "setImageURI", uri);
596             mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
597 
598             Bitmap imageViewBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap();
599             Bitmap expectedBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
600                     mContext.getResources(), R.raw.testimage, imageViewBitmap.getConfig());
601             WidgetTestUtils.assertEquals(expectedBitmap, imageViewBitmap);
602 
603             mExpectedException.expect(ActionException.class);
604             mRemoteViews.setUri(R.id.remoteView_absolute, "setImageURI", uri);
605             mRemoteViews.reapply(mContext, mResult);
606         } finally {
607             // remove the test image file
608             imagefile.delete();
609         }
610     }
611 
612     @Test
testSetTextColor()613     public void testSetTextColor() throws Throwable {
614         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
615 
616         mRemoteViews.setTextColor(R.id.remoteView_text, R.color.testcolor1);
617         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
618         assertSame(ColorStateList.valueOf(R.color.testcolor1), textView.getTextColors());
619 
620         mRemoteViews.setTextColor(R.id.remoteView_text, R.color.testcolor2);
621         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
622         assertSame(ColorStateList.valueOf(R.color.testcolor2), textView.getTextColors());
623 
624         mExpectedException.expect(ActionException.class);
625         mRemoteViews.setTextColor(R.id.remoteView_absolute, R.color.testcolor1);
626         mRemoteViews.reapply(mContext, mResult);
627     }
628 
629     @Test
testSetTextCompoundDrawables()630     public void testSetTextCompoundDrawables() throws Throwable {
631         TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text);
632 
633         TestUtils.verifyCompoundDrawables(textView, -1, -1, -1, -1);
634 
635         mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_text, R.drawable.start,
636                 R.drawable.pass, R.drawable.failed, 0);
637         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
638         TestUtils.verifyCompoundDrawables(textView, R.drawable.start, R.drawable.failed,
639                 R.drawable.pass, -1);
640 
641         mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_text, 0,
642                 R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green);
643         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
644         TestUtils.verifyCompoundDrawables(textView, -1,  R.drawable.icon_red, R.drawable.icon_black,
645                 R.drawable.icon_green);
646 
647         mExpectedException.expect(Throwable.class);
648         mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_absolute, 0,
649                 R.drawable.start, R.drawable.failed, 0);
650         mRemoteViews.reapply(mContext, mResult);
651     }
652 
653     @Test
testSetTextCompoundDrawablesRelative()654     public void testSetTextCompoundDrawablesRelative() throws Throwable {
655         TextView textViewLtr = (TextView) mResult.findViewById(R.id.remoteView_text_ltr);
656         TextView textViewRtl = (TextView) mResult.findViewById(R.id.remoteView_text_rtl);
657 
658         TestUtils.verifyCompoundDrawables(textViewLtr, -1, -1, -1, -1);
659         TestUtils.verifyCompoundDrawables(textViewRtl, -1, -1, -1, -1);
660 
661         mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_ltr,
662                 R.drawable.start, R.drawable.pass, R.drawable.failed, 0);
663         mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_rtl,
664                 R.drawable.start, R.drawable.pass, R.drawable.failed, 0);
665         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
666         TestUtils.verifyCompoundDrawables(textViewLtr, R.drawable.start, R.drawable.failed,
667                 R.drawable.pass, -1);
668         TestUtils.verifyCompoundDrawables(textViewRtl, R.drawable.failed, R.drawable.start,
669                 R.drawable.pass, -1);
670 
671         mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_ltr, 0,
672                 R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green);
673         mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_rtl, 0,
674                 R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green);
675         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
676         TestUtils.verifyCompoundDrawables(textViewLtr, -1, R.drawable.icon_red,
677                 R.drawable.icon_black, R.drawable.icon_green);
678         TestUtils.verifyCompoundDrawables(textViewRtl, R.drawable.icon_red, -1,
679                 R.drawable.icon_black, R.drawable.icon_green);
680 
681         mExpectedException.expect(Throwable.class);
682         mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_absolute, 0,
683                 R.drawable.start, R.drawable.failed, 0);
684         mRemoteViews.reapply(mContext, mResult);
685     }
686 
687     @LargeTest
688     @Test
testSetOnClickPendingIntent()689     public void testSetOnClickPendingIntent() throws Throwable {
690         Uri uri = Uri.parse("ctstest://RemoteView/test");
691         ActivityMonitor am = mInstrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
692                 null, false);
693         View view = mResult.findViewById(R.id.remoteView_image);
694         view.performClick();
695         Activity newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT);
696         assertNull(newActivity);
697 
698         Intent intent = new Intent(Intent.ACTION_VIEW, uri);
699         PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
700         mRemoteViews.setOnClickPendingIntent(R.id.remoteView_image, pendingIntent);
701         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
702         mActivityRule.runOnUiThread(() -> view.performClick());
703         newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT);
704         assertNotNull(newActivity);
705         assertTrue(newActivity instanceof MockURLSpanTestActivity);
706         newActivity.finish();
707     }
708 
709     @Test
testSetLong()710     public void testSetLong() throws Throwable {
711         long base1 = 50;
712         long base2 = -50;
713         Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer);
714 
715         mRemoteViews.setLong(R.id.remoteView_chronometer, "setBase", base1);
716         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
717         assertEquals(base1, chronometer.getBase());
718 
719         mRemoteViews.setLong(R.id.remoteView_chronometer, "setBase", base2);
720         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
721         assertEquals(base2, chronometer.getBase());
722 
723         mExpectedException.expect(ActionException.class);
724         mRemoteViews.setLong(R.id.remoteView_absolute, "setBase", base1);
725         mRemoteViews.reapply(mContext, mResult);
726     }
727 
728     @Test
testSetFloat()729     public void testSetFloat() throws Throwable {
730         LinearLayout linearLayout = (LinearLayout) mResult.findViewById(R.id.remoteView_linear);
731         assertTrue(linearLayout.getWeightSum() <= 0.0f);
732 
733         mRemoteViews.setFloat(R.id.remoteView_linear, "setWeightSum", 0.5f);
734         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
735         assertEquals(0.5f, linearLayout.getWeightSum(), 0.001f);
736 
737         mExpectedException.expect(ActionException.class);
738         mRemoteViews.setFloat(R.id.remoteView_absolute, "setWeightSum", 1.0f);
739         mRemoteViews.reapply(mContext, mResult);
740     }
741 
742     @Test
testSetByte()743     public void testSetByte() throws Throwable {
744         MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
745         assertEquals(0, customView.getByteField());
746 
747         byte b = 100;
748         mRemoteViews.setByte(R.id.remoteView_custom, "setByteField", b);
749         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
750         assertEquals(b, customView.getByteField());
751 
752         mExpectedException.expect(ActionException.class);
753         mRemoteViews.setByte(R.id.remoteView_absolute, "setByteField", b);
754         mRemoteViews.reapply(mContext, mResult);
755     }
756 
757     @Test
testSetChar()758     public void testSetChar() throws Throwable {
759         MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
760         assertEquals('\u0000', customView.getCharField());
761 
762         mRemoteViews.setChar(R.id.remoteView_custom, "setCharField", 'q');
763         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
764         assertEquals('q', customView.getCharField());
765 
766         mExpectedException.expect(ActionException.class);
767         mRemoteViews.setChar(R.id.remoteView_absolute, "setCharField", 'w');
768         mRemoteViews.reapply(mContext, mResult);
769     }
770 
771     @Test
testSetDouble()772     public void testSetDouble() throws Throwable {
773         MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
774         assertEquals(0.0, customView.getDoubleField(), 0.0f);
775 
776         mRemoteViews.setDouble(R.id.remoteView_custom, "setDoubleField", 0.5);
777         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
778         assertEquals(0.5, customView.getDoubleField(), 0.001f);
779 
780         mExpectedException.expect(ActionException.class);
781         mRemoteViews.setDouble(R.id.remoteView_absolute, "setDoubleField", 1.0);
782         mRemoteViews.reapply(mContext, mResult);
783     }
784 
785     @Test
testSetShort()786     public void testSetShort() throws Throwable {
787         MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
788         assertEquals(0, customView.getShortField());
789 
790         short s = 25;
791         mRemoteViews.setShort(R.id.remoteView_custom, "setShortField", s);
792         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
793         assertEquals(s, customView.getShortField());
794 
795         mExpectedException.expect(ActionException.class);
796         mRemoteViews.setShort(R.id.remoteView_absolute, "setShortField", s);
797         mRemoteViews.reapply(mContext, mResult);
798     }
799 
800     @Test
testSetBundle()801     public void testSetBundle() throws Throwable {
802         MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
803         assertNull(customView.getBundleField());
804 
805         final Bundle bundle = new Bundle();
806         bundle.putString("STR", "brexit");
807         bundle.putInt("INT", 2016);
808         mRemoteViews.setBundle(R.id.remoteView_custom, "setBundleField", bundle);
809         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
810         final Bundle fromRemote = customView.getBundleField();
811         assertEquals("brexit", fromRemote.getString("STR", ""));
812         assertEquals(2016, fromRemote.getInt("INT", 0));
813 
814         mExpectedException.expect(ActionException.class);
815         mRemoteViews.setBundle(R.id.remoteView_absolute, "setBundleField", bundle);
816         mRemoteViews.reapply(mContext, mResult);
817     }
818 
819     @Test
testSetIntent()820     public void testSetIntent() throws Throwable {
821         MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom);
822         assertNull(customView.getIntentField());
823 
824         final Intent intent = new Intent(mContext, SwitchCtsActivity.class);
825         intent.putExtra("STR", "brexit");
826         intent.putExtra("INT", 2016);
827         mRemoteViews.setIntent(R.id.remoteView_custom, "setIntentField", intent);
828         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
829         final Intent fromRemote = customView.getIntentField();
830         assertEquals(SwitchCtsActivity.class.getName(), fromRemote.getComponent().getClassName());
831         assertEquals("brexit", fromRemote.getStringExtra("STR"));
832         assertEquals(2016, fromRemote.getIntExtra("INT", 0));
833 
834         mExpectedException.expect(ActionException.class);
835         mRemoteViews.setIntent(R.id.remoteView_absolute, "setIntentField", intent);
836         mRemoteViews.reapply(mContext, mResult);
837     }
838 
839     @Test
testRemoveAllViews()840     public void testRemoveAllViews() throws Throwable {
841         ViewGroup root = (ViewGroup) mResult.findViewById(R.id.remoteViews_good);
842         assertTrue(root.getChildCount() > 0);
843 
844         mRemoteViews.removeAllViews(R.id.remoteViews_good);
845         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
846         assertEquals(0, root.getChildCount());
847     }
848 
849     @Test
testAddView()850     public void testAddView() throws Throwable {
851         ViewGroup root = (ViewGroup) mResult.findViewById(R.id.remoteViews_good);
852         int originalChildCount = root.getChildCount();
853 
854         assertNull(root.findViewById(R.id.remoteView_frame_extra));
855 
856         // Create a RemoteViews wrapper around a layout and add it to our root
857         RemoteViews extra = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_extra);
858         mRemoteViews.addView(R.id.remoteViews_good, extra);
859         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
860 
861         // Verify that our root has that layout as its last (new) child
862         assertEquals(originalChildCount + 1, root.getChildCount());
863         assertNotNull(root.findViewById(R.id.remoteView_frame_extra));
864         assertEquals(R.id.remoteView_frame_extra, root.getChildAt(originalChildCount).getId());
865     }
866 
867     @Test
testSetLabelFor()868     public void testSetLabelFor() throws Throwable {
869         View labelView = mResult.findViewById(R.id.remoteView_label);
870         assertEquals(View.NO_ID, labelView.getLabelFor());
871 
872         mRemoteViews.setLabelFor(R.id.remoteView_label, R.id.remoteView_text);
873         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
874         assertEquals(R.id.remoteView_text, labelView.getLabelFor());
875     }
876 
877     @Test
testSetAccessibilityTraversalAfter()878     public void testSetAccessibilityTraversalAfter() throws Throwable {
879         View textView = mResult.findViewById(R.id.remoteView_text);
880 
881         mRemoteViews.setAccessibilityTraversalAfter(R.id.remoteView_text, R.id.remoteView_frame);
882         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
883         assertEquals(R.id.remoteView_frame, textView.getAccessibilityTraversalAfter());
884 
885         mRemoteViews.setAccessibilityTraversalAfter(R.id.remoteView_text, R.id.remoteView_linear);
886         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
887         assertEquals(R.id.remoteView_linear, textView.getAccessibilityTraversalAfter());
888     }
889 
890     @Test
testSetAccessibilityTraversalBefore()891     public void testSetAccessibilityTraversalBefore() throws Throwable {
892         View textView = mResult.findViewById(R.id.remoteView_text);
893 
894         mRemoteViews.setAccessibilityTraversalBefore(R.id.remoteView_text, R.id.remoteView_frame);
895         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
896         assertEquals(R.id.remoteView_frame, textView.getAccessibilityTraversalBefore());
897 
898         mRemoteViews.setAccessibilityTraversalBefore(R.id.remoteView_text, R.id.remoteView_linear);
899         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
900         assertEquals(R.id.remoteView_linear, textView.getAccessibilityTraversalBefore());
901     }
902 
903     @Test
testSetViewPadding()904     public void testSetViewPadding() throws Throwable {
905         View textView = mResult.findViewById(R.id.remoteView_text);
906 
907         mRemoteViews.setViewPadding(R.id.remoteView_text, 10, 20, 30, 40);
908         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
909         assertEquals(10, textView.getPaddingLeft());
910         assertEquals(20, textView.getPaddingTop());
911         assertEquals(30, textView.getPaddingRight());
912         assertEquals(40, textView.getPaddingBottom());
913 
914         mRemoteViews.setViewPadding(R.id.remoteView_text, 40, 30, 20, 10);
915         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
916         assertEquals(40, textView.getPaddingLeft());
917         assertEquals(30, textView.getPaddingTop());
918         assertEquals(20, textView.getPaddingRight());
919         assertEquals(10, textView.getPaddingBottom());
920     }
921 
createSampleImage(File imagefile, int resid)922     private void createSampleImage(File imagefile, int resid) throws IOException {
923         try (InputStream source = mContext.getResources().openRawResource(resid);
924              OutputStream target = new FileOutputStream(imagefile)) {
925 
926             byte[] buffer = new byte[1024];
927             for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
928                 target.write(buffer, 0, len);
929             }
930         }
931     }
932 }
933