Skip to content

Commit

Permalink
Merge branch 'google' into 'master'
Browse files Browse the repository at this point in the history
  • Loading branch information
hoisie committed Apr 9, 2023
2 parents 301c158 + 1d3cdab commit 732290a
Show file tree
Hide file tree
Showing 47 changed files with 1,562 additions and 256 deletions.
Expand Up @@ -9,9 +9,9 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import androidx.appcompat.R;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.R;
import androidx.lifecycle.Lifecycle.State;
import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
Expand Down Expand Up @@ -69,7 +69,7 @@ public void onPause() {
@Override
public void onStop() {
super.onStop();
callbacks.add("onStop");
callbacks.add("onStop " + isChangingConfigurations());
}

@Override
Expand Down Expand Up @@ -134,10 +134,18 @@ public void launch_stopAndResume_callbackSequence() {
assertThat(activityScenario).isNotNull();
activityScenario.moveToState(State.CREATED);
activityScenario.moveToState(State.RESUMED);
assertThat(callbacks)
.containsExactly(
"onCreate", "onStart", "onPostCreate", "onResume", "onWindowFocusChanged true",
"onPause", "onStop", "onRestart", "onStart", "onResume");
assertThat(callbacks)
.containsExactly(
"onCreate",
"onStart",
"onPostCreate",
"onResume",
"onWindowFocusChanged true",
"onPause",
"onStop false",
"onRestart",
"onStart",
"onResume");
}

@Test
Expand Down Expand Up @@ -220,6 +228,16 @@ public void recreate_nonRetainFragmentHostingActivity() {
.isNotSameInstanceAs(fragment));
}

@Test
public void recreate_isChangingConfigurations() {
try (ActivityScenario<TranscriptActivity> activityScenario =
ActivityScenario.launch(TranscriptActivity.class)) {
activityScenario.recreate();

assertThat(callbacks).contains("onStop true");
}
}

@Config(minSdk = JELLY_BEAN_MR2)
@Test
public void setRotation_recreatesActivity() {
Expand Down
Expand Up @@ -146,6 +146,39 @@ public void onIdle_looperIsIdle() throws Exception {
}
}

@SuppressWarnings("FutureReturnValueIgnored")
@Test
public void onIdle_looperPostsToMainThread_shouldWaitForTheTaskOnMainThreadToFinish()
throws Exception {
HandlerThread handlerThread = new HandlerThread("Test");
try {
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
CountDownLatch handlerStarted = new CountDownLatch(1);
CountDownLatch releaseHandler = new CountDownLatch(1);
AtomicBoolean mainThreadPosted = new AtomicBoolean(false);
handler.post(
() -> {
handlerStarted.countDown();
try {
releaseHandler.await();
new Handler(Looper.getMainLooper()).post(() -> mainThreadPosted.set(true));
} catch (InterruptedException e) {
// Ignore
}
});
handlerStarted.await();
idlingRegistry.registerLooperAsIdlingResource(handlerThread.getLooper());

executor.submit(releaseHandler::countDown);
onIdle();

assertThat(mainThreadPosted.get()).isTrue();
} finally {
handlerThread.quit();
}
}

