Skip to content

Commit 1f9cfed

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge "Merge branch 'upstream-google' of sso://android.googlesource.com/platform/external/robolectric into upgrade" into main
2 parents cd2b911 + 298acb3 commit 1f9cfed

File tree

13 files changed

+269
-38
lines changed

13 files changed

+269
-38
lines changed

robolectric/src/test/java/org/robolectric/shadows/ShadowBackupManagerTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.robolectric.shadows;
22

33
import static android.os.Build.VERSION_CODES.M;
4+
import static android.os.Build.VERSION_CODES.P;
45
import static android.os.Build.VERSION_CODES.Q;
56
import static com.google.common.truth.Truth.assertThat;
67
import static org.junit.Assert.assertThrows;
@@ -13,6 +14,7 @@
1314
import android.app.backup.RestoreObserver;
1415
import android.app.backup.RestoreSession;
1516
import android.app.backup.RestoreSet;
17+
import android.os.UserHandle;
1618
import androidx.test.core.app.ApplicationProvider;
1719
import androidx.test.ext.junit.runners.AndroidJUnit4;
1820
import com.google.common.collect.ImmutableList;
@@ -93,6 +95,13 @@ public void isBackupEnabled_noPermission_shouldThrowSecurityException() {
9395
assertThrows(SecurityException.class, () -> backupManager.isBackupEnabled());
9496
}
9597

