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 android.appwidget.flags.Flags.drawDataParcel; 20 import static android.util.TypedValue.COMPLEX_UNIT_DIP; 21 import static android.util.TypedValue.COMPLEX_UNIT_PX; 22 import static android.view.View.MeasureSpec.makeMeasureSpec; 23 import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR; 24 import static android.widget.RemoteViews.MARGIN_BOTTOM; 25 import static android.widget.RemoteViews.MARGIN_END; 26 import static android.widget.RemoteViews.MARGIN_LEFT; 27 import static android.widget.RemoteViews.MARGIN_RIGHT; 28 import static android.widget.RemoteViews.MARGIN_START; 29 import static android.widget.RemoteViews.MARGIN_TOP; 30 31 import static com.android.compatibility.common.util.SystemUtil.runShellCommand; 32 import static com.android.compatibility.common.util.TestUtils.waitUntil; 33 34 import static junit.framework.Assert.fail; 35 36 import static org.junit.Assert.assertEquals; 37 import static org.junit.Assert.assertFalse; 38 import static org.junit.Assert.assertNotNull; 39 import static org.junit.Assert.assertNull; 40 import static org.junit.Assert.assertSame; 41 import static org.junit.Assert.assertThrows; 42 import static org.junit.Assert.assertTrue; 43 44 import android.Manifest; 45 import android.app.Activity; 46 import android.app.Instrumentation; 47 import android.app.Instrumentation.ActivityMonitor; 48 import android.app.PendingIntent; 49 import android.content.BroadcastReceiver; 50 import android.content.Context; 51 import android.content.Intent; 52 import android.content.IntentFilter; 53 import android.content.res.ColorStateList; 54 import android.graphics.Bitmap; 55 import android.graphics.BitmapFactory; 56 import android.graphics.BlendMode; 57 import android.graphics.Canvas; 58 import android.graphics.Color; 59 import android.graphics.drawable.BitmapDrawable; 60 import android.graphics.drawable.Icon; 61 import android.net.Uri; 62 import android.os.Bundle; 63 import android.os.Parcel; 64 import android.os.Parcelable; 65 import android.os.SystemClock; 66 import android.platform.test.annotations.RequiresFlagsEnabled; 67 import android.platform.test.flag.junit.CheckFlagsRule; 68 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 69 import android.text.TextUtils; 70 import android.util.ArrayMap; 71 import android.util.DisplayMetrics; 72 import android.util.SizeF; 73 import android.util.TypedValue; 74 import android.view.MotionEvent; 75 import android.view.View; 76 import android.view.ViewGroup; 77 import android.widget.AbsoluteLayout; 78 import android.widget.AnalogClock; 79 import android.widget.Button; 80 import android.widget.CheckBox; 81 import android.widget.Chronometer; 82 import android.widget.CompoundButton; 83 import android.widget.DatePicker; 84 import android.widget.EditText; 85 import android.widget.FrameLayout; 86 import android.widget.GridLayout; 87 import android.widget.GridView; 88 import android.widget.ImageButton; 89 import android.widget.ImageView; 90 import android.widget.LinearLayout; 91 import android.widget.ListView; 92 import android.widget.NumberPicker; 93 import android.widget.ProgressBar; 94 import android.widget.RadioButton; 95 import android.widget.RadioGroup; 96 import android.widget.RatingBar; 97 import android.widget.RelativeLayout; 98 import android.widget.RemoteViews; 99 import android.widget.RemoteViews.ActionException; 100 import android.widget.SeekBar; 101 import android.widget.StackView; 102 import android.widget.Switch; 103 import android.widget.TextClock; 104 import android.widget.TextView; 105 import android.widget.ViewFlipper; 106 import android.widget.cts.util.RemoteViewsUtil; 107 import android.widget.cts.util.TestUtils; 108 109 import androidx.test.InstrumentationRegistry; 110 import androidx.test.filters.LargeTest; 111 import androidx.test.filters.MediumTest; 112 import androidx.test.rule.ActivityTestRule; 113 114 import com.android.compatibility.common.util.AdoptShellPermissionsRule; 115 import com.android.compatibility.common.util.ThrowingRunnable; 116 import com.android.compatibility.common.util.WidgetTestUtils; 117 118 import org.junit.After; 119 import org.junit.Assert; 120 import org.junit.Before; 121 import org.junit.Rule; 122 import org.junit.Test; 123 import org.junit.rules.ExpectedException; 124 import org.junit.runner.RunWith; 125 import org.junit.runners.Parameterized; 126 127 import java.io.File; 128 import java.io.FileOutputStream; 129 import java.io.IOException; 130 import java.io.InputStream; 131 import java.io.OutputStream; 132 import java.util.Arrays; 133 import java.util.Collections; 134 import java.util.List; 135 import java.util.Map; 136 import java.util.concurrent.CountDownLatch; 137 import java.util.concurrent.TimeUnit; 138 import java.util.function.Consumer; 139 import java.util.function.Function; 140 141 /** Test {@link RemoteViews}. */ 142 @MediumTest 143 @RunWith(Parameterized.class) 144 public class RemoteViewsTest { 145 private static final String PACKAGE_NAME = "android.widget.cts"; 146 147 private static final int INVALID_ID = -1; 148 149 private static final long TEST_TIMEOUT = 5000; 150 151 @Rule(order = 0) 152 public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( 153 androidx.test.platform.app.InstrumentationRegistry 154 .getInstrumentation().getUiAutomation(), 155 Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX); 156 157 @Rule(order = 1) 158 public ActivityTestRule<RemoteViewsCtsActivity> mActivityRule = 159 new ActivityTestRule<>(RemoteViewsCtsActivity.class); 160 161 @Rule 162 public ExpectedException mExpectedException = ExpectedException.none(); 163 164 @Rule 165 public final CheckFlagsRule mCheckFlagsRule = 166 DeviceFlagsValueProvider.createCheckFlagsRule(); 167 168 @Parameterized.Parameters(name = "isProtoTest={0}") parameters()169 public static Object[] parameters() { 170 return new Object[] {false, true}; 171 } 172 173 /** 174 * When this parameter is true, the test serializes and deserializes the RemoteViews to/from 175 * proto before applying. This ensures that proto serialization does not cause a change in the 176 * structure or function of RemoteViews, apart from PendingIntent based APIs. 177 */ 178 @Parameterized.Parameter(0) 179 public boolean isProtoTest; 180 181 private Instrumentation mInstrumentation; 182 183 private Context mContext; 184 185 private RemoteViews mRemoteViews; 186 187 private View mResult; 188 189 private String mInitialNightMode; 190 191 @Before setUp()192 public void setUp() throws Throwable { 193 RemoteViewsUtil.checkRemoteViewsProtoFlag(isProtoTest); 194 // Ensure the UI is currently NOT in night mode. 195 mInitialNightMode = changeNightMode(false); 196 197 mActivityRule.runOnUiThread(() -> { 198 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 199 mContext = mInstrumentation.getTargetContext(); 200 mRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 201 mResult = mRemoteViews.apply(mContext, null); 202 203 // Add our host view to the activity behind this test. This is similar to how launchers 204 // add widgets to the on-screen UI. 205 ViewGroup root = (ViewGroup) mActivityRule.getActivity().findViewById( 206 R.id.remoteView_host); 207 FrameLayout.MarginLayoutParams lp = new FrameLayout.MarginLayoutParams( 208 ViewGroup.LayoutParams.MATCH_PARENT, 209 ViewGroup.LayoutParams.MATCH_PARENT); 210 mResult.setLayoutParams(lp); 211 212 root.addView(mResult); 213 }); 214 } 215 216 @After tearDown()217 public void tearDown() { 218 runShellCommand("cmd uimode night " + mInitialNightMode); 219 } 220 221 @Test testConstructor()222 public void testConstructor() { 223 new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 224 225 new RemoteViews(Parcel.obtain()); 226 } 227 228 @Test testGetPackage()229 public void testGetPackage() { 230 assertEquals(PACKAGE_NAME, mRemoteViews.getPackage()); 231 232 mRemoteViews = new RemoteViews(null, R.layout.remoteviews_good); 233 assertNull(mRemoteViews.getPackage()); 234 } 235 236 @Test testGetLayoutId()237 public void testGetLayoutId() { 238 assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId()); 239 240 mRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout); 241 assertEquals(R.layout.listview_layout, mRemoteViews.getLayoutId()); 242 243 mRemoteViews = new RemoteViews(PACKAGE_NAME, INVALID_ID); 244 assertEquals(INVALID_ID, mRemoteViews.getLayoutId()); 245 246 mRemoteViews = new RemoteViews(PACKAGE_NAME, 0); 247 assertEquals(0, mRemoteViews.getLayoutId()); 248 } 249 250 @Test testSetContentDescription()251 public void testSetContentDescription() throws Throwable { 252 View view = mResult.findViewById(R.id.remoteView_frame); 253 254 assertNull(view.getContentDescription()); 255 256 CharSequence contentDescription = mContext.getString(R.string.remote_content_description); 257 mRemoteViews.setContentDescription(R.id.remoteView_frame, contentDescription); 258 reapplyRemoteViews(); 259 assertTrue(TextUtils.equals(contentDescription, view.getContentDescription())); 260 } 261 262 @Test testSetViewVisibility()263 public void testSetViewVisibility() throws Throwable { 264 View view = mResult.findViewById(R.id.remoteView_chronometer); 265 assertEquals(View.VISIBLE, view.getVisibility()); 266 267 mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.INVISIBLE); 268 reapplyRemoteViews(); 269 assertEquals(View.INVISIBLE, view.getVisibility()); 270 271 mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.GONE); 272 reapplyRemoteViews(); 273 assertEquals(View.GONE, view.getVisibility()); 274 275 mRemoteViews.setViewVisibility(R.id.remoteView_chronometer, View.VISIBLE); 276 reapplyRemoteViews(); 277 assertEquals(View.VISIBLE, view.getVisibility()); 278 } 279 280 @Test testSetTextViewText()281 public void testSetTextViewText() throws Throwable { 282 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 283 assertEquals("", textView.getText().toString()); 284 285 String expected = "This is content"; 286 mRemoteViews.setTextViewText(R.id.remoteView_text, expected); 287 reapplyRemoteViews(); 288 assertEquals(expected, textView.getText().toString()); 289 290 mRemoteViews.setTextViewText(R.id.remoteView_text, null); 291 reapplyRemoteViews(); 292 assertEquals("", textView.getText().toString()); 293 294 mRemoteViews.setTextViewText(R.id.remoteView_absolute, ""); 295 assertThrowsOnReapply(ActionException.class); 296 } 297 298 @Test testSetTextViewTextSize()299 public void testSetTextViewTextSize() throws Throwable { 300 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 301 302 mRemoteViews.setTextViewTextSize(R.id.remoteView_text, TypedValue.COMPLEX_UNIT_SP, 18); 303 reapplyRemoteViews(); 304 float expectedTextSizePx = TypedValue.convertDimensionToPixels( 305 TypedValue.COMPLEX_UNIT_SP, 306 18, 307 mContext.getResources().getDisplayMetrics() 308 ); 309 assertEquals(expectedTextSizePx, textView.getTextSize(), 0.001f); 310 311 mRemoteViews.setTextViewTextSize(R.id.remoteView_absolute, TypedValue.COMPLEX_UNIT_SP, 20); 312 assertThrowsOnReapply(Throwable.class); 313 } 314 315 @Test testSetIcon()316 public void testSetIcon() throws Throwable { 317 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 318 assertNull(image.getDrawable()); 319 320 Icon iconBlack = Icon.createWithResource(mContext, R.drawable.icon_black); 321 mRemoteViews.setIcon(R.id.remoteView_image, "setImageIcon", iconBlack); 322 reapplyRemoteViews(); 323 assertNotNull(image.getDrawable()); 324 BitmapDrawable dBlack = (BitmapDrawable) mContext.getDrawable(R.drawable.icon_black); 325 WidgetTestUtils.assertEquals(dBlack.getBitmap(), 326 ((BitmapDrawable) image.getDrawable()).getBitmap()); 327 } 328 329 @Test testSetIcon_nightMode()330 public void testSetIcon_nightMode() throws Throwable { 331 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 332 Icon iconLight = Icon.createWithResource(mContext, R.drawable.icon_green); 333 Icon iconDark = Icon.createWithResource(mContext, R.drawable.icon_blue); 334 mRemoteViews.setIcon(R.id.remoteView_image, "setImageIcon", iconLight, iconDark); 335 336 applyNightModeThenReapplyAndTest(false, () -> { 337 assertNotNull(image.getDrawable()); 338 BitmapDrawable dLight = (BitmapDrawable) mContext.getDrawable(R.drawable.icon_green); 339 WidgetTestUtils.assertEquals(dLight.getBitmap(), 340 ((BitmapDrawable) image.getDrawable()).getBitmap()); 341 }); 342 applyNightModeThenReapplyAndTest(true, () -> { 343 assertNotNull(image.getDrawable()); 344 BitmapDrawable dDark = (BitmapDrawable) mContext.getDrawable(R.drawable.icon_blue); 345 WidgetTestUtils.assertEquals(dDark.getBitmap(), 346 ((BitmapDrawable) image.getDrawable()).getBitmap()); 347 }); 348 } 349 350 @Test testSetImageViewIcon()351 public void testSetImageViewIcon() throws Throwable { 352 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 353 assertNull(image.getDrawable()); 354 355 Icon iconBlue = Icon.createWithResource(mContext, R.drawable.icon_blue); 356 mRemoteViews.setImageViewIcon(R.id.remoteView_image, iconBlue); 357 reapplyRemoteViews(); 358 assertNotNull(image.getDrawable()); 359 BitmapDrawable dBlue = (BitmapDrawable) mContext.getDrawable(R.drawable.icon_blue); 360 WidgetTestUtils.assertEquals(dBlue.getBitmap(), 361 ((BitmapDrawable) image.getDrawable()).getBitmap()); 362 363 } 364 365 @Test testSetImageViewResource()366 public void testSetImageViewResource() throws Throwable { 367 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 368 assertNull(image.getDrawable()); 369 370 mRemoteViews.setImageViewResource(R.id.remoteView_image, R.drawable.testimage); 371 reapplyRemoteViews(); 372 assertNotNull(image.getDrawable()); 373 BitmapDrawable d = (BitmapDrawable) mContext.getDrawable(R.drawable.testimage); 374 WidgetTestUtils.assertEquals(d.getBitmap(), 375 ((BitmapDrawable) image.getDrawable()).getBitmap()); 376 377 mRemoteViews.setImageViewResource(R.id.remoteView_absolute, R.drawable.testimage); 378 assertThrowsOnReapply(ActionException.class); 379 } 380 381 @Test testSetImageViewUri()382 public void testSetImageViewUri() throws Throwable { 383 String path = getTestImagePath(); 384 File imageFile = new File(path); 385 386 try { 387 createSampleImage(imageFile, R.raw.testimage); 388 389 Uri uri = Uri.parse(path); 390 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 391 assertNull(image.getDrawable()); 392 393 mRemoteViews.setImageViewUri(R.id.remoteView_image, uri); 394 reapplyRemoteViews(); 395 396 Bitmap imageViewBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap(); 397 Bitmap expectedBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap( 398 mContext.getResources(), R.raw.testimage, imageViewBitmap.getConfig()); 399 WidgetTestUtils.assertEquals(expectedBitmap, imageViewBitmap); 400 } finally { 401 imageFile.delete(); 402 } 403 } 404 405 /** 406 * Returns absolute file path of location where test image should be stored 407 */ getTestImagePath()408 private String getTestImagePath() { 409 return mContext.getFilesDir() + "/test.jpg"; 410 } 411 412 @Test testSetChronometer()413 public void testSetChronometer() throws Throwable { 414 long base1 = 50; 415 long base2 = -50; 416 Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer); 417 418 mRemoteViews.setChronometer(R.id.remoteView_chronometer, base1, "HH:MM:SS", 419 false); 420 reapplyRemoteViews(); 421 assertEquals(base1, chronometer.getBase()); 422 assertEquals("HH:MM:SS", chronometer.getFormat()); 423 424 mRemoteViews.setChronometer(R.id.remoteView_chronometer, base2, "HH:MM:SS", 425 false); 426 reapplyRemoteViews(); 427 assertEquals(base2, chronometer.getBase()); 428 assertEquals("HH:MM:SS", chronometer.getFormat()); 429 430 mRemoteViews.setChronometer(R.id.remoteView_chronometer, base1, "invalid", 431 true); 432 reapplyRemoteViews(); 433 assertEquals(base1, chronometer.getBase()); 434 assertEquals("invalid", chronometer.getFormat()); 435 436 mRemoteViews.setChronometer(R.id.remoteView_absolute, base1, "invalid", true); 437 assertThrowsOnReapply(ActionException.class); 438 } 439 440 @Test testSetChronometerCountDown()441 public void testSetChronometerCountDown() throws Throwable { 442 Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer); 443 444 mRemoteViews.setChronometerCountDown(R.id.remoteView_chronometer, true); 445 reapplyRemoteViews(); 446 assertTrue(chronometer.isCountDown()); 447 448 mRemoteViews.setChronometerCountDown(R.id.remoteView_chronometer, false); 449 reapplyRemoteViews(); 450 assertFalse(chronometer.isCountDown()); 451 452 mRemoteViews.setChronometerCountDown(R.id.remoteView_absolute, true); 453 assertThrowsOnReapply(ActionException.class); 454 } 455 456 @Test testSetProgressBar()457 public void testSetProgressBar() throws Throwable { 458 ProgressBar progress = (ProgressBar) mResult.findViewById(R.id.remoteView_progress); 459 assertEquals(100, progress.getMax()); 460 assertEquals(0, progress.getProgress()); 461 // the view uses style progressBarHorizontal, so the default is false 462 assertFalse(progress.isIndeterminate()); 463 464 mRemoteViews.setProgressBar(R.id.remoteView_progress, 80, 50, true); 465 reapplyRemoteViews(); 466 // make the bar indeterminate will not affect max and progress 467 assertEquals(100, progress.getMax()); 468 assertEquals(0, progress.getProgress()); 469 assertTrue(progress.isIndeterminate()); 470 471 mRemoteViews.setProgressBar(R.id.remoteView_progress, 60, 50, false); 472 reapplyRemoteViews(); 473 assertEquals(60, progress.getMax()); 474 assertEquals(50, progress.getProgress()); 475 assertFalse(progress.isIndeterminate()); 476 477 mRemoteViews.setProgressBar(R.id.remoteView_relative, 60, 50, false); 478 assertThrowsOnReapply(ActionException.class); 479 } 480 481 @Test testApply()482 public void testApply() { 483 assertNotNull(mResult); 484 assertNotNull(mResult.findViewById(R.id.remoteViews_good)); 485 assertNotNull(mResult.findViewById(R.id.remoteView_absolute)); 486 assertNotNull(mResult.findViewById(R.id.remoteView_chronometer)); 487 assertNotNull(mResult.findViewById(R.id.remoteView_frame)); 488 assertNotNull(mResult.findViewById(R.id.remoteView_image)); 489 assertNotNull(mResult.findViewById(R.id.remoteView_linear)); 490 assertNotNull(mResult.findViewById(R.id.remoteView_progress)); 491 assertNotNull(mResult.findViewById(R.id.remoteView_relative)); 492 assertNotNull(mResult.findViewById(R.id.remoteView_text)); 493 } 494 495 @Test testReapply()496 public void testReapply() throws Throwable { 497 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 498 assertNull(image.getDrawable()); 499 500 mRemoteViews.setImageViewResource(R.id.remoteView_image, R.drawable.testimage); 501 reapplyRemoteViews(); 502 assertNotNull(image.getDrawable()); 503 BitmapDrawable d = (BitmapDrawable) mContext 504 .getResources().getDrawable(R.drawable.testimage); 505 WidgetTestUtils.assertEquals(d.getBitmap(), 506 ((BitmapDrawable) image.getDrawable()).getBitmap()); 507 } 508 509 @Test testApplyWithDrawInstructions()510 public void testApplyWithDrawInstructions() throws Throwable { 511 if (!drawDataParcel()) { 512 return; 513 } 514 final RemoteViews.DrawInstructions drawInstructions = 515 getDrawInstructions(mContext, R.raw.widget); 516 final String key = "mykey"; 517 final String action = "myaction"; 518 final MockBroadcastReceiver receiver = new MockBroadcastReceiver(); 519 mContext.registerReceiver(receiver, new IntentFilter(action), Context.RECEIVER_EXPORTED); 520 521 final Intent intent = new Intent(action).setPackage(mContext.getPackageName()); 522 final PendingIntent pendingIntent = 523 PendingIntent.getBroadcast( 524 mContext, 525 0, 526 intent, 527 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); 528 final ActivityMonitor am = mInstrumentation.addMonitor( 529 MockURLSpanTestActivity.class.getName(), null, false); 530 Activity newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT); 531 assertNull(newActivity); 532 533 // Proto serialization removes PendingIntents from the RemoteViews. 534 if (isProtoTest) return; 535 536 final RemoteViews remoteViews = new RemoteViews(drawInstructions); 537 remoteViews.setPendingIntentTemplate(1, pendingIntent); 538 remoteViews.setOnClickFillInIntent(1, new Intent().putExtra(key, 1)); 539 final View result = remoteViews.apply(mContext, null); 540 mActivityRule.runOnUiThread( 541 () -> { 542 final ViewGroup root = 543 (ViewGroup) 544 mActivityRule.getActivity().findViewById(R.id.remoteView_host); 545 root.removeAllViews(); 546 root.addView(result); 547 }); 548 final int offset = 2; 549 verifyClick(result, receiver, offset, offset, 1); 550 } 551 552 @Test testDrawInstructionsBlend()553 public void testDrawInstructionsBlend() throws Throwable { 554 if (!drawDataParcel()) { 555 return; 556 } 557 testSingleDrawInstruction("blend_clear", 558 R.raw.blend_clear, R.drawable.blend_clear); 559 testSingleDrawInstruction("blend_color", 560 R.raw.blend_color, R.drawable.blend_color); 561 testSingleDrawInstruction("blend_color_burn", 562 R.raw.blend_color_burn, R.drawable.blend_color_burn); 563 testSingleDrawInstruction("blend_color_dodge", 564 R.raw.blend_color_dodge, R.drawable.blend_color_dodge); 565 testSingleDrawInstruction("blend_darken", 566 R.raw.blend_darken, R.drawable.blend_darken); 567 testSingleDrawInstruction("blend_difference", 568 R.raw.blend_difference, R.drawable.blend_difference); 569 testSingleDrawInstruction("blend_dst", 570 R.raw.blend_dst, R.drawable.blend_dst); 571 testSingleDrawInstruction("blend_dst_atop", 572 R.raw.blend_dst_atop, R.drawable.blend_dst_atop); 573 testSingleDrawInstruction("blend_dst_in", 574 R.raw.blend_dst_in, R.drawable.blend_dst_in); 575 testSingleDrawInstruction("blend_dst_out", 576 R.raw.blend_dst_out, R.drawable.blend_dst_out); 577 testSingleDrawInstruction("blend_dst_over", 578 R.raw.blend_dst_over, R.drawable.blend_dst_over); 579 testSingleDrawInstruction("blend_exclusion", 580 R.raw.blend_exclusion, R.drawable.blend_exclusion); 581 testSingleDrawInstruction("blend_hard_light", 582 R.raw.blend_hard_light, R.drawable.blend_hard_light); 583 testSingleDrawInstruction("blend_hue", 584 R.raw.blend_hue, R.drawable.blend_hue); 585 testSingleDrawInstruction("blend_lighten", 586 R.raw.blend_lighten, R.drawable.blend_lighten); 587 testSingleDrawInstruction("blend_luminosity", 588 R.raw.blend_luminosity, R.drawable.blend_luminosity); 589 testSingleDrawInstruction("blend_modulate", 590 R.raw.blend_modulate, R.drawable.blend_modulate); 591 testSingleDrawInstruction("blend_multiply", 592 R.raw.blend_multiply, R.drawable.blend_multiply); 593 testSingleDrawInstruction("blend_overlay", 594 R.raw.blend_overlay, R.drawable.blend_overlay); 595 testSingleDrawInstruction("blend_plus", 596 R.raw.blend_plus, R.drawable.blend_plus); 597 testSingleDrawInstruction("blend_saturation", 598 R.raw.blend_saturation, R.drawable.blend_saturation); 599 testSingleDrawInstruction("blend_screen", 600 R.raw.blend_screen, R.drawable.blend_screen); 601 testSingleDrawInstruction("blend_soft_light", 602 R.raw.blend_soft_light, R.drawable.blend_soft_light); 603 testSingleDrawInstruction("blend_src", 604 R.raw.blend_src, R.drawable.blend_src); 605 testSingleDrawInstruction("blend_src_atop", 606 R.raw.blend_src_atop, R.drawable.blend_src_atop); 607 testSingleDrawInstruction("blend_src_in", 608 R.raw.blend_src_in, R.drawable.blend_src_in); 609 testSingleDrawInstruction("blend_src_out", 610 R.raw.blend_src_out, R.drawable.blend_src_out); 611 testSingleDrawInstruction("blend_src_over", 612 R.raw.blend_src_over, R.drawable.blend_src_over); 613 testSingleDrawInstruction("blend_xor", 614 R.raw.blend_xor, R.drawable.blend_xor); 615 } 616 617 @Test testDrawInstructionsClip()618 public void testDrawInstructionsClip() throws Throwable { 619 if (!drawDataParcel()) { 620 return; 621 } 622 testSingleDrawInstruction("clip_path", 623 R.raw.clip_path, R.drawable.clip_path); 624 testSingleDrawInstruction("clip_rect", 625 R.raw.clip_rect, R.drawable.clip_rect); 626 } 627 628 @Test testDrawInstructionsText()629 public void testDrawInstructionsText() throws Throwable { 630 if (!drawDataParcel()) { 631 return; 632 } 633 testSingleDrawInstruction("draw_text", 634 R.raw.draw_text, R.drawable.draw_text); 635 testSingleDrawInstruction("text_font", 636 R.raw.text_font, R.drawable.text_font); 637 testSingleDrawInstruction("text_font_monospace", 638 R.raw.text_font_monospace, R.drawable.text_font_monospace); 639 testSingleDrawInstruction("text_font_san_serif", 640 R.raw.text_font_san_serif, R.drawable.text_font_san_serif); 641 testSingleDrawInstruction("text_font_san_serif_800", 642 R.raw.text_font_san_serif_800, R.drawable.text_font_san_serif_800); 643 testSingleDrawInstruction("text_font_serif", 644 R.raw.text_font_serif, R.drawable.text_font_serif); 645 } 646 647 @Test testDrawInstructionsGradient()648 public void testDrawInstructionsGradient() throws Throwable { 649 if (!drawDataParcel()) { 650 return; 651 } 652 testSingleDrawInstruction("linear_gradient_1", 653 R.raw.linear_gradient_1, R.drawable.linear_gradient_1); 654 testSingleDrawInstruction("linear_gradient_2", 655 R.raw.linear_gradient_2, R.drawable.linear_gradient_2); 656 testSingleDrawInstruction("radial_gradient_1", 657 R.raw.radial_gradient_1, R.drawable.radial_gradient_1); 658 testSingleDrawInstruction("radial_gradient_2", 659 R.raw.radial_gradient_2, R.drawable.radial_gradient_2); 660 testSingleDrawInstruction("sweep_gradient_1", 661 R.raw.sweep_gradient_1, R.drawable.sweep_gradient_1); 662 testSingleDrawInstruction("sweep_gradient_2", 663 R.raw.sweep_gradient_2, R.drawable.sweep_gradient_2); 664 } 665 666 @Test testDrawInstructionsMatrix()667 public void testDrawInstructionsMatrix() throws Throwable { 668 if (!drawDataParcel()) { 669 return; 670 } 671 testSingleDrawInstruction("matrix_rotate_1", 672 R.raw.matrix_rotate_1, R.drawable.matrix_rotate_1); 673 testSingleDrawInstruction("matrix_rotate_2", 674 R.raw.matrix_rotate_2, R.drawable.matrix_rotate_2); 675 testSingleDrawInstruction("matrix_scale_1", 676 R.raw.matrix_scale_1, R.drawable.matrix_scale_1); 677 testSingleDrawInstruction("matrix_scale_2", 678 R.raw.matrix_scale_2, R.drawable.matrix_scale_2); 679 testSingleDrawInstruction("matrix_skew", 680 R.raw.matrix_skew, R.drawable.matrix_skew); 681 testSingleDrawInstruction("matrix_translate", 682 R.raw.matrix_translate, R.drawable.matrix_translate); 683 } 684 685 @Test testDrawInstructionsMulti()686 public void testDrawInstructionsMulti() throws Throwable { 687 if (!drawDataParcel()) { 688 return; 689 } 690 testSingleDrawInstruction("multi_path", 691 R.raw.multi_path, R.drawable.multi_path); 692 testSingleDrawInstruction("multiple_draw_commands", 693 R.raw.multiple_draw_commands, R.drawable.multiple_draw_commands); 694 } 695 696 @Test testDrawInstructionsPaint()697 public void testDrawInstructionsPaint() throws Throwable { 698 if (!drawDataParcel()) { 699 return; 700 } 701 testSingleDrawInstruction("paint_filter_bitmap_1", 702 R.raw.paint_filter_bitmap_1, R.drawable.paint_filter_bitmap_1); 703 testSingleDrawInstruction("paint_filter_bitmap_2", 704 R.raw.paint_filter_bitmap_2, R.drawable.paint_filter_bitmap_2); 705 testSingleDrawInstruction("paint_filter_bitmap_3", 706 R.raw.paint_filter_bitmap_3, R.drawable.paint_filter_bitmap_3); 707 testSingleDrawInstruction("paint_set_color", 708 R.raw.paint_set_color, R.drawable.paint_set_color); 709 testSingleDrawInstruction("paint_set_stroke", 710 R.raw.paint_set_stroke, R.drawable.paint_set_stroke); 711 testSingleDrawInstruction("paint_stroke_miter", 712 R.raw.paint_stroke_miter, R.drawable.paint_stroke_miter); 713 } 714 715 @Test testDrawInstructionsPath()716 public void testDrawInstructionsPath() throws Throwable { 717 if (!drawDataParcel()) { 718 return; 719 } 720 testSingleDrawInstruction("path_cubic_to", 721 R.raw.path_cubic_to, R.drawable.path_cubic_to); 722 testSingleDrawInstruction("path_line_to", 723 R.raw.path_line_to, R.drawable.path_line_to); 724 testSingleDrawInstruction("path_quad_to", 725 R.raw.path_quad_to, R.drawable.path_quad_to); 726 testSingleDrawInstruction("path_tween_test_1", 727 R.raw.path_tween_test_1, R.drawable.path_tween_test_1); 728 testSingleDrawInstruction("path_tween_test_2", 729 R.raw.path_tween_test_2, R.drawable.path_tween_test_2); 730 testSingleDrawInstruction("paint_stroke_miter", 731 R.raw.paint_stroke_miter, R.drawable.paint_stroke_miter); 732 } 733 734 @Test testDrawInstructionsPorter()735 public void testDrawInstructionsPorter() throws Throwable { 736 if (!drawDataParcel()) { 737 return; 738 } 739 testSingleDrawInstruction("porter_add", 740 R.raw.porter_add, R.drawable.porter_add); 741 testSingleDrawInstruction("porter_clear", 742 R.raw.porter_clear, R.drawable.porter_clear); 743 testSingleDrawInstruction("porter_darken", 744 R.raw.porter_darken, R.drawable.porter_darken); 745 testSingleDrawInstruction("porter_dst", 746 R.raw.porter_dst, R.drawable.porter_dst); 747 testSingleDrawInstruction("porter_dst_atop", 748 R.raw.porter_dst_atop, R.drawable.porter_dst_atop); 749 testSingleDrawInstruction("porter_dst_in", 750 R.raw.porter_dst_in, R.drawable.porter_dst_in); 751 testSingleDrawInstruction("porter_dst_out", 752 R.raw.porter_dst_out, R.drawable.porter_dst_out); 753 testSingleDrawInstruction("porter_dst_over", 754 R.raw.porter_dst_over, R.drawable.porter_dst_over); 755 testSingleDrawInstruction("porter_lighten", 756 R.raw.porter_lighten, R.drawable.porter_lighten); 757 testSingleDrawInstruction("porter_multiply", 758 R.raw.porter_multiply, R.drawable.porter_multiply); 759 testSingleDrawInstruction("porter_overlay", 760 R.raw.porter_overlay, R.drawable.porter_overlay); 761 testSingleDrawInstruction("porter_screen", 762 R.raw.porter_screen, R.drawable.porter_screen); 763 testSingleDrawInstruction("porter_src", 764 R.raw.porter_src, R.drawable.porter_src); 765 testSingleDrawInstruction("porter_src_atop", 766 R.raw.porter_src_atop, R.drawable.porter_src_atop); 767 testSingleDrawInstruction("porter_src_in", 768 R.raw.porter_src_in, R.drawable.porter_src_in); 769 testSingleDrawInstruction("porter_src_out", 770 R.raw.porter_src_out, R.drawable.porter_src_out); 771 testSingleDrawInstruction("porter_src_over", 772 R.raw.porter_src_over, R.drawable.porter_src_over); 773 testSingleDrawInstruction("porter_xor", 774 R.raw.porter_xor, R.drawable.porter_xor); 775 } 776 testSingleDrawInstruction(final String resourceName, final int docId, final int bitmapId)777 private void testSingleDrawInstruction(final String resourceName, final int docId, 778 final int bitmapId) throws Throwable { 779 final RemoteViews.DrawInstructions drawInstructions = 780 getDrawInstructions(mContext, docId); 781 final Bitmap expectedBitmap = getBitmapFromFile(mContext, bitmapId); 782 mRemoteViews = new RemoteViews(drawInstructions); 783 applyRemoteViews(); 784 verifyBitmap(expectedBitmap.getWidth(), expectedBitmap.getHeight(), (actualBitmap) -> { 785 final float rmse = compareImages(expectedBitmap, actualBitmap, resourceName); 786 // reject if root-square-mean-error is above threshold and saves screenshots for debug 787 if (rmse > 8.0f) { 788 try { 789 final String actualPath = saveBitmapToFile( 790 actualBitmap, resourceName + "_actual"); 791 final String expectedPath = saveBitmapToFile( 792 expectedBitmap, resourceName + "_expected"); 793 Assert.fail("Failed validating " + resourceName + " rmse=" + rmse 794 + ". Bitmaps saved as " + actualPath + " and " + expectedPath); 795 } catch (IOException e) { 796 throw new RuntimeException(e); 797 } 798 } 799 }); 800 } 801 getDrawInstructions( final Context context, final int resourceId)802 private static RemoteViews.DrawInstructions getDrawInstructions( 803 final Context context, final int resourceId) throws IOException { 804 try (InputStream is = context.getResources().openRawResource(resourceId) 805 ) { 806 final byte[] bytes = new byte[(int) is.available()]; 807 final int result = is.read(bytes); 808 return new RemoteViews.DrawInstructions.Builder( 809 Collections.singletonList(bytes)).build(); 810 } 811 } 812 getBitmapFromFile(final Context context, final int resourceId)813 private static Bitmap getBitmapFromFile(final Context context, final int resourceId) { 814 final BitmapFactory.Options opts = new BitmapFactory.Options(); 815 opts.inScaled = false; 816 return BitmapFactory.decodeResource(context.getResources(), resourceId, opts); 817 } 818 saveBitmapToFile(final Bitmap image, final String resourceName)819 private String saveBitmapToFile(final Bitmap image, final String resourceName) 820 throws IOException { 821 final int quality = 100; 822 final File dir = mContext.getFilesDir(); 823 if (!dir.exists()) { 824 dir.mkdirs(); 825 } 826 final File dest = new File(dir, resourceName + "_" + System.currentTimeMillis() + ".png"); 827 dest.createNewFile(); 828 try (FileOutputStream fos = new FileOutputStream(dest)) { 829 image.compress(Bitmap.CompressFormat.PNG, quality, fos); 830 } 831 return dest.getAbsolutePath(); 832 } 833 verifyBitmap(final int width, final int height, final Consumer<Bitmap> cb)834 private void verifyBitmap(final int width, final int height, final Consumer<Bitmap> cb) 835 throws Throwable { 836 final Bitmap bitmap = blank(width, height); 837 mActivityRule.runOnUiThread(() -> { 838 mResult.measure(makeMeasureSpec(width, View.MeasureSpec.EXACTLY), 839 makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); 840 mResult.layout(0, 0, width, height); 841 mResult.draw(new Canvas(bitmap)); 842 }); 843 cb.accept(bitmap); 844 bitmap.recycle(); 845 } 846 blank(final int width, final int height)847 private Bitmap blank(final int width, final int height) { 848 final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 849 bitmap.eraseColor(0xFFAABBCC); 850 return bitmap; 851 } 852 compareImages(Bitmap bitmap1, Bitmap bitmap2, String testLabel)853 private static float compareImages(Bitmap bitmap1, Bitmap bitmap2, String testLabel) { 854 if (bitmap1.getWidth() != bitmap2.getWidth() 855 || bitmap1.getHeight() != bitmap2.getHeight()) { 856 throw new IllegalArgumentException("Size mismatches when running " + testLabel 857 + " expected:[w=" + bitmap1.getWidth() + ",h=" + bitmap1.getHeight() + "]" 858 + " actual:[w=" + bitmap2.getWidth() + ",h=" + bitmap2.getHeight() + "]"); 859 } 860 float sqr_sum = 0; 861 int count = 0; 862 for (int y = 1; y < bitmap1.getHeight() - 1; y++) { 863 for (int x = 1; x < bitmap1.getWidth() - 1; x++) { 864 int pix1 = bitmap1.getPixel(x, y); 865 if (pix1 != bitmap1.getPixel(x, y - 1) 866 || pix1 != bitmap1.getPixel(x, y + 1) 867 || pix1 != bitmap1.getPixel(x - 1, y - 1) 868 || pix1 != bitmap1.getPixel(x - 1, y - 1)) { 869 // Skips if a pixel's color doesn't match its neighboring pixel 870 continue; 871 } 872 // Ignores least significant bit 873 float r1 = (pix1 & 0xFF0000) >> 17; 874 float g1 = (pix1 & 0xFF00) >> 9; 875 float b1 = (pix1 & 0xFF) >> 1; 876 int pix2 = bitmap2.getPixel(x, y); 877 float r2 = (pix2 & 0xFF0000) >> 17; 878 float g2 = (pix2 & 0xFF00) >> 9; 879 float b2 = (pix2 & 0xFF) >> 1; 880 sqr_sum += (r1 - r2) * (r1 - r2); 881 sqr_sum += (g1 - g2) * (g1 - g2); 882 sqr_sum += (b1 - b2) * (b1 - b2); 883 count += 3; 884 } 885 } 886 return (float) Math.sqrt(sqr_sum / count); 887 } 888 verifyColorsOnFourCorners(final int expectedColor, final Bitmap bitmap)889 private static void verifyColorsOnFourCorners(final int expectedColor, final Bitmap bitmap) { 890 final int w = bitmap.getWidth(); 891 final int h = bitmap.getHeight(); 892 final int offset = 2; 893 assertEquals(expectedColor, bitmap.getPixel(offset, offset)); 894 assertEquals(expectedColor, bitmap.getPixel(w - offset, offset)); 895 assertEquals(expectedColor, bitmap.getPixel(offset, h - offset)); 896 assertEquals(expectedColor, bitmap.getPixel(w - offset, h - offset)); 897 } 898 verifyClick( final View result, final MockBroadcastReceiver receiver, final int x, final int y, final int expectedValue)899 private void verifyClick( 900 final View result, 901 final MockBroadcastReceiver receiver, 902 final int x, 903 final int y, 904 final int expectedValue) 905 throws Throwable { 906 mActivityRule.runOnUiThread(() -> performClick(result, x, y)); 907 final Intent intent = receiver.awaitIntent(); 908 assertNotNull(intent); 909 assertEquals(expectedValue, intent.getIntExtra("mykey", 0)); 910 } 911 performClick(final View v, final int x, final int y)912 private static void performClick(final View v, final int x, final int y) { 913 final long ts = SystemClock.uptimeMillis(); 914 final MotionEvent down = MotionEvent.obtain( 915 ts, 916 ts + 100, 917 MotionEvent.ACTION_DOWN, x, y, 0); 918 final MotionEvent up = MotionEvent.obtain( 919 ts + 200, 920 ts + 300, 921 MotionEvent.ACTION_UP, x, y, 0); 922 v.dispatchTouchEvent(down); 923 v.dispatchTouchEvent(up); 924 } 925 926 @Test testOnLoadClass()927 public void testOnLoadClass() { 928 mRemoteViews = new RemoteViews(Parcel.obtain()); 929 930 assertTrue(mRemoteViews.onLoadClass(AbsoluteLayout.class)); 931 assertTrue(mRemoteViews.onLoadClass(AnalogClock.class)); 932 assertTrue(mRemoteViews.onLoadClass(Button.class)); 933 assertTrue(mRemoteViews.onLoadClass(CheckBox.class)); 934 assertTrue(mRemoteViews.onLoadClass(Chronometer.class)); 935 assertTrue(mRemoteViews.onLoadClass(FrameLayout.class)); 936 assertTrue(mRemoteViews.onLoadClass(GridLayout.class)); 937 assertTrue(mRemoteViews.onLoadClass(GridView.class)); 938 assertTrue(mRemoteViews.onLoadClass(ImageButton.class)); 939 assertTrue(mRemoteViews.onLoadClass(ImageView.class)); 940 assertTrue(mRemoteViews.onLoadClass(LinearLayout.class)); 941 assertTrue(mRemoteViews.onLoadClass(ListView.class)); 942 assertTrue(mRemoteViews.onLoadClass(ProgressBar.class)); 943 assertTrue(mRemoteViews.onLoadClass(RadioButton.class)); 944 assertTrue(mRemoteViews.onLoadClass(RadioGroup.class)); 945 assertTrue(mRemoteViews.onLoadClass(RelativeLayout.class)); 946 assertTrue(mRemoteViews.onLoadClass(StackView.class)); 947 assertTrue(mRemoteViews.onLoadClass(Switch.class)); 948 assertTrue(mRemoteViews.onLoadClass(TextClock.class)); 949 assertTrue(mRemoteViews.onLoadClass(TextView.class)); 950 assertTrue(mRemoteViews.onLoadClass(ViewFlipper.class)); 951 952 // those classes without annotation @RemoteView 953 assertFalse(mRemoteViews.onLoadClass(EditText.class)); 954 assertFalse(mRemoteViews.onLoadClass(DatePicker.class)); 955 assertFalse(mRemoteViews.onLoadClass(NumberPicker.class)); 956 assertFalse(mRemoteViews.onLoadClass(RatingBar.class)); 957 assertFalse(mRemoteViews.onLoadClass(SeekBar.class)); 958 } 959 960 @Test testDescribeContents()961 public void testDescribeContents() { 962 mRemoteViews = new RemoteViews(Parcel.obtain()); 963 mRemoteViews.describeContents(); 964 } 965 966 @Test testWriteToParcel()967 public void testWriteToParcel() throws Throwable { 968 mRemoteViews.setTextViewText(R.id.remoteView_text, "This is content"); 969 mRemoteViews.setViewVisibility(R.id.remoteView_frame, View.GONE); 970 971 // the package and layout are successfully written into parcel 972 mRemoteViews = parcelAndUnparcel(mRemoteViews); 973 applyRemoteViews(); 974 assertEquals(PACKAGE_NAME, mRemoteViews.getPackage()); 975 assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId()); 976 assertEquals( 977 "This is content", 978 ((TextView) mResult.findViewById(R.id.remoteView_text)).getText().toString()); 979 assertEquals(View.GONE, mResult.findViewById(R.id.remoteView_frame).getVisibility()); 980 981 // currently the flag is not used 982 parcelAndUnparcel(mRemoteViews, /* flags= */ -1); 983 984 RemoteViews[] remote = RemoteViews.CREATOR.newArray(1); 985 assertNotNull(remote); 986 assertEquals(1, remote.length); 987 } 988 989 @Test(expected=NullPointerException.class) testWriteNullToParcel()990 public void testWriteNullToParcel() { 991 mRemoteViews.writeToParcel(null, 0); 992 } 993 994 @Test testWriteToParcel_landscapePortrait()995 public void testWriteToParcel_landscapePortrait() throws Throwable { 996 RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 997 landscape.setTextViewText(R.id.remoteView_text, "Hello world"); 998 RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 999 portrait.setTextViewText(R.id.remoteView_text, "Hello world"); 1000 int landscapeParcelledSize = getParcelledSize(landscape); 1001 mRemoteViews = new RemoteViews(landscape, portrait); 1002 1003 mRemoteViews = parcelAndUnparcel(mRemoteViews); 1004 assertEquals(PACKAGE_NAME, mRemoteViews.getPackage()); 1005 applyRemoteViews(); 1006 assertEquals( 1007 "Hello world", 1008 ((TextView) mResult.findViewById(R.id.remoteView_text)).getText().toString()); 1009 1010 // The ApplicationInfo should only have been written once, so this should be much smaller 1011 // than twice the size of parcelling one RemoteViews. 1012 assertLessThan(landscapeParcelledSize * 2, getParcelledSize(mRemoteViews)); 1013 } 1014 1015 @Test testWriteToParcel_sizeMap()1016 public void testWriteToParcel_sizeMap() throws Throwable { 1017 List<SizeF> sizes = 1018 Arrays.asList(new SizeF(50, 50), new SizeF(100, 100), new SizeF(100, 200)); 1019 Map<SizeF, RemoteViews> sizeMap = new ArrayMap<>(); 1020 int singelParcelledSize = 0; 1021 for (SizeF size : sizes) { 1022 RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 1023 views.setTextViewText(R.id.remoteView_text, "Hello world"); 1024 sizeMap.put(size, views); 1025 singelParcelledSize = getParcelledSize(views); 1026 } 1027 mRemoteViews = new RemoteViews(sizeMap); 1028 1029 mRemoteViews = parcelAndUnparcel(mRemoteViews); 1030 assertEquals(PACKAGE_NAME, mRemoteViews.getPackage()); 1031 applyRemoteViews(); 1032 assertEquals( 1033 "Hello world", 1034 ((TextView) mResult.findViewById(R.id.remoteView_text)).getText().toString()); 1035 1036 // The ApplicationInfo should only have been written once, so this should be much smaller 1037 // than thrice the size of parcelling one RemoteViews. 1038 assertLessThan(singelParcelledSize * 3, getParcelledSize(mRemoteViews)); 1039 } 1040 1041 @Test(expected=NegativeArraySizeException.class) testCreateNegativeSizedArray()1042 public void testCreateNegativeSizedArray() { 1043 RemoteViews.CREATOR.newArray(-1); 1044 } 1045 1046 @Test testSetImageViewBitmap()1047 public void testSetImageViewBitmap() throws Throwable { 1048 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 1049 assertNull(image.getDrawable()); 1050 1051 Bitmap bitmap = 1052 BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage); 1053 mRemoteViews.setImageViewBitmap(R.id.remoteView_image, bitmap); 1054 reapplyRemoteViews(); 1055 assertNotNull(image.getDrawable()); 1056 WidgetTestUtils.assertEquals(bitmap, ((BitmapDrawable) image.getDrawable()).getBitmap()); 1057 1058 mRemoteViews.setImageViewBitmap(R.id.remoteView_absolute, bitmap); 1059 assertThrowsOnReapply(ActionException.class); 1060 } 1061 1062 @Test testSetImageViewBitmap_afterCopying()1063 public void testSetImageViewBitmap_afterCopying() throws Throwable { 1064 Bitmap bitmap = 1065 BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage); 1066 RemoteViews original = 1067 new RemoteViews(mContext.getPackageName(), R.layout.remoteviews_good); 1068 original.setImageViewBitmap(R.id.remoteView_image, bitmap); 1069 mRemoteViews = new RemoteViews(original); 1070 1071 applyRemoteViews(); 1072 1073 ImageView image = mResult.findViewById(R.id.remoteView_image); 1074 assertNotNull(image.getDrawable()); 1075 WidgetTestUtils.assertEquals(bitmap, ((BitmapDrawable) image.getDrawable()).getBitmap()); 1076 } 1077 1078 @Test testSetBitmap()1079 public void testSetBitmap() throws Throwable { 1080 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 1081 assertNull(image.getDrawable()); 1082 1083 Bitmap bitmap = 1084 BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage); 1085 mRemoteViews.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap); 1086 reapplyRemoteViews(); 1087 assertNotNull(image.getDrawable()); 1088 WidgetTestUtils.assertEquals(bitmap, ((BitmapDrawable) image.getDrawable()).getBitmap()); 1089 1090 mRemoteViews.setBitmap(R.id.remoteView_absolute, "setImageBitmap", bitmap); 1091 assertThrowsOnReapply(ActionException.class); 1092 1093 assertEquals(bitmap.getAllocationByteCount(), mRemoteViews.estimateMemoryUsage()); 1094 } 1095 1096 @Test testSetBoolean()1097 public void testSetBoolean() throws Throwable { 1098 ProgressBar progress = (ProgressBar) mResult.findViewById(R.id.remoteView_progress); 1099 // the view uses style progressBarHorizontal, so the default is false 1100 assertFalse(progress.isIndeterminate()); 1101 1102 mRemoteViews.setBoolean(R.id.remoteView_progress, "setIndeterminate", true); 1103 reapplyRemoteViews(); 1104 assertTrue(progress.isIndeterminate()); 1105 1106 mRemoteViews.setBoolean(R.id.remoteView_relative, "setIndeterminate", false); 1107 assertThrowsOnReapply(ActionException.class); 1108 } 1109 1110 @Test testSetCharSequence()1111 public void testSetCharSequence() throws Throwable { 1112 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 1113 assertEquals("", textView.getText().toString()); 1114 1115 String expected = "test setCharSequence"; 1116 mRemoteViews.setCharSequence(R.id.remoteView_text, "setText", expected); 1117 reapplyRemoteViews(); 1118 assertEquals(expected, textView.getText().toString()); 1119 1120 mRemoteViews.setCharSequence(R.id.remoteView_text, "setText", null); 1121 reapplyRemoteViews(); 1122 assertEquals("", textView.getText().toString()); 1123 1124 mRemoteViews.setCharSequence(R.id.remoteView_absolute, "setText", ""); 1125 assertThrowsOnReapply(ActionException.class); 1126 } 1127 1128 @Test testSetCharSequenceAttr()1129 public void testSetCharSequenceAttr() throws Throwable { 1130 mRemoteViews.setCharSequenceAttr(R.id.remoteView_text, "setText", R.attr.themeString); 1131 applyNightModeThenApplyAndTest(false, () -> { 1132 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 1133 assertEquals("Day", textView.getText().toString()); 1134 }); 1135 1136 applyNightModeThenApplyAndTest(true, () -> { 1137 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 1138 assertEquals("Night", textView.getText().toString()); 1139 }); 1140 1141 mRemoteViews.setCharSequenceAttr(R.id.remoteView_absolute, "setText", 1142 R.attr.themeColor); 1143 assertThrowsOnReapply(ActionException.class); 1144 } 1145 1146 @Test testSetInt()1147 public void testSetInt() throws Throwable { 1148 View view = mResult.findViewById(R.id.remoteView_chronometer); 1149 assertEquals(View.VISIBLE, view.getVisibility()); 1150 1151 mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.INVISIBLE); 1152 reapplyRemoteViews(); 1153 assertEquals(View.INVISIBLE, view.getVisibility()); 1154 1155 mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.GONE); 1156 reapplyRemoteViews(); 1157 assertEquals(View.GONE, view.getVisibility()); 1158 1159 mRemoteViews.setInt(R.id.remoteView_chronometer, "setVisibility", View.VISIBLE); 1160 reapplyRemoteViews(); 1161 assertEquals(View.VISIBLE, view.getVisibility()); 1162 } 1163 1164 @Test testSetString()1165 public void testSetString() throws Throwable { 1166 String format = "HH:MM:SS"; 1167 Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer); 1168 assertNull(chronometer.getFormat()); 1169 1170 mRemoteViews.setString(R.id.remoteView_chronometer, "setFormat", format); 1171 reapplyRemoteViews(); 1172 assertEquals(format, chronometer.getFormat()); 1173 1174 mRemoteViews.setString(R.id.remoteView_image, "setFormat", format); 1175 assertThrowsOnReapply(ActionException.class); 1176 } 1177 1178 @Test testSetUri()1179 public void testSetUri() throws Throwable { 1180 String path = getTestImagePath(); 1181 File imagefile = new File(path); 1182 1183 try { 1184 createSampleImage(imagefile, R.raw.testimage); 1185 1186 Uri uri = Uri.parse(path); 1187 ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image); 1188 assertNull(image.getDrawable()); 1189 1190 mRemoteViews.setUri(R.id.remoteView_image, "setImageURI", uri); 1191 reapplyRemoteViews(); 1192 1193 Bitmap imageViewBitmap = ((BitmapDrawable) image.getDrawable()).getBitmap(); 1194 Bitmap expectedBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap( 1195 mContext.getResources(), R.raw.testimage, imageViewBitmap.getConfig()); 1196 WidgetTestUtils.assertEquals(expectedBitmap, imageViewBitmap); 1197 1198 mRemoteViews.setUri(R.id.remoteView_absolute, "setImageURI", uri); 1199 assertThrowsOnReapply(ActionException.class); 1200 } finally { 1201 // remove the test image file 1202 imagefile.delete(); 1203 } 1204 } 1205 1206 @Test testSetTextColor()1207 public void testSetTextColor() throws Throwable { 1208 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 1209 1210 mRemoteViews.setTextColor(R.id.remoteView_text, R.color.testcolor1); 1211 reapplyRemoteViews(); 1212 assertSame(ColorStateList.valueOf(R.color.testcolor1), textView.getTextColors()); 1213 1214 mRemoteViews.setTextColor(R.id.remoteView_text, R.color.testcolor2); 1215 reapplyRemoteViews(); 1216 assertSame(ColorStateList.valueOf(R.color.testcolor2), textView.getTextColors()); 1217 1218 mRemoteViews.setTextColor(R.id.remoteView_absolute, R.color.testcolor1); 1219 assertThrowsOnReapply(ActionException.class); 1220 } 1221 1222 @Test testSetTextCompoundDrawables()1223 public void testSetTextCompoundDrawables() throws Throwable { 1224 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 1225 1226 TestUtils.verifyCompoundDrawables(textView, -1, -1, -1, -1); 1227 1228 mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_text, R.drawable.start, 1229 R.drawable.pass, R.drawable.failed, 0); 1230 reapplyRemoteViews(); 1231 TestUtils.verifyCompoundDrawables(textView, R.drawable.start, R.drawable.failed, 1232 R.drawable.pass, -1); 1233 1234 mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_text, 0, 1235 R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green); 1236 reapplyRemoteViews(); 1237 TestUtils.verifyCompoundDrawables(textView, -1, R.drawable.icon_red, R.drawable.icon_black, 1238 R.drawable.icon_green); 1239 1240 mRemoteViews.setTextViewCompoundDrawables(R.id.remoteView_absolute, 0, 1241 R.drawable.start, R.drawable.failed, 0); 1242 assertThrowsOnReapply(Throwable.class); 1243 } 1244 1245 @Test testSetTextCompoundDrawablesRelative()1246 public void testSetTextCompoundDrawablesRelative() throws Throwable { 1247 TextView textViewLtr = (TextView) mResult.findViewById(R.id.remoteView_text_ltr); 1248 TextView textViewRtl = (TextView) mResult.findViewById(R.id.remoteView_text_rtl); 1249 1250 TestUtils.verifyCompoundDrawables(textViewLtr, -1, -1, -1, -1); 1251 TestUtils.verifyCompoundDrawables(textViewRtl, -1, -1, -1, -1); 1252 1253 mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_ltr, 1254 R.drawable.start, R.drawable.pass, R.drawable.failed, 0); 1255 mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_rtl, 1256 R.drawable.start, R.drawable.pass, R.drawable.failed, 0); 1257 reapplyRemoteViews(); 1258 TestUtils.verifyCompoundDrawables(textViewLtr, R.drawable.start, R.drawable.failed, 1259 R.drawable.pass, -1); 1260 TestUtils.verifyCompoundDrawables(textViewRtl, R.drawable.failed, R.drawable.start, 1261 R.drawable.pass, -1); 1262 1263 mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_ltr, 0, 1264 R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green); 1265 mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_text_rtl, 0, 1266 R.drawable.icon_black, R.drawable.icon_red, R.drawable.icon_green); 1267 reapplyRemoteViews(); 1268 TestUtils.verifyCompoundDrawables(textViewLtr, -1, R.drawable.icon_red, 1269 R.drawable.icon_black, R.drawable.icon_green); 1270 TestUtils.verifyCompoundDrawables(textViewRtl, R.drawable.icon_red, -1, 1271 R.drawable.icon_black, R.drawable.icon_green); 1272 1273 mRemoteViews.setTextViewCompoundDrawablesRelative(R.id.remoteView_absolute, 0, 1274 R.drawable.start, R.drawable.failed, 0); 1275 assertThrowsOnReapply(Throwable.class); 1276 } 1277 1278 @LargeTest 1279 @Test testSetOnClickPendingIntent()1280 public void testSetOnClickPendingIntent() throws Throwable { 1281 Uri uri = Uri.parse("ctstest://RemoteView/test"); 1282 ActivityMonitor am = mInstrumentation.addMonitor(MockURLSpanTestActivity.class.getName(), 1283 null, false); 1284 View view = mResult.findViewById(R.id.remoteView_image); 1285 view.performClick(); 1286 Activity newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT); 1287 assertNull(newActivity); 1288 1289 Intent intent = new Intent(Intent.ACTION_VIEW, uri); 1290 PendingIntent pendingIntent = 1291 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); 1292 mRemoteViews.setOnClickPendingIntent(R.id.remoteView_image, pendingIntent); 1293 reapplyRemoteViews(); 1294 mActivityRule.runOnUiThread(() -> view.performClick()); 1295 newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT); 1296 1297 // Proto serialization removes PendingIntents from the RemoteViews. 1298 if (isProtoTest) { 1299 assertNull(newActivity); 1300 return; 1301 } 1302 assertNotNull(newActivity); 1303 assertTrue(newActivity instanceof MockURLSpanTestActivity); 1304 newActivity.finish(); 1305 } 1306 1307 @LargeTest 1308 @Test 1309 @RequiresFlagsEnabled(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) testSetOnStylusHandwritingPendingIntent()1310 public void testSetOnStylusHandwritingPendingIntent() throws Throwable { 1311 ActivityMonitor am = mInstrumentation.addMonitor(MockURLSpanTestActivity.class.getName(), 1312 null, false); 1313 1314 Uri uri = Uri.parse("ctstest://RemoteView/test"); 1315 Intent intent = new Intent(Intent.ACTION_VIEW, uri); 1316 PendingIntent pendingIntent = 1317 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); 1318 mRemoteViews.setOnStylusHandwritingPendingIntent(R.id.remoteView_image, pendingIntent); 1319 reapplyRemoteViews(); 1320 View view = mResult.findViewById(R.id.remoteView_image); 1321 assertNotNull(view); 1322 mActivityRule.runOnUiThread( 1323 () -> { 1324 Runnable callback = view.getHandwritingDelegatorCallback(); 1325 // Proto serialization removes PendingIntents from the RemoteViews. 1326 if (isProtoTest) { 1327 assertNull(callback); 1328 } else { 1329 callback.run(); 1330 } 1331 }); 1332 1333 Activity newActivity = am.waitForActivityWithTimeout(TEST_TIMEOUT); 1334 if (isProtoTest) { 1335 assertNull(newActivity); 1336 return; 1337 } 1338 assertNotNull(newActivity); 1339 assertTrue(newActivity instanceof MockURLSpanTestActivity); 1340 newActivity.finish(); 1341 } 1342 1343 @LargeTest 1344 @Test 1345 @RequiresFlagsEnabled(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) testSetOnStylusHandwritingPendingIntent_null()1346 public void testSetOnStylusHandwritingPendingIntent_null() throws Throwable { 1347 ActivityMonitor am = mInstrumentation.addMonitor(MockURLSpanTestActivity.class.getName(), 1348 null, false); 1349 1350 Uri uri = Uri.parse("ctstest://RemoteView/test"); 1351 Intent intent = new Intent(Intent.ACTION_VIEW, uri); 1352 PendingIntent pendingIntent = 1353 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); 1354 mRemoteViews.setOnStylusHandwritingPendingIntent(R.id.remoteView_image, pendingIntent); 1355 reapplyRemoteViews(); 1356 mRemoteViews.setOnStylusHandwritingPendingIntent(R.id.remoteView_image, null); 1357 reapplyRemoteViews(); 1358 1359 View view = mResult.findViewById(R.id.remoteView_image); 1360 assertNull(view.getHandwritingDelegatorCallback()); 1361 } 1362 1363 @Test testSetOnCheckedChangeResponse()1364 public void testSetOnCheckedChangeResponse() throws Throwable { 1365 String action = "my-checked-change-action"; 1366 MockBroadcastReceiver receiver = new MockBroadcastReceiver(); 1367 mContext.registerReceiver(receiver, new IntentFilter(action), 1368 Context.RECEIVER_EXPORTED_UNAUDITED); 1369 1370 Intent intent = new Intent(action).setPackage(mContext.getPackageName()); 1371 PendingIntent pendingIntent = 1372 PendingIntent.getBroadcast( 1373 mContext, 1374 0, 1375 intent, 1376 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); 1377 mRemoteViews.setOnCheckedChangeResponse(R.id.remoteView_checkBox, 1378 RemoteViews.RemoteResponse.fromPendingIntent(pendingIntent)); 1379 1380 // View being checked to true should launch the intent with the extra set to true. 1381 CompoundButton view = mResult.findViewById(R.id.remoteView_checkBox); 1382 reapplyRemoteViews(); 1383 mActivityRule.runOnUiThread(() -> view.setChecked(true)); 1384 mInstrumentation.waitForIdleSync(); 1385 // Proto serialization removes PendingIntents from the RemoteViews. 1386 if (isProtoTest) { 1387 assertNull(receiver.mIntent); 1388 } else { 1389 assertNotNull(receiver.mIntent); 1390 assertTrue(receiver.mIntent.getBooleanExtra(RemoteViews.EXTRA_CHECKED, false)); 1391 } 1392 1393 // Changing the checked state from a RemoteViews action should not launch the intent. 1394 receiver.mIntent = null; 1395 mRemoteViews.setCompoundButtonChecked(R.id.remoteView_checkBox, false); 1396 reapplyRemoteViews(); 1397 mInstrumentation.waitForIdleSync(); 1398 if (isProtoTest) { 1399 assertNull(receiver.mIntent); 1400 } else { 1401 assertFalse(view.isChecked()); 1402 assertNull(receiver.mIntent); 1403 } 1404 1405 // View being checked to false should launch the intent with the extra set to false. 1406 receiver.mIntent = null; 1407 reapplyRemoteViews(); 1408 mActivityRule.runOnUiThread(() -> view.setChecked(true)); 1409 mActivityRule.runOnUiThread(() -> view.setChecked(false)); 1410 mInstrumentation.waitForIdleSync(); 1411 if (isProtoTest) { 1412 assertNull(receiver.mIntent); 1413 } else { 1414 assertNotNull(receiver.mIntent); 1415 assertFalse(receiver.mIntent.getBooleanExtra(RemoteViews.EXTRA_CHECKED, true)); 1416 } 1417 } 1418 1419 @Test testSetLong()1420 public void testSetLong() throws Throwable { 1421 long base1 = 50; 1422 long base2 = -50; 1423 Chronometer chronometer = (Chronometer) mResult.findViewById(R.id.remoteView_chronometer); 1424 1425 mRemoteViews.setLong(R.id.remoteView_chronometer, "setBase", base1); 1426 reapplyRemoteViews(); 1427 assertEquals(base1, chronometer.getBase()); 1428 1429 mRemoteViews.setLong(R.id.remoteView_chronometer, "setBase", base2); 1430 reapplyRemoteViews(); 1431 assertEquals(base2, chronometer.getBase()); 1432 1433 mRemoteViews.setLong(R.id.remoteView_absolute, "setBase", base1); 1434 assertThrowsOnReapply(ActionException.class); 1435 } 1436 1437 @Test testSetFloat()1438 public void testSetFloat() throws Throwable { 1439 LinearLayout linearLayout = (LinearLayout) mResult.findViewById(R.id.remoteView_linear); 1440 assertTrue(linearLayout.getWeightSum() <= 0.0f); 1441 1442 mRemoteViews.setFloat(R.id.remoteView_linear, "setWeightSum", 0.5f); 1443 reapplyRemoteViews(); 1444 assertEquals(0.5f, linearLayout.getWeightSum(), 0.001f); 1445 1446 mRemoteViews.setFloat(R.id.remoteView_absolute, "setWeightSum", 1.0f); 1447 assertThrowsOnReapply(ActionException.class); 1448 } 1449 1450 @Test testSetByte()1451 public void testSetByte() throws Throwable { 1452 MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom); 1453 assertEquals(0, customView.getByteField()); 1454 1455 byte b = 100; 1456 mRemoteViews.setByte(R.id.remoteView_custom, "setByteField", b); 1457 reapplyRemoteViews(); 1458 assertEquals(b, customView.getByteField()); 1459 1460 mRemoteViews.setByte(R.id.remoteView_absolute, "setByteField", b); 1461 assertThrowsOnReapply(ActionException.class); 1462 } 1463 1464 @Test testSetChar()1465 public void testSetChar() throws Throwable { 1466 MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom); 1467 assertEquals('\u0000', customView.getCharField()); 1468 1469 mRemoteViews.setChar(R.id.remoteView_custom, "setCharField", 'q'); 1470 reapplyRemoteViews(); 1471 assertEquals('q', customView.getCharField()); 1472 1473 mRemoteViews.setChar(R.id.remoteView_absolute, "setCharField", 'w'); 1474 assertThrowsOnReapply(ActionException.class); 1475 } 1476 1477 @Test testSetDouble()1478 public void testSetDouble() throws Throwable { 1479 MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom); 1480 assertEquals(0.0, customView.getDoubleField(), 0.0f); 1481 1482 mRemoteViews.setDouble(R.id.remoteView_custom, "setDoubleField", 0.5); 1483 reapplyRemoteViews(); 1484 assertEquals(0.5, customView.getDoubleField(), 0.001f); 1485 1486 mRemoteViews.setDouble(R.id.remoteView_absolute, "setDoubleField", 1.0); 1487 assertThrowsOnReapply(ActionException.class); 1488 } 1489 1490 @Test testSetShort()1491 public void testSetShort() throws Throwable { 1492 MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom); 1493 assertEquals(0, customView.getShortField()); 1494 1495 short s = 25; 1496 mRemoteViews.setShort(R.id.remoteView_custom, "setShortField", s); 1497 reapplyRemoteViews(); 1498 assertEquals(s, customView.getShortField()); 1499 1500 mRemoteViews.setShort(R.id.remoteView_absolute, "setShortField", s); 1501 assertThrowsOnReapply(ActionException.class); 1502 } 1503 1504 @Test testSetBundle()1505 public void testSetBundle() throws Throwable { 1506 MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom); 1507 assertNull(customView.getBundleField()); 1508 1509 final Bundle bundle = new Bundle(); 1510 bundle.putString("STR", "brexit"); 1511 bundle.putInt("INT", 2016); 1512 mRemoteViews.setBundle(R.id.remoteView_custom, "setBundleField", bundle); 1513 reapplyRemoteViews(); 1514 final Bundle fromRemote = customView.getBundleField(); 1515 // Proto serialization removes PendingIntents from the RemoteViews. 1516 if (isProtoTest) { 1517 assertNull(fromRemote); 1518 } else { 1519 assertEquals("brexit", fromRemote.getString("STR", "")); 1520 assertEquals(2016, fromRemote.getInt("INT", 0)); 1521 1522 mRemoteViews.setBundle(R.id.remoteView_absolute, "setBundleField", bundle); 1523 assertThrowsOnReapply(ActionException.class); 1524 } 1525 } 1526 1527 @Test testSetIntent()1528 public void testSetIntent() throws Throwable { 1529 MyRemotableView customView = (MyRemotableView) mResult.findViewById(R.id.remoteView_custom); 1530 assertNull(customView.getIntentField()); 1531 1532 final Intent intent = new Intent(mContext, SwitchCtsActivity.class); 1533 intent.putExtra("STR", "brexit"); 1534 intent.putExtra("INT", 2016); 1535 mRemoteViews.setIntent(R.id.remoteView_custom, "setIntentField", intent); 1536 reapplyRemoteViews(); 1537 final Intent fromRemote = customView.getIntentField(); 1538 // Proto serialization removes PendingIntents from the RemoteViews. 1539 if (isProtoTest) { 1540 assertNull(fromRemote); 1541 } else { 1542 assertEquals( 1543 SwitchCtsActivity.class.getName(), fromRemote.getComponent().getClassName()); 1544 assertEquals("brexit", fromRemote.getStringExtra("STR")); 1545 assertEquals(2016, fromRemote.getIntExtra("INT", 0)); 1546 1547 mRemoteViews.setIntent(R.id.remoteView_absolute, "setIntentField", intent); 1548 assertThrowsOnReapply(ActionException.class); 1549 } 1550 } 1551 1552 @Test testSetBlendMode()1553 public void testSetBlendMode() throws Throwable { 1554 ImageView imageView = mResult.findViewById(R.id.remoteView_image); 1555 1556 mRemoteViews.setBlendMode(R.id.remoteView_image, "setImageTintBlendMode", BlendMode.PLUS); 1557 reapplyRemoteViews(); 1558 assertEquals(BlendMode.PLUS, imageView.getImageTintBlendMode()); 1559 1560 mRemoteViews.setBlendMode(R.id.remoteView_image, "setImageTintBlendMode", BlendMode.SRC_IN); 1561 reapplyRemoteViews(); 1562 assertEquals(BlendMode.SRC_IN, imageView.getImageTintBlendMode()); 1563 1564 mRemoteViews.setBlendMode(R.id.remoteView_image, "setImageTintBlendMode", null); 1565 reapplyRemoteViews(); 1566 assertNull(imageView.getImageTintBlendMode()); 1567 } 1568 1569 @Test testRemoveAllViews()1570 public void testRemoveAllViews() throws Throwable { 1571 ViewGroup root = (ViewGroup) mResult.findViewById(R.id.remoteViews_good); 1572 assertTrue(root.getChildCount() > 0); 1573 1574 mRemoteViews.removeAllViews(R.id.remoteViews_good); 1575 reapplyRemoteViews(); 1576 assertEquals(0, root.getChildCount()); 1577 } 1578 1579 @Test testAddView()1580 public void testAddView() throws Throwable { 1581 ViewGroup root = (ViewGroup) mResult.findViewById(R.id.remoteViews_good); 1582 int originalChildCount = root.getChildCount(); 1583 1584 assertNull(root.findViewById(R.id.remoteView_frame_extra)); 1585 1586 // Create a RemoteViews wrapper around a layout and add it to our root 1587 RemoteViews extra = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_extra); 1588 mRemoteViews.addView(R.id.remoteViews_good, extra); 1589 reapplyRemoteViews(); 1590 1591 // Verify that our root has that layout as its last (new) child 1592 assertEquals(originalChildCount + 1, root.getChildCount()); 1593 assertNotNull(root.findViewById(R.id.remoteView_frame_extra)); 1594 assertEquals(R.id.remoteView_frame_extra, root.getChildAt(originalChildCount).getId()); 1595 } 1596 1597 @Test testSetLabelFor()1598 public void testSetLabelFor() throws Throwable { 1599 View labelView = mResult.findViewById(R.id.remoteView_label); 1600 assertEquals(View.NO_ID, labelView.getLabelFor()); 1601 1602 mRemoteViews.setLabelFor(R.id.remoteView_label, R.id.remoteView_text); 1603 reapplyRemoteViews(); 1604 assertEquals(R.id.remoteView_text, labelView.getLabelFor()); 1605 } 1606 1607 @Test testSetAccessibilityTraversalAfter()1608 public void testSetAccessibilityTraversalAfter() throws Throwable { 1609 View textView = mResult.findViewById(R.id.remoteView_text); 1610 1611 mRemoteViews.setAccessibilityTraversalAfter(R.id.remoteView_text, R.id.remoteView_frame); 1612 reapplyRemoteViews(); 1613 assertEquals(R.id.remoteView_frame, textView.getAccessibilityTraversalAfter()); 1614 1615 mRemoteViews.setAccessibilityTraversalAfter(R.id.remoteView_text, R.id.remoteView_linear); 1616 reapplyRemoteViews(); 1617 assertEquals(R.id.remoteView_linear, textView.getAccessibilityTraversalAfter()); 1618 } 1619 1620 @Test testSetAccessibilityTraversalBefore()1621 public void testSetAccessibilityTraversalBefore() throws Throwable { 1622 View textView = mResult.findViewById(R.id.remoteView_text); 1623 1624 mRemoteViews.setAccessibilityTraversalBefore(R.id.remoteView_text, R.id.remoteView_frame); 1625 reapplyRemoteViews(); 1626 assertEquals(R.id.remoteView_frame, textView.getAccessibilityTraversalBefore()); 1627 1628 mRemoteViews.setAccessibilityTraversalBefore(R.id.remoteView_text, R.id.remoteView_linear); 1629 reapplyRemoteViews(); 1630 assertEquals(R.id.remoteView_linear, textView.getAccessibilityTraversalBefore()); 1631 } 1632 1633 @Test testSetViewPadding()1634 public void testSetViewPadding() throws Throwable { 1635 View textView = mResult.findViewById(R.id.remoteView_text); 1636 1637 mRemoteViews.setViewPadding(R.id.remoteView_text, 10, 20, 30, 40); 1638 reapplyRemoteViews(); 1639 assertEquals(10, textView.getPaddingLeft()); 1640 assertEquals(20, textView.getPaddingTop()); 1641 assertEquals(30, textView.getPaddingRight()); 1642 assertEquals(40, textView.getPaddingBottom()); 1643 1644 mRemoteViews.setViewPadding(R.id.remoteView_text, 40, 30, 20, 10); 1645 reapplyRemoteViews(); 1646 assertEquals(40, textView.getPaddingLeft()); 1647 assertEquals(30, textView.getPaddingTop()); 1648 assertEquals(20, textView.getPaddingRight()); 1649 assertEquals(10, textView.getPaddingBottom()); 1650 } 1651 1652 @Test testSetViewLayoutMargin()1653 public void testSetViewLayoutMargin() throws Throwable { 1654 View textView = mResult.findViewById(R.id.remoteView_text); 1655 1656 mRemoteViews.setViewLayoutMargin(R.id.remoteView_text, MARGIN_LEFT, 10, COMPLEX_UNIT_PX); 1657 mRemoteViews.setViewLayoutMargin(R.id.remoteView_text, MARGIN_TOP, 20, COMPLEX_UNIT_PX); 1658 mRemoteViews.setViewLayoutMargin(R.id.remoteView_text, MARGIN_RIGHT, 30, COMPLEX_UNIT_PX); 1659 mRemoteViews.setViewLayoutMargin(R.id.remoteView_text, MARGIN_BOTTOM, 40, COMPLEX_UNIT_PX); 1660 reapplyRemoteViews(); 1661 assertMargins(textView, 10, 20, 30, 40); 1662 1663 mRemoteViews.setViewLayoutMargin(R.id.remoteView_text, MARGIN_LEFT, 10, COMPLEX_UNIT_DIP); 1664 mRemoteViews.setViewLayoutMargin(R.id.remoteView_text, MARGIN_TOP, 20, COMPLEX_UNIT_DIP); 1665 mRemoteViews.setViewLayoutMargin(R.id.remoteView_text, MARGIN_RIGHT, 30, COMPLEX_UNIT_DIP); 1666 mRemoteViews.setViewLayoutMargin(R.id.remoteView_text, MARGIN_BOTTOM, 40, COMPLEX_UNIT_DIP); 1667 reapplyRemoteViews(); 1668 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 1669 assertMargins( 1670 textView, 1671 resolveDimenOffset(10, COMPLEX_UNIT_DIP, displayMetrics), 1672 resolveDimenOffset(20, COMPLEX_UNIT_DIP, displayMetrics), 1673 resolveDimenOffset(30, COMPLEX_UNIT_DIP, displayMetrics), 1674 resolveDimenOffset(40, COMPLEX_UNIT_DIP, displayMetrics)); 1675 } 1676 1677 @Test testSetViewLayoutMargin_layoutDirection()1678 public void testSetViewLayoutMargin_layoutDirection() throws Throwable { 1679 View textViewLtr = mResult.findViewById(R.id.remoteView_text_ltr); 1680 mRemoteViews.setViewLayoutMargin(textViewLtr.getId(), MARGIN_START, 10, COMPLEX_UNIT_DIP); 1681 mRemoteViews.setViewLayoutMargin(textViewLtr.getId(), MARGIN_TOP, 20, COMPLEX_UNIT_DIP); 1682 mRemoteViews.setViewLayoutMargin(textViewLtr.getId(), MARGIN_END, 30, COMPLEX_UNIT_DIP); 1683 mRemoteViews.setViewLayoutMargin(textViewLtr.getId(), MARGIN_BOTTOM, 40, COMPLEX_UNIT_DIP); 1684 reapplyRemoteViews(); 1685 DisplayMetrics displayMetrics = textViewLtr.getResources().getDisplayMetrics(); 1686 assertMargins( 1687 textViewLtr, 1688 resolveDimenOffset(10, COMPLEX_UNIT_DIP, displayMetrics), 1689 resolveDimenOffset(20, COMPLEX_UNIT_DIP, displayMetrics), 1690 resolveDimenOffset(30, COMPLEX_UNIT_DIP, displayMetrics), 1691 resolveDimenOffset(40, COMPLEX_UNIT_DIP, displayMetrics)); 1692 1693 View textViewRtl = mResult.findViewById(R.id.remoteView_text_rtl); 1694 mRemoteViews.setViewLayoutMargin(textViewRtl.getId(), MARGIN_START, 10, COMPLEX_UNIT_DIP); 1695 mRemoteViews.setViewLayoutMargin(textViewRtl.getId(), MARGIN_TOP, 20, COMPLEX_UNIT_DIP); 1696 mRemoteViews.setViewLayoutMargin(textViewRtl.getId(), MARGIN_END, 30, COMPLEX_UNIT_DIP); 1697 mRemoteViews.setViewLayoutMargin(textViewRtl.getId(), MARGIN_BOTTOM, 40, COMPLEX_UNIT_DIP); 1698 reapplyRemoteViews(); 1699 displayMetrics = textViewRtl.getResources().getDisplayMetrics(); 1700 assertMargins( 1701 textViewRtl, 1702 resolveDimenOffset(30, COMPLEX_UNIT_DIP, displayMetrics), 1703 resolveDimenOffset(20, COMPLEX_UNIT_DIP, displayMetrics), 1704 resolveDimenOffset(10, COMPLEX_UNIT_DIP, displayMetrics), 1705 resolveDimenOffset(40, COMPLEX_UNIT_DIP, displayMetrics)); 1706 } 1707 1708 @Test testSetViewLayoutMarginDimen()1709 public void testSetViewLayoutMarginDimen() throws Throwable { 1710 View textView = mResult.findViewById(R.id.remoteView_text); 1711 mRemoteViews.setViewLayoutMarginDimen( 1712 R.id.remoteView_text, MARGIN_LEFT, R.dimen.textview_padding_left); 1713 mRemoteViews.setViewLayoutMarginDimen( 1714 R.id.remoteView_text, MARGIN_TOP, R.dimen.textview_padding_top); 1715 mRemoteViews.setViewLayoutMarginDimen( 1716 R.id.remoteView_text, MARGIN_RIGHT, R.dimen.textview_padding_right); 1717 mRemoteViews.setViewLayoutMarginDimen( 1718 R.id.remoteView_text, MARGIN_BOTTOM, R.dimen.textview_padding_bottom); 1719 reapplyRemoteViews(); 1720 assertMargins( 1721 textView, 1722 textView.getResources().getDimensionPixelOffset(R.dimen.textview_padding_left), 1723 textView.getResources().getDimensionPixelOffset(R.dimen.textview_padding_top), 1724 textView.getResources().getDimensionPixelOffset(R.dimen.textview_padding_right), 1725 textView.getResources().getDimensionPixelOffset(R.dimen.textview_padding_bottom)); 1726 } 1727 1728 @Test testSetViewLayoutMarginDimen_layoutDirection()1729 public void testSetViewLayoutMarginDimen_layoutDirection() throws Throwable { 1730 View textViewLtr = mResult.findViewById(R.id.remoteView_text_ltr); 1731 mRemoteViews.setViewLayoutMarginDimen( 1732 R.id.remoteView_text_ltr, MARGIN_START, R.dimen.textview_padding_left); 1733 mRemoteViews.setViewLayoutMarginDimen( 1734 R.id.remoteView_text_ltr, MARGIN_TOP, R.dimen.textview_padding_top); 1735 mRemoteViews.setViewLayoutMarginDimen( 1736 R.id.remoteView_text_ltr, MARGIN_END, R.dimen.textview_padding_right); 1737 mRemoteViews.setViewLayoutMarginDimen( 1738 R.id.remoteView_text_ltr, MARGIN_BOTTOM, R.dimen.textview_padding_bottom); 1739 reapplyRemoteViews(); 1740 assertMargins( 1741 textViewLtr, 1742 textViewLtr.getResources().getDimensionPixelOffset(R.dimen.textview_padding_left), 1743 textViewLtr.getResources().getDimensionPixelOffset(R.dimen.textview_padding_top), 1744 textViewLtr.getResources().getDimensionPixelOffset(R.dimen.textview_padding_right), 1745 textViewLtr.getResources().getDimensionPixelOffset( 1746 R.dimen.textview_padding_bottom)); 1747 1748 View textViewRtl = mResult.findViewById(R.id.remoteView_text_rtl); 1749 mRemoteViews.setViewLayoutMarginDimen( 1750 R.id.remoteView_text_rtl, MARGIN_START, R.dimen.textview_padding_left); 1751 mRemoteViews.setViewLayoutMarginDimen( 1752 R.id.remoteView_text_rtl, MARGIN_TOP, R.dimen.textview_padding_top); 1753 mRemoteViews.setViewLayoutMarginDimen( 1754 R.id.remoteView_text_rtl, MARGIN_END, R.dimen.textview_padding_right); 1755 mRemoteViews.setViewLayoutMarginDimen( 1756 R.id.remoteView_text_rtl, MARGIN_BOTTOM, R.dimen.textview_padding_bottom); 1757 reapplyRemoteViews(); 1758 assertMargins( 1759 textViewRtl, 1760 textViewRtl.getResources().getDimensionPixelOffset(R.dimen.textview_padding_right), 1761 textViewRtl.getResources().getDimensionPixelOffset(R.dimen.textview_padding_top), 1762 textViewRtl.getResources().getDimensionPixelOffset(R.dimen.textview_padding_left), 1763 textViewRtl.getResources().getDimensionPixelOffset( 1764 R.dimen.textview_padding_bottom)); 1765 } 1766 1767 @Test testSetViewLayoutMarginAttr()1768 public void testSetViewLayoutMarginAttr() throws Throwable { 1769 mRemoteViews.setViewLayoutMarginAttr( 1770 R.id.remoteView_text, MARGIN_LEFT, R.attr.themeDimension); 1771 mRemoteViews.setViewLayoutMarginAttr( 1772 R.id.remoteView_text, MARGIN_TOP, R.attr.themeDimension2); 1773 mRemoteViews.setViewLayoutMarginAttr( 1774 R.id.remoteView_text, MARGIN_RIGHT, R.attr.themeDimension3); 1775 mRemoteViews.setViewLayoutMarginAttr( 1776 R.id.remoteView_text, MARGIN_BOTTOM, R.attr.themeDimension4); 1777 1778 applyNightModeThenApplyAndTest(false, () -> { 1779 View textView = mResult.findViewById(R.id.remoteView_text); 1780 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 1781 assertMargins( 1782 textView, 1783 resolveDimenOffset(5.5123f, COMPLEX_UNIT_DIP, displayMetrics), 1784 resolveDimenOffset(2.5f, COMPLEX_UNIT_DIP, displayMetrics), 1785 resolveDimenOffset(3.5f, COMPLEX_UNIT_DIP, displayMetrics), 1786 resolveDimenOffset(4.5f, COMPLEX_UNIT_DIP, displayMetrics)); 1787 }); 1788 1789 applyNightModeThenApplyAndTest(true, () -> { 1790 View textView = mResult.findViewById(R.id.remoteView_text); 1791 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 1792 assertMargins( 1793 textView, 1794 resolveDimenOffset(7.5123f, COMPLEX_UNIT_DIP, displayMetrics), 1795 resolveDimenOffset(4.5f, COMPLEX_UNIT_DIP, displayMetrics), 1796 resolveDimenOffset(5.5f, COMPLEX_UNIT_DIP, displayMetrics), 1797 resolveDimenOffset(6.5f, COMPLEX_UNIT_DIP, displayMetrics)); 1798 }); 1799 1800 // Test that zeros resolve to 0 1801 mRemoteViews.setViewLayoutMarginAttr(R.id.remoteView_text, MARGIN_LEFT, 0); 1802 mRemoteViews.setViewLayoutMarginAttr(R.id.remoteView_text, MARGIN_TOP, 0); 1803 mRemoteViews.setViewLayoutMarginAttr(R.id.remoteView_text, MARGIN_RIGHT, 0); 1804 applyNightModeThenApplyAndTest(false, () -> { 1805 View textView = mResult.findViewById(R.id.remoteView_text); 1806 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 1807 assertMargins(textView, 0, 0, 0, 1808 resolveDimenOffset(4.5f, COMPLEX_UNIT_DIP, displayMetrics)); 1809 }); 1810 applyNightModeThenApplyAndTest(true, () -> { 1811 View textView = mResult.findViewById(R.id.remoteView_text); 1812 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 1813 assertMargins(textView, 0, 0, 0, 1814 resolveDimenOffset(6.5f, COMPLEX_UNIT_DIP, displayMetrics)); 1815 }); 1816 1817 mRemoteViews.setViewLayoutMarginAttr( 1818 R.id.remoteView_text, MARGIN_LEFT, R.attr.themeColor); 1819 assertThrowsOnReapply(ActionException.class); 1820 } 1821 1822 @Test testSetViewLayoutMarginAttr_layoutDirection()1823 public void testSetViewLayoutMarginAttr_layoutDirection() throws Throwable { 1824 mRemoteViews.setViewLayoutMarginAttr( 1825 R.id.remoteView_text_ltr, MARGIN_START, R.attr.themeDimension); 1826 mRemoteViews.setViewLayoutMarginAttr( 1827 R.id.remoteView_text_ltr, MARGIN_TOP, R.attr.themeDimension2); 1828 mRemoteViews.setViewLayoutMarginAttr( 1829 R.id.remoteView_text_ltr, MARGIN_END, R.attr.themeDimension3); 1830 mRemoteViews.setViewLayoutMarginAttr( 1831 R.id.remoteView_text_ltr, MARGIN_BOTTOM, R.attr.themeDimension4); 1832 1833 mRemoteViews.setViewLayoutMarginAttr( 1834 R.id.remoteView_text_rtl, MARGIN_START, R.attr.themeDimension); 1835 mRemoteViews.setViewLayoutMarginAttr( 1836 R.id.remoteView_text_rtl, MARGIN_TOP, R.attr.themeDimension2); 1837 mRemoteViews.setViewLayoutMarginAttr( 1838 R.id.remoteView_text_rtl, MARGIN_END, R.attr.themeDimension3); 1839 mRemoteViews.setViewLayoutMarginAttr( 1840 R.id.remoteView_text_rtl, MARGIN_BOTTOM, R.attr.themeDimension4); 1841 1842 reapplyRemoteViews(); 1843 1844 View textViewLtr = mResult.findViewById(R.id.remoteView_text_ltr); 1845 DisplayMetrics displayMetrics = textViewLtr.getResources().getDisplayMetrics(); 1846 1847 assertMargins( 1848 textViewLtr, 1849 resolveDimenOffset(5.5123f, COMPLEX_UNIT_DIP, displayMetrics), 1850 resolveDimenOffset(2.5f, COMPLEX_UNIT_DIP, displayMetrics), 1851 resolveDimenOffset(3.5f, COMPLEX_UNIT_DIP, displayMetrics), 1852 resolveDimenOffset(4.5f, COMPLEX_UNIT_DIP, displayMetrics)); 1853 1854 View textViewRtl = mResult.findViewById(R.id.remoteView_text_rtl); 1855 assertMargins( 1856 textViewRtl, 1857 resolveDimenOffset(3.5f, COMPLEX_UNIT_DIP, displayMetrics), 1858 resolveDimenOffset(2.5f, COMPLEX_UNIT_DIP, displayMetrics), 1859 resolveDimenOffset(5.5123f, COMPLEX_UNIT_DIP, displayMetrics), 1860 resolveDimenOffset(4.5f, COMPLEX_UNIT_DIP, displayMetrics)); 1861 } 1862 1863 @Test testSetViewLayoutWidth()1864 public void testSetViewLayoutWidth() throws Throwable { 1865 View textView = mResult.findViewById(R.id.remoteView_text); 1866 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 1867 1868 mRemoteViews.setViewLayoutWidth(R.id.remoteView_text, 10, COMPLEX_UNIT_PX); 1869 reapplyRemoteViews(); 1870 assertEquals(10, textView.getLayoutParams().width); 1871 1872 mRemoteViews.setViewLayoutWidth(R.id.remoteView_text, 20, COMPLEX_UNIT_DIP); 1873 reapplyRemoteViews(); 1874 assertEquals( 1875 resolveDimenSize(20, COMPLEX_UNIT_DIP, displayMetrics), 1876 textView.getLayoutParams().width); 1877 1878 mRemoteViews.setViewLayoutWidth( 1879 R.id.remoteView_text, ViewGroup.LayoutParams.MATCH_PARENT, COMPLEX_UNIT_PX); 1880 reapplyRemoteViews(); 1881 assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, textView.getLayoutParams().width); 1882 } 1883 1884 @Test testSetViewLayoutWidthDimen()1885 public void testSetViewLayoutWidthDimen() throws Throwable { 1886 View textView = mResult.findViewById(R.id.remoteView_text); 1887 mRemoteViews.setViewLayoutWidthDimen(R.id.remoteView_text, R.dimen.textview_fixed_width); 1888 reapplyRemoteViews(); 1889 assertEquals( 1890 textView.getResources().getDimensionPixelSize(R.dimen.textview_fixed_width), 1891 textView.getLayoutParams().width); 1892 1893 mRemoteViews.setViewLayoutWidthDimen(R.id.remoteView_text, 0); 1894 reapplyRemoteViews(); 1895 assertEquals(0, textView.getLayoutParams().width); 1896 } 1897 1898 @Test testSetViewLayoutWidthAttr()1899 public void testSetViewLayoutWidthAttr() throws Throwable { 1900 View textView = mResult.findViewById(R.id.remoteView_text); 1901 mRemoteViews.setViewLayoutWidthAttr(R.id.remoteView_text, R.attr.themeDimension); 1902 reapplyRemoteViews(); 1903 assertEquals( 1904 resolveDimenSize(5.5123f, COMPLEX_UNIT_DIP, 1905 textView.getResources().getDisplayMetrics()), 1906 textView.getLayoutParams().width); 1907 1908 mRemoteViews.setViewLayoutWidthAttr(R.id.remoteView_text, 0); 1909 reapplyRemoteViews(); 1910 assertEquals(0, textView.getLayoutParams().width); 1911 1912 mRemoteViews.setViewLayoutWidthAttr(R.id.remoteView_text, R.attr.themeColor); 1913 assertThrowsOnReapply(ActionException.class); 1914 } 1915 1916 @Test testSetViewLayoutHeight()1917 public void testSetViewLayoutHeight() throws Throwable { 1918 View textView = mResult.findViewById(R.id.remoteView_text); 1919 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 1920 1921 mRemoteViews.setViewLayoutHeight(R.id.remoteView_text, 10, COMPLEX_UNIT_PX); 1922 reapplyRemoteViews(); 1923 assertEquals(10, textView.getLayoutParams().height); 1924 1925 mRemoteViews.setViewLayoutHeight(R.id.remoteView_text, 20, COMPLEX_UNIT_DIP); 1926 reapplyRemoteViews(); 1927 assertEquals( 1928 resolveDimenSize(20, COMPLEX_UNIT_DIP, displayMetrics), 1929 textView.getLayoutParams().height); 1930 1931 mRemoteViews.setViewLayoutHeight( 1932 R.id.remoteView_text, ViewGroup.LayoutParams.MATCH_PARENT, COMPLEX_UNIT_PX); 1933 reapplyRemoteViews(); 1934 assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, textView.getLayoutParams().height); 1935 } 1936 1937 @Test testSetViewLayoutHeightDimen()1938 public void testSetViewLayoutHeightDimen() throws Throwable { 1939 View textView = mResult.findViewById(R.id.remoteView_text); 1940 mRemoteViews.setViewLayoutHeightDimen(R.id.remoteView_text, R.dimen.textview_fixed_height); 1941 reapplyRemoteViews(); 1942 assertEquals( 1943 textView.getResources().getDimensionPixelSize(R.dimen.textview_fixed_height), 1944 textView.getLayoutParams().height); 1945 1946 mRemoteViews.setViewLayoutHeightDimen(R.id.remoteView_text, 0); 1947 reapplyRemoteViews(); 1948 assertEquals(0, textView.getLayoutParams().height); 1949 } 1950 1951 @Test testSetViewLayoutHeightAttr()1952 public void testSetViewLayoutHeightAttr() throws Throwable { 1953 View textView = mResult.findViewById(R.id.remoteView_text); 1954 mRemoteViews.setViewLayoutHeightAttr(R.id.remoteView_text, R.attr.themeDimension); 1955 reapplyRemoteViews(); 1956 assertEquals( 1957 resolveDimenSize(5.5123f, COMPLEX_UNIT_DIP, 1958 textView.getResources().getDisplayMetrics()), 1959 textView.getLayoutParams().height); 1960 1961 mRemoteViews.setViewLayoutHeightAttr(R.id.remoteView_text, 0); 1962 reapplyRemoteViews(); 1963 assertEquals(0, textView.getLayoutParams().height); 1964 1965 mRemoteViews.setViewLayoutHeightAttr( 1966 R.id.remoteView_text, R.attr.themeColor); 1967 assertThrowsOnReapply(ActionException.class); 1968 } 1969 1970 @Test testSetIntDimen_fromResources()1971 public void testSetIntDimen_fromResources() throws Throwable { 1972 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 1973 int expectedValue = mContext.getResources().getDimensionPixelSize(R.dimen.popup_row_height); 1974 1975 mRemoteViews.setIntDimen(R.id.remoteView_text, "setCompoundDrawablePadding", 1976 R.dimen.popup_row_height); 1977 reapplyRemoteViews(); 1978 assertEquals(expectedValue, textView.getCompoundDrawablePadding()); 1979 1980 // test that passing 0 for the dimen sets 0 on the method. 1981 mRemoteViews.setIntDimen(R.id.remoteView_text, "setCompoundDrawablePadding", 0); 1982 reapplyRemoteViews(); 1983 assertEquals(0, textView.getCompoundDrawablePadding()); 1984 1985 mRemoteViews.setIntDimen(R.id.remoteView_text, "setCompoundDrawablePadding", 1986 R.color.testcolor1); 1987 assertThrowsOnReapply(ActionException.class); 1988 } 1989 1990 @Test testSetIntDimen_fromUnitDimension()1991 public void testSetIntDimen_fromUnitDimension() throws Throwable { 1992 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 1993 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 1994 1995 mRemoteViews.setIntDimen(R.id.remoteView_text, "setCompoundDrawablePadding", 1996 12f, COMPLEX_UNIT_DIP); 1997 reapplyRemoteViews(); 1998 assertEquals(resolveDimenSize(12f, COMPLEX_UNIT_DIP, displayMetrics), 1999 textView.getCompoundDrawablePadding()); 2000 2001 mRemoteViews.setIntDimen(R.id.remoteView_text, "setCompoundDrawablePadding", 2002 12f, TypedValue.COMPLEX_UNIT_SP); 2003 reapplyRemoteViews(); 2004 assertEquals(resolveDimenSize(12f, TypedValue.COMPLEX_UNIT_SP, displayMetrics), 2005 textView.getCompoundDrawablePadding()); 2006 2007 mRemoteViews.setIntDimen(R.id.remoteView_text, "setCompoundDrawablePadding", 2008 12f, TypedValue.COMPLEX_UNIT_PX); 2009 reapplyRemoteViews(); 2010 assertEquals(resolveDimenSize(12f, TypedValue.COMPLEX_UNIT_PX, displayMetrics), 2011 textView.getCompoundDrawablePadding()); 2012 2013 mRemoteViews.setIntDimen(R.id.remoteView_text, "setCompoundDrawablePadding", 2014 12f, 123456); 2015 assertThrowsOnReapply(ActionException.class); 2016 } 2017 2018 @Test testSetIntDimenAttr()2019 public void testSetIntDimenAttr() throws Throwable { 2020 mRemoteViews.setIntDimenAttr(R.id.remoteView_text, "setCompoundDrawablePadding", 2021 R.attr.themeDimension); 2022 applyNightModeThenApplyAndTest(false, () -> { 2023 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2024 assertEquals(resolveDimenSize(5.5123f, COMPLEX_UNIT_DIP, 2025 textView.getResources().getDisplayMetrics()), 2026 textView.getCompoundDrawablePadding()); 2027 }); 2028 2029 applyNightModeThenApplyAndTest(true, () -> { 2030 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2031 assertEquals(resolveDimenSize(7.5123f, COMPLEX_UNIT_DIP, 2032 textView.getResources().getDisplayMetrics()), 2033 textView.getCompoundDrawablePadding()); 2034 }); 2035 2036 // test that 0 resolves to 0 2037 mRemoteViews.setIntDimenAttr(R.id.remoteView_text, "setCompoundDrawablePadding", 0); 2038 applyNightModeThenApplyAndTest(false, () -> { 2039 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2040 assertEquals(0, textView.getCompoundDrawablePadding()); 2041 }); 2042 2043 applyNightModeThenApplyAndTest(true, () -> { 2044 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2045 assertEquals(0, textView.getCompoundDrawablePadding()); 2046 }); 2047 2048 mRemoteViews.setIntDimenAttr(R.id.remoteView_text, "setCompoundDrawablePadding", 2049 R.attr.themeColor); 2050 assertThrowsOnReapply(ActionException.class); 2051 } 2052 2053 2054 @Test testSetFloatDimen_fromResources()2055 public void testSetFloatDimen_fromResources() throws Throwable { 2056 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2057 2058 mRemoteViews.setFloatDimen(R.id.remoteView_text, "setTextScaleX", 2059 R.dimen.remoteviews_float_dimen); 2060 reapplyRemoteViews(); 2061 assertEquals(textView.getResources().getDimension(R.dimen.remoteviews_float_dimen), 2062 textView.getTextScaleX(), 1e-4f); 2063 2064 // test that passing 0 for the dimen sets 0f on the method. 2065 mRemoteViews.setFloatDimen(R.id.remoteView_text, "setTextScaleX", 0); 2066 reapplyRemoteViews(); 2067 assertEquals(0f, textView.getTextScaleX(), 1e-4f); 2068 2069 mRemoteViews.setFloatDimen(R.id.remoteView_text, "setTextScaleX", R.color.testcolor1); 2070 assertThrowsOnReapply(ActionException.class); 2071 } 2072 2073 @Test testSetFloatDimen_fromUnitDimension()2074 public void testSetFloatDimen_fromUnitDimension() throws Throwable { 2075 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2076 DisplayMetrics displayMetrics = textView.getResources().getDisplayMetrics(); 2077 2078 mRemoteViews.setFloatDimen(R.id.remoteView_text, "setTextScaleX", 2079 3.5f, COMPLEX_UNIT_DIP); 2080 reapplyRemoteViews(); 2081 assertEquals(TypedValue.applyDimension(COMPLEX_UNIT_DIP, 3.5f, displayMetrics), 2082 textView.getTextScaleX(), 1e-4f); 2083 2084 mRemoteViews.setFloatDimen(R.id.remoteView_text, "setTextScaleX", 2085 3.5f, TypedValue.COMPLEX_UNIT_SP); 2086 reapplyRemoteViews(); 2087 assertEquals(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 3.5f, displayMetrics), 2088 textView.getTextScaleX(), 1e-4f); 2089 2090 mRemoteViews.setFloatDimen(R.id.remoteView_text, "setTextScaleX", 2091 3.5f, TypedValue.COMPLEX_UNIT_PX); 2092 reapplyRemoteViews(); 2093 assertEquals(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 3.5f, displayMetrics), 2094 textView.getTextScaleX(), 1e-4f); 2095 2096 mRemoteViews.setFloatDimen(R.id.remoteView_text, "setTextScaleX", 2097 3.5f, 123456); 2098 assertThrowsOnReapply(ActionException.class); 2099 } 2100 2101 @Test testSetFloatDimenAttr()2102 public void testSetFloatDimenAttr() throws Throwable { 2103 mRemoteViews.setFloatDimenAttr(R.id.remoteView_text, "setTextScaleX", 2104 R.attr.themeDimension); 2105 applyNightModeThenApplyAndTest(false, () -> { 2106 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2107 assertEquals(TypedValue.applyDimension(COMPLEX_UNIT_DIP, 5.5123f, 2108 textView.getResources().getDisplayMetrics()), textView.getTextScaleX(), 1e-4f); 2109 }); 2110 2111 applyNightModeThenApplyAndTest(true, () -> { 2112 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2113 assertEquals(TypedValue.applyDimension(COMPLEX_UNIT_DIP, 7.5123f, 2114 textView.getResources().getDisplayMetrics()), textView.getTextScaleX(), 1e-4f); 2115 }); 2116 2117 // test that 0 resolves to 0 2118 mRemoteViews.setFloatDimenAttr(R.id.remoteView_text, "setTextScaleX", 0); 2119 applyNightModeThenApplyAndTest(false, () -> { 2120 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2121 assertEquals(0f, textView.getTextScaleX(), 1e-4f); 2122 }); 2123 2124 applyNightModeThenApplyAndTest(true, () -> { 2125 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2126 assertEquals(0f, textView.getTextScaleX(), 1e-4f); 2127 }); 2128 2129 mRemoteViews.setFloatDimenAttr(R.id.remoteView_text, "setTextScaleX", 2130 R.attr.themeColor); 2131 assertThrowsOnReapply(ActionException.class); 2132 } 2133 2134 @Test testSetColor()2135 public void testSetColor() throws Throwable { 2136 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2137 int expectedValue = mContext.getColor(R.color.testcolor1); 2138 2139 mRemoteViews.setColor(R.id.remoteView_text, "setTextColor", R.color.testcolor1); 2140 reapplyRemoteViews(); 2141 assertSameColorStateList(ColorStateList.valueOf(expectedValue), textView.getTextColors()); 2142 2143 mRemoteViews.setColor(R.id.remoteView_text, "setTextColor", 0); 2144 reapplyRemoteViews(); 2145 assertSameColorStateList(ColorStateList.valueOf(0), textView.getTextColors()); 2146 2147 mRemoteViews.setColor(R.id.remoteView_text, "setTextColor", R.dimen.popup_row_height); 2148 assertThrowsOnReapply(ActionException.class); 2149 } 2150 2151 @Test testSetColorAttr()2152 public void testSetColorAttr() throws Throwable { 2153 // Ensure the configuration is "light" 2154 mRemoteViews.setColorAttr(R.id.remoteView_text, "setTextColor", R.attr.themeColor); 2155 2156 applyNightModeThenApplyAndTest(false, () -> { 2157 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2158 assertSameColorStateList(ColorStateList.valueOf(0x0f00ff00), textView.getTextColors()); 2159 }); 2160 2161 // Switch to night mode 2162 applyNightModeThenApplyAndTest(true, () -> { 2163 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2164 assertSameColorStateList(ColorStateList.valueOf(0x0f00ffff), textView.getTextColors()); 2165 }); 2166 2167 // Set to 0 and test that the colors are set to 0 2168 mRemoteViews.setColorAttr(R.id.remoteView_text, "setTextColor", 0); 2169 2170 applyNightModeThenApplyAndTest(false, () -> { 2171 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2172 assertSameColorStateList(ColorStateList.valueOf(0), textView.getTextColors()); 2173 }); 2174 2175 // Switch to night mode 2176 applyNightModeThenApplyAndTest(true, () -> { 2177 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2178 assertSameColorStateList(ColorStateList.valueOf(0), textView.getTextColors()); 2179 }); 2180 2181 mRemoteViews.setColorAttr(R.id.remoteView_text, "setTextColor", R.attr.themeDimension); 2182 assertThrowsOnReapply(ActionException.class); 2183 } 2184 2185 @Test testSetColorStateList()2186 public void testSetColorStateList() throws Throwable { 2187 ProgressBar progressBar = mResult.findViewById(R.id.remoteView_progress); 2188 2189 ColorStateList tintList = new ColorStateList( 2190 new int[][] {{android.R.attr.state_checked}, {}}, 2191 new int[] {Color.BLACK, Color.WHITE}); 2192 mRemoteViews.setColorStateList(R.id.remoteView_progress, "setProgressTintList", tintList); 2193 reapplyRemoteViews(); 2194 assertSameColorStateList(tintList, progressBar.getProgressTintList()); 2195 2196 mRemoteViews.setColorStateList(R.id.remoteView_progress, "setProgressTintList", null); 2197 reapplyRemoteViews(); 2198 assertNull(progressBar.getProgressTintList()); 2199 2200 TextView textView = mResult.findViewById(R.id.remoteView_text); 2201 mRemoteViews.setColorStateList(R.id.remoteView_text, "setTextColor", tintList); 2202 reapplyRemoteViews(); 2203 assertSameColorStateList(tintList, textView.getTextColors()); 2204 2205 ColorStateList solid = ColorStateList.valueOf(Color.RED); 2206 mRemoteViews.setColorStateList(R.id.remoteView_text, "setBackgroundTintList", solid); 2207 reapplyRemoteViews(); 2208 assertSameColorStateList(solid, textView.getBackgroundTintList()); 2209 } 2210 2211 @Test testSetColorStateListAttr()2212 public void testSetColorStateListAttr() throws Throwable { 2213 mRemoteViews.setColorStateListAttr(R.id.remoteView_progress, "setProgressTintList", 2214 R.attr.themeColor); 2215 applyNightModeThenApplyAndTest(false, () -> { 2216 ProgressBar progressBar = mResult.findViewById(R.id.remoteView_progress); 2217 assertSameColorStateList(ColorStateList.valueOf(0x0f00ff00), 2218 progressBar.getProgressTintList()); 2219 }); 2220 2221 applyNightModeThenApplyAndTest(true, () -> { 2222 ProgressBar progressBar = mResult.findViewById(R.id.remoteView_progress); 2223 assertSameColorStateList(ColorStateList.valueOf(0x0f00ffff), 2224 progressBar.getProgressTintList()); 2225 }); 2226 2227 mRemoteViews.setColorStateListAttr(R.id.remoteView_progress, "setProgressTintList", 0); 2228 applyNightModeThenApplyAndTest(false, () -> { 2229 ProgressBar progressBar = mResult.findViewById(R.id.remoteView_progress); 2230 assertSameColorStateList(null, progressBar.getProgressTintList()); 2231 }); 2232 2233 applyNightModeThenApplyAndTest(true, () -> { 2234 ProgressBar progressBar = mResult.findViewById(R.id.remoteView_progress); 2235 assertSameColorStateList(null, progressBar.getProgressTintList()); 2236 }); 2237 2238 mRemoteViews.setColorAttr(R.id.remoteView_progress, 2239 "setProgressTintList", R.attr.themeDimension); 2240 assertThrowsOnReapply(ActionException.class); 2241 } 2242 2243 @Test testSetColorStateInt_nightMode()2244 public void testSetColorStateInt_nightMode() throws Throwable { 2245 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2246 mRemoteViews.setColorInt(R.id.remoteView_text, "setTextColor", Color.BLACK, Color.WHITE); 2247 2248 applyNightModeThenReapplyAndTest( 2249 false, 2250 () -> assertSameColorStateList(ColorStateList.valueOf(Color.BLACK), 2251 textView.getTextColors()) 2252 ); 2253 applyNightModeThenReapplyAndTest( 2254 true, 2255 () -> assertSameColorStateList(ColorStateList.valueOf(Color.WHITE), 2256 textView.getTextColors()) 2257 ); 2258 } 2259 2260 @Test testSetColorStateList_fromResources()2261 public void testSetColorStateList_fromResources() throws Throwable { 2262 ProgressBar progressBar = (ProgressBar) mResult.findViewById(R.id.remoteView_progress); 2263 ColorStateList expectedValue = mContext.getColorStateList(R.color.testcolorstatelist1); 2264 2265 mRemoteViews.setColorStateList(R.id.remoteView_progress, "setProgressTintList", 2266 R.color.testcolorstatelist1); 2267 reapplyRemoteViews(); 2268 assertSameColorStateList(expectedValue, progressBar.getProgressTintList()); 2269 2270 mRemoteViews.setColorStateList(R.id.remoteView_progress, "setProgressTintList", 2271 R.color.testcolor1); 2272 reapplyRemoteViews(); 2273 expectedValue = mContext.getResources().getColorStateList(R.color.testcolor1, 2274 mContext.getTheme()); 2275 assertSameColorStateList(expectedValue, progressBar.getProgressTintList()); 2276 2277 // 0 should resolve to null 2278 mRemoteViews.setColorStateList(R.id.remoteView_progress, "setProgressTintList", 0); 2279 reapplyRemoteViews(); 2280 assertSameColorStateList(null, progressBar.getProgressTintList()); 2281 2282 mRemoteViews.setColorStateList(R.id.remoteView_progress, "setProgressTintList", 2283 R.dimen.popup_row_height); 2284 assertThrowsOnReapply(ActionException.class); 2285 } 2286 2287 @Test testSetColorStateList_nightMode()2288 public void testSetColorStateList_nightMode() throws Throwable { 2289 TextView textView = (TextView) mResult.findViewById(R.id.remoteView_text); 2290 ColorStateList lightMode = ColorStateList.valueOf(Color.BLACK); 2291 ColorStateList darkMode = ColorStateList.valueOf(Color.WHITE); 2292 mRemoteViews.setColorStateList(R.id.remoteView_text, "setTextColor", lightMode, darkMode); 2293 2294 applyNightModeThenReapplyAndTest(false, 2295 () -> assertSameColorStateList(lightMode, textView.getTextColors())); 2296 applyNightModeThenReapplyAndTest(true, 2297 () -> assertSameColorStateList(darkMode, textView.getTextColors())); 2298 } 2299 2300 @Test testSetViewOutlinePreferredRadius()2301 public void testSetViewOutlinePreferredRadius() throws Throwable { 2302 View root = mResult.findViewById(R.id.remoteViews_good); 2303 DisplayMetrics displayMetrics = root.getResources().getDisplayMetrics(); 2304 2305 mRemoteViews.setViewOutlinePreferredRadius( 2306 R.id.remoteViews_good, 8, COMPLEX_UNIT_DIP); 2307 reapplyRemoteViews(); 2308 assertEquals( 2309 TypedValue.applyDimension(COMPLEX_UNIT_DIP, 8, displayMetrics), 2310 ((RemoteViews.RemoteViewOutlineProvider) root.getOutlineProvider()).getRadius(), 2311 0.1 /* delta */); 2312 2313 mRemoteViews.setViewOutlinePreferredRadius( 2314 R.id.remoteViews_good, 16, COMPLEX_UNIT_PX); 2315 reapplyRemoteViews(); 2316 assertEquals( 2317 16, 2318 ((RemoteViews.RemoteViewOutlineProvider) root.getOutlineProvider()).getRadius(), 2319 0.1 /* delta */); 2320 } 2321 2322 @Test testSetViewOutlinePreferredRadiusDimen()2323 public void testSetViewOutlinePreferredRadiusDimen() throws Throwable { 2324 View root = mResult.findViewById(R.id.remoteViews_good); 2325 2326 mRemoteViews.setViewOutlinePreferredRadiusDimen( 2327 R.id.remoteViews_good, R.dimen.popup_row_height); 2328 reapplyRemoteViews(); 2329 assertEquals( 2330 root.getResources().getDimension(R.dimen.popup_row_height), 2331 ((RemoteViews.RemoteViewOutlineProvider) root.getOutlineProvider()).getRadius(), 2332 0.1 /* delta */); 2333 2334 mRemoteViews.setViewOutlinePreferredRadiusDimen( 2335 R.id.remoteViews_good, 0); 2336 reapplyRemoteViews(); 2337 assertEquals( 2338 0, 2339 ((RemoteViews.RemoteViewOutlineProvider) root.getOutlineProvider()).getRadius(), 2340 0.1 /* delta */); 2341 } 2342 2343 @Test testSetViewOutlinePreferredRadiusAttr()2344 public void testSetViewOutlinePreferredRadiusAttr() throws Throwable { 2345 mRemoteViews.setViewOutlinePreferredRadiusAttr( 2346 R.id.remoteViews_good, R.attr.themeDimension); 2347 2348 applyNightModeThenApplyAndTest(false, 2349 () -> { 2350 View root = mResult.findViewById(R.id.remoteViews_good); 2351 assertEquals( 2352 TypedValue.applyDimension(COMPLEX_UNIT_DIP, 5.5123f, 2353 root.getResources().getDisplayMetrics()), 2354 ((RemoteViews.RemoteViewOutlineProvider) 2355 root.getOutlineProvider()).getRadius(), 2356 0.1 /* delta */); 2357 }); 2358 2359 applyNightModeThenApplyAndTest(true, 2360 () -> { 2361 View root = mResult.findViewById(R.id.remoteViews_good); 2362 assertEquals( 2363 TypedValue.applyDimension(COMPLEX_UNIT_DIP, 7.5123f, 2364 root.getResources().getDisplayMetrics()), 2365 ((RemoteViews.RemoteViewOutlineProvider) 2366 root.getOutlineProvider()).getRadius(), 2367 0.1 /* delta */); 2368 }); 2369 2370 mRemoteViews.setViewOutlinePreferredRadiusAttr( 2371 R.id.remoteViews_good, R.attr.themeColor); 2372 assertThrowsOnReapply(ActionException.class); 2373 } 2374 2375 @Test testSetSwitchChecked()2376 public void testSetSwitchChecked() throws Throwable { 2377 Switch toggle = mResult.findViewById(R.id.remoteView_switch); 2378 2379 mRemoteViews.setCompoundButtonChecked(R.id.remoteView_switch, true); 2380 reapplyRemoteViews(); 2381 assertTrue(toggle.isChecked()); 2382 2383 mRemoteViews.setCompoundButtonChecked(R.id.remoteView_switch, false); 2384 reapplyRemoteViews(); 2385 assertFalse(toggle.isChecked()); 2386 } 2387 2388 @Test testSetCheckBoxChecked()2389 public void testSetCheckBoxChecked() throws Throwable { 2390 CheckBox checkBox = mResult.findViewById(R.id.remoteView_checkBox); 2391 2392 mRemoteViews.setCompoundButtonChecked(R.id.remoteView_checkBox, true); 2393 reapplyRemoteViews(); 2394 assertTrue(checkBox.isChecked()); 2395 2396 mRemoteViews.setCompoundButtonChecked(R.id.remoteView_checkBox, false); 2397 reapplyRemoteViews(); 2398 assertFalse(checkBox.isChecked()); 2399 } 2400 2401 @Test testSetRadioButtonChecked()2402 public void testSetRadioButtonChecked() throws Throwable { 2403 RadioButton radioButton = mResult.findViewById(R.id.remoteView_radioButton1); 2404 2405 mRemoteViews.setCompoundButtonChecked(R.id.remoteView_radioButton1, true); 2406 reapplyRemoteViews(); 2407 assertTrue(radioButton.isChecked()); 2408 2409 mRemoteViews.setCompoundButtonChecked(R.id.remoteView_radioButton1, false); 2410 reapplyRemoteViews(); 2411 assertFalse(radioButton.isChecked()); 2412 } 2413 2414 @Test testSetRadioGroupChecked()2415 public void testSetRadioGroupChecked() throws Throwable { 2416 RadioGroup radioGroup = mResult.findViewById(R.id.remoteView_radioGroup); 2417 RadioButton button1 = mResult.findViewById(R.id.remoteView_radioButton1); 2418 RadioButton button2 = mResult.findViewById(R.id.remoteView_radioButton2); 2419 2420 mRemoteViews.setRadioGroupChecked(R.id.remoteView_radioGroup, R.id.remoteView_radioButton1); 2421 reapplyRemoteViews(); 2422 assertTrue(button1.isChecked()); 2423 assertFalse(button2.isChecked()); 2424 2425 mRemoteViews.setRadioGroupChecked(R.id.remoteView_radioGroup, R.id.remoteView_radioButton2); 2426 reapplyRemoteViews(); 2427 assertFalse(button1.isChecked()); 2428 assertTrue(button2.isChecked()); 2429 2430 mRemoteViews.setRadioGroupChecked(R.id.remoteView_radioGroup, -1); 2431 reapplyRemoteViews(); 2432 assertFalse(button1.isChecked()); 2433 assertFalse(button2.isChecked()); 2434 } 2435 2436 @Test testCanRecycleView()2437 public void testCanRecycleView() throws Throwable { 2438 mRemoteViews = 2439 new RemoteViews( 2440 PACKAGE_NAME, R.layout.remoteviews_textview, R.id.view2 /* viewId */); 2441 2442 applyRemoteViews(); 2443 2444 mRemoteViews = 2445 new RemoteViews( 2446 PACKAGE_NAME, R.layout.remoteviews_textview, R.id.view3 /* viewId */); 2447 assertFalse(mRemoteViews.canRecycleView(mResult)); 2448 2449 mRemoteViews = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_textview); 2450 assertFalse(mRemoteViews.canRecycleView(mResult)); 2451 2452 mRemoteViews = 2453 new RemoteViews( 2454 PACKAGE_NAME, R.layout.remoteviews_textview, R.id.view2 /* viewId */); 2455 assertTrue(mRemoteViews.canRecycleView(mResult)); 2456 2457 mRemoteViews = 2458 new RemoteViews(PACKAGE_NAME, R.layout.listview_layout, R.id.view2 /* viewId */); 2459 assertFalse(mRemoteViews.canRecycleView(mResult)); 2460 2461 assertFalse(mRemoteViews.canRecycleView(null)); 2462 assertFalse(mRemoteViews.canRecycleView(new View(mContext))); 2463 } 2464 2465 @Test testSameBitmapIsCached_landscapePortrait()2466 public void testSameBitmapIsCached_landscapePortrait() { 2467 Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage); 2468 mRemoteViews.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap); 2469 long originalMemoryUsage = mRemoteViews.estimateMemoryUsage(); 2470 assertEquals(bitmap.getAllocationByteCount(), originalMemoryUsage); 2471 2472 // Create a remoteviews with the same bitmap in landscape and portrait, and confirm 2473 // that the cache is reconstructed after deserialization. 2474 RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 2475 landscape.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap); 2476 RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 2477 portrait.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap); 2478 mRemoteViews = new RemoteViews(portrait, landscape); 2479 assertEquals(originalMemoryUsage, mRemoteViews.estimateMemoryUsage()); 2480 2481 RemoteViews recreated; 2482 if (isProtoTest) { 2483 recreated = RemoteViewsUtil.recreateFromProto(mContext, mRemoteViews); 2484 } else { 2485 recreated = parcelAndUnparcel(mRemoteViews); 2486 } 2487 assertEquals(originalMemoryUsage, recreated.estimateMemoryUsage()); 2488 } 2489 2490 @Test testSameBitmapIsCached_sizedViews()2491 public void testSameBitmapIsCached_sizedViews() { 2492 Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage); 2493 mRemoteViews.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap); 2494 long originalMemoryUsage = mRemoteViews.estimateMemoryUsage(); 2495 assertEquals(bitmap.getAllocationByteCount(), originalMemoryUsage); 2496 2497 // Create a remoteviews with the same bitmap in different sized views, and confirm 2498 // that the cache is reconstructed after deserialization. 2499 RemoteViews child = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 2500 child.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap); 2501 Map<SizeF, RemoteViews> map = new ArrayMap<>(); 2502 map.put(new SizeF(0, 0), child); 2503 map.put(new SizeF(100, 100), child); 2504 map.put(new SizeF(200, 200), child); 2505 mRemoteViews = new RemoteViews(map); 2506 assertEquals(originalMemoryUsage, mRemoteViews.estimateMemoryUsage()); 2507 2508 RemoteViews recreated; 2509 if (isProtoTest) { 2510 recreated = RemoteViewsUtil.recreateFromProto(mContext, mRemoteViews); 2511 } else { 2512 recreated = parcelAndUnparcel(mRemoteViews); 2513 } 2514 assertEquals(originalMemoryUsage, recreated.estimateMemoryUsage()); 2515 } 2516 2517 @Test testSameBitmapIsCached_nestedViews()2518 public void testSameBitmapIsCached_nestedViews() { 2519 Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.testimage); 2520 mRemoteViews.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap); 2521 long originalMemoryUsage = mRemoteViews.estimateMemoryUsage(); 2522 assertEquals(bitmap.getAllocationByteCount(), originalMemoryUsage); 2523 2524 // Create a remoteviews with the same bitmap in nested views, and confirm that the cache is 2525 // reconstructed after deserialization. 2526 RemoteViews child = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good); 2527 child.setBitmap(R.id.remoteView_image, "setImageBitmap", bitmap); 2528 mRemoteViews.addView(R.id.remoteViews_good, child); 2529 mRemoteViews.addView(R.id.remoteViews_good, child); 2530 mRemoteViews.addView(R.id.remoteViews_good, child); 2531 assertEquals(originalMemoryUsage, mRemoteViews.estimateMemoryUsage()); 2532 2533 RemoteViews recreated; 2534 if (isProtoTest) { 2535 recreated = RemoteViewsUtil.recreateFromProto(mContext, mRemoteViews); 2536 } else { 2537 recreated = parcelAndUnparcel(mRemoteViews); 2538 } 2539 assertEquals(originalMemoryUsage, recreated.estimateMemoryUsage()); 2540 } 2541 createSampleImage(File imagefile, int resid)2542 private void createSampleImage(File imagefile, int resid) throws IOException { 2543 try (InputStream source = mContext.getResources().openRawResource(resid); 2544 OutputStream target = new FileOutputStream(imagefile)) { 2545 2546 byte[] buffer = new byte[1024]; 2547 for (int len = source.read(buffer); len > 0; len = source.read(buffer)) { 2548 target.write(buffer, 0, len); 2549 } 2550 } 2551 } 2552 2553 /** 2554 * Sets the night mode, reapplies the remote views, runs test, and then restores the previous 2555 * night mode. 2556 */ applyNightModeThenReapplyAndTest(boolean nightMode, ThrowingRunnable test)2557 private void applyNightModeThenReapplyAndTest(boolean nightMode, ThrowingRunnable test) 2558 throws Throwable { 2559 applyNightModeAndTest( 2560 nightMode, 2561 () -> { 2562 try { 2563 reapplyRemoteViews(); 2564 } catch (Throwable e) { 2565 throw new RuntimeException(e); 2566 } 2567 }, 2568 test); 2569 } 2570 2571 /** 2572 * Sets the night mode, reapplies the remote views, runs test, and then restores the previous 2573 * night mode. 2574 */ applyNightModeThenApplyAndTest( boolean nightMode, ThrowingRunnable test)2575 private void applyNightModeThenApplyAndTest( 2576 boolean nightMode, ThrowingRunnable test) throws Throwable { 2577 applyNightModeAndTest( 2578 nightMode, 2579 () -> { 2580 try { 2581 applyRemoteViews(); 2582 } catch (Throwable e) { 2583 throw new RuntimeException(e); 2584 } 2585 }, 2586 test); 2587 } 2588 applyNightModeAndTest( boolean nightMode, ThrowingRunnable uiThreadSetup, ThrowingRunnable test)2589 private void applyNightModeAndTest( 2590 boolean nightMode, ThrowingRunnable uiThreadSetup, ThrowingRunnable test) 2591 throws Throwable { 2592 final String initialNightMode = changeNightMode(nightMode); 2593 try { 2594 mActivityRule.runOnUiThread( 2595 () -> { 2596 try { 2597 uiThreadSetup.run(); 2598 } catch (Throwable e) { 2599 throw new RuntimeException(e); 2600 } 2601 }); 2602 test.run(); 2603 } finally { 2604 runShellCommand("cmd uimode night " + initialNightMode); 2605 } 2606 } 2607 assertMargins(View view, int left, int top, int right, int bottom)2608 private static void assertMargins(View view, int left, int top, int right, int bottom) { 2609 ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); 2610 if (!(layoutParams instanceof ViewGroup.MarginLayoutParams)) { 2611 fail("View doesn't have MarginLayoutParams"); 2612 } 2613 2614 ViewGroup.MarginLayoutParams margins = (ViewGroup.MarginLayoutParams) layoutParams; 2615 assertEquals("[left margin]", left, margins.leftMargin); 2616 assertEquals("[top margin]", top, margins.topMargin); 2617 assertEquals("[right margin]", right, margins.rightMargin); 2618 assertEquals("[bottom margin]", bottom, margins.bottomMargin); 2619 } 2620 resolveDimenOffset(float value, int unit, DisplayMetrics displayMetrics)2621 private static int resolveDimenOffset(float value, int unit, DisplayMetrics displayMetrics) { 2622 return TypedValue.complexToDimensionPixelOffset( 2623 TypedValue.createComplexDimension(value, unit), displayMetrics); 2624 } 2625 resolveDimenSize(float value, int unit, DisplayMetrics displayMetrics)2626 private static int resolveDimenSize(float value, int unit, DisplayMetrics displayMetrics) { 2627 return TypedValue.complexToDimensionPixelSize( 2628 TypedValue.createComplexDimension(value, unit), displayMetrics); 2629 } 2630 2631 private static final class MockBroadcastReceiver extends BroadcastReceiver { 2632 2633 Intent mIntent; 2634 2635 private CountDownLatch mCountDownLatch; 2636 2637 @Override onReceive(Context context, Intent intent)2638 public synchronized void onReceive(Context context, Intent intent) { 2639 mIntent = intent; 2640 if (mCountDownLatch != null) { 2641 mCountDownLatch.countDown(); 2642 mCountDownLatch = null; 2643 } 2644 } 2645 2646 /** Waits for an intent to be received and returns it. */ awaitIntent()2647 public Intent awaitIntent() { 2648 CountDownLatch countDownLatch; 2649 synchronized (this) { 2650 // If we already have an intent, don't wait and just return it now. 2651 if (mIntent != null) return getIntentAndResetLocked(); 2652 2653 countDownLatch = new CountDownLatch(1); 2654 mCountDownLatch = countDownLatch; 2655 } 2656 2657 try { 2658 // Note: if the latch already counted down, this will return true immediately. 2659 countDownLatch.await(20, TimeUnit.SECONDS); 2660 } catch (InterruptedException e) { 2661 throw new RuntimeException(e); 2662 } 2663 2664 synchronized (this) { 2665 if (mIntent == null) { 2666 Assert.fail("Expected to receive a broadcast within 20 seconds"); 2667 } 2668 2669 return getIntentAndResetLocked(); 2670 } 2671 } 2672 getIntentAndResetLocked()2673 private Intent getIntentAndResetLocked() { 2674 final Intent intent = mIntent; 2675 mIntent = null; 2676 return intent; 2677 } 2678 } 2679 assertSameColorStateList(ColorStateList expected, ColorStateList actual)2680 private void assertSameColorStateList(ColorStateList expected, ColorStateList actual) { 2681 assertEquals(expected == null ? null : expected.toString(), 2682 actual == null ? null : actual.toString()); 2683 } 2684 assertThrowsOnReapply(Class<T> klass)2685 private <T extends Throwable> void assertThrowsOnReapply(Class<T> klass) throws Throwable { 2686 assertThrows(klass, this::reapplyRemoteViews); 2687 } 2688 getCurrentNightMode()2689 private String getCurrentNightMode() { 2690 final String nightModeText = runShellCommand("cmd uimode night"); 2691 final String[] nightModeSplit = nightModeText.split(":"); 2692 if (nightModeSplit.length != 2) { 2693 fail("Failed to get initial night mode value from " + nightModeText); 2694 } 2695 return nightModeSplit[1].trim(); 2696 } 2697 2698 // Change the night mode and return the previous mode changeNightMode(boolean nightMode)2699 private String changeNightMode(boolean nightMode) throws Exception { 2700 String previousMode = getCurrentNightMode(); 2701 String wantedNightMode = nightMode ? "yes" : "no"; 2702 runShellCommand("cmd uimode night " + wantedNightMode); 2703 waitUntil( 2704 /* message= */ "Night mode did not change to " + wantedNightMode, 2705 /* timeoutSecond= */ 5, 2706 /* predicate= */ () -> wantedNightMode.equals(getCurrentNightMode()) 2707 ); 2708 return previousMode; 2709 } 2710 applyRemoteViews()2711 private void applyRemoteViews() throws Throwable { 2712 mResult = 2713 RemoteViewsUtil.applyRemoteViews( 2714 mActivityRule, mContext, mRemoteViews, isProtoTest); 2715 } 2716 reapplyRemoteViews()2717 private void reapplyRemoteViews() throws Throwable { 2718 RemoteViewsUtil.reapplyRemoteViews( 2719 mActivityRule, mContext, mRemoteViews, mResult, isProtoTest); 2720 } 2721 parcelAndUnparcel(RemoteViews views)2722 private static RemoteViews parcelAndUnparcel(RemoteViews views) { 2723 return parcelAndUnparcel(views, /* flags= */ 0); 2724 } 2725 2726 /** 2727 * Returns the result of writing {@code views} to a {@link Parcel} and then creating a new 2728 * {@link RemoteViews} from the parcel. 2729 */ parcelAndUnparcel(RemoteViews views, int flags)2730 private static RemoteViews parcelAndUnparcel(RemoteViews views, int flags) { 2731 return parcelAndRun(views, flags, RemoteViews.CREATOR::createFromParcel); 2732 } 2733 2734 /** Returns the data size from writing {@code parcelable} to a {@link Parcel}. */ getParcelledSize(Parcelable parcelable)2735 private static int getParcelledSize(Parcelable parcelable) { 2736 return parcelAndRun(parcelable, /* flags= */ 0, Parcel::dataSize); 2737 } 2738 parcelAndRun( Parcelable parcelable, int flags, Function<Parcel, T> function)2739 private static <T> T parcelAndRun( 2740 Parcelable parcelable, 2741 int flags, 2742 Function<Parcel, T> function) { 2743 Parcel parcel = Parcel.obtain(); 2744 parcelable.writeToParcel(parcel, flags); 2745 parcel.setDataPosition(0); 2746 try { 2747 return function.apply(parcel); 2748 } finally { 2749 parcel.recycle(); 2750 } 2751 } 2752 assertLessThan(int expected, int actual)2753 private static void assertLessThan(int expected, int actual) { 2754 if (actual >= expected) { 2755 Assert.fail("Expected to be less than " + expected + ", but was " + actual); 2756 } 2757 } 2758 } 2759