private static class NamedIdleResource implements IdlingResource {
final String name;
final AtomicBoolean isIdle;
Expand Down
Expand Up @@ -8,14 +8,13 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.io.CharStreams;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.robolectric.annotation.internal.DoNotInstrument;

Expand All @@ -26,9 +25,6 @@
@RunWith(AndroidJUnit4.class)
public class AssetManagerTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

private AssetManager assetManager;

private static final Charset UTF_8 = Charset.forName("UTF-8");
Expand Down Expand Up @@ -70,8 +66,10 @@ public void open_withAccessMode_shouldOpenFile() throws IOException {
@Test
public void openFd_shouldProvideFileDescriptorForAsset() throws Exception {
AssetFileDescriptor assetFileDescriptor = assetManager.openFd("assetsHome.txt");
assertThat(CharStreams.toString(new InputStreamReader(assetFileDescriptor.createInputStream(), UTF_8)))
.isEqualTo("assetsHome!");
FileInputStream fis = assetFileDescriptor.createInputStream();
InputStreamReader isr = new InputStreamReader(fis, UTF_8);
String actual = CharStreams.toString(isr);
assertThat(actual).isEqualTo("assetsHome!");
assertThat(assetFileDescriptor.getLength()).isEqualTo(11);
}

Expand All @@ -84,6 +82,7 @@ public void open_shouldProvideFileDescriptor() throws Exception {
+ "open_shouldProvideFileDescriptor.txt");
FileOutputStream output = new FileOutputStream(file);
output.write("hi".getBytes());
output.close();

ParcelFileDescriptor parcelFileDescriptor =
ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
Expand Down
Expand Up @@ -7,6 +7,9 @@
import androidx.test.filters.SdkSuppress;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -16,20 +19,40 @@
/** Tests that Robolectric's android.text.format.DateFormat support is consistent with device. */
@RunWith(AndroidJUnit4.class)
@DoNotInstrument
@Config(qualifiers = "+en-rUS")
public class DateFormatTest {

private Locale originalLocale;
private TimeZone originalTimeZone;
private Date dateAM;
private Date datePM;

@Before
public void setDate() {
// Always set default Locale+Timezone in any time-related unit test to
// avoid flakiness when testing in non-US environments.
originalLocale = Locale.getDefault();
Locale.setDefault(Locale.US);
originalTimeZone = TimeZone.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

Calendar c = Calendar.getInstance();
c.set(2000, 10, 25, 8, 24, 30);
dateAM = c.getTime();
c.set(2000, 10, 25, 16, 24, 30);
datePM = c.getTime();
}

@After
public void tearDown() throws Exception {
if (originalTimeZone != null) {
TimeZone.setDefault(originalTimeZone);
}
if (originalLocale != null) {
Locale.setDefault(originalLocale);
}
}

@Test
public void getLongDateFormat() {
assertThat(DateFormat.getLongDateFormat(getApplicationContext()).format(dateAM))
Expand Down Expand Up @@ -60,15 +83,17 @@ public void getDateFormat() {

@Test
public void getTimeFormat_am() {
// allow both regular and thin whitespace separators
// Allow both ASCII and Unicode space-class separators.
// Output may also contain U+202F (UTF-8 E2 80 AF), a.k.a. NARROW NO-BREAK SPACE
// which is in the \p{Zs} Unicode category.
assertThat(DateFormat.getTimeFormat(getApplicationContext()).format(dateAM))
.matches("8:24\\sAM");
.matches("8:24\\p{Z}AM");
}

@Test
public void getTimeFormat_pm() {
// allow both regular and thin whitespace separators
// Allow both ASCII and Unicode space-class separators.
assertThat(DateFormat.getTimeFormat(getApplicationContext()).format(datePM))
.matches("4:24\\sPM");
.matches("4:24\\p{Z}PM");
}
}
8 changes: 5 additions & 3 deletions integration_tests/nativegraphics/build.gradle
Expand Up @@ -29,10 +29,12 @@ android {
}

dependencies {
testImplementation project(':robolectric')
testImplementation AndroidSdk.MAX_SDK.coordinates
testImplementation project(':robolectric')

testImplementation "androidx.core:core:$coreVersion"
testImplementation "androidx.test.ext:junit:$axtJunitVersion"
testImplementation "com.google.truth:truth:${truthVersion}"
testImplementation "junit:junit:${junitVersion}"
testImplementation("com.google.truth:truth:${truthVersion}")
testImplementation("androidx.test.ext:junit:$axtJunitVersion")
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
}
@@ -0,0 +1,37 @@
package org.robolectric.integrationtests.nativegraphics;

import static android.os.Build.VERSION_CODES.O;
import static java.util.concurrent.TimeUnit.SECONDS;

import android.graphics.Bitmap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@Config(minSdk = O)
@RunWith(RobolectricTestRunner.class)
public class BitmapLoadingTest {

/**
* There is a potential race that happens if Bitmap classes are loaded by multiple threads. The
* race is due to the lazy initialization of ColorSpace class members in hwui's jni/Graphics.cpp.
*/
@Test
public void bitmapLoading_backgroundThreads_doesNotRace() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(4);
for (int i = 0; i < 10; i++) {
executorService.execute(
() -> {
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
// createScaledBitmap triggers lazy ColorSpace member initialization in hwui
// Graphics.cpp.
Bitmap.createScaledBitmap(bitmap, 200, 200, false);
});
}
executorService.shutdown();
executorService.awaitTermination(10, SECONDS);
}
}
@@ -0,0 +1,27 @@
package org.robolectric.integrationtests.nativegraphics;

import static android.os.Build.VERSION_CODES.O;

import androidx.core.content.res.ResourcesCompat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

@Config(minSdk = O)
@RunWith(RobolectricTestRunner.class)
public class FontLoadingTest {

/**
* There is a potential static initializer cycle that can happen when creating fonts triggers
* loading RNR. Because statically initializing Typeface is the last step of loading RNR, and the
* static initializer of Typeface causes a lot of Font objects to be created, there has to be
* special logic when fonts are loaded to avoid statically initializing Typeface. This is captured
* in a test here.
*/
@Test
public void loadFont_doesNotCauseStaticInitializerCycle() {
ResourcesCompat.getFont(RuntimeEnvironment.getApplication(), R.font.multiweight_family);
}
}
@@ -0,0 +1,29 @@
package org.robolectric.integrationtests.nativegraphics;

import static android.os.Build.VERSION_CODES.S;

import android.app.Activity;
import android.view.WindowManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(minSdk = S)
public class HardwareAcceleratedActivityRenderTest {
@Test
public void setupHardwareAcceleratedActivity() {
// This will exercise much of the HardwareRenderer / RenderNode / RecordingCanvas native code.
ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
controller
.get()
.getWindow()
.setFlags(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
controller.setup();
}
}
@@ -0,0 +1,28 @@
package org.robolectric.integrationtests.nativegraphics;

import static android.os.Build.VERSION_CODES.O;
import static com.google.common.truth.Truth.assertThat;

import android.graphics.Bitmap;
import android.net.Uri;
import android.provider.MediaStore;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(minSdk = O)
public class MediaStoreTest {

@Test
public void getBitmap_legacyAPI_alwaysReturnsABitmap() throws IOException {
Uri screenshotUri = new Uri.Builder().scheme("content").appendPath("invalid_file").build();
Bitmap bitmap =
MediaStore.Images.Media.getBitmap(
RuntimeEnvironment.getApplication().getContentResolver(), screenshotUri);
assertThat(bitmap).isNotNull();
}
}
@@ -0,0 +1,36 @@
package org.robolectric.integrationtests.nativegraphics;

import static android.os.Build.VERSION_CODES.O;
import static com.google.common.truth.Truth.assertThat;

import android.app.Activity;
import android.widget.ScrollView;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

@RunWith(RobolectricTestRunner.class)
@Config(minSdk = O)
public final class ScrollViewTest {

/**
* Checks that even if {@code robolectric.useRealScrolling} is set to false, real scrolling code
* is used when RNG is enabled.
*/
@Test
public void smoothScrollTo_usesRealCode_whenRNGEnabled() {
try {
System.setProperty("robolectric.useRealScrolling", "false");
Activity activity = Robolectric.setupActivity(Activity.class);
ScrollView scrollView = new ScrollView(activity);
scrollView.smoothScrollTo(100, 100);
// Because the scroll view has no children, it should not get scrolled.
assertThat(scrollView.getScrollX()).isEqualTo(0);
assertThat(scrollView.getScrollY()).isEqualTo(0);
} finally {
System.clearProperty("robolectric.useRealScrolling");
}
}
}

0 comments on commit 732290a

Please sign in to comment.