98+
@Test
99+
@Config(minSdk = P)
100+
public void setBackupS_setToFalse_shouldDisableBackup() {
101+
shadowOf(backupManager).setBackupServiceActive(UserHandle.of(0), false);
102+
assertThat(backupManager.isBackupServiceActive(UserHandle.of(0))).isFalse();
103+
}
104+
96105
@Test
97106
public void getAvailableRestoreSets_shouldCallbackToRestoreSetsAvailable() {
98107
RestoreSession restoreSession = backupManager.beginRestoreSession();

robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
import org.robolectric.annotation.Config;
136136
import org.robolectric.annotation.GetInstallerPackageNameMode;
137137
import org.robolectric.annotation.GetInstallerPackageNameMode.Mode;
138+
import org.robolectric.junit.rules.SetSystemPropertyRule;
138139
import org.robolectric.shadow.api.Shadow;
139140
import org.robolectric.shadows.ShadowPackageManager.PackageSetting;
140141
import org.robolectric.shadows.ShadowPackageManager.ResolveInfoComparator;
@@ -162,6 +163,7 @@ public class ShadowPackageManagerTest {
162163
public static final String ORIGINATING_PACKAGE_NAME = "originating.package";
163164
public static final String UPDATE_OWNER_PACKAGE_NAME = "update.owner.package";
164165

166+
@Rule public final SetSystemPropertyRule setSystemPropertyRule = new SetSystemPropertyRule();
165167
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
166168
private Context context;
167169
private PackageManager packageManager;
@@ -2198,6 +2200,23 @@ public void getApplicationIcon_applicationInfo_matches() {
21982200
assertThat(packageManager.getApplicationIcon(applicationInfo)).isSameInstanceAs(d);
21992201
}
22002202

2203+
@Test
2204+
public void getApplicationIcon_fromInfoNoShadow_returnsDrawable() {
2205+
setSystemPropertyRule.set("robolectric.useValidGetApplicationIcon", "true");
2206+
ApplicationInfo applicationInfo = new ApplicationInfo();
2207+
applicationInfo.packageName = TEST_PACKAGE_NAME;
2208+
2209+
Drawable d = packageManager.getApplicationIcon(applicationInfo);
2210+
assertThat(d).isNotNull();
2211+
}
2212+
2213+
@Test
2214+
public void getApplicationIcon_fromPackageNoShadow_throws() {
2215+
setSystemPropertyRule.set("robolectric.useValidGetApplicationIcon", "true");
2216+
assertThrows(
2217+
NameNotFoundException.class, () -> packageManager.getApplicationIcon(TEST_PACKAGE_NAME));
2218+
}
2219+
22012220
@Test
22022221
public void hasSystemFeature() {
22032222
// uninitialized

robolectric/src/test/java/org/robolectric/shadows/ShadowServiceTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static android.os.Build.VERSION_CODES.N;
44
import static android.os.Build.VERSION_CODES.Q;
55
import static com.google.common.truth.Truth.assertThat;
6+
import static org.junit.Assert.assertThrows;
67
import static org.junit.Assert.fail;
78
import static org.robolectric.Shadows.shadowOf;
89

@@ -95,6 +96,14 @@ public void startForegroundWithForegroundServiceType() {
9596
assertThat(service.getForegroundServiceType()).isEqualTo(64);
9697
}
9798

99+
@Test
100+
public void startForegroundWithException() {
101+
shadowOf(service).setThrowInStartForeground(new RuntimeException("test"));
102+
Notification n = notBuilder.build();
103+
RuntimeException e = assertThrows(RuntimeException.class, () -> service.startForeground(23, n));
104+
assertThat(e).hasMessageThat().isEqualTo("test");
105+
}
106+
98107
@Test
99108
public void stopForeground() {
100109
service.stopForeground(true);
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package org.robolectric.shadows;
2+
3+
import static android.os.Build.VERSION_CODES.O;
4+
import static com.google.common.truth.Truth.assertThat;
5+
import static org.robolectric.Shadows.shadowOf;
6+
7+
import android.app.Activity;
8+
import android.app.UiAutomation;
9+
import android.graphics.Bitmap;
10+
import android.os.Looper;
11+
import android.os.SystemClock;
12+
import android.view.View;
13+
import android.view.ViewGroup;
14+
import android.view.animation.Transformation;
15+
import android.view.animation.TranslateAnimation;
16+
import androidx.test.ext.junit.runners.AndroidJUnit4;
17+
import androidx.test.platform.app.InstrumentationRegistry;
18+
import java.time.Instant;
19+
import java.util.concurrent.TimeUnit;
20+
import org.junit.Test;
21+
import org.junit.runner.RunWith;
22+
import org.robolectric.Robolectric;
23+
import org.robolectric.annotation.Config;
24+
import org.robolectric.annotation.GraphicsMode;
25+
import org.robolectric.annotation.GraphicsMode.Mode;
26+
27+
@RunWith(AndroidJUnit4.class)
28+
@Config(minSdk = O)
29+
@GraphicsMode(Mode.NATIVE)
30+
public class ViewAnimationTest {
31+
@Test
32+
public void viewAnimations_interpolateWhenDrawIsCalled() {
33+
try {
34+
ShadowView.setUseRealViewAnimations(true);
35+
Activity activity = Robolectric.setupActivity(Activity.class);
36+
View view = new View(activity);
37+
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(100, 100);
38+
view.setLayoutParams(params);
39+
((ViewGroup) activity.findViewById(android.R.id.content)).addView(view);
40+
41+
shadowOf(Looper.getMainLooper()).runToEndOfTasks();
42+
43+
long startTime = SystemClock.uptimeMillis();
44+
45+
final TestTranslateAnimation animation = new TestTranslateAnimation(0, 100, 0, 0);
46+
animation.setDuration(1000);
47+
view.startAnimation(animation);
48+
49+
shadowOf(Looper.getMainLooper()).idleFor(500, TimeUnit.MILLISECONDS);
50+
UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
51+
Bitmap bitmap = uiAutomation.takeScreenshot();
52+
assertThat(bitmap).isNotNull();
53+
assertThat(animation.lastAnimationTime.toEpochMilli()).isEqualTo(startTime + 500);
54+
} finally {
55+
ShadowView.setUseRealViewAnimations(false);
56+
}
57+
}
58+
59+
public static class TestTranslateAnimation extends TranslateAnimation {
60+
61+
public Instant lastAnimationTime;
62+
63+
public TestTranslateAnimation(
64+
float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) {
65+
super(fromXDelta, toXDelta, fromYDelta, toYDelta);
66+
}
67+
68+
@Override
69+
public boolean getTransformation(
70+
long currentTime, Transformation outTransformation, float scale) {
71+
boolean result = super.getTransformation(currentTime, outTransformation, scale);
72+
lastAnimationTime = Instant.ofEpochMilli(currentTime);
73+
return result;
74+
}
75+
}
76+
}

shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,12 +1285,26 @@ protected boolean isSafeMode() {
12851285

12861286
@Implementation
12871287
protected Drawable getApplicationIcon(String packageName) throws NameNotFoundException {
1288-
return applicationIcons.get(packageName);
1288+
Drawable result = applicationIcons.get(packageName);
1289+
if (useValidGetApplicationIcon() && result == null) {
1290+
throw new NameNotFoundException(packageName);
1291+
}
1292+
return result;
1293+
}
1294+
1295+
private static boolean useValidGetApplicationIcon() {
1296+
return Boolean.parseBoolean(
1297+
System.getProperty("robolectric.useValidGetApplicationIcon", "false"));
12891298
}
12901299

12911300
@Implementation
12921301
protected Drawable getApplicationIcon(ApplicationInfo info) throws NameNotFoundException {
1293-
return getApplicationIcon(info.packageName);
1302+
try {
1303+
return getApplicationIcon(info.packageName);
1304+
} catch (NameNotFoundException e) {
1305+
// This method should not return null. Return a default icon instead.
1306+
return getDefaultActivityIcon();
1307+
}
12941308
}
12951309

12961310
@Implementation

shadows/framework/src/main/java/org/robolectric/shadows/ShadowBackupManager.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.robolectric.shadows;
22

33
import static android.os.Build.VERSION_CODES.M;
4+
import static android.os.Build.VERSION_CODES.P;
45

56
import android.app.backup.BackupManager;
67
import android.app.backup.BackupTransport;
@@ -14,6 +15,7 @@
1415
import android.os.IBinder;
1516
import android.os.Looper;
1617
import android.os.RemoteException;
18+
import android.os.UserHandle;
1719
import com.google.common.collect.ArrayListMultimap;
1820
import com.google.common.collect.ListMultimap;
1921
import java.util.ArrayList;
@@ -88,6 +90,17 @@ protected boolean isBackupEnabled() {
8890
return serviceState.backupEnabled;
8991
}
9092

93+
@Implementation(minSdk = P)
94+
@HiddenApi // SystemApi
95+
protected boolean isBackupServiceActive(UserHandle user) {
96+
enforceBackupPermission("isBackupServiceActive");
97+
return serviceState.backupServiceActive;
98+
}
99+
100+
public void setBackupServiceActive(UserHandle user, boolean makeActive) {
101+
serviceState.backupServiceActive = makeActive;
102+
}
103+
91104
@Implementation
92105
@HiddenApi // SystemApi
93106
protected RestoreSession beginRestoreSession() {
@@ -263,6 +276,7 @@ private void post(RemoteRunnable runnable) {
263276
}
264277

265278
private static class BackupManagerServiceState {
279+
boolean backupServiceActive = true;
266280
boolean backupEnabled = true;
267281
boolean nullRestoreData;
268282
long lastRestoreToken = 0L;

shadows/framework/src/main/java/org/robolectric/shadows/ShadowService.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class ShadowService extends ShadowContextWrapper {
2424
private boolean selfStopped = false;
2525
private boolean foregroundStopped;
2626
private boolean notificationShouldRemoved;
27+
private Exception exceptionForStartForeground = null;
2728
private int stopSelfId;
2829
private int stopSelfResultId;
2930
private int foregroundServiceType;
@@ -55,7 +56,10 @@ protected boolean stopSelfResult(int id) {
5556
}
5657

5758
@Implementation
58-
protected void startForeground(int id, Notification notification) {
59+
protected void startForeground(int id, Notification notification) throws Exception {
60+
if (exceptionForStartForeground != null) {
61+
throw exceptionForStartForeground;
62+
}
5963
foregroundStopped = false;
6064
lastForegroundNotificationId = id;
6165
lastForegroundNotification = notification;
@@ -70,7 +74,8 @@ protected void startForeground(int id, Notification notification) {
7074

7175
@Implementation(minSdk = Q)
7276
protected void startForeground(
73-
int id, Notification notification, @ForegroundServiceType int foregroundServiceType) {
77+
int id, Notification notification, @ForegroundServiceType int foregroundServiceType)
78+
throws Exception {
7479
startForeground(id, notification);
7580
this.foregroundServiceType = foregroundServiceType;
7681
}
@@ -153,4 +158,22 @@ public int getStopSelfId() {
153158
public int getStopSelfResultId() {
154159
return stopSelfResultId;
155160
}
161+
162+
/**
163+
* Configures the ShadowService so that calls to startForeground() will throw the given Exception.
164+
* It can throw: {@link android.app.ForegroundServiceStartNotAllowedException}:
165+
* https://developer.android.com/reference/android/app/ForegroundServiceStartNotAllowedException
166+
* Or {@link android.app.InvalidForegroundServiceTypeException}:
167+
* https://developer.android.com/reference/android/app/InvalidForegroundServiceTypeException Or
168+
* {@link android.app.MissingForegroundServiceTypeException}:
169+
* https://developer.android.com/reference/android/app/MissingForegroundServiceTypeException Or
170+
* {@link java.lang.SecurityException}:
171+
* https://developer.android.com/reference/java/lang/SecurityException
172+
*
173+
* <p>Details in:
174+
* https://developer.android.com/reference/android/app/Service#startForeground(int,%20android.app.Notification)
175+
*/
176+
public void setThrowInStartForeground(Exception e) {
177+
exceptionForStartForeground = e;
178+
}
156179
}

shadows/framework/src/main/java/org/robolectric/shadows/ShadowUiAutomation.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import android.graphics.Paint;
2525
import android.graphics.Point;
2626
import android.os.IBinder;
27+
import android.os.SystemClock;
2728
import android.provider.Settings;
2829
import android.view.Display;
2930
import android.view.InputEvent;
@@ -47,6 +48,7 @@
4748
import org.robolectric.RuntimeEnvironment;
4849
import org.robolectric.annotation.Implementation;
4950
import org.robolectric.annotation.Implements;
51+
import org.robolectric.shadow.api.Shadow;
5052
import org.robolectric.util.ReflectionHelpers;
5153

5254
/** Shadow for {@link UiAutomation}. */
@@ -123,8 +125,12 @@ protected Bitmap takeScreenshot() throws Exception {
123125
Bitmap.createBitmap(displaySize.x, displaySize.y, Bitmap.Config.ARGB_8888);
124126
Canvas screenshotCanvas = new Canvas(screenshot);
125127
Paint paint = new Paint();
128+
long drawingTime = SystemClock.uptimeMillis();
126129
for (Root root : getViewRoots().reverse()) {
127130
View rootView = root.getRootView();
131+
if (ShadowView.useRealViewAnimations()) {
132+
((ShadowView) Shadow.extract(rootView)).setDrawingTime(drawingTime);
133+
}
128134
if (rootView.getWidth() <= 0 || rootView.getHeight() <= 0) {
129135
continue;
130136
}

0 commit comments

Comments
 (0)