diff options
706 files changed, 14302 insertions, 5964 deletions
diff --git a/Android.mk b/Android.mk index 83bfef3ce..6d6e3c0a2 100644 --- a/Android.mk +++ b/Android.mk @@ -43,9 +43,9 @@ include $(call first-makefiles-under, $(LOCAL_PATH)) ############################################## include $(CLEAR_VARS) -.PHONY: Run_all_robolectric_tests +.PHONY: Run_robolectric_test_suite -Run_all_robolectric_tests: \ +Run_robolectric_test_suite: \ Run_robolectric_utils_tests \ Run_robolectric_sandbox_tests \ Run_robolectric_processor_tests \ @@ -37,7 +37,7 @@ If you'd like to start a new project with Robolectric tests you can refer to `de #### build.gradle: ```groovy -testCompile "org.robolectric:robolectric:3.8" +testImplementation "org.robolectric:robolectric:4.0.2" ``` ## Building And Contributing @@ -66,6 +66,6 @@ repositories { } dependencies { - testCompile "org.robolectric:robolectric:4.0-alpha-4-SNAPSHOT" + testImplementation "org.robolectric:robolectric:4.1-SNAPSHOT" } ``` diff --git a/annotations/build.gradle b/annotations/build.gradle index f4d2b6042..f1b281f87 100644 --- a/annotations/build.gradle +++ b/annotations/build.gradle @@ -1,14 +1,9 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) dependencies { - // Compile dependencies - compile project(":shadowapi") - compileOnly "com.google.code.findbugs:jsr305:3.0.1" + api project(":shadowapi") + compileOnly "com.google.code.findbugs:jsr305:3.0.2" compileOnly AndroidSdk.MAX_SDK.coordinates -}
\ No newline at end of file +} diff --git a/annotations/src/main/java/org/robolectric/annotation/Config.java b/annotations/src/main/java/org/robolectric/annotation/Config.java index 2fc82fe5e..d370c59d8 100644 --- a/annotations/src/main/java/org/robolectric/annotation/Config.java +++ b/annotations/src/main/java/org/robolectric/annotation/Config.java @@ -1,6 +1,7 @@ package org.robolectric.annotation; import android.app.Application; +import android.content.pm.PackageInfo; import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -87,14 +88,22 @@ public @interface Config { Class<? extends Application> application() default DefaultApplication.class; // DEFAULT_APPLICATION /** - * Java package name where the "R.class" file is located. This only needs to be specified if you define - * an {@code applicationId} associated with {@code productFlavors} or specify {@code applicationIdSuffix} - * in your build.gradle. + * Java package name where the "R.class" file is located. This only needs to be specified if you + * define an {@code applicationId} associated with {@code productFlavors} or specify {@code + * applicationIdSuffix} in your build.gradle. * - * If not specified, Robolectric defaults to the {@code applicationId}. + * <p>If not specified, Robolectric defaults to the {@code applicationId}. * * @return The java package name for R.class. + * @deprecated To change your package name please override the applicationId in your build system. + * Changing package name here is broken as the package name will no longer match the package + * name encoded in the arsc resources file. If you are looking to simulate another application + * you can create another applications Context using {@link + * android.content.Context#createPackageContext(String, int)}. Note that you must add this + * package to {@link org.robolectric.shadows.ShadowPackageManager#addPackage(PackageInfo)} + * first. */ + @Deprecated String packageName() default DEFAULT_PACKAGE_NAME; /** diff --git a/build.gradle b/build.gradle index 25ac5aa74..ad7f93dba 100644 --- a/build.gradle +++ b/build.gradle @@ -4,24 +4,23 @@ buildscript { repositories { google() jcenter() + gradlePluginPortal() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.0-alpha08' - classpath 'com.netflix.nebula:gradle-aggregate-javadocs-plugin:2.2.+' + classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.6' + classpath 'com.netflix.nebula:gradle-aggregate-javadocs-plugin:2.2.1' classpath 'ch.raffael.pegdown-doclet:pegdown-doclet:1.3' } } -plugins { - id "net.ltgt.apt" version "0.13" // automatic annotation processing -} - allprojects { repositories { mavenLocal() - jcenter() google() + jcenter() + mavenCentral() } group = "org.robolectric" @@ -29,7 +28,6 @@ allprojects { } apply plugin: 'idea' -apply plugin: 'net.ltgt.apt' project.ext.configAnnotationProcessing = [] project.afterEvaluate { @@ -100,10 +98,10 @@ task prefetchDependencies() { doLast { allprojects.each { p -> - ['compile', 'runtime', 'testCompile', 'testRuntime'].each { configName -> - if (p.configurations.findByName(configName)) { - // causes dependencies to be resolved: - p.configurations[configName].files + p.configurations.each { config -> + // causes dependencies to be resolved: + if (config.isCanBeResolved()) { + config.files } } } diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 7619b4cae..eede5417b 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,3 +1,4 @@ +apply plugin: "java-library" apply plugin: "groovy" repositories { @@ -6,8 +7,8 @@ repositories { } dependencies { - compile gradleApi() - compile localGroovy() + implementation gradleApi() + implementation localGroovy() - compile "org.ow2.asm:asm-tree:5.0.1" + implementation "org.ow2.asm:asm-tree:7.0" } diff --git a/buildSrc/src/main/groovy/CheckApiChangesPlugin.groovy b/buildSrc/src/main/groovy/CheckApiChangesPlugin.groovy index b107f6512..c0671c598 100644 --- a/buildSrc/src/main/groovy/CheckApiChangesPlugin.groovy +++ b/buildSrc/src/main/groovy/CheckApiChangesPlugin.groovy @@ -9,6 +9,7 @@ import java.util.jar.JarEntry import java.util.jar.JarInputStream import java.util.regex.Pattern +import static org.objectweb.asm.Opcodes.ACC_PRIVATE import static org.objectweb.asm.Opcodes.ACC_PROTECTED import static org.objectweb.asm.Opcodes.ACC_PUBLIC import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC @@ -295,7 +296,7 @@ class CheckApiChangesPlugin implements Plugin<Project> { case 'V': write('void'); break; } } - "$methodAccessString $methodNode.name(${args.toString()}): ${returnType.toString()}" + "$methodAccessString ${isHiddenApi() ? "@HiddenApi " : ""}${isImplementation() ? "@Implementation " : ""}$methodNode.name(${args.toString()}): ${returnType.toString()}" } @Override @@ -324,21 +325,31 @@ class CheckApiChangesPlugin implements Plugin<Project> { containsAnnotation(methodNode.visibleAnnotations, "Ljava/lang/Deprecated;") } + boolean isImplementation() { + containsAnnotation(methodNode.visibleAnnotations, "Lorg/robolectric/annotation/Implementation;") + } + + boolean isHiddenApi() { + containsAnnotation(methodNode.visibleAnnotations, "Lorg/robolectric/annotation/HiddenApi;") + } + String getMethodAccessString() { - if (bitSet(methodNode.access, ACC_PROTECTED)) { - return "protected" - } - if (bitSet(methodNode.access, ACC_PUBLIC)) { - return "public" - } + return getAccessString(methodNode.access) } - String getClassAccessString() { - if (bitSet(classNode.access, ACC_PROTECTED)) { + private String getClassAccessString() { + return getAccessString(classNode.access) + } + + String getAccessString(int access) { + if (bitSet(access, ACC_PROTECTED)) { return "protected" - } - if (bitSet(classNode.access, ACC_PUBLIC)) { + } else if (bitSet(access, ACC_PUBLIC)) { return "public" + } else if (bitSet(access, ACC_PRIVATE)) { + return "private" + } else { + return "[package]" } } diff --git a/buildSrc/src/main/groovy/RoboJavaModulePlugin.groovy b/buildSrc/src/main/groovy/RoboJavaModulePlugin.groovy index b18ad6628..8a34039e5 100644 --- a/buildSrc/src/main/groovy/RoboJavaModulePlugin.groovy +++ b/buildSrc/src/main/groovy/RoboJavaModulePlugin.groovy @@ -9,10 +9,17 @@ class RoboJavaModulePlugin implements Plugin<Project> { Boolean deploy = false; Closure doApply = { - apply plugin: "java" + apply plugin: "java-library" + apply plugin: "net.ltgt.errorprone" + sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 + project.dependencies { + errorprone("com.google.errorprone:error_prone_core:$errorproneVersion") + errorproneJavac("com.google.errorprone:javac:$errorproneJavacVersion") + } + tasks.withType(JavaCompile) { task -> sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 @@ -24,7 +31,6 @@ class RoboJavaModulePlugin implements Plugin<Project> { } compilerArgs << "-Xlint:-options" // Turn off "missing" bootclasspath warning encoding = "utf-8" // Make sure source encoding is UTF-8 - incremental = true } def noRebuild = System.getenv('NO_REBUILD') == "true" diff --git a/buildSrc/src/main/groovy/ShadowsPlugin.groovy b/buildSrc/src/main/groovy/ShadowsPlugin.groovy index 5d38188ef..7374af682 100644 --- a/buildSrc/src/main/groovy/ShadowsPlugin.groovy +++ b/buildSrc/src/main/groovy/ShadowsPlugin.groovy @@ -8,28 +8,32 @@ import java.util.jar.JarFile class ShadowsPlugin implements Plugin<Project> { @Override void apply(Project project) { - project.apply plugin: "net.ltgt.apt" project.apply plugin: 'idea' project.extensions.create("shadows", ShadowsPluginExtension) project.dependencies { - apt project.project(":processor") + annotationProcessor project.project(":processor") } def compileJavaTask = project.tasks["compileJava"] + + // write generated Java into its own dir... see https://github.com/gradle/gradle/issues/4956 + def generatedSrcRelPath = 'build/generated/src/apt/main' + def generatedSrcDir = project.file(generatedSrcRelPath) + + project.sourceSets.main.java { srcDir generatedSrcRelPath } + project.mkdir(generatedSrcDir) + compileJavaTask.options.annotationProcessorGeneratedSourcesDirectory = generatedSrcDir + compileJavaTask.outputs.dir(generatedSrcDir) + compileJavaTask.doFirst { options.compilerArgs.add("-Aorg.robolectric.annotation.processing.shadowPackage=${project.shadows.packageName}") options.compilerArgs.add("-Aorg.robolectric.annotation.processing.sdkCheckMode=${project.shadows.sdkCheckMode}") } - // this doesn't seem to have any effect in IDEA yet, unfortunately... - def aptGeneratedSrcDir = new File(project.buildDir, 'generated/source/apt/main') - project.idea.module.generatedSourceDirs << aptGeneratedSrcDir - - // include generated sources in javadoc and source jars - project.tasks['javadoc'].source(aptGeneratedSrcDir) - project.tasks['sourcesJar'].from(project.fileTree(aptGeneratedSrcDir)) + // include generated sources in javadoc jar + project.tasks['javadoc'].source(generatedSrcDir) // verify that we have the apt-generated files in our javadoc and sources jars project.tasks['javadocJar'].doLast { task -> diff --git a/errorprone/build.gradle b/errorprone/build.gradle index 8707f56c0..78c2d5866 100644 --- a/errorprone/build.gradle +++ b/errorprone/build.gradle @@ -1,7 +1,3 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true, ).apply(project) @@ -20,12 +16,14 @@ dependencies { compile project(":annotations") // Compile dependencies - compile "com.google.errorprone:error_prone_annotation:2.3.1" - compile "com.google.errorprone:error_prone_refaster:2.3.1" - compile "com.google.errorprone:error_prone_check_api:2.3.1" + compile "com.google.errorprone:error_prone_annotation:2.3.2" + compile "com.google.errorprone:error_prone_refaster:2.3.2" + compile "com.google.errorprone:error_prone_check_api:2.3.2" compile "com.google.auto.service:auto-service:1.0-rc4" compileOnly(AndroidSdk.MAX_SDK.coordinates) { force = true } + annotationProcessor "com.google.auto.service:auto-service:1.0-rc4" + // in jdk 9, tools.jar disappears! def toolsJar = org.gradle.internal.jvm.Jvm.current().getToolsJar() if (toolsJar != null) { @@ -34,7 +32,7 @@ dependencies { // Testing dependencies testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.36" + testCompile "com.google.truth:truth:0.42" testCompile("com.google.errorprone:error_prone_test_helpers:2.3.1") { exclude group: 'junit', module: 'junit' // because it depends on a snapshot!? } diff --git a/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/DeprecatedMethodsCheck.java b/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/DeprecatedMethodsCheck.java index 52450114c..c028e611b 100644 --- a/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/DeprecatedMethodsCheck.java +++ b/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/DeprecatedMethodsCheck.java @@ -3,12 +3,15 @@ package org.robolectric.errorprone.bugpatterns; import static com.google.errorprone.BugPattern.Category.ANDROID; import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; import static com.google.errorprone.matchers.Description.NO_MATCH; +import static com.google.errorprone.matchers.Matchers.instanceMethod; import static com.google.errorprone.matchers.Matchers.staticMethod; import static com.google.errorprone.util.ASTHelpers.hasAnnotation; +import static org.robolectric.errorprone.bugpatterns.Helpers.isCastableTo; import static org.robolectric.errorprone.bugpatterns.Helpers.isInShadowClass; import com.google.auto.service.AutoService; import com.google.errorprone.BugPattern; +import com.google.errorprone.BugPattern.LinkType; import com.google.errorprone.BugPattern.ProvidesFix; import com.google.errorprone.BugPattern.StandardTags; import com.google.errorprone.VisitorState; @@ -17,8 +20,7 @@ import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher; import com.google.errorprone.fixes.Fix; import com.google.errorprone.fixes.SuggestedFix; import com.google.errorprone.matchers.Description; -import com.google.errorprone.matchers.Matcher; -import com.google.errorprone.matchers.Matchers; +import com.google.errorprone.matchers.method.MethodMatchers.MethodNameMatcher; import com.sun.source.tree.ClassTree; import com.sun.source.tree.ImportTree; import com.sun.source.tree.MethodInvocationTree; @@ -34,12 +36,11 @@ import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeMaker; -import com.sun.tools.javac.util.List; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import org.robolectric.annotation.Implements; -import org.robolectric.errorprone.bugpatterns.ShadowUsageCheck.ShadowInliner; /** @author christianw@google.com (Christian Williams) */ @AutoService(BugChecker.class) @@ -50,15 +51,74 @@ import org.robolectric.errorprone.bugpatterns.ShadowUsageCheck.ShadowInliner; severity = WARNING, documentSuppression = false, tags = StandardTags.REFACTORING, - providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION) -public final class DeprecatedMethodsCheck extends BugChecker implements ClassTreeMatcher { - /** Matches calls to <code>ShadowApplication#getInstance()</code>. */ - private static final Matcher<MethodInvocationTree> shadowAppGetInstanceMatcher = - Matchers.anyOf( - staticMethod().onClass("org.robolectric.shadows.ShadowApplication").named("getInstance"), - staticMethod() - .onClass("xxx.XShadowApplication") // for tests - .named("getInstance")); + providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION, + link = "http://robolectric.org/migrating/#deprecations", + linkType = LinkType.CUSTOM) +public class DeprecatedMethodsCheck extends BugChecker implements ClassTreeMatcher { + private final java.util.List<MethodInvocationMatcher> matchers = + Arrays.asList( + // Matches calls to <code>ShadowApplication.getInstance()</code>. + (MethodInvocationMatcher) + new MethodInvocationMatcher() { + @Override + MethodNameMatcher matcher() { + return staticMethod() + .onClass(shadowName("org.robolectric.shadows.ShadowApplication")) + .named("getInstance"); + } + + @Override + void replace( + MethodInvocationTree tree, + VisitorState state, + SuggestedFix.Builder fixBuilder, + HashMap<Tree, Runnable> possibleFixes) { + MethodCall surroundingMethodCall = getSurroundingMethodCall(tree, state); + + if (surroundingMethodCall != null + && surroundingMethodCall.getName().equals("getApplicationContext")) { + // transform `ShadowApplication.getInstance().getApplicationContext()` + // to `RuntimeEnvironment.application`: + + fixBuilder + .replace(surroundingMethodCall.node, "RuntimeEnvironment.application") + .addImport("org.robolectric.RuntimeEnvironment"); + } else { + // transform `ShadowApplication.getInstance()` + // to `shadowOf(RuntimeEnvironment.application)`: + Tree parent = state.getPath().getParentPath().getLeaf(); + // replaceAssignmentRhs(parent, createSyntheticShadowAccess(state)); + + possibleFixes.put( + parent, + () -> + fixBuilder + .addImport("org.robolectric.RuntimeEnvironment") + .replace( + tree, + wrapInShadows( + state, fixBuilder, "RuntimeEnvironment.application"))); + } + } + }, + new AppGetLastMatcher( + "org.robolectric.shadows.ShadowAlertDialog", + "ShadowAlertDialog", + "getLatestAlertDialog"), + new AppGetLastMatcher( + "org.robolectric.shadows.ShadowDialog", "ShadowDialog", "getLatestDialog"), + new AppGetLastMatcher( + "org.robolectric.shadows.ShadowPopupMenu", "ShadowPopupMenu", "getLatestPopupMenu")); + + abstract class MethodInvocationMatcher { + abstract MethodNameMatcher matcher(); + + abstract void replace( + MethodInvocationTree tree, + VisitorState state, + SuggestedFix.Builder fixBuilder, + HashMap<Tree, Runnable> possibleFixes); + } @Override public Description matchClass(ClassTree tree, VisitorState state) { @@ -88,41 +148,10 @@ public final class DeprecatedMethodsCheck extends BugChecker implements ClassTre VisitorState nowState = state.withPath(TreePath.getPath(state.getPath(), tree)); if (!inShadowClass) { - if (shadowAppGetInstanceMatcher.matches(tree, state)) { - MethodCall surroundingMethodCall = getSurroundingMethodCall(tree, state); - - if (surroundingMethodCall != null - && surroundingMethodCall.getName().equals("getApplicationContext")) { - // transform `ShadowApplication.getInstance().getApplicationContext()` - // to `RuntimeEnvironment.application`: - - fixBuilder - .replace(surroundingMethodCall.node, "RuntimeEnvironment.application") - .addImport("org.robolectric.RuntimeEnvironment"); - } else { - // transform `ShadowApplication.getInstance()` - // to `shadowOf(RuntimeEnvironment.application)`: - Tree parent = nowState.getPath().getParentPath().getLeaf(); - replaceAssignmentRhs(parent, createSyntheticShadowAccess(state)); - - // replacements below might be removed, but always add this import... - fixBuilder - .addImport("org.robolectric.RuntimeEnvironment") - .addImport("org.robolectric.Shadows"); - - Set<String> imports = getImports(state); - if (imports.contains("org.robolectric.Shadows")) { - possibleFixes.put( - parent, - () -> - fixBuilder.replace( - tree, "Shadows.shadowOf(RuntimeEnvironment.application)")); - } else { - fixBuilder.addStaticImport("org.robolectric.Shadows.shadowOf"); - possibleFixes.put( - parent, - () -> fixBuilder.replace(tree, "shadowOf(RuntimeEnvironment.application)")); - } + for (MethodInvocationMatcher matcher : matchers) { + if (matcher.matcher().matches(tree, state)) { + matcher.replace(tree, nowState, fixBuilder, possibleFixes); + return null; } } } @@ -132,8 +161,8 @@ public final class DeprecatedMethodsCheck extends BugChecker implements ClassTre }.scan(tree, state); if (!fixBuilder.isEmpty() || !possibleFixes.isEmpty()) { - ShadowInliner shadowInliner = new ShadowInliner(fixBuilder, possibleFixes); - shadowInliner.scan(tree, state); + // ShadowInliner shadowInliner = new ShadowInliner(fixBuilder, possibleFixes); + // shadowInliner.scan(tree, state); } for (Runnable runnable : possibleFixes.values()) { @@ -144,6 +173,19 @@ public final class DeprecatedMethodsCheck extends BugChecker implements ClassTre return fix.isEmpty() ? NO_MATCH : describeMatch(tree, fix); } + private String wrapInShadows( + VisitorState state, SuggestedFix.Builder fixBuilder, String content) { + Set<String> imports = getImports(state); + String shadowyContent; + if (imports.contains(shadowName("org.robolectric.Shadows"))) { + shadowyContent = shortShadowName("Shadows") + ".shadowOf(" + content + ")"; + } else { + fixBuilder.addStaticImport(shadowName("org.robolectric.Shadows.shadowOf")); + shadowyContent = "shadowOf(" + content + ")"; + } + return shadowyContent; + } + private void replaceAssignmentRhs(Tree parent, JCExpression replacementExpr) { if (parent instanceof JCFieldAccess) { JCFieldAccess parentFieldAccess = (JCFieldAccess) parent; @@ -169,7 +211,8 @@ public final class DeprecatedMethodsCheck extends BugChecker implements ClassTre treeMaker.Ident(findSymbol(state, "org.robolectric.Shadows")), findSymbol(state, "org.robolectric.Shadows", "shadowOf(android.app.Application)")); - JCMethodInvocation callShadowOf = treeMaker.Apply(null, shadowOfApp, List.of(application)); + JCMethodInvocation callShadowOf = + treeMaker.Apply(null, shadowOfApp, com.sun.tools.javac.util.List.of(application)); callShadowOf.type = callShadowOf.meth.type; return callShadowOf; } @@ -227,4 +270,51 @@ public final class DeprecatedMethodsCheck extends BugChecker implements ClassTre return ((JCFieldAccess) node.getMethodSelect()).name.toString(); } } + + String shadowName(String className) { + return className; + } + + String shortShadowName(String shadowClassName) { + return shadowClassName; + } + + private class AppGetLastMatcher extends MethodInvocationMatcher { + private final String methodName; + private final String shadowClassName; + private final String shadowShortClassName; + + AppGetLastMatcher( + String shadowClassName, String shadowShortClassName, String methodName) { + this.methodName = methodName; + this.shadowClassName = shadowClassName; + this.shadowShortClassName = shadowShortClassName; + } + + @Override + MethodNameMatcher matcher() { + return instanceMethod() + .onClass(isCastableTo(shadowName("org.robolectric.shadows.ShadowApplication"))) + .named(methodName); + } + + @Override + void replace( + MethodInvocationTree tree, + VisitorState state, + SuggestedFix.Builder fixBuilder, + HashMap<Tree, Runnable> possibleFixes) { + possibleFixes.put( + tree, + () -> + fixBuilder + .addImport(shadowName(shadowClassName)) + .replace( + tree, + wrapInShadows( + state, + fixBuilder, + shortShadowName(shadowShortClassName) + "." + methodName + "()"))); + } + } } diff --git a/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/RobolectricShadow.java b/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/RobolectricShadow.java index 234f36203..da6640a55 100644 --- a/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/RobolectricShadow.java +++ b/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/RobolectricShadow.java @@ -22,6 +22,7 @@ import com.sun.source.doctree.StartElementTree; import com.sun.source.doctree.TextTree; import com.sun.source.tree.AnnotationTree; import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ExpressionTree; import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.ModifiersTree; @@ -33,6 +34,7 @@ import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DCTree.DCDocComment; import com.sun.tools.javac.tree.DCTree.DCReference; import com.sun.tools.javac.tree.DCTree.DCStartElement; +import com.sun.tools.javac.tree.JCTree.JCAssign; import com.sun.tools.javac.tree.JCTree.JCIdent; import java.util.ArrayList; import java.util.List; @@ -65,53 +67,27 @@ public final class RobolectricShadow extends BugChecker implements ClassTreeMatc List<Optional<SuggestedFix>> fixes = new ArrayList<>(); if (implementsClassMatcher.matches(classTree, state)) { - JavacTrees trees = JavacTrees.instance(state.context); + boolean inSdk = true; - new TreePathScanner<Void, Void>() { - @Override - public Void visitMethod(MethodTree methodTree, Void aVoid) { - if (implementationMethodMatcher.matches(methodTree, state)) { - processImplementationMethod(methodTree); - } - return super.visitMethod(methodTree, aVoid); - } - - private void processImplementationMethod(MethodTree methodTree) { - String methodName = methodTree.getName().toString(); - if ("toString".equals(methodName) - || "equals".equals(methodName) - || "hashCode".equals(methodName)) { - return; // they need to remain public - } - ModifiersTree modifiersTree = methodTree.getModifiers(); - for (AnnotationTree annotationTree : modifiersTree.getAnnotations()) { - JCIdent ident = (JCIdent) annotationTree.getAnnotationType(); - if ("java.lang.Override".equals(ident.sym.getQualifiedName().toString())) { - return; // can't have more restrictive permissions than the overridden method + JavacTrees trees = JavacTrees.instance(state.context); + for (AnnotationTree annotationTree : classTree.getModifiers().getAnnotations()) { + JCIdent ident = (JCIdent) annotationTree.getAnnotationType(); + String annotationClassName = ident.sym.getQualifiedName().toString(); + if ("org.robolectric.annotation.Implements".equals(annotationClassName)) { + for (ExpressionTree expressionTree : annotationTree.getArguments()) { + JCAssign jcAnnotation = (JCAssign) expressionTree; + if ("isInAndroidSdk".equals(jcAnnotation.lhs.toString()) + && "false".equals(jcAnnotation.rhs.toString())) { + // shadows of classes not in the public Android SDK can keep their public methods. + inSdk = false; } } - - Set<Modifier> modifiers = modifiersTree.getFlags(); - if (!modifiers.contains(Modifier.PROTECTED)) { - fixes.add( - SuggestedFixes.removeModifiers( - methodTree, state, Modifier.PUBLIC, Modifier.PRIVATE)); - fixes.add(SuggestedFixes.addModifiers(methodTree, state, Modifier.PROTECTED)); - } - - if (doScanJavadoc) { - scanJavadoc(); - } } + } - private void scanJavadoc() { - DocCommentTree commentTree = trees.getDocCommentTree(getCurrentPath()); - if (commentTree != null) { - DocTreePath docTrees = new DocTreePath(getCurrentPath(), commentTree); - new DocTreeSymbolScanner(trees, fixes).scan(docTrees, null); - } - } - }.scan(state.getPath(), null); + if (inSdk) { + new ImplementationMethodScanner(state, fixes, trees).scan(state.getPath(), null); + } } SuggestedFix.Builder builder = SuggestedFix.builder(); @@ -194,4 +170,68 @@ public final class RobolectricShadow extends BugChecker implements ClassTreeMatc return null; } } + + private class ImplementationMethodScanner extends TreePathScanner<Void, Void> { + + private final com.google.errorprone.VisitorState state; + private final List<Optional<SuggestedFix>> fixes; + private final JavacTrees trees; + + ImplementationMethodScanner(com.google.errorprone.VisitorState state, + List<Optional<SuggestedFix>> fixes, JavacTrees trees) { + this.state = state; + this.fixes = fixes; + this.trees = trees; + } + + @Override + public Void visitMethod(MethodTree methodTree, Void aVoid) { + if (implementationMethodMatcher.matches(methodTree, state)) { + processImplementationMethod(methodTree); + } + return super.visitMethod(methodTree, aVoid); + } + + private void processImplementationMethod(MethodTree methodTree) { + String methodName = methodTree.getName().toString(); + if ("toString".equals(methodName) + || "equals".equals(methodName) + || "hashCode".equals(methodName)) { + return; // they need to remain public + } + ModifiersTree modifiersTree = methodTree.getModifiers(); + for (AnnotationTree annotationTree : modifiersTree.getAnnotations()) { + JCIdent ident = (JCIdent) annotationTree.getAnnotationType(); + String annotationClassName = ident.sym.getQualifiedName().toString(); + if ("java.lang.Override".equals(annotationClassName)) { + // can't have more restrictive permissions than the overridden method. + return; + } + if ("org.robolectric.annotation.HiddenApi".equals(annotationClassName)) { + // @HiddenApi implementation methods can stay public for the convenience of tests. + return; + } + } + + Set<Modifier> modifiers = modifiersTree.getFlags(); + if (!modifiers.contains(Modifier.PROTECTED)) { + fixes.add( + SuggestedFixes.removeModifiers( + methodTree, state, Modifier.PUBLIC, Modifier.PRIVATE)); + fixes.add(SuggestedFixes.addModifiers(methodTree, state, Modifier.PROTECTED)); + } + + if (doScanJavadoc) { + scanJavadoc(); + } + } + + private void scanJavadoc() { + DocCommentTree commentTree = trees.getDocCommentTree(getCurrentPath()); + if (commentTree != null) { + DocTreePath docTrees = new DocTreePath(getCurrentPath(), commentTree); + new DocTreeSymbolScanner(trees, fixes).scan(docTrees, null); + } + } + } } diff --git a/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/ShadowUsageCheck.java b/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/ShadowUsageCheck.java index c5ecf47c0..7e0cfc5d2 100644 --- a/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/ShadowUsageCheck.java +++ b/errorprone/src/main/java/org/robolectric/errorprone/bugpatterns/ShadowUsageCheck.java @@ -52,6 +52,7 @@ import com.sun.tools.javac.code.Type.UnknownType; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; @@ -61,9 +62,12 @@ import com.sun.tools.javac.tree.JCTree.JCNewClass; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeMaker; -import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.Name; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -85,7 +89,7 @@ import org.robolectric.errorprone.bugpatterns.Helpers.AnnotatedMethodMatcher; severity = SUGGESTION, documentSuppression = false, tags = StandardTags.REFACTORING, - link = "http://robolectric.org/errorprone-refactorings/", + link = "http://robolectric.org/migrating/#improper-use-of-shadows", linkType = LinkType.CUSTOM, providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION) public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatcher { @@ -108,20 +112,16 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch return NO_MATCH; } - final ShadowInliner shadowInliner = new ShadowInliner(); + final ShadowInliner shadowInliner = new ShadowInliner( + (JCCompilationUnit) state.getPath().getCompilationUnit()); shadowInliner.scan(tree, state); - for (Runnable runnable : shadowInliner.possibleFixes.values()) { - runnable.run(); - } - - Fix fix = shadowInliner.fixBuilder.build(); + Fix fix = shadowInliner.possibleFixes.getFix(); return fix.isEmpty() ? NO_MATCH : describeMatch(tree, fix); } static class ShadowInliner extends TreeScanner<Void, VisitorState> { - private final SuggestedFix.Builder fixBuilder; - private final Map<Tree, Runnable> possibleFixes; + private final PossibleFixes possibleFixes; private final Set<String> knownFields = new HashSet<>(); private final Set<String> knownLocalVars = new HashSet<>(); @@ -129,12 +129,11 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch private boolean inShadowClass; - ShadowInliner() { - this(SuggestedFix.builder(), new HashMap<>()); + ShadowInliner(JCCompilationUnit compilationUnit) { + this(new PossibleFixes(SuggestedFix.builder(), compilationUnit)); } - ShadowInliner(SuggestedFix.Builder fixBuilder, Map<Tree, Runnable> possibleFixes) { - this.fixBuilder = fixBuilder; + ShadowInliner(PossibleFixes possibleFixes) { this.possibleFixes = possibleFixes; } @@ -152,234 +151,230 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch switch (parent.getKind()) { case VARIABLE: // ShadowType shadowType = shadowOf(type); - { - // shadow is being assigned to a variable; don't do that! - JCVariableDecl variableDecl = (JCVariableDecl) parent; - String oldVarName = variableDecl.getName().toString(); - - // since it's being declared here, no danger of a collision on this var name... - knownLocalVars.remove(oldVarName); - - String newVarName = pickNewName(shadowOfArg, oldVarName, this); - varRemapping.put(getSymbol(variableDecl), newVarName); - - // ... but be careful not to collide with it later. - knownLocalVars.add(newVarName); - - // replace shadow variable declaration with shadowed type and name - if (!newVarName.equals(shadowOfArg.toString())) { - Type shadowedType = getUpperBound(shadowOfArgType, state); - String shadowedTypeName = SuggestedFixes.prettyType(state, fixBuilder, shadowedType); - String newAssignment = - shadowedTypeName + " " + newVarName + " = " + shadowOfArg + ";"; - - // avoid overlapping replacements: - if (shadowOfArg instanceof JCMethodInvocation) { - JCExpression jcExpression = ((JCMethodInvocation) shadowOfArg).meth; - if (jcExpression instanceof JCFieldAccess) { - possibleFixes.remove(((JCFieldAccess) jcExpression).selected); - } + { + // shadow is being assigned to a variable; don't do that! + JCVariableDecl variableDecl = (JCVariableDecl) parent; + String oldVarName = variableDecl.getName().toString(); + + // since it's being declared here, no danger of a collision on this var name... + knownLocalVars.remove(oldVarName); + + String newVarName = pickNewName(shadowOfArg, oldVarName, this); + varRemapping.put(getSymbol(variableDecl), newVarName); + + // ... but be careful not to collide with it later. + knownLocalVars.add(newVarName); + + // replace shadow variable declaration with shadowed type and name + if (!newVarName.equals(shadowOfArg.toString())) { + Type shadowedType = getUpperBound(shadowOfArgType, state); + String shadowedTypeName = + SuggestedFixes.prettyType(state, possibleFixes.fixBuilder, shadowedType); + String newAssignment = + shadowedTypeName + " " + newVarName + " = " + shadowOfArg + ";"; + + // avoid overlapping replacements: + if (shadowOfArg instanceof JCMethodInvocation) { + JCExpression jcExpression = ((JCMethodInvocation) shadowOfArg).meth; + if (jcExpression instanceof JCFieldAccess) { + possibleFixes.removeFixFor(((JCFieldAccess) jcExpression).selected); } - - possibleFixes.remove(parent); - fixBuilder.replace(parent, newAssignment); - } else { - possibleFixes.remove(parent); - fixBuilder.delete(parent); } - // replace shadow variable reference with `nonShadowInstance` or - // `shadowOf(nonShadowInstance)` as appropriate. - new TreePathScanner<Void, Void>() { - @Override - public Void visitIdentifier(IdentifierTree identifierTreeX, Void aVoid) { - JCIdent identifierTree = (JCIdent) identifierTreeX; - - Symbol symbol = getSymbol(identifierTree); - if (variableDecl.sym.equals(symbol) && !isLeftSideOfAssignment(identifierTree)) { - TreePath idPath = TreePath.getPath(compilationUnit, identifierTree); - Tree parent = idPath.getParentPath().getLeaf(); - boolean callDirectlyOnFramework = shouldCallDirectlyOnFramework(idPath); - - JCTree replaceNode; - if (parent instanceof JCFieldAccess && !callDirectlyOnFramework) { - JCFieldAccess fieldAccess = (JCFieldAccess) parent; - replaceNode = - fieldAccess.selected = - createSyntheticShadowAccess( - identifierTree, fieldAccess, shadowOfCall, newVarName, state); - } else { - identifierTree.name = state.getName(newVarName); - identifierTree.sym.name = state.getName(newVarName); - replaceNode = identifierTree; - } + possibleFixes.fixByReplacing(parent, newAssignment); + } else { + possibleFixes.fixByDeleting(parent); + } - possibleFixes.put( - replaceNode, - () -> { - fixBuilder.replace( - identifierTree, - callDirectlyOnFramework - ? newVarName - : shadowOfCall.getMethodSelect() + "(" + newVarName + ")"); - }); + // replace shadow variable reference with `nonShadowInstance` or + // `shadowOf(nonShadowInstance)` as appropriate. + new TreePathScanner<Void, Void>() { + @Override + public Void visitIdentifier(IdentifierTree identifierTreeX, Void aVoid) { + JCIdent identifierTree = (JCIdent) identifierTreeX; + + Symbol symbol = getSymbol(identifierTree); + if (variableDecl.sym.equals(symbol) && !isLeftSideOfAssignment(identifierTree)) { + TreePath idPath = TreePath.getPath(compilationUnit, identifierTree); + Tree parent = idPath.getParentPath().getLeaf(); + boolean callDirectlyOnFramework = shouldCallDirectlyOnFramework(idPath); + + JCTree replaceNode; + if (parent instanceof JCFieldAccess && !callDirectlyOnFramework) { + JCFieldAccess fieldAccess = (JCFieldAccess) parent; + JCMethodInvocation newShadowOfCall = + createSyntheticShadowAccess(shadowOfCall, newVarName, symbol, state); + + replaceFieldSelected(fieldAccess, newShadowOfCall, state); + replaceNode = newShadowOfCall; + } else { + identifierTree.name = state.getName(newVarName); + identifierTree.sym.name = state.getName(newVarName); + replaceNode = identifierTree; } - return super.visitIdentifier(identifierTree, aVoid); - } - private boolean isLeftSideOfAssignment(IdentifierTree identifierTree) { - Tree parent = getCurrentPath().getParentPath().getLeaf(); - if (parent instanceof AssignmentTree) { - return identifierTree.equals(((AssignmentTree) parent).getVariable()); - } - return false; + String replaceWith = + callDirectlyOnFramework + ? newVarName + : shadowOfCall.getMethodSelect() + "(" + newVarName + ")"; + + possibleFixes.put( + replaceNode, possibleFixes.new ReplacementFix(identifierTree, replaceWith)); } - }.scan(compilationUnit, null); - } - break; + return super.visitIdentifier(identifierTree, aVoid); + } - case ASSIGNMENT: // this.shadowType = shadowOf(type); - { - // shadow is being assigned to a field or variable; don't do that! - JCAssign assignment = (JCAssign) parent; - Symbol fieldSymbol = getSymbol(assignment.lhs); - - String oldFieldName = assignment.lhs.toString(); - String remappedName = varRemapping.get(fieldSymbol); - - // since it's being declared here, no danger of a collision on this var name... - knownFields.remove(oldFieldName); - - String newFieldName = - remappedName == null ? pickNewName(shadowOfArg, oldFieldName, this) : remappedName; - varRemapping.put(fieldSymbol, newFieldName); - - // ... but be careful not to collide with it later. - knownLocalVars.add(newFieldName); - - // local variable declaration should have been handled above in the VARIABLE case; - // just strip shadowOf() and assign it to the de-shadowed variable. - if (fieldSymbol.getKind() == ElementKind.LOCAL_VARIABLE) { - if (newFieldName.equals(shadowOfArg.toString())) { - // assigning to self, don't bother - TreePath assignmentPath = TreePath.getPath(compilationUnit, assignment); - Tree assignmentParent = assignmentPath.getParentPath().getLeaf(); - if (assignmentParent instanceof ExpressionStatementTree) { - possibleFixes.remove(assignmentParent); - fixBuilder.delete(assignmentParent); - } - } else { - possibleFixes.remove(assignment); - fixBuilder.replace(assignment, newFieldName + " = " + shadowOfArg.toString()); + private boolean isLeftSideOfAssignment(IdentifierTree identifierTree) { + Tree parent = getCurrentPath().getParentPath().getLeaf(); + if (parent instanceof AssignmentTree) { + return identifierTree.equals(((AssignmentTree) parent).getVariable()); } - break; + return false; } + }.scan(compilationUnit, null); + } + break; - Symbol shadowOfArgSym = getSymbol(shadowOfArg); - ElementKind shadowOfArgDomicile = - shadowOfArgSym == null - ? ElementKind.OTHER // it's probably an expression, not a var... - : shadowOfArgSym.getKind(); - boolean namesAreSame = newFieldName.equals(shadowOfArg.toString()); - - boolean useExistingField = - shadowOfArgDomicile == ElementKind.FIELD - && namesAreSame - && !isMethodParam(ASTHelpers.getSymbol(shadowOfArg), state.getPath()); - - if (useExistingField) { - fixVar(fieldSymbol, state, fixBuilder).delete(); - - ExpressionStatementTree enclosingNode = - ASTHelpers.findEnclosingNode( - TreePath.getPath(compilationUnit, parent), ExpressionStatementTree.class); - if (enclosingNode != null) { - fixBuilder.delete(enclosingNode); + case ASSIGNMENT: // this.shadowType = shadowOf(type); + { + // shadow is being assigned to a field or variable; don't do that! + JCAssign assignment = (JCAssign) parent; + Symbol fieldSymbol = getSymbol(assignment.lhs); + + String oldFieldName = assignment.lhs.toString(); + String remappedName = varRemapping.get(fieldSymbol); + + // since it's being declared here, no danger of a collision on this var name... + knownFields.remove(oldFieldName); + + String newFieldName = + remappedName == null ? pickNewName(shadowOfArg, oldFieldName, this) : remappedName; + varRemapping.put(fieldSymbol, newFieldName); + + // ... but be careful not to collide with it later. + knownLocalVars.add(newFieldName); + + // local variable declaration should have been handled above in the VARIABLE case; + // just strip shadowOf() and assign it to the de-shadowed variable. + if (fieldSymbol.getKind() == ElementKind.LOCAL_VARIABLE) { + if (newFieldName.equals(shadowOfArg.toString())) { + // assigning to self, don't bother + TreePath assignmentPath = TreePath.getPath(compilationUnit, assignment); + Tree assignmentParent = assignmentPath.getParentPath().getLeaf(); + if (assignmentParent instanceof ExpressionStatementTree) { + possibleFixes.fixByDeleting(assignmentParent); } } else { - Type shadowedType = getUpperBound(shadowOfArgType, state); - String shadowedTypeName = SuggestedFixes.prettyType(state, fixBuilder, shadowedType); - fixVar(fieldSymbol, state, fixBuilder) - .setName(newFieldName) - .setTypeName(shadowedTypeName) - .setRenameUses(false) - .modify(); - - String thisStr = ""; - if (((JCAssign) parent).lhs.toString().startsWith("this.") - || (shadowOfArgDomicile == ElementKind.LOCAL_VARIABLE && namesAreSame)) { - thisStr = "this."; - } + possibleFixes.fixByReplacing( + assignment, newFieldName + " = " + shadowOfArg.toString()); + } + break; + } - possibleFixes.remove(parent); - fixBuilder.replace(parent, thisStr + newFieldName + " = " + shadowOfArg); + Symbol shadowOfArgSym = getSymbol(shadowOfArg); + ElementKind shadowOfArgDomicile = + shadowOfArgSym == null + ? ElementKind.OTHER // it's probably an expression, not a var... + : shadowOfArgSym.getKind(); + boolean namesAreSame = newFieldName.equals(shadowOfArg.toString()); + + boolean useExistingField = + shadowOfArgDomicile == ElementKind.FIELD + && namesAreSame + && !isMethodParam(ASTHelpers.getSymbol(shadowOfArg), state.getPath()); + + if (useExistingField) { + fixVar(fieldSymbol, state, possibleFixes).delete(); + + ExpressionStatementTree enclosingNode = + ASTHelpers.findEnclosingNode( + TreePath.getPath(compilationUnit, assignment), ExpressionStatementTree.class); + if (enclosingNode != null) { + possibleFixes.fixByDeleting(enclosingNode); + } + } else { + Type shadowedType = getUpperBound(shadowOfArgType, state); + String shadowedTypeName = + SuggestedFixes.prettyType(state, possibleFixes.fixBuilder, shadowedType); + fixVar(fieldSymbol, state, possibleFixes) + .setName(newFieldName) + .setTypeName(shadowedTypeName) + .setRenameUses(false) + .modify(); + + String thisStr = ""; + if (assignment.lhs.toString().startsWith("this.") + || (shadowOfArgDomicile == ElementKind.LOCAL_VARIABLE && namesAreSame)) { + thisStr = "this."; } - TreePath containingBlock = findParentOfKind(state, Kind.BLOCK); - if (containingBlock != null) { - // replace shadow field reference with `nonShadowInstance` or - // `shadowOf(nonShadowInstance)` as appropriate. - new TreePathScanner<Void, Void>() { - @Override - public Void visitMemberSelect(MemberSelectTree memberSelectTree, Void aVoid) { - maybeReplaceFieldRef(memberSelectTree.getExpression()); + possibleFixes.fixByReplacing( + assignment, thisStr + newFieldName + " = " + shadowOfArg); + } - return super.visitMemberSelect(memberSelectTree, aVoid); - } + TreePath containingBlock = findParentOfKind(state, Kind.BLOCK); + if (containingBlock != null) { + // replace shadow field reference with `nonShadowInstance` or + // `shadowOf(nonShadowInstance)` as appropriate. + new TreePathScanner<Void, Void>() { + @Override + public Void visitMemberSelect(MemberSelectTree memberSelectTree, Void aVoid) { + maybeReplaceFieldRef(memberSelectTree.getExpression()); - @Override - public Void visitIdentifier(IdentifierTree identifierTree, Void aVoid) { - maybeReplaceFieldRef(identifierTree); + return super.visitMemberSelect(memberSelectTree, aVoid); + } - return super.visitIdentifier(identifierTree, aVoid); - } + @Override + public Void visitIdentifier(IdentifierTree identifierTree, Void aVoid) { + maybeReplaceFieldRef(identifierTree); + + return super.visitIdentifier(identifierTree, aVoid); + } - private void maybeReplaceFieldRef(ExpressionTree subject) { - Symbol symbol = getSymbol(subject); - if (symbol != null && symbol.getKind() == ElementKind.FIELD) { - TreePath subjectPath = TreePath.getPath(compilationUnit, subject); - - if (symbol.equals(fieldSymbol) && isPartOfMethodInvocation(subjectPath)) { - String fieldRef = - subject.toString().startsWith("this.") - ? "this." + newFieldName - : newFieldName; - - JCTree replaceNode = (JCTree) subject; - Tree container = subjectPath.getParentPath().getLeaf(); - if (container instanceof JCFieldAccess) { - replaceNode = - createSyntheticShadowAccess( - replaceNode, - (JCFieldAccess) container, - shadowOfCall, - newFieldName, - state); - } - - String replaceWith = - shouldCallDirectlyOnFramework(subjectPath) - ? fieldRef - : shadowOfCall.getMethodSelect() + "(" + fieldRef + ")"; - possibleFixes.put( - replaceNode, () -> fixBuilder.replace(subject, replaceWith)); + private void maybeReplaceFieldRef(ExpressionTree subject) { + Symbol symbol = getSymbol(subject); + if (symbol != null && symbol.getKind() == ElementKind.FIELD) { + TreePath subjectPath = TreePath.getPath(compilationUnit, subject); + + if (symbol.equals(fieldSymbol) && isPartOfMethodInvocation(subjectPath)) { + String fieldRef = + subject.toString().startsWith("this.") + ? "this." + newFieldName + : newFieldName; + + JCTree replaceNode = (JCTree) subject; + Tree container = subjectPath.getParentPath().getLeaf(); + if (container instanceof JCFieldAccess) { + JCFieldAccess fieldAccess = (JCFieldAccess) container; + JCMethodInvocation newShadowOfCall = + createSyntheticShadowAccess(shadowOfCall, newFieldName, symbol, state); + replaceFieldSelected(fieldAccess, newShadowOfCall, state); + replaceNode = newShadowOfCall; } + + String replaceWith = + shouldCallDirectlyOnFramework(subjectPath) + ? fieldRef + : shadowOfCall.getMethodSelect() + "(" + fieldRef + ")"; + possibleFixes.put( + replaceNode, possibleFixes.new ReplacementFix(subject, replaceWith)); } } - }.scan(compilationUnit, null); - } + } + }.scan(compilationUnit, null); } - break; + } + break; case MEMBER_SELECT: // shadowOf(type).method(); - { - if (shouldCallDirectlyOnFramework(state.getPath())) { - if (!isInSyntheticShadowAccess(state)) { - fixBuilder.replace(shadowOfCall, shadowOfArg.toString()); - } + { + if (shouldCallDirectlyOnFramework(state.getPath())) { + if (!isInSyntheticShadowAccess(state)) { + possibleFixes.fixByReplacing(shadowOfCall, shadowOfArg.toString()); } } - break; + } + break; case TYPE_CAST: System.out.println("WARN: not sure what to do with " + parent.getKind() + ": " + parent); @@ -391,6 +386,29 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch } } + private void replaceFieldSelected(JCFieldAccess fieldAccess, JCMethodInvocation newShadowOfCall, + VisitorState state) { + int priorStartPosition = fieldAccess.selected.getStartPosition(); + int priorEndPosition = getEndPosition(state, fieldAccess.selected); + + fieldAccess.selected = newShadowOfCall; + + newShadowOfCall.pos = priorStartPosition; + if (newShadowOfCall.meth instanceof JCIdent) { + ((JCIdent) newShadowOfCall.meth).pos = priorStartPosition; + } + setEndPosition(state, newShadowOfCall, priorEndPosition); + } + + private int getEndPosition(VisitorState state, JCTree node) { + return state.getEndPosition(node); + } + + private void setEndPosition(VisitorState state, JCTree tree, int endPosition) { + JCCompilationUnit compilationUnit = (JCCompilationUnit) state.getPath().getCompilationUnit(); + compilationUnit.endPositions.storeEnd(tree, endPosition); + } + @Override public Void visitClass(ClassTree classTree, VisitorState visitorState) { boolean priorInShadowClass = inShadowClass; @@ -428,8 +446,9 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch ClassSymbol owner = (ClassSymbol) methodSelect.sym.owner; ClassType shadowedClass = determineShadowedClassName(owner, nowState); - String shadowedTypeName = SuggestedFixes.prettyType(state, fixBuilder, shadowedClass); - fixBuilder.replace(methodSelect.selected, shadowedTypeName); + String shadowedTypeName = + SuggestedFixes.prettyType(state, possibleFixes.fixBuilder, shadowedClass); + possibleFixes.fixByReplacing(methodSelect.selected, shadowedTypeName); } if (!inShadowClass && shadowOfMatcher.matches(tree, nowState)) { @@ -450,24 +469,43 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch } private static JCMethodInvocation createSyntheticShadowAccess( - JCTree replaceNode, - JCFieldAccess fieldAccess, MethodInvocationTree shadowOfCall, String newFieldName, + Symbol originalSymbol, VisitorState state) { TreeMaker treeMaker = state.getTreeMaker(); + Symbol newSymbol = createSymbol(originalSymbol, state.getName(newFieldName), + ((JCExpression) shadowOfCall.getArguments().get(0)).type); + + JCExpression methodSelect = (JCExpression) shadowOfCall.getMethodSelect(); + if (methodSelect instanceof JCIdent) { + // clone so start pos can be changed... + methodSelect = treeMaker.Ident(((JCIdent) shadowOfCall.getMethodSelect()).sym); + } JCMethodInvocation callShadowOf = treeMaker.Apply( null, - (JCExpression) shadowOfCall.getMethodSelect(), - List.of(treeMaker.Ident(state.getName(newFieldName)))); - callShadowOf.type = new UnknownType(); - fieldAccess.selected = callShadowOf; - callShadowOf.pos = replaceNode.pos; + methodSelect, + com.sun.tools.javac.util.List.of(createIdent(treeMaker, newSymbol))); + callShadowOf.type = ((JCMethodInvocation) shadowOfCall).type; return callShadowOf; } + private static Symbol createSymbol(Symbol oldSymbol, Name newName, Type newType) { + Symbol newSymbol = oldSymbol.clone(oldSymbol.owner); + newSymbol.name = newName; + newSymbol.type = newType; + return newSymbol; + } + + private static JCIdent createIdent(TreeMaker treeMaker, Symbol symbol) { + JCIdent newFieldIdent = treeMaker.Ident(symbol.name); + newFieldIdent.type = symbol.type; + newFieldIdent.sym = symbol; + return newFieldIdent; + } + private static boolean isMethodParam(Symbol fieldSymbol, TreePath path) { JCMethodDecl enclosingMethodDecl = ASTHelpers.findEnclosingNode(path, JCMethodDecl.class); if (enclosingMethodDecl != null) { @@ -622,23 +660,23 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch * Renames the given {@link Symbol} and its usages in the current compilation unit to {@code * newName}. */ - static VariableFixer fixVar(Symbol symbol, VisitorState state, Builder fixBuilder) { - return new VariableFixer(symbol, state, fixBuilder); + static VariableFixer fixVar(Symbol symbol, VisitorState state, PossibleFixes possibleFixes) { + return new VariableFixer(symbol, state, possibleFixes); } private static class VariableFixer { private final Symbol symbol; private final VisitorState state; - private final SuggestedFix.Builder fixBuilder; + private final PossibleFixes possibleFixes; private boolean renameUses = true; private String newName; private String newTypeName; - public VariableFixer(Symbol symbol, VisitorState state, Builder fixBuilder) { + public VariableFixer(Symbol symbol, VisitorState state, PossibleFixes possibleFixes) { this.symbol = symbol; this.state = state; - this.fixBuilder = fixBuilder; + this.possibleFixes = possibleFixes; } VariableFixer setName(String newName) { @@ -665,7 +703,7 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch // For a lambda parameter without explicit type, it will return null. String source = state.getSourceForNode(variableTree.getType()); if (newTypeName != null) { - fixBuilder.replace(variableTree.getType(), newTypeName); + possibleFixes.fixByReplacing(variableTree.getType(), newTypeName); } if (newName != null && !newName.equals(name)) { @@ -673,7 +711,7 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch int pos = ((JCTree) variableTree).getStartPosition() + state.getSourceForNode(variableTree).indexOf(name, typeLength); - fixBuilder.replace(pos, pos + name.length(), newName); + possibleFixes.fixByReplacing(pos, pos + name.length(), newName); } } @@ -688,7 +726,7 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch @Override public void visitIdent(JCTree.JCIdent tree) { if (symbol.equals(getSymbol(tree))) { - fixBuilder.replace(tree, newName); + possibleFixes.fixByReplacing(tree, newName); } } }); @@ -700,7 +738,7 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch @Override public Void visitVariable(VariableTree variableTree, Void v) { if (getSymbol(variableTree).equals(symbol)) { - fixBuilder.delete(variableTree); + possibleFixes.fixByDeleting(variableTree); } return super.visitVariable(variableTree, v); @@ -735,4 +773,150 @@ public final class ShadowUsageCheck extends BugChecker implements ClassTreeMatch private static Tree findParent(Tree node, VisitorState state) { return TreePath.getPath(state.getPath().getCompilationUnit(), node).getParentPath().getLeaf(); } + + static class PossibleFixes { + + private final Builder fixBuilder; + private final JCCompilationUnit compilationUnit; + private final Map<Tree, PossibleFix> map = new HashMap<>(); + private final List<PossibleFix> list = new ArrayList<>(); + + public PossibleFixes(Builder builder, JCCompilationUnit compilationUnit) { + fixBuilder = builder; + this.compilationUnit = compilationUnit; + } + + public void put(Tree tree, PossibleFix possibleFix) { + if (tree != null) { + PossibleFix priorFix = map.put(tree, possibleFix); + if (priorFix != null) { + list.remove(priorFix); + } + } + + list.add(possibleFix); + } + + public void removeFixFor(Tree tree) { + PossibleFix possibleFix = map.remove(tree); + list.remove(possibleFix); + } + + public void fixByReplacing(Tree tree, String value) { + put(tree, new ReplacementFix(tree, value)); + } + + public void fixByDeleting(Tree tree) { + put(tree, new DeletionFix(tree)); + } + + public void fixByReplacing(int startPos, int endPos, String replaceWith) { + put(null, new PositionalReplacementFix(startPos, endPos, replaceWith)); + } + + public Fix getFix() { + for (PossibleFix possibleFix : list) { + possibleFix.applyFix(fixBuilder); + } + + return fixBuilder.build(); + } + + abstract class PossibleFix { + protected final Tree tree; + protected final int startPosition; + protected final int endPosition; + private final Throwable trace; + + PossibleFix(Tree tree) { + this.tree = tree; + + DiagnosticPosition position = (DiagnosticPosition) tree; + this.startPosition = position.getStartPosition(); + this.endPosition = position.getEndPosition(compilationUnit.endPositions); + + this.trace = new RuntimeException(); + } + + PossibleFix(int startPosition, int endPosition) { + this.tree = null; + + this.startPosition = startPosition; + this.endPosition = endPosition; + + this.trace = new RuntimeException(); + } + + abstract void applyFix(Builder fixBuilder); + + @Override + public String toString() { + return "PossibleFix{" + + "tree=" + + tree + + ", startPosition=" + + startPosition + + ", endPosition=" + + endPosition + + '}'; + } + } + + class ReplacementFix extends PossibleFix { + + private final String replaceWith; + + public ReplacementFix(Tree tree, String replaceWith) { + super(tree); + this.replaceWith = replaceWith; + } + + @Override + void applyFix(Builder fixBuilder) { + fixBuilder.replace(tree, replaceWith); + } + + @Override + public String toString() { + return super.toString() + " [replace with " + replaceWith + "]"; + } + } + + private class PositionalReplacementFix extends PossibleFix { + + private final String replaceWith; + + public PositionalReplacementFix(int startPos, int endPos, String replaceWith) { + super(startPos, endPos); + this.replaceWith = replaceWith; + } + + @Override + void applyFix(Builder fixBuilder) { + fixBuilder.replace(startPosition, endPosition, replaceWith); + } + + @Override + public String toString() { + return super.toString() + " [replace with " + replaceWith + "]"; + } + } + + class DeletionFix extends PossibleFix { + + public DeletionFix(Tree tree) { + super(tree); + } + + @Override + void applyFix(Builder fixBuilder) { + fixBuilder.delete(tree); + } + + @Override + public String toString() { + return super.toString() + " [delete]"; + } + } + } } diff --git a/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/DeprecatedMethodsCheckTest.java b/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/DeprecatedMethodsCheckTest.java index 1898c7394..9bbbd0090 100644 --- a/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/DeprecatedMethodsCheckTest.java +++ b/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/DeprecatedMethodsCheckTest.java @@ -1,8 +1,13 @@ package org.robolectric.errorprone.bugpatterns; +import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; + import com.google.errorprone.BugCheckerRefactoringTestHelper; +import com.google.errorprone.BugPattern; +import com.google.errorprone.BugPattern.ProvidesFix; import java.io.IOException; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -16,7 +21,8 @@ public class DeprecatedMethodsCheckTest { @Before public void setUp() { this.testHelper = - BugCheckerRefactoringTestHelper.newInstance(new DeprecatedMethodsCheck(), getClass()); + BugCheckerRefactoringTestHelper.newInstance( + new DeprecatedMethodsCheckForTest(), getClass()); } @Test @@ -37,12 +43,11 @@ public class DeprecatedMethodsCheckTest { "}") .addOutputLines( "in/SomeTest.java", - "import static org.robolectric.Shadows.shadowOf;", + "import static xxx.XShadows.shadowOf;", "", "import android.content.Context;", "import org.junit.Test;", "import org.robolectric.RuntimeEnvironment;", - "import org.robolectric.Shadows;", "import xxx.XShadowApplication;", // removable "", "public class SomeTest {", @@ -56,6 +61,49 @@ public class DeprecatedMethodsCheckTest { } @Test + public void replaceShadowApplicationGetLatestStuff() throws IOException { + testHelper + .addInputLines( + "in/SomeTest.java", + "import static xxx.XShadows.shadowOf;", + "", + "import org.junit.Test;", + "import org.robolectric.RuntimeEnvironment;", + "import xxx.XShadowApplication;", + "import xxx.XShadowAlertDialog;", + "import xxx.XShadowDialog;", + "import xxx.XShadowPopupMenu;", + "", + "public class SomeTest {", + " @Test void theTest() {", + " XShadowAlertDialog ad = shadowOf(RuntimeEnvironment.application).getLatestAlertDialog();", + " XShadowDialog d = shadowOf(RuntimeEnvironment.application).getLatestDialog();", + " XShadowPopupMenu pm = shadowOf(RuntimeEnvironment.application).getLatestPopupMenu();", + " }", + "}") + .addOutputLines( + "in/SomeTest.java", + "import static xxx.XShadows.shadowOf;", + "", + "import org.junit.Test;", + "import org.robolectric.RuntimeEnvironment;", // removable + "import xxx.XShadowApplication;", + "import xxx.XShadowAlertDialog;", + "import xxx.XShadowDialog;", + "import xxx.XShadowPopupMenu;", + "", + "public class SomeTest {", + " @Test void theTest() {", + " XShadowAlertDialog ad = shadowOf(XShadowAlertDialog.getLatestAlertDialog());", + " XShadowDialog d = shadowOf(XShadowDialog.getLatestDialog());", + " XShadowPopupMenu pm = shadowOf(XShadowPopupMenu.getLatestPopupMenu());", + " }", + "}") + .doTest(); + } + + @Test + @Ignore("multiple-step refactorings not currently supported") public void inlineShadowVars() throws IOException { testHelper .addInputLines( @@ -71,7 +119,7 @@ public class DeprecatedMethodsCheckTest { "}") .addOutputLines( "in/SomeTest.java", - "import static org.robolectric.Shadows.shadowOf;", + "import static xxx.XShadows.shadowOf;", "", "import android.app.Application;", "import org.junit.Test;", @@ -82,7 +130,7 @@ public class DeprecatedMethodsCheckTest { "public class SomeTest {", " @Test void theTest() {", " Application application = RuntimeEnvironment.application;", - " Shadows.shadowOf(application).runBackgroundTasks();", + " XShadows.shadowOf(application).runBackgroundTasks();", " }", "}") .doTest(); @@ -95,7 +143,7 @@ public class DeprecatedMethodsCheckTest { "in/SomeTest.java", "import android.content.Context;", "import org.junit.Test;", - "import org.robolectric.Shadows;", + "import xxx.XShadows;", "import xxx.XShadowApplication;", "", "public class SomeTest {", @@ -110,13 +158,13 @@ public class DeprecatedMethodsCheckTest { "import android.content.Context;", "import org.junit.Test;", "import org.robolectric.RuntimeEnvironment;", - "import org.robolectric.Shadows;", "import xxx.XShadowApplication;", // removable + "import xxx.XShadows;", "", "public class SomeTest {", " Context application;", " @Test void theTest() {", - " Shadows.shadowOf(RuntimeEnvironment.application).runBackgroundTasks();", + " XShadows.shadowOf(RuntimeEnvironment.application).runBackgroundTasks();", " application = RuntimeEnvironment.application;", " }", "}") @@ -124,6 +172,7 @@ public class DeprecatedMethodsCheckTest { } @Test + @Ignore("multiple-step refactorings not currently supported") public void useFrameworkMethodWhenAppropriateAfterApplicationSubstitution() throws IOException { testHelper .addInputLines( @@ -147,7 +196,7 @@ public class DeprecatedMethodsCheckTest { "import android.content.Context;", "import org.junit.Test;", "import org.robolectric.RuntimeEnvironment;", - "import org.robolectric.Shadows;", + "import xxx.XShadows;", "import xxx.XShadowApplication;", // removable "", "public class SomeTest {", @@ -155,9 +204,26 @@ public class DeprecatedMethodsCheckTest { " @Test void theTest() {", " application = RuntimeEnvironment.application;", " application.getMainLooper();", - " Shadows.shadowOf(application).runBackgroundTasks();", + " XShadows.shadowOf(application).runBackgroundTasks();", " }", "}") .doTest(); } + + @BugPattern( + name = "DeprecatedMethods", + providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION, + summary = "", + severity = WARNING) + private static class DeprecatedMethodsCheckForTest extends DeprecatedMethodsCheck { + @Override + String shadowName(String className) { + return className.replaceAll("org\\.robolectric\\..*Shadow", "xxx.XShadow"); + } + + @Override + String shortShadowName(String className) { + return className.replaceAll("Shadow", "XShadow"); + } + } } diff --git a/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/RobolectricShadowTest.java b/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/RobolectricShadowTest.java index e4b6659b3..a28d21fa1 100644 --- a/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/RobolectricShadowTest.java +++ b/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/RobolectricShadowTest.java @@ -23,24 +23,28 @@ public class RobolectricShadowTest { testHelper .addInputLines( "in/SomeShadow.java", + "import org.robolectric.annotation.HiddenApi;", "import org.robolectric.annotation.Implementation;", "import org.robolectric.annotation.Implements;", "", "@Implements(Object.class)", "public class SomeShadow {", " @Implementation public void publicMethod() {}", + " @Implementation @HiddenApi public void publicHiddenMethod() {}", " @Implementation protected void protectedMethod() {}", " @Implementation void packageMethod() {}", " @Implementation private void privateMethod() {}", "}") .addOutputLines( "in/SomeShadow.java", + "import org.robolectric.annotation.HiddenApi;", "import org.robolectric.annotation.Implementation;", "import org.robolectric.annotation.Implements;", "", "@Implements(Object.class)", "public class SomeShadow {", " @Implementation protected void publicMethod() {}", + " @Implementation @HiddenApi public void publicHiddenMethod() {}", " @Implementation protected void protectedMethod() {}", " @Implementation protected void packageMethod() {}", " @Implementation protected void privateMethod() {}", @@ -49,6 +53,40 @@ public class RobolectricShadowTest { } @Test + public void implMethodsNotProtectedForClassesNotInAndroidSdk() throws IOException { + testHelper + .addInputLines( + "in/SomeShadow.java", + "import org.robolectric.annotation.HiddenApi;", + "import org.robolectric.annotation.Implementation;", + "import org.robolectric.annotation.Implements;", + "", + "@Implements(value = Object.class, isInAndroidSdk = false)", + "public class SomeShadow {", + " @Implementation public void publicMethod() {}", + " @Implementation @HiddenApi public void publicHiddenMethod() {}", + " @Implementation protected void protectedMethod() {}", + " @Implementation void packageMethod() {}", + " @Implementation private void privateMethod() {}", + "}") + .addOutputLines( + "in/SomeShadow.java", + "import org.robolectric.annotation.HiddenApi;", + "import org.robolectric.annotation.Implementation;", + "import org.robolectric.annotation.Implements;", + "", + "@Implements(value = Object.class, isInAndroidSdk = false)", + "public class SomeShadow {", + " @Implementation public void publicMethod() {}", + " @Implementation @HiddenApi public void publicHiddenMethod() {}", + " @Implementation protected void protectedMethod() {}", + " @Implementation void packageMethod() {}", + " @Implementation private void privateMethod() {}", + "}") + .doTest(); + } + + @Test public void implMethodJavadocShouldBeMarkdown() throws Exception { testHelper .addInputLines( diff --git a/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/ShadowUsageCheckTest.java b/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/ShadowUsageCheckTest.java index c62c068a3..977726846 100644 --- a/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/ShadowUsageCheckTest.java +++ b/errorprone/src/test/java/org/robolectric/errorprone/bugpatterns/ShadowUsageCheckTest.java @@ -27,19 +27,19 @@ public class ShadowUsageCheckTest { "in/SomeTest.java", "import android.os.Looper;", "import org.junit.Test;", - "import org.robolectric.shadows.ShadowLooper;", + "import xxx.XShadowLooper;", "", "public class SomeTest {", " @Test void theTest() {", " Looper.getMainLooper();", - " ShadowLooper.getMainLooper();", + " XShadowLooper.getMainLooper();", " }", "}") .addOutputLines( "in/SomeTest.java", "import android.os.Looper;", "import org.junit.Test;", - "import org.robolectric.shadows.ShadowLooper;", // removable + "import xxx.XShadowLooper;", // removable "", "public class SomeTest {", " @Test void theTest() {", @@ -496,7 +496,7 @@ public class ShadowUsageCheckTest { " @Test void theTest() {", " linearLayout = new LinearLayout(RuntimeEnvironment.application);", " linearLayout.getLayoutAnimation().start();", - " this.linearLayout.getLayoutAnimation().start();", + " linearLayout.getLayoutAnimation().start();", " shadowOf(linearLayout).getGravity();", " shadowOf(this.linearLayout).getGravity();", " }", @@ -550,7 +550,7 @@ public class ShadowUsageCheckTest { " linearLayout = new LinearLayout(RuntimeEnvironment.application);", " linearLayout2 = new LinearLayout(RuntimeEnvironment.application);", " linearLayout2.getLayoutAnimation().start();", - " this.linearLayout2.getLayoutAnimation().start();", + " linearLayout2.getLayoutAnimation().start();", " shadowOf(linearLayout2).getGravity();", " shadowOf(this.linearLayout2).getGravity();", " }", @@ -563,35 +563,35 @@ public class ShadowUsageCheckTest { testHelper .addInputLines( "in/SomeTest.java", - "import static org.robolectric.Shadows.shadowOf;", + "import static xxx.XShadows.shadowOf;", "", "import android.os.Looper;", "import org.junit.Before;", "import org.junit.Test;", "import org.robolectric.RuntimeEnvironment;", - "import org.robolectric.shadows.ShadowLooper;", + "import xxx.XShadowLooper;", "", "public class SomeTest {", - " private ShadowLooper shadowLooper;", + " private XShadowLooper XShadowLooper;", "", " @Before void setUp() {", " Looper looper = RuntimeEnvironment.application.getMainLooper();", - " shadowLooper = shadowOf(looper);", + " XShadowLooper = shadowOf(looper);", " }", "", " @Test void theTest() {", - " shadowLooper.runToEndOfTasks();", + " XShadowLooper.runToEndOfTasks();", " }", "}") .addOutputLines( "out/SomeTest.java", - "import static org.robolectric.Shadows.shadowOf;", + "import static xxx.XShadows.shadowOf;", "", "import android.os.Looper;", "import org.junit.Before;", "import org.junit.Test;", "import org.robolectric.RuntimeEnvironment;", - "import org.robolectric.shadows.ShadowLooper;", + "import xxx.XShadowLooper;", "", "public class SomeTest {", " private Looper looper;", @@ -740,28 +740,28 @@ public class ShadowUsageCheckTest { testHelper .addInputLines( "in/SomeTestHelper.java", - "import static org.robolectric.Shadows.shadowOf;", + "import static xxx.XShadows.shadowOf;", "", "import android.os.Looper;", - "import org.robolectric.shadows.ShadowLooper;", + "import xxx.XShadowLooper;", "", "public class SomeTestHelper {", - " private final ShadowLooper theShadowLooper;", + " private final XShadowLooper theShadowLooper;", "", " SomeTestHelper(Looper looper) {", " this.theShadowLooper = shadowOf(looper);", " }", "", " boolean moreTasks() {", - " return theShadowLooper.getScheduler().areAnyRunnable();", + " return theShadowLooper.getSchedule().isEmpty();", " }", "}") .addOutputLines( "in/SomeTestHelper.java", - "import static org.robolectric.Shadows.shadowOf;", + "import static xxx.XShadows.shadowOf;", "", "import android.os.Looper;", - "import org.robolectric.shadows.ShadowLooper;", + "import xxx.XShadowLooper;", "", "public class SomeTestHelper {", " private final Looper looper;", @@ -771,7 +771,7 @@ public class ShadowUsageCheckTest { " }", "", " boolean moreTasks() {", - " return shadowOf(looper).getScheduler().areAnyRunnable();", + " return shadowOf(looper).getSchedule().isEmpty();", " }", "}") .doTest(); @@ -782,36 +782,36 @@ public class ShadowUsageCheckTest { testHelper .addInputLines( "in/SomeTest.java", - "import static org.robolectric.Shadows.shadowOf;", + "import static xxx.XShadows.shadowOf;", "", "import android.content.Context;", "import android.net.ConnectivityManager;", "import android.net.NetworkInfo;", "import org.junit.Test;", "import org.robolectric.RuntimeEnvironment;", - "import org.robolectric.shadows.ShadowConnectivityManager;", - "import org.robolectric.shadows.ShadowNetworkInfo;", + "import xxx.XShadowConnectivityManager;", + "import xxx.XShadowNetworkInfo;", "", "public class SomeTest {", " @Test void theTest() {", - " ShadowConnectivityManager shadowConnectivityManager =", + " XShadowConnectivityManager shadowConnectivityManager =", " shadowOf((ConnectivityManager) RuntimeEnvironment.application.getSystemService(Context.CONNECTIVITY_SERVICE));", - " ShadowNetworkInfo shadowActiveNetworkInfo =", + " XShadowNetworkInfo shadowActiveNetworkInfo =", " shadowOf(shadowConnectivityManager.getActiveNetworkInfo());", " shadowActiveNetworkInfo.setConnectionType(ConnectivityManager.TYPE_MOBILE);", " }", "}") .addOutputLines( "out/SomeTest.java", - "import static org.robolectric.Shadows.shadowOf;", + "import static xxx.XShadows.shadowOf;", "", "import android.content.Context;", "import android.net.ConnectivityManager;", "import android.net.NetworkInfo;", "import org.junit.Test;", "import org.robolectric.RuntimeEnvironment;", - "import org.robolectric.shadows.ShadowConnectivityManager;", - "import org.robolectric.shadows.ShadowNetworkInfo;", + "import xxx.XShadowConnectivityManager;", + "import xxx.XShadowNetworkInfo;", "", "public class SomeTest {", " @Test void theTest() {", @@ -911,13 +911,13 @@ public class ShadowUsageCheckTest { "import android.os.Looper;", "import org.robolectric.annotation.Implementation;", "import org.robolectric.annotation.Implements;", - "import org.robolectric.shadows.ShadowLooper;", + "import xxx.XShadowLooper;", "", "@Implements(Looper.class)", - "public class SomeShadow extends ShadowLooper {", + "public class SomeShadow extends XShadowLooper {", " @Implementation", " public static Looper getMainLooper() {", - " return ShadowLooper.getMainLooper();", + " return XShadowLooper.getMainLooper();", " }", "}") .addOutputLines( @@ -925,13 +925,13 @@ public class ShadowUsageCheckTest { "import android.os.Looper;", "import org.robolectric.annotation.Implementation;", "import org.robolectric.annotation.Implements;", - "import org.robolectric.shadows.ShadowLooper;", + "import xxx.XShadowLooper;", "", "@Implements(Looper.class)", - "public class SomeShadow extends ShadowLooper {", + "public class SomeShadow extends XShadowLooper {", " @Implementation", " public static Looper getMainLooper() {", - " return ShadowLooper.getMainLooper();", + " return XShadowLooper.getMainLooper();", " }", "}") .doTest(); @@ -1269,7 +1269,7 @@ public class ShadowUsageCheckTest { @Test @Ignore public void handleStaticMethodRefs() throws IOException { - // shadowLooper::idle -> looper::idle + // XShadowLooper::idle -> looper::idle } @Test diff --git a/errorprone/src/test/java/xxx/XShadowAlertDialog.java b/errorprone/src/test/java/xxx/XShadowAlertDialog.java new file mode 100644 index 000000000..9713a76ff --- /dev/null +++ b/errorprone/src/test/java/xxx/XShadowAlertDialog.java @@ -0,0 +1,14 @@ +package xxx; + +import android.app.AlertDialog; +import org.robolectric.annotation.Implements; + +/** + * Fake shadow for testing {@link org.robolectric.errorprone.bugpatterns.DeprecatedMethodsCheck}. + */ +@Implements(AlertDialog.class) +public class XShadowAlertDialog { + public static AlertDialog getLatestAlertDialog() { + return null; + } +} diff --git a/errorprone/src/test/java/xxx/XShadowApplication.java b/errorprone/src/test/java/xxx/XShadowApplication.java index 0049e61d4..28728a298 100644 --- a/errorprone/src/test/java/xxx/XShadowApplication.java +++ b/errorprone/src/test/java/xxx/XShadowApplication.java @@ -20,6 +20,18 @@ public class XShadowApplication { return null; } + public XShadowAlertDialog getLatestAlertDialog() { + return null; + } + + public XShadowDialog getLatestDialog() { + return null; + } + + public XShadowPopupMenu getLatestPopupMenu() { + return null; + } + @Implementation public Looper getMainLooper() { return null; diff --git a/errorprone/src/test/java/xxx/XShadowConnectivityManager.java b/errorprone/src/test/java/xxx/XShadowConnectivityManager.java new file mode 100644 index 000000000..c6da432c6 --- /dev/null +++ b/errorprone/src/test/java/xxx/XShadowConnectivityManager.java @@ -0,0 +1,17 @@ +package xxx; + +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +/** + * Fake shadow for testing {@link org.robolectric.errorprone.bugpatterns.DeprecatedMethodsCheck}. + */ +@Implements(ConnectivityManager.class) +public class XShadowConnectivityManager { + @Implementation + public NetworkInfo getActiveNetworkInfo() { + return null; + } +} diff --git a/errorprone/src/test/java/xxx/XShadowDialog.java b/errorprone/src/test/java/xxx/XShadowDialog.java new file mode 100644 index 000000000..c9ffdbfc3 --- /dev/null +++ b/errorprone/src/test/java/xxx/XShadowDialog.java @@ -0,0 +1,14 @@ +package xxx; + +import android.app.Dialog; +import org.robolectric.annotation.Implements; + +/** + * Fake shadow for testing {@link org.robolectric.errorprone.bugpatterns.DeprecatedMethodsCheck}. + */ +@Implements(Dialog.class) +public class XShadowDialog { + public static Dialog getLatestDialog() { + return null; + } +} diff --git a/errorprone/src/test/java/xxx/XShadowLooper.java b/errorprone/src/test/java/xxx/XShadowLooper.java new file mode 100644 index 000000000..619a0831f --- /dev/null +++ b/errorprone/src/test/java/xxx/XShadowLooper.java @@ -0,0 +1,23 @@ +package xxx; + +import android.os.Looper; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +/** + * Fake shadow for testing {@link org.robolectric.errorprone.bugpatterns.DeprecatedMethodsCheck}. + */ +@Implements(Looper.class) +public class XShadowLooper { + @Implementation + public static Looper getMainLooper() { + return null; + } + + public String getSchedule() { + return null; + } + + public void runToEndOfTasks() { + } +} diff --git a/errorprone/src/test/java/xxx/XShadowNetworkInfo.java b/errorprone/src/test/java/xxx/XShadowNetworkInfo.java new file mode 100644 index 000000000..17e15ca31 --- /dev/null +++ b/errorprone/src/test/java/xxx/XShadowNetworkInfo.java @@ -0,0 +1,13 @@ +package xxx; + +import android.net.ConnectivityManager; +import org.robolectric.annotation.Implements; + +/** + * Fake shadow for testing {@link org.robolectric.errorprone.bugpatterns.DeprecatedMethodsCheck}. + */ +@Implements(ConnectivityManager.class) +public class XShadowNetworkInfo { + public void setConnectionType(int connectionType) { + } +} diff --git a/errorprone/src/test/java/xxx/XShadowPopupMenu.java b/errorprone/src/test/java/xxx/XShadowPopupMenu.java new file mode 100644 index 000000000..56764765c --- /dev/null +++ b/errorprone/src/test/java/xxx/XShadowPopupMenu.java @@ -0,0 +1,14 @@ +package xxx; + +import android.widget.PopupMenu; +import org.robolectric.annotation.Implements; + +/** + * Fake shadow for testing {@link org.robolectric.errorprone.bugpatterns.DeprecatedMethodsCheck}. + */ +@Implements(PopupMenu.class) +public class XShadowPopupMenu { + public static PopupMenu getLatestPopupMenu() { + return null; + } +} diff --git a/errorprone/src/test/java/xxx/XShadows.java b/errorprone/src/test/java/xxx/XShadows.java index dbccd65ed..45e1546cd 100644 --- a/errorprone/src/test/java/xxx/XShadows.java +++ b/errorprone/src/test/java/xxx/XShadows.java @@ -1,24 +1,42 @@ package xxx; +import android.app.AlertDialog; import android.app.Application; +import android.app.Dialog; import android.graphics.drawable.Drawable; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Looper; import android.view.ViewGroup; import android.widget.LinearLayout; +import android.widget.PopupMenu; /** * Fake {@link org.robolectric.internal.ShadowProvider} for testing * {@link org.robolectric.errorprone.bugpatterns.ShadowUsageCheck}. */ public class XShadows implements org.robolectric.internal.ShadowProvider { + public static XShadowAlertDialog shadowOf(AlertDialog actual) { + return null; + } + public static XShadowApplication shadowOf(Application actual) { return null; } + public static XShadowConnectivityManager shadowOf(ConnectivityManager actual) { + return null; + } + + public static XShadowDialog shadowOf(Dialog actual) { + return null; + } + public static XShadowDrawable shadowOf(Drawable actual) { return null; } - public static XShadowViewGroup shadowOf(ViewGroup actual) { + public static XShadowLooper shadowOf(Looper actual) { return null; } @@ -26,6 +44,18 @@ public class XShadows implements org.robolectric.internal.ShadowProvider { return null; } + public static XShadowNetworkInfo shadowOf(NetworkInfo actual) { + return null; + } + + public static XShadowPopupMenu shadowOf(PopupMenu actual) { + return null; + } + + public static XShadowViewGroup shadowOf(ViewGroup actual) { + return null; + } + @Override public void reset() {} diff --git a/gradle.properties b/gradle.properties index 8204ee9bf..1f181dac2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,8 @@ -thisVersion=4.0-alpha-4-SNAPSHOT +thisVersion=4.1-SNAPSHOT apiCompatVersion=3.8 + +errorproneVersion=2.3.1 +errorproneJavacVersion=9+181-r4173-1 + +android.enableUnitTestBinaryResources=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar Binary files differindex 7a3265ee9..29953ea14 100644 --- a/gradle/wrapper/gradle-wrapper.jar +++ b/gradle/wrapper/gradle-wrapper.jar diff --git a/integration_tests/androidx_test/build.gradle b/integration_tests/androidx_test/build.gradle index 4c9fb7687..da275644c 100644 --- a/integration_tests/androidx_test/build.gradle +++ b/integration_tests/androidx_test/build.gradle @@ -1,11 +1,17 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - apply plugin: 'com.android.library' android { - compileSdkVersion 27 + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 16 + targetSdkVersion 28 + } + + compileOptions { + sourceCompatibility = '1.8' + targetCompatibility = '1.8' + } android { testOptions { @@ -20,13 +26,19 @@ android { dependencies { implementation project(":robolectric") implementation "junit:junit:4.12" - implementation("androidx.test:runner:1.1.0-alpha4") + implementation("androidx.test:runner:1.1.0") + implementation("androidx.appcompat:appcompat:1.0.0") // Testing dependencies - testImplementation("androidx.test:runner:1.1.0-alpha4") - testImplementation("androidx.test:rules:1.1.0-alpha4") - testImplementation("androidx.test.espresso:espresso-intents:3.1.0-alpha4") - testImplementation("androidx.test.espresso:espresso-core:3.1.0-alpha4") - testImplementation("androidx.test.ext:truth:1.0.0-alpha4") - testImplementation("com.google.truth:truth:0.36") + testImplementation("androidx.test:runner:1.1.0") + testImplementation("androidx.test:rules:1.1.0") + testImplementation("androidx.test.espresso:espresso-intents:3.1.0") + testImplementation("androidx.test.espresso:espresso-core:3.1.0") + testImplementation("androidx.test.ext:truth:1.0.0") + testImplementation("androidx.test:core:1.0.0") + // TODO: this should be a transitive dependency of core... + testImplementation("androidx.lifecycle:lifecycle-common:2.0.0") + testImplementation("androidx.test.ext:junit:1.0.0") + testImplementation("com.google.truth:truth:0.42") + } diff --git a/integration_tests/androidx_test/src/test/java/org/robolectric/integration_tests/axt/ActivityScenarioTest.java b/integration_tests/androidx_test/src/test/java/org/robolectric/integration_tests/axt/ActivityScenarioTest.java new file mode 100644 index 000000000..859fe774f --- /dev/null +++ b/integration_tests/androidx_test/src/test/java/org/robolectric/integration_tests/axt/ActivityScenarioTest.java @@ -0,0 +1,120 @@ +package org.robolectric.integration_tests.axt; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Activity; +import androidx.lifecycle.Lifecycle.State; +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.R; +import androidx.test.core.app.ActivityScenario; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import java.util.ArrayList; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Integration tests for {@link ActivityScenario} that verify it behaves consistently on device and + * Robolectric. + */ +@RunWith(AndroidJUnit4.class) +public class ActivityScenarioTest { + + private static final List<String> callbacks = new ArrayList<>(); + + public static class TranscriptActivity extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + callbacks.add("onCreate"); + } + + @Override + public void onStart() { + super.onStart(); + callbacks.add("onStart"); + } + + @Override + public void onResume() { + super.onResume(); + callbacks.add("onResume"); + } + + @Override + public void onPause() { + super.onPause(); + callbacks.add("onPause"); + } + + @Override + public void onStop() { + super.onStop(); + callbacks.add("onStop"); + } + + @Override + public void onRestart() { + super.onRestart(); + callbacks.add("onRestart"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + callbacks.add("onDestroy"); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + callbacks.add("onWindowFocusChanged " + hasFocus); + } + } + + public static class LifecycleOwnerActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle bundle) { + super.onCreate(bundle); + setTheme(R.style.Theme_AppCompat); + } + } + + @Before + public void setUp() { + callbacks.clear(); + } + + @Test + public void launch_callbackSequence() { + ActivityScenario<TranscriptActivity> activityScenario = + ActivityScenario.launch(TranscriptActivity.class); + assertThat(activityScenario).isNotNull(); + assertThat(callbacks) + .containsExactly("onCreate", "onStart", "onResume", "onWindowFocusChanged true"); + } + + @Test + public void launch_lifecycleOwnerActivity() { + ActivityScenario<LifecycleOwnerActivity> activityScenario = + ActivityScenario.launch(LifecycleOwnerActivity.class); + assertThat(activityScenario).isNotNull(); + activityScenario.onActivity( + activity -> { + assertThat(activity.getLifecycle().getCurrentState()).isEqualTo(State.RESUMED); + }); + activityScenario.moveToState(State.STARTED); + activityScenario.onActivity( + activity -> { + assertThat(activity.getLifecycle().getCurrentState()).isEqualTo(State.STARTED); + }); + activityScenario.moveToState(State.CREATED); + activityScenario.onActivity( + activity -> { + assertThat(activity.getLifecycle().getCurrentState()).isEqualTo(State.CREATED); + }); + } +} diff --git a/integration_tests/ctesque/AndroidManifest.xml b/integration_tests/ctesque/AndroidManifest.xml index 848850f24..f6cfadcd5 100644 --- a/integration_tests/ctesque/AndroidManifest.xml +++ b/integration_tests/ctesque/AndroidManifest.xml @@ -4,7 +4,9 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.robolectric.integration_tests.ctesque"> - <uses-sdk android:targetSdkVersion="27"/> + <uses-sdk + android:minSdkVersion="16" + android:targetSdkVersion="27" /> <!-- For SettingsTest --> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> diff --git a/integration_tests/ctesque/build.gradle b/integration_tests/ctesque/build.gradle index c7662aaf0..5f8fd96ba 100644 --- a/integration_tests/ctesque/build.gradle +++ b/integration_tests/ctesque/build.gradle @@ -1,11 +1,11 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - apply plugin: 'com.android.library' android { - compileSdkVersion 27 + compileSdkVersion 28 + defaultConfig { + minSdkVersion 16 + targetSdkVersion 28 + } lintOptions { abortOnError false @@ -30,21 +30,20 @@ dependencies { implementation project(path: ':testapp', configuration: 'default') implementation project(path: ':shadowapi', configuration: 'default') - // Testing dependencies testImplementation project(":robolectric") testImplementation "junit:junit:4.12" - testImplementation("androidx.test:monitor:1.1.0-alpha4") - testImplementation("androidx.test:runner:1.1.0-alpha4") - testImplementation("androidx.test:rules:1.1.0-alpha4") - testImplementation("androidx.test.ext:truth:1.0.0-alpha4") - testImplementation("androidx.test:core:1.0.0-alpha4") - testImplementation "com.google.truth:truth:0.36" - testImplementation "com.google.guava:guava:20.0" + testImplementation("androidx.test:monitor:1.1.0") + testImplementation("androidx.test:runner:1.1.0") + testImplementation("androidx.test:rules:1.1.0") + testImplementation("androidx.test.ext:truth:1.0.0") + testImplementation("androidx.test:core:1.0.0") + testImplementation("com.google.truth:truth:0.42") + testImplementation("com.google.guava:guava:20.0") // Testing dependencies - androidTestImplementation("androidx.test:monitor:1.1.0-alpha4") - androidTestImplementation("androidx.test:runner:1.1.0-alpha4") - androidTestImplementation("androidx.test:rules:1.1.0-alpha4") - androidTestImplementation "com.google.truth:truth:0.36" - androidTestImplementation "com.google.guava:guava:20.0" + androidTestImplementation("androidx.test:monitor:1.1.0") + androidTestImplementation("androidx.test:runner:1.1.0") + androidTestImplementation("androidx.test:rules:1.1.0") + androidTestImplementation("com.google.truth:truth:0.42") + androidTestImplementation("com.google.guava:guava:20.0") } diff --git a/integration_tests/ctesque/src/test/java/android/content/pm/PackageManagerTest.java b/integration_tests/ctesque/src/test/java/android/content/pm/PackageManagerTest.java new file mode 100644 index 000000000..1ff59571c --- /dev/null +++ b/integration_tests/ctesque/src/test/java/android/content/pm/PackageManagerTest.java @@ -0,0 +1,49 @@ +package android.content.pm; + +import static android.os.Build.VERSION_CODES.O; +import static com.google.common.truth.Truth.assertThat; + +import android.content.ComponentName; +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SdkSuppress; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.internal.DoNotInstrument; + +/** + * Compatibility test for {@link PackageManager} + */ +@DoNotInstrument +@RunWith(AndroidJUnit4.class) +public final class PackageManagerTest { + + private Context context; + + @Before + public void setup() throws Exception { + context = InstrumentationRegistry.getTargetContext(); + } + + @Test + @Config(minSdk = O) + @SdkSuppress(minSdkVersion = O) + public void isInstantApp_shouldNotBlowup() { + assertThat(context.getPackageManager().isInstantApp()).isFalse(); + } + + @Test + public void whenComponentDisabled_itIsReportedAsSuch() throws Exception { + PackageManager pm = context.getPackageManager(); + ComponentName disabledActivityName = + new ComponentName(context, "org.robolectric.DisabledTestActivity"); + + ActivityInfo info = + pm.getActivityInfo(disabledActivityName, PackageManager.GET_DISABLED_COMPONENTS); + assertThat(info).isNotNull(); + assertThat(info.enabled).isFalse(); + } +} diff --git a/integration_tests/ctesque/src/test/java/android/content/res/AssetManagerTest.java b/integration_tests/ctesque/src/test/java/android/content/res/AssetManagerTest.java index b65dcb92e..9ae361e1a 100644 --- a/integration_tests/ctesque/src/test/java/android/content/res/AssetManagerTest.java +++ b/integration_tests/ctesque/src/test/java/android/content/res/AssetManagerTest.java @@ -13,6 +13,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -64,7 +65,7 @@ public class AssetManagerTest { assertThat(contents).isEqualTo("assetsHome!"); } - @Test + @Test @Ignore("TODO(xian): re-enable; see https://github.com/robolectric/robolectric/issues/4091") public void openFd_shouldProvideFileDescriptorForAsset() throws Exception { AssetFileDescriptor assetFileDescriptor = assetManager.openFd("assetsHome.txt"); assertThat(CharStreams.toString(new InputStreamReader(assetFileDescriptor.createInputStream(), UTF_8))) @@ -88,8 +89,8 @@ public class AssetManagerTest { new AssetFileDescriptor(parcelFileDescriptor, 0, "hi".getBytes().length); assertThat( - CharStreams.toString( - new InputStreamReader(assetFileDescriptor.createInputStream(), UTF_8))) + CharStreams.toString( + new InputStreamReader(assetFileDescriptor.createInputStream(), UTF_8))) .isEqualTo("hi"); assertThat(assetFileDescriptor.getLength()).isEqualTo(2); assetFileDescriptor.close(); diff --git a/integration_tests/ctesque/src/test/java/android/content/res/ResourcesTest.java b/integration_tests/ctesque/src/test/java/android/content/res/ResourcesTest.java index d0fbafe7f..67a837418 100644 --- a/integration_tests/ctesque/src/test/java/android/content/res/ResourcesTest.java +++ b/integration_tests/ctesque/src/test/java/android/content/res/ResourcesTest.java @@ -3,6 +3,7 @@ package android.content.res; import static android.os.Build.VERSION_CODES.KITKAT; import static android.os.Build.VERSION_CODES.KITKAT_WATCH; import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.O; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static android.util.TypedValue.COMPLEX_UNIT_IN; import static android.util.TypedValue.COMPLEX_UNIT_MM; @@ -27,6 +28,7 @@ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; +import android.graphics.Typeface; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; @@ -42,6 +44,7 @@ import androidx.test.runner.AndroidJUnit4; import com.google.common.collect.Range; import java.io.File; import java.io.InputStream; +import java.lang.reflect.Method; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -284,7 +287,7 @@ public class ResourcesTest { } @Test - public void getDimensionPixelOffset() throws Exception { + public void getDimensionPixelOffset() { assertThat(resources.getDimensionPixelOffset(R.dimen.test_dip_dimen)) .isEqualTo(convertDimension(COMPLEX_UNIT_DIP, 20)); assertThat(resources.getDimensionPixelOffset(R.dimen.test_dp_dimen)) @@ -306,31 +309,40 @@ public class ResourcesTest { } @Test - public void getDimension_withReference() throws Exception { + public void getDimension_withReference() { assertThat(resources.getBoolean(R.bool.reference_to_true)).isEqualTo(true); } @Test(expected = Resources.NotFoundException.class) - public void getStringArray_shouldThrowExceptionIfNotFound() throws Exception { + public void getStringArray_shouldThrowExceptionIfNotFound() { resources.getStringArray(-1); } @Test(expected = Resources.NotFoundException.class) - public void getIntegerArray_shouldThrowExceptionIfNotFound() throws Exception { + public void getIntegerArray_shouldThrowExceptionIfNotFound() { resources.getIntArray(-1); } @Test - @Ignore("todo: incorrect behavior on robolectric vs framework?") - public void getQuantityString() throws Exception { - assertThat(resources.getQuantityString(R.plurals.beer, 0)).isEqualTo("Howdy"); - assertThat(resources.getQuantityString(R.plurals.beer, 1)).isEqualTo("One beer"); - assertThat(resources.getQuantityString(R.plurals.beer, 2)).isEqualTo("Two beers"); - assertThat(resources.getQuantityString(R.plurals.beer, 3)).isEqualTo("%d beers, yay!"); + public void getQuantityString() { + assertThat(resources.getQuantityString(R.plurals.beer, 1)).isEqualTo("a beer"); + assertThat(resources.getQuantityString(R.plurals.beer, 2)).isEqualTo("some beers"); + assertThat(resources.getQuantityString(R.plurals.beer, 3)).isEqualTo("some beers"); } @Test - public void getFraction() throws Exception { + public void getQuantityText() { + // Feature not supported in legacy (raw) resource mode. + if (isRobolectricLegacyMode()) { + return; + } + assertThat(resources.getQuantityText(R.plurals.beer, 1)).isEqualTo("a beer"); + assertThat(resources.getQuantityText(R.plurals.beer, 2)).isEqualTo("some beers"); + assertThat(resources.getQuantityText(R.plurals.beer, 3)).isEqualTo("some beers"); + } + + @Test + public void getFraction() { final int myself = 300; final int myParent = 600; assertThat(resources.getFraction(R.fraction.half, myself, myParent)).isEqualTo(150f); @@ -361,7 +373,7 @@ public class ResourcesTest { } @Test(expected = Resources.NotFoundException.class) - public void testGetDrawableNullRClass() throws Exception { + public void testGetDrawableNullRClass() { assertThat(resources.getDrawable(-12345)).isInstanceOf(BitmapDrawable.class); } @@ -1037,6 +1049,18 @@ public class ResourcesTest { .isEqualTo("TextAppearance.Small"); } + @Test + @SdkSuppress(minSdkVersion = O) + @Config(minSdk = O) + public void getFont() { + // Feature not supported in legacy (raw) resource mode. + if (isRobolectricLegacyMode()) { + return; + } + Typeface typeface = resources.getFont(R.font.vt323_regular); + assertThat(typeface).isNotNull(); + } + /////////////////// private static String findRootTag(XmlResourceParser parser) throws Exception { @@ -1052,4 +1076,16 @@ public class ResourcesTest { super(res.getAssets(), res.getDisplayMetrics(), res.getConfiguration()); } } + + private static boolean isRobolectricLegacyMode() { + try { + Class runtimeEnvironmentClass = Class.forName("org.robolectric.RuntimeEnvironment"); + Method useLegacyResourcesMethod = + runtimeEnvironmentClass.getDeclaredMethod("useLegacyResources"); + boolean result = (Boolean) useLegacyResourcesMethod.invoke(null); + return result; + } catch (Exception e) { + return false; + } + } } diff --git a/integration_tests/ctesque/src/test/java/android/graphics/BitmapTest.java b/integration_tests/ctesque/src/test/java/android/graphics/BitmapTest.java new file mode 100644 index 000000000..4c88615cb --- /dev/null +++ b/integration_tests/ctesque/src/test/java/android/graphics/BitmapTest.java @@ -0,0 +1,46 @@ +package android.graphics; + +import static android.os.Build.VERSION_CODES.P; +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.filters.SdkSuppress; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.internal.DoNotInstrument; + +/** Compatibility test for {@link Bitmap} */ +@DoNotInstrument +@RunWith(AndroidJUnit4.class) +public class BitmapTest { + + @Config(minSdk = P) + @SdkSuppress(minSdkVersion = P) + @Test public void createBitmap() { + + Picture picture = new Picture(); + Canvas canvas = picture.beginRecording(200, 100); + + Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); + + p.setColor(0x88FF0000); + canvas.drawCircle(50, 50, 40, p); + + p.setColor(Color.GREEN); + p.setTextSize(30); + canvas.drawText("Pictures", 60, 60, p); + picture.endRecording(); + + Bitmap bitmap = Bitmap.createBitmap(picture); + assertThat(bitmap.isMutable()).isFalse(); + } + + @Test + public void testEraseColor() { + Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + bitmap.eraseColor(0xffff0000); + assertThat(bitmap.getPixel(10, 10)).isEqualTo(0xffff0000); + assertThat(bitmap.getPixel(50, 50)).isEqualTo(0xffff0000); + } +} diff --git a/integration_tests/ctesque/src/test/java/android/graphics/MatrixTest.java b/integration_tests/ctesque/src/test/java/android/graphics/MatrixTest.java new file mode 100644 index 000000000..d4ec68266 --- /dev/null +++ b/integration_tests/ctesque/src/test/java/android/graphics/MatrixTest.java @@ -0,0 +1,125 @@ +package android.graphics; + +import static com.google.common.truth.Truth.assertThat; + +import android.graphics.Matrix.ScaleToFit; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.internal.DoNotInstrument; + +/** Compatibility test for {@link Matrix} */ +@DoNotInstrument +@RunWith(AndroidJUnit4.class) +public final class MatrixTest { + + @Test + public void mapRadius() throws Exception { + Matrix matrix = new Matrix(); + + assertThat(matrix.mapRadius(100f)).isEqualTo(100f); + assertThat(matrix.mapRadius(Float.MAX_VALUE)).isEqualTo(Float.POSITIVE_INFINITY); + assertThat(matrix.mapRadius(Float.MIN_VALUE)).isEqualTo(0f); + + matrix.postScale(2.0f, 2.0f); + assertThat(matrix.mapRadius(1.0f)).isWithin(0.01f).of(2.0f); + } + + @Test + public void mapPoints() { + float[] value = new float[9]; + value[0] = 100f; + new Matrix().mapPoints(value); + assertThat(value[0]).isEqualTo(100f); + } + + @Test(expected = Exception.class) + public void mapPointsNull() { + new Matrix().mapPoints(null); + } + + @Test + public void mapPoints2() { + float[] dst = new float[9]; + dst[0] = 100f; + float[] src = new float[9]; + src[0] = 200f; + new Matrix().mapPoints(dst, src); + assertThat(dst[0]).isEqualTo(200f); + } + + @Test(expected = Exception.class) + public void mapPointsArraysMismatch() { + new Matrix().mapPoints(new float[8], new float[9]); + } + + @Test + public void mapPointsWithIndices() { + float[] dst = new float[9]; + dst[0] = 100f; + float[] src = new float[9]; + src[0] = 200f; + new Matrix().mapPoints(dst, 0, src, 0, 9 >> 1); + assertThat(dst[0]).isEqualTo(200f); + } + + @Test(expected = Exception.class) + public void mapPointsWithIndicesNull() { + new Matrix().mapPoints(null, 0, new float[9], 0, 1); + } + + @Test + public void setRectToRect() { + RectF r1 = new RectF(); + r1.set(1f, 2f, 3f, 3f); + RectF r2 = new RectF(); + r1.set(10f, 20f, 30f, 30f); + Matrix matrix = new Matrix(); + float[] result = new float[9]; + + assertThat(matrix.setRectToRect(r1, r2, ScaleToFit.CENTER)).isTrue(); + matrix.getValues(result); + assertThat(result) + .isEqualTo(new float[] {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}); + + matrix.setRectToRect(r1, r2, ScaleToFit.END); + matrix.getValues(result); + assertThat(result) + .isEqualTo(new float[] {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}); + + matrix.setRectToRect(r1, r2, ScaleToFit.FILL); + matrix.getValues(result); + assertThat(result) + .isEqualTo(new float[] {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}); + + matrix.setRectToRect(r1, r2, ScaleToFit.START); + matrix.getValues(result); + assertThat(result) + .isEqualTo(new float[] {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}); + + assertThat(matrix.setRectToRect(r2, r1, ScaleToFit.CENTER)).isFalse(); + matrix.getValues(result); + assertThat(result) + .isEqualTo(new float[] {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}); + + assertThat(matrix.setRectToRect(r2, r1, ScaleToFit.FILL)).isFalse(); + matrix.getValues(result); + assertThat(result) + .isEqualTo(new float[] {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}); + + assertThat(matrix.setRectToRect(r2, r1, ScaleToFit.START)).isFalse(); + matrix.getValues(result); + assertThat(result) + .isEqualTo(new float[] {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}); + + assertThat(matrix.setRectToRect(r2, r1, ScaleToFit.END)).isFalse(); + matrix.getValues(result); + assertThat(result) + .isEqualTo(new float[] {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}); + } + + @Test(expected = Exception.class) + public void testSetRectToRectNull() { + new Matrix().setRectToRect(null, null, ScaleToFit.CENTER); + } +} diff --git a/integration_tests/ctesque/src/test/java/android/graphics/PathTest.java b/integration_tests/ctesque/src/test/java/android/graphics/PathTest.java new file mode 100644 index 000000000..a362df409 --- /dev/null +++ b/integration_tests/ctesque/src/test/java/android/graphics/PathTest.java @@ -0,0 +1,117 @@ +package android.graphics; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.internal.DoNotInstrument; + +/** Compatibility test for {@link Path} */ +@DoNotInstrument +@RunWith(AndroidJUnit4.class) +public class PathTest { + + // Test constants + private static final float LEFT = 10.0f; + private static final float RIGHT = 50.0f; + private static final float TOP = 10.0f; + private static final float BOTTOM = 50.0f; + private static final float XCOORD = 40.0f; + private static final float YCOORD = 40.0f; + + @Test + public void moveTo() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + + path.moveTo(0, 0); + assertThat(path.isEmpty()).isFalse(); + } + + @Test + public void lineTo() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + path.lineTo(XCOORD, YCOORD); + assertThat(path.isEmpty()).isFalse(); + } + + @Test + public void quadTo() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + path.quadTo(20.0f, 20.0f, 40.0f, 40.0f); + assertThat(path.isEmpty()).isFalse(); + } + + @Test + public void addRect1() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + RectF rect = new RectF(LEFT, TOP, RIGHT, BOTTOM); + path.addRect(rect, Path.Direction.CW); + assertThat(path.isEmpty()).isFalse(); + } + + @Test + public void addRect2() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + path.addRect(LEFT, TOP, RIGHT, BOTTOM, Path.Direction.CW); + assertThat(path.isEmpty()).isFalse(); + } + + @Test + public void getFillType() { + Path path = new Path(); + path.setFillType(Path.FillType.EVEN_ODD); + assertThat(path.getFillType()).isEqualTo(Path.FillType.EVEN_ODD); + } + + @Test + public void transform() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + + Path dst = new Path(); + path.addRect(new RectF(LEFT, TOP, RIGHT, BOTTOM), Path.Direction.CW); + path.transform(new Matrix(), dst); + + assertThat(dst.isEmpty()).isFalse(); + } + + @Test + public void testAddCircle() { + // new the Path instance + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + path.addCircle(XCOORD, YCOORD, 10.0f, Path.Direction.CW); + assertThat(path.isEmpty()).isFalse(); + } + + @Test + public void arcTo1() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM); + path.arcTo(oval, 0.0f, 30.0f, true); + assertThat(path.isEmpty()).isFalse(); + } + + @Test + public void arcTo2() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + RectF oval = new RectF(LEFT, TOP, RIGHT, BOTTOM); + path.arcTo(oval, 0.0f, 30.0f); + assertThat(path.isEmpty()).isFalse(); + } + + @Test + public void close() { + Path path = new Path(); + assertThat(path.isEmpty()).isTrue(); + path.close(); + } +} diff --git a/integration_tests/ctesque/src/test/java/android/view/MotionEventTest.java b/integration_tests/ctesque/src/test/java/android/view/MotionEventTest.java index ca4f62ed8..dcd712c03 100644 --- a/integration_tests/ctesque/src/test/java/android/view/MotionEventTest.java +++ b/integration_tests/ctesque/src/test/java/android/view/MotionEventTest.java @@ -1,7 +1,5 @@ package android.view; -import static androidx.test.core.view.PointerCoordsBuilder.buildPointerCoords; -import static androidx.test.core.view.PointerPropertiesBuilder.buildPointerProperties; import static androidx.test.ext.truth.view.MotionEventSubject.assertThat; import static androidx.test.ext.truth.view.PointerCoordsSubject.assertThat; import static androidx.test.ext.truth.view.PointerPropertiesSubject.assertThat; @@ -16,6 +14,8 @@ import android.os.Parcelable; import android.os.SystemClock; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; +import androidx.test.core.view.PointerCoordsBuilder; +import androidx.test.core.view.PointerPropertiesBuilder; import androidx.test.runner.AndroidJUnit4; import com.google.common.truth.FailureMetadata; import com.google.common.truth.Subject; @@ -168,14 +168,14 @@ public class MotionEventTest { @Test public void testObtainFromPropertyArrays() { PointerCoords coords0 = - buildPointerCoords() + PointerCoordsBuilder.newBuilder() .setCoords(X_3F, Y_4F) .setPressure(PRESSURE_1F) .setSize(SIZE_1F) .setTool(1.2f, 1.4f) .build(); PointerCoords coords1 = - buildPointerCoords() + PointerCoordsBuilder.newBuilder() .setCoords(X_3F + 1.0f, Y_4F - 2.0f) .setPressure(PRESSURE_1F + 0.2f) .setSize(SIZE_1F + 0.5f) @@ -183,9 +183,15 @@ public class MotionEventTest { .build(); PointerProperties properties0 = - buildPointerProperties().setId(0).setToolType(MotionEvent.TOOL_TYPE_FINGER).build(); + PointerPropertiesBuilder.newBuilder() + .setId(0) + .setToolType(MotionEvent.TOOL_TYPE_FINGER) + .build(); PointerProperties properties1 = - buildPointerProperties().setId(1).setToolType(MotionEvent.TOOL_TYPE_FINGER).build(); + PointerPropertiesBuilder.newBuilder() + .setId(1) + .setToolType(MotionEvent.TOOL_TYPE_FINGER) + .build(); motionEventDynamic = MotionEvent.obtain( @@ -389,14 +395,14 @@ public class MotionEventTest { @Test public void testGetCurrentDataWithTwoPointers() { PointerCoords coords0 = - buildPointerCoords() + PointerCoordsBuilder.newBuilder() .setCoords(10.0f, 20.0f) .setPressure(1.2f) .setSize(2.0f) .setTool(1.2f, 1.4f) .build(); PointerCoords coords1 = - buildPointerCoords() + PointerCoordsBuilder.newBuilder() .setCoords(30.0f, 40.0f) .setPressure(1.4f) .setSize(3.0f) @@ -404,9 +410,15 @@ public class MotionEventTest { .build(); PointerProperties properties0 = - buildPointerProperties().setId(0).setToolType(MotionEvent.TOOL_TYPE_FINGER).build(); + PointerPropertiesBuilder.newBuilder() + .setId(0) + .setToolType(MotionEvent.TOOL_TYPE_FINGER) + .build(); PointerProperties properties1 = - buildPointerProperties().setId(1).setToolType(MotionEvent.TOOL_TYPE_FINGER).build(); + PointerPropertiesBuilder.newBuilder() + .setId(1) + .setToolType(MotionEvent.TOOL_TYPE_FINGER) + .build(); motionEventDynamic = MotionEvent.obtain( @@ -445,7 +457,7 @@ public class MotionEventTest { public void testGetHistoricalDataWithTwoPointers() { // PHASE 1 - construct the initial data for the event PointerCoords coordsInitial0 = - buildPointerCoords() + PointerCoordsBuilder.newBuilder() .setCoords(10.0f, 20.0f) .setPressure(1.2f) .setSize(2.0f) @@ -454,7 +466,7 @@ public class MotionEventTest { .setOrientation(2.0f) .build(); PointerCoords coordsInitial1 = - buildPointerCoords() + PointerCoordsBuilder.newBuilder() .setCoords(30.0f, 40.0f) .setPressure(1.4f) .setSize(3.0f) @@ -464,9 +476,15 @@ public class MotionEventTest { .build(); PointerProperties properties0 = - buildPointerProperties().setId(0).setToolType(MotionEvent.TOOL_TYPE_FINGER).build(); + PointerPropertiesBuilder.newBuilder() + .setId(0) + .setToolType(MotionEvent.TOOL_TYPE_FINGER) + .build(); PointerProperties properties1 = - buildPointerProperties().setId(1).setToolType(MotionEvent.TOOL_TYPE_FINGER).build(); + PointerPropertiesBuilder.newBuilder() + .setId(1) + .setToolType(MotionEvent.TOOL_TYPE_FINGER) + .build(); motionEventDynamic = MotionEvent.obtain( @@ -501,7 +519,7 @@ public class MotionEventTest { // PHASE 2 - add a new batch of data to our event PointerCoords coordsNext0 = - buildPointerCoords() + PointerCoordsBuilder.newBuilder() .setCoords(15.0f, 25.0f) .setPressure(1.6f) .setSize(2.2f) @@ -510,7 +528,7 @@ public class MotionEventTest { .setOrientation(2.2f) .build(); PointerCoords coordsNext1 = - buildPointerCoords() + PointerCoordsBuilder.newBuilder() .setCoords(35.0f, 45.0f) .setPressure(1.8f) .setSize(3.2f) diff --git a/integration_tests/dependency-on-stubs/build.gradle b/integration_tests/dependency-on-stubs/build.gradle index dd69b4ca7..8bce7d21e 100644 --- a/integration_tests/dependency-on-stubs/build.gradle +++ b/integration_tests/dependency-on-stubs/build.gradle @@ -1,17 +1,12 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - apply plugin: RoboJavaModulePlugin // test with a project that depends on the stubs jar, not org.robolectric:android-all dependencies { - compile project(":robolectric") - compile "junit:junit:4.12" - testCompile "com.google.android:android-stubs:28" + api project(":robolectric") + api "junit:junit:4.12" + testImplementation "com.google.android:android-stubs:28" - // Testing dependencies - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" } diff --git a/integration_tests/libphonenumber/build.gradle b/integration_tests/libphonenumber/build.gradle index b26c1981a..b5e29ff34 100644 --- a/integration_tests/libphonenumber/build.gradle +++ b/integration_tests/libphonenumber/build.gradle @@ -1,16 +1,11 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - apply plugin: RoboJavaModulePlugin dependencies { - compile project(":robolectric") - compile "junit:junit:4.12" + api project(":robolectric") + api "junit:junit:4.12" compileOnly AndroidSdk.MAX_SDK.coordinates - // Testing dependencies testRuntime AndroidSdk.MAX_SDK.coordinates - testImplementation "com.google.truth:truth:0.39" - testCompile 'com.googlecode.libphonenumber:libphonenumber:8.0.0' + testImplementation "com.google.truth:truth:0.42" + testImplementation 'com.googlecode.libphonenumber:libphonenumber:8.0.0' }
\ No newline at end of file diff --git a/integration_tests/mockito-experimental/build.gradle b/integration_tests/mockito-experimental/build.gradle index 4ff913436..0346926d9 100644 --- a/integration_tests/mockito-experimental/build.gradle +++ b/integration_tests/mockito-experimental/build.gradle @@ -1,16 +1,11 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - apply plugin: RoboJavaModulePlugin dependencies { - compile project(":robolectric") + api project(":robolectric") compileOnly AndroidSdk.MAX_SDK.coordinates - // Testing dependencies testRuntime AndroidSdk.MAX_SDK.coordinates - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.36" - testCompile "org.mockito:mockito-core:2.5.4" + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" }
\ No newline at end of file diff --git a/integration_tests/mockito/build.gradle b/integration_tests/mockito/build.gradle index 2808ec920..0346926d9 100644 --- a/integration_tests/mockito/build.gradle +++ b/integration_tests/mockito/build.gradle @@ -1,16 +1,11 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - apply plugin: RoboJavaModulePlugin dependencies { - compile project(":robolectric") + api project(":robolectric") compileOnly AndroidSdk.MAX_SDK.coordinates - // Testing dependencies testRuntime AndroidSdk.MAX_SDK.coordinates - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" }
\ No newline at end of file diff --git a/integration_tests/multidex/src/test/AndroidManifest.xml b/integration_tests/multidex/src/test/AndroidManifest.xml new file mode 100644 index 000000000..c9bd6ab42 --- /dev/null +++ b/integration_tests/multidex/src/test/AndroidManifest.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + package="org.robolectric.integration_tests.multidex"> + + <uses-sdk + android:minSdkVersion="16" + android:targetSdkVersion="27"/> + + <application /> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="org.robolectric.integration_tests.multidex"/> + +</manifest> diff --git a/integration_tests/multidex/src/test/java/org/robolectric/integration_tests/multidex/MultiDexTest.java b/integration_tests/multidex/src/test/java/org/robolectric/integration_tests/multidex/MultiDexTest.java new file mode 100644 index 000000000..bc441a82f --- /dev/null +++ b/integration_tests/multidex/src/test/java/org/robolectric/integration_tests/multidex/MultiDexTest.java @@ -0,0 +1,17 @@ +package org.robolectric.integration_tests.multidex; + +import android.support.multidex.MultiDex; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Integration tests for MultiDex Robolectric. */ +@RunWith(AndroidJUnit4.class) +public class MultiDexTest { + + @Test + public void testIntendedFailEmpty() { + MultiDex.install(ApplicationProvider.getApplicationContext()); + } +} diff --git a/integration_tests/multidex/src/test/java/org/robolectric/integration_tests/multidex/robolectric.properties b/integration_tests/multidex/src/test/java/org/robolectric/integration_tests/multidex/robolectric.properties new file mode 100644 index 000000000..5b66826f3 --- /dev/null +++ b/integration_tests/multidex/src/test/java/org/robolectric/integration_tests/multidex/robolectric.properties @@ -0,0 +1,3 @@ +sdk=ALL_SDKS +# make Robolectric match the emulator used +qualifiers=w480dp-h800dp diff --git a/integration_tests/powermock/build.gradle b/integration_tests/powermock/build.gradle index 53a86e562..66af18c86 100644 --- a/integration_tests/powermock/build.gradle +++ b/integration_tests/powermock/build.gradle @@ -1,20 +1,15 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - apply plugin: RoboJavaModulePlugin dependencies { - compile project(":robolectric") + api project(":robolectric") compileOnly AndroidSdk.MAX_SDK.coordinates - // Testing dependencies testRuntime AndroidSdk.MAX_SDK.coordinates - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" - testCompile "org.powermock:powermock-module-junit4:1.6.6" - testCompile "org.powermock:powermock-module-junit4-rule:1.6.6" - testCompile "org.powermock:powermock-api-mockito:1.6.6" - testCompile "org.powermock:powermock-classloading-xstream:1.6.6" + testImplementation "org.powermock:powermock-module-junit4:1.6.6" + testImplementation "org.powermock:powermock-module-junit4-rule:1.6.6" + testImplementation "org.powermock:powermock-api-mockito:1.6.6" + testImplementation "org.powermock:powermock-classloading-xstream:1.6.6" }
\ No newline at end of file diff --git a/junit/build.gradle b/junit/build.gradle index 7b246e075..8d5bcac69 100644 --- a/junit/build.gradle +++ b/junit/build.gradle @@ -1,17 +1,12 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) dependencies { - // Compile dependencies - compile project(":annotations") - compile project(":sandbox") - compile project(":shadowapi") + api project(":annotations") + api project(":sandbox") + api project(":shadowapi") - compileOnly "com.google.code.findbugs:jsr305:3.0.1" + compileOnly "com.google.code.findbugs:jsr305:3.0.2" compileOnly "junit:junit:4.12" -}
\ No newline at end of file +} diff --git a/processor/build.gradle b/processor/build.gradle index e74588dc1..ebdb4b780 100644 --- a/processor/build.gradle +++ b/processor/build.gradle @@ -1,7 +1,3 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) @@ -35,30 +31,18 @@ task('generateSdksFile', type: GenerateSdksFileTask) { tasks['classes'].dependsOn(generateSdksFile) -// Disable annotation processor for tests -compileTestJava { - options.compilerArgs.add("-proc:none") -} - dependencies { - // Project dependencies - compile project(":annotations") + implementation project(":annotations") - // Compile dependencies - compile "com.google.guava:guava:20.0" - compileOnly "com.google.code.findbugs:jsr305:3.0.1" - compile "com.google.code.gson:gson:2.8.0" - compile 'ch.raffael.pegdown-doclet:pegdown-doclet:1.3' + compileOnly "com.google.code.findbugs:jsr305:3.0.2" + implementation "com.google.guava:guava:20.0" + implementation "com.google.code.gson:gson:2.8.2" + implementation 'ch.raffael.pegdown-doclet:pegdown-doclet:1.3' - // in jdk 9, tools.jar disappears! - def toolsJar = org.gradle.internal.jvm.Jvm.current().getToolsJar() - if (toolsJar != null) { - compile files(toolsJar) - } + implementation files(org.gradle.internal.jvm.Jvm.current().getToolsJar()) - // Testing dependencies - testCompile "junit:junit:4.12" - testCompile "org.mockito:mockito-core:2.5.4" - testCompile "com.google.testing.compile:compile-testing:0.15" - testCompile "com.google.truth:truth:0.42" + testImplementation "junit:junit:4.12" + testImplementation "org.mockito:mockito-core:2.5.4" + testImplementation "com.google.testing.compile:compile-testing:0.15" + testImplementation "com.google.truth:truth:0.42" } diff --git a/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java b/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java index f9a790ccc..ee92a7f2e 100644 --- a/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java +++ b/processor/src/main/java/org/robolectric/annotation/processing/validator/ImplementsValidator.java @@ -66,13 +66,7 @@ public class ImplementsValidator extends Validator { private TypeElement getClassNameTypeElement(AnnotationValue cv) { String className = Helpers.getAnnotationStringValue(cv); - TypeElement type = elements.getTypeElement(className.replace('$', '.')); - - if (type == null) { - error("@Implements: could not resolve class <" + className + '>', cv); - return null; - } - return type; + return elements.getTypeElement(className.replace('$', '.')); } @Override @@ -104,17 +98,7 @@ public class ImplementsValidator extends Validator { // This shadow doesn't apply to the current SDK. todo: check each SDK. if (maxSdk != -1 && maxSdk < MAX_SUPPORTED_ANDROID_SDK) { - String sdkClassName; - if (av == null) { - sdkClassName = Helpers.getAnnotationStringValue(cv).replace('$', '.'); - } else { - sdkClassName = av.toString(); - } - - // there's no such type at the current SDK level, so just use strings... - // getQualifiedName() uses Outer.Inner and we want Outer$Inner, so: - String name = getClassFQName(shadowType); - modelBuilder.addExtraShadow(sdkClassName, name); + addShadowNotInSdk(shadowType, av, cv); return null; } @@ -125,6 +109,12 @@ public class ImplementsValidator extends Validator { return null; } actualType = getClassNameTypeElement(cv); + + if (actualType == null + && !suppressWarnings(shadowType, "robolectric.internal.IgnoreMissingClass")) { + error("@Implements: could not resolve class <" + cv + '>', cv); + return null; + } } else { TypeMirror value = Helpers.getAnnotationTypeMirrorValue(av); if (value == null) { @@ -137,6 +127,7 @@ public class ImplementsValidator extends Validator { } } if (actualType == null) { + addShadowNotInSdk(shadowType, av, cv); return null; } final List<? extends TypeParameterElement> typeTP = actualType.getTypeParameters(); @@ -173,6 +164,32 @@ public class ImplementsValidator extends Validator { return null; } + private void addShadowNotInSdk(TypeElement shadowType, AnnotationValue av, AnnotationValue cv) { + String sdkClassName; + if (av == null) { + sdkClassName = Helpers.getAnnotationStringValue(cv).replace('$', '.'); + } else { + sdkClassName = av.toString(); + } + + // there's no such type at the current SDK level, so just use strings... + // getQualifiedName() uses Outer.Inner and we want Outer$Inner, so: + String name = getClassFQName(shadowType); + modelBuilder.addExtraShadow(sdkClassName, name); + } + + private static boolean suppressWarnings(Element element, String warningName) { + SuppressWarnings[] suppressWarnings = element.getAnnotationsByType(SuppressWarnings.class); + for (SuppressWarnings suppression : suppressWarnings) { + for (String name : suppression.value()) { + if (warningName.equals(name)) { + return true; + } + } + } + return false; + } + static String getClassFQName(TypeElement elem) { StringBuilder name = new StringBuilder(); while (isClassy(elem.getEnclosingElement().getKind())) { diff --git a/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java b/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java index c65076e78..e01674dba 100644 --- a/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java +++ b/processor/src/main/java/org/robolectric/annotation/processing/validator/SdkStore.java @@ -99,6 +99,20 @@ class SdkStore { } } + private static String canonicalize(TypeMirror typeMirror) { + if (typeMirror instanceof TypeVar) { + return ((TypeVar) typeMirror).getUpperBound().toString(); + } else if (typeMirror instanceof ArrayType) { + return canonicalize(((ArrayType) typeMirror).elemtype) + "[]"; + } else { + return typeMirror.toString(); + } + } + + private static String typeWithoutGenerics(String paramType) { + return paramType.replaceAll("<.*", ""); + } + static class Sdk implements Comparable<Sdk> { private static final ClassInfo NULL_CLASS_INFO = new ClassInfo(); @@ -138,22 +152,61 @@ class SdkStore { } MethodExtraInfo implMethod = new MethodExtraInfo(methodElement); - if (sdkMethod.equals(implMethod)) { + if (!sdkMethod.equals(implMethod) + && !suppressWarnings(methodElement, "robolectric.ShadowReturnTypeMismatch")) { if (implMethod.isStatic != sdkMethod.isStatic) { return "@Implementation for " + methodElement.getSimpleName() + " is " + (implMethod.isStatic ? "static" : "not static") + " unlike the SDK method"; } if (!implMethod.returnType.equals(sdkMethod.returnType)) { - return "@Implementation for " + methodElement.getSimpleName() - + " has a return type of " + implMethod.returnType - + ", not " + sdkMethod.returnType + " as in the SDK method"; + if ( + (looseSignatures && typeIsOkForLooseSignatures(implMethod, sdkMethod)) + || (looseSignatures && implMethod.returnType.equals("java.lang.Object[]")) + // Number is allowed for int or long return types + || typeIsNumeric(sdkMethod, implMethod)) { + return null; + } else { + return "@Implementation for " + methodElement.getSimpleName() + + " has a return type of " + implMethod.returnType + + ", not " + sdkMethod.returnType + " as in the SDK method"; + } } } return null; } + private boolean suppressWarnings(ExecutableElement methodElement, String warningName) { + SuppressWarnings[] suppressWarnings = methodElement.getAnnotationsByType(SuppressWarnings.class); + for (SuppressWarnings suppression : suppressWarnings) { + for (String name : suppression.value()) { + if (warningName.equals(name)) { + return true; + } + } + } + return false; + } + + private boolean typeIsNumeric(MethodExtraInfo sdkMethod, MethodExtraInfo implMethod) { + return implMethod.returnType.equals("java.lang.Number") + && isNumericType(sdkMethod.returnType); + } + + private boolean typeIsOkForLooseSignatures(MethodExtraInfo implMethod, MethodExtraInfo sdkMethod) { + return + // loose signatures allow a return type of Object... + implMethod.returnType.equals("java.lang.Object") + // or Object[] for arrays... + || (implMethod.returnType.equals("java.lang.Object[]") + && sdkMethod.returnType.endsWith("[]")); + } + + private boolean isNumericType(String type) { + return type.equals("int") || type.equals("long"); + } + /** * Load and analyze bytecode for the specified class, with caching. * @@ -293,7 +346,7 @@ class SdkStore { public MethodInfo(MethodNode method) { this.name = method.name; for (Type type : Type.getArgumentTypes(method.desc)) { - paramTypes.add(type.getClassName().replace('$', '.')); + paramTypes.add(normalize(type)); } } @@ -312,21 +365,11 @@ class SdkStore { for (VariableElement variableElement : methodElement.getParameters()) { TypeMirror varTypeMirror = variableElement.asType(); String paramType = canonicalize(varTypeMirror); - String paramTypeWithoutGenerics = paramType.replaceAll("<.*", ""); + String paramTypeWithoutGenerics = typeWithoutGenerics(paramType); paramTypes.add(paramTypeWithoutGenerics); } } - private String canonicalize(TypeMirror typeMirror) { - if (typeMirror instanceof TypeVar) { - return ((TypeVar) typeMirror).getUpperBound().toString(); - } else if (typeMirror instanceof ArrayType) { - return canonicalize(((ArrayType) typeMirror).elemtype) + "[]"; - } else { - return typeMirror.toString(); - } - } - private String cleanMethodName(ExecutableElement methodElement) { String name = methodElement.getSimpleName().toString(); if (CONSTRUCTOR_METHOD_NAME.equals(name)) { @@ -359,7 +402,6 @@ class SdkStore { public int hashCode() { return Objects.hash(name, paramTypes); } - @Override public String toString() { return "MethodInfo{" @@ -369,18 +411,40 @@ class SdkStore { } } + private static String normalize(Type type) { + return type.getClassName().replace('$', '.'); + } + static class MethodExtraInfo { private final boolean isStatic; private final String returnType; public MethodExtraInfo(MethodNode method) { this.isStatic = (method.access & Opcodes.ACC_STATIC) != 0; - this.returnType = Type.getReturnType(method.desc).getClassName(); + this.returnType = typeWithoutGenerics(normalize(Type.getReturnType(method.desc))); } public MethodExtraInfo(ExecutableElement methodElement) { this.isStatic = methodElement.getModifiers().contains(Modifier.STATIC); - this.returnType = methodElement.getReturnType().toString(); + this.returnType = typeWithoutGenerics(canonicalize(methodElement.getReturnType())); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MethodExtraInfo that = (MethodExtraInfo) o; + return isStatic == that.isStatic && + Objects.equals(returnType, that.returnType); + } + + @Override + public int hashCode() { + return Objects.hash(isStatic, returnType); } } } diff --git a/resources/build.gradle b/resources/build.gradle index 42f221819..1ce690698 100644 --- a/resources/build.gradle +++ b/resources/build.gradle @@ -1,23 +1,16 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) dependencies { - // Project dependencies - compile project(":utils") - compile project(":annotations") + api project(":utils") + api project(":annotations") - // Compile dependencies - compile "com.google.guava:guava:20.0" - compileOnly "com.google.code.findbugs:jsr305:3.0.1" + api "com.google.guava:guava:20.0" + compileOnly "com.google.code.findbugs:jsr305:3.0.2" - // Testing dependencies - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" - testCompile "com.google.testing.compile:compile-testing:0.6" - testCompile "org.mockito:mockito-core:2.5.4" + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "com.google.testing.compile:compile-testing:0.6" + testImplementation "org.mockito:mockito-core:2.5.4" } diff --git a/resources/src/main/java/org/robolectric/RoboSettings.java b/resources/src/main/java/org/robolectric/RoboSettings.java index 3ca247618..3dc800ab5 100644 --- a/resources/src/main/java/org/robolectric/RoboSettings.java +++ b/resources/src/main/java/org/robolectric/RoboSettings.java @@ -7,11 +7,15 @@ public class RoboSettings { private static String mavenRepositoryId; private static String mavenRepositoryUrl; + private static String mavenRepositoryUserName; + private static String mavenRepositoryPassword; private static boolean useGlobalScheduler; static { mavenRepositoryId = System.getProperty("robolectric.dependency.repo.id", "sonatype"); mavenRepositoryUrl = System.getProperty("robolectric.dependency.repo.url", "https://oss.sonatype.org/content/groups/public/"); + mavenRepositoryUserName = System.getProperty("robolectric.dependency.repo.username"); + mavenRepositoryPassword = System.getProperty("robolectric.dependency.repo.password"); useGlobalScheduler = Boolean.getBoolean("robolectric.scheduling.global"); } @@ -31,6 +35,22 @@ public class RoboSettings { RoboSettings.mavenRepositoryUrl = mavenRepositoryUrl; } + public static String getMavenRepositoryUserName() { + return mavenRepositoryUserName; + } + + public static void setMavenRepositoryUserName(String mavenRepositoryUserName) { + RoboSettings.mavenRepositoryUserName = mavenRepositoryUserName; + } + + public static String getMavenRepositoryPassword() { + return mavenRepositoryPassword; + } + + public static void setMavenRepositoryPassword(String mavenRepositoryPassword) { + RoboSettings.mavenRepositoryPassword = mavenRepositoryPassword; + } + public static boolean isUseGlobalScheduler() { return useGlobalScheduler; } diff --git a/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java b/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java index 57def481c..7bb8862a6 100644 --- a/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java +++ b/resources/src/main/java/org/robolectric/manifest/AndroidManifest.java @@ -284,11 +284,11 @@ public class AndroidManifest implements UsesSdk { List<PathPermissionData> pathPermissionDatas = new ArrayList<>(); for (Node node : getChildrenTags(contentProviderNode, "path-permission")) { pathPermissionDatas.add(new PathPermissionData( - getAttributeValue(node, "android:path"), - getAttributeValue(node, "android:pathPrefix"), - getAttributeValue(node, "android:pathPattern"), - getAttributeValue(node, "android:readPermission"), - getAttributeValue(node, "android:writePermission") + getAttributeValue(node, "android:path"), + getAttributeValue(node, "android:pathPrefix"), + getAttributeValue(node, "android:pathPattern"), + getAttributeValue(node, "android:readPermission"), + getAttributeValue(node, "android:writePermission") )); } @@ -297,10 +297,8 @@ public class AndroidManifest implements UsesSdk { resolveClassRef(name), metaData, authorities, - getAttributeValue(contentProviderNode, "android:readPermission"), - getAttributeValue(contentProviderNode, "android:writePermission"), - pathPermissionDatas, - getAttributeValue(contentProviderNode, "android:grantUriPermissions"))); + parseNodeAttributes(contentProviderNode), + pathPermissionDatas)); } } diff --git a/resources/src/main/java/org/robolectric/manifest/BroadcastReceiverData.java b/resources/src/main/java/org/robolectric/manifest/BroadcastReceiverData.java index 7361beb94..41539a456 100644 --- a/resources/src/main/java/org/robolectric/manifest/BroadcastReceiverData.java +++ b/resources/src/main/java/org/robolectric/manifest/BroadcastReceiverData.java @@ -10,6 +10,7 @@ public class BroadcastReceiverData extends PackageItemData { private static final String EXPORTED = "android:exported"; private static final String NAME = "android:name"; private static final String PERMISSION = "android:permission"; + private static final String ENABLED = "android:enabled"; private final Map<String, String> attributes; private final List<String> actions; @@ -75,4 +76,8 @@ public class BroadcastReceiverData extends PackageItemData { ? Boolean.parseBoolean(attributes.get(EXPORTED)) : defaultValue); } + + public boolean isEnabled() { + return attributes.containsKey(ENABLED) ? Boolean.parseBoolean(attributes.get(ENABLED)) : true; + } } diff --git a/resources/src/main/java/org/robolectric/manifest/ContentProviderData.java b/resources/src/main/java/org/robolectric/manifest/ContentProviderData.java index 1db52c926..b1c063a0b 100644 --- a/resources/src/main/java/org/robolectric/manifest/ContentProviderData.java +++ b/resources/src/main/java/org/robolectric/manifest/ContentProviderData.java @@ -1,28 +1,28 @@ package org.robolectric.manifest; import java.util.List; +import java.util.Map; public class ContentProviderData extends PackageItemData { + private static final String READ_PERMISSION = "android:readPermission"; + private static final String WRITE_PERMISSION = "android:writePermission"; + private static final String GRANT_URI_PERMISSION = "android:grantUriPermissions"; + private static final String ENABLED = "android:enabled"; + private final String authority; - private final String readPermission; - private final String writePermission; + private final Map<String, String> attributes; private final List<PathPermissionData> pathPermissionDatas; - private final boolean grantUriPermissions; public ContentProviderData( String className, MetaData metaData, String authority, - String readPermission, - String writePermission, - List<PathPermissionData> pathPermissionDatas, - String grantUriPermissions) { + Map<String, String> attributes, + List<PathPermissionData> pathPermissionDatas) { super(className, metaData); this.authority = authority; - this.readPermission = readPermission; - this.writePermission = writePermission; + this.attributes = attributes; this.pathPermissionDatas = pathPermissionDatas; - this.grantUriPermissions = Boolean.parseBoolean(grantUriPermissions); } public String getAuthorities() { @@ -30,11 +30,11 @@ public class ContentProviderData extends PackageItemData { } public String getReadPermission() { - return readPermission; + return attributes.get(READ_PERMISSION); } public String getWritePermission() { - return writePermission; + return attributes.get(WRITE_PERMISSION); } public List<PathPermissionData> getPathPermissionDatas() { @@ -42,6 +42,10 @@ public class ContentProviderData extends PackageItemData { } public boolean getGrantUriPermissions() { - return grantUriPermissions; + return Boolean.parseBoolean(attributes.get(GRANT_URI_PERMISSION)); + } + + public boolean isEnabled() { + return attributes.containsKey(ENABLED) ? Boolean.parseBoolean(attributes.get(ENABLED)) : true; } } diff --git a/resources/src/main/java/org/robolectric/manifest/ServiceData.java b/resources/src/main/java/org/robolectric/manifest/ServiceData.java index 64ac10643..82f9d8777 100644 --- a/resources/src/main/java/org/robolectric/manifest/ServiceData.java +++ b/resources/src/main/java/org/robolectric/manifest/ServiceData.java @@ -12,6 +12,7 @@ public class ServiceData extends PackageItemData { private static final String EXPORTED = "android:exported"; private static final String NAME = "android:name"; private static final String PERMISSION = "android:permission"; + private static final String ENABLED = "android:enabled"; private final Map<String, String> attributes; private final List<String> actions; @@ -70,4 +71,8 @@ public class ServiceData extends PackageItemData { ? Boolean.parseBoolean(attributes.get(EXPORTED)) : defaultValue); } + + public boolean isEnabled() { + return attributes.containsKey(ENABLED) ? Boolean.parseBoolean(attributes.get(ENABLED)) : true; + } } diff --git a/resources/src/main/java/org/robolectric/res/android/AConfiguration.java b/resources/src/main/java/org/robolectric/res/android/AConfiguration.java index 0fa6bd298..0aca39044 100644 --- a/resources/src/main/java/org/robolectric/res/android/AConfiguration.java +++ b/resources/src/main/java/org/robolectric/res/android/AConfiguration.java @@ -1,8 +1,8 @@ package org.robolectric.res.android; -// transliterated from https://android.googlesource.com/platform/frameworks/native/+/android-9.0.0_r3/include/android/configuration.h +// transliterated from https://android.googlesource.com/platform/frameworks/native/+/android-9.0.0_r12/include/android/configuration.h public class AConfiguration { -/** Orientation: not specified. */ + /** Orientation: not specified. */ public static final int ACONFIGURATION_ORIENTATION_ANY = 0x0000; /** * Orientation: value corresponding to the @@ -275,10 +275,10 @@ public class AConfiguration { * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a> resource qualifier specified. */ public static final int ACONFIGURATION_UI_MODE_TYPE_WATCH = 0x06; - /** - * UI mode: value that corresponds to - * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">vr</a> resource qualifier specified. - */ + /** + * UI mode: value that corresponds to + * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">vr</a> resource qualifier specified. + */ public static final int ACONFIGURATION_UI_MODE_TYPE_VR_HEADSET = 0x07; /** UI night mode: not specified.*/ public static final int ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00; diff --git a/resources/src/main/java/org/robolectric/res/android/Asset.java b/resources/src/main/java/org/robolectric/res/android/Asset.java index 7417963b9..4484884e8 100644 --- a/resources/src/main/java/org/robolectric/res/android/Asset.java +++ b/resources/src/main/java/org/robolectric/res/android/Asset.java @@ -17,6 +17,8 @@ import java.util.zip.ZipFile; import org.robolectric.res.FileTypedResource; import org.robolectric.res.FsFile; +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/Asset.cpp +// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/Asset.h /* * Instances of this class provide read-only operations on a byte stream. * @@ -100,14 +102,14 @@ public abstract class Asset { */ public abstract long seek(long offset, int whence); - /* - * Close the asset, freeing all associated resources. - */ - public abstract void close(); + /* + * Close the asset, freeing all associated resources. + */ + public abstract void close(); - /* - * Get a pointer to a buffer with the entire contents of the file. - */ + /* + * Get a pointer to a buffer with the entire contents of the file. + */ public abstract byte[] getBuffer(boolean wordAligned); /* @@ -120,11 +122,11 @@ public abstract class Asset { */ public abstract long getRemainingLength(); - /* - * Open a new file descriptor that can be used to read this asset. - * Returns -1 if you can not use the file descriptor (for example if the - * asset is compressed). - */ + /* + * Open a new file descriptor that can be used to read this asset. + * Returns -1 if you can not use the file descriptor (for example if the + * asset is compressed). + */ public abstract FileDescriptor openFileDescriptor(Ref<Long> outStart, Ref<Long> outLength); public abstract File getFile(); @@ -253,43 +255,43 @@ public abstract class Asset { void registerAsset(Asset asset) { - // AutoMutex _l(gAssetLock); - // gCount++; - // asset.mNext = asset.mPrev = null; - // if (gTail == null) { - // gHead = gTail = asset; - // } else { - // asset.mPrev = gTail; - // gTail.mNext = asset; - // gTail = asset; - // } - // - // if (kIsDebug) { - // ALOGI("Creating Asset %s #%d\n", asset, gCount); - // } + // AutoMutex _l(gAssetLock); + // gCount++; + // asset.mNext = asset.mPrev = null; + // if (gTail == null) { + // gHead = gTail = asset; + // } else { + // asset.mPrev = gTail; + // gTail.mNext = asset; + // gTail = asset; + // } + // + // if (kIsDebug) { + // ALOGI("Creating Asset %s #%d\n", asset, gCount); + // } } void unregisterAsset(Asset asset) { - // AutoMutex _l(gAssetLock); - // gCount--; - // if (gHead == asset) { - // gHead = asset.mNext; - // } - // if (gTail == asset) { - // gTail = asset.mPrev; - // } - // if (asset.mNext != null) { - // asset.mNext.mPrev = asset.mPrev; - // } - // if (asset.mPrev != null) { - // asset.mPrev.mNext = asset.mNext; - // } - // asset.mNext = asset.mPrev = null; - // - // if (kIsDebug) { - // ALOGI("Destroying Asset in %s #%d\n", asset, gCount); - // } + // AutoMutex _l(gAssetLock); + // gCount--; + // if (gHead == asset) { + // gHead = asset.mNext; + // } + // if (gTail == asset) { + // gTail = asset.mPrev; + // } + // if (asset.mNext != null) { + // asset.mNext.mPrev = asset.mPrev; + // } + // if (asset.mPrev != null) { + // asset.mPrev.mNext = asset.mNext; + // } + // asset.mNext = asset.mPrev = null; + // + // if (kIsDebug) { + // ALOGI("Destroying Asset in %s #%d\n", asset, gCount); + // } } public static int getGlobalCount() @@ -510,7 +512,7 @@ public abstract class Asset { /* * Create a new Asset from compressed data in a memory mapping. */ -static Asset createFromCompressedMap(FileMap dataMap, + static Asset createFromCompressedMap(FileMap dataMap, int uncompressedLen, AccessMode mode) { _CompressedAsset pAsset; @@ -601,7 +603,7 @@ static Asset createFromCompressedMap(FileMap dataMap, @Override public long getRemainingLength() { return mLength-mOffset; } -// virtual int openFileDescriptor(long* outStart, long* outLength) final; + // virtual int openFileDescriptor(long* outStart, long* outLength) final; @Override boolean isAllocated() { return mBuf != null; } @@ -629,18 +631,18 @@ static Asset createFromCompressedMap(FileMap dataMap, * just read them in. */ // enum { - public static int kReadVsMapThreshold = 4096; + public static int kReadVsMapThreshold = 4096; // }; FileMap mMap; // for memory map byte[] mBuf; // for read // final void* ensureAlignment(FileMap map); -/* - * =========================================================================== - * _FileAsset - * =========================================================================== - */ + /* + * =========================================================================== + * _FileAsset + * =========================================================================== + */ /* * Constructor. @@ -742,12 +744,12 @@ static Asset createFromCompressedMap(FileMap dataMap, assert(mOffset >= 0 && mOffset <= mLength); if (getAccessMode() == ACCESS_BUFFER) { - /* - * On first access, read or map the entire file. The caller has - * requested buffer access, either because they're going to be - * using the buffer or because what they're doing has appropriate - * performance needs and access patterns. - */ + /* + * On first access, read or map the entire file. The caller has + * requested buffer access, either because they're going to be + * using the buffer or because what they're doing has appropriate + * performance needs and access patterns. + */ if (mBuf == null) getBuffer(false); } @@ -762,19 +764,19 @@ static Asset createFromCompressedMap(FileMap dataMap, } if (mMap != null) { - /* copy from mapped area */ + /* copy from mapped area */ //printf("map read\n"); // memcpy(buf, (String)mMap.getDataPtr() + mOffset, count); System.arraycopy(mMap.getDataPtr(), toIntExact(mOffset), buf, bufOffset, count); actual = count; } else if (mBuf != null) { - /* copy from buffer */ + /* copy from buffer */ //printf("buf read\n"); // memcpy(buf, (String)mBuf + mOffset, count); System.arraycopy(mBuf, toIntExact(mOffset), buf, bufOffset, count); actual = count; } else { - /* read from the file */ + /* read from the file */ //printf("file read\n"); // if (ftell(mFp) != mStart + mOffset) { try { @@ -873,7 +875,7 @@ static Asset createFromCompressedMap(FileMap dataMap, return mBuf; if (mMap != null) { // if (!wordAligned) { - return mMap.getDataPtr(); + return mMap.getDataPtr(); // } // return ensureAlignment(mMap); } @@ -884,8 +886,8 @@ static Asset createFromCompressedMap(FileMap dataMap, byte[] buf; int allocLen; - /* zero-length files are allowed; not sure about zero-len allocs */ - /* (works fine with gcc + x86linux) */ + /* zero-length files are allowed; not sure about zero-len allocs */ + /* (works fine with gcc + x86linux) */ allocLen = toIntExact(mLength); if (mLength == 0) allocLen = 1; @@ -1113,11 +1115,11 @@ static Asset createFromCompressedMap(FileMap dataMap, // class StreamingZipInflater mZipInflater; // for streaming large compressed assets byte[] mBuf; // for getBuffer() -/* - * =========================================================================== - * _CompressedAsset - * =========================================================================== - */ + /* + * =========================================================================== + * _CompressedAsset + * =========================================================================== + */ /* * Constructor. @@ -1232,7 +1234,7 @@ static Asset createFromCompressedMap(FileMap dataMap, assert(mOffset >= 0 && mOffset <= mUncompressedLen); - /* If we're relying on a streaming inflater, go through that */ + /* If we're relying on a streaming inflater, go through that */ // if (mZipInflater) { // actual = mZipInflater.read(buf, count); // } else { @@ -1275,7 +1277,7 @@ static Asset createFromCompressedMap(FileMap dataMap, // compute new position within chunk newPosn = handleSeek(offset, whence, mOffset, mUncompressedLen); if (newPosn == (long) -1) - return newPosn; + return newPosn; // if (mZipInflater) { // mZipInflater.seekAbsolute(newPosn); @@ -1289,21 +1291,21 @@ static Asset createFromCompressedMap(FileMap dataMap, */ @Override public void close() { - if (mMap != null) { + if (mMap != null) { // delete mMap; - mMap = null; - } + mMap = null; + } // delete[] mBuf; - mBuf = null; + mBuf = null; // delete mZipInflater; // mZipInflater = null; - if (mFd > 0) { + if (mFd > 0) { // ::close(mFd); - mFd = -1; - } + mFd = -1; + } } /* diff --git a/resources/src/main/java/org/robolectric/res/android/AssetDir.java b/resources/src/main/java/org/robolectric/res/android/AssetDir.java index f7ef778e6..ea3d10bf6 100644 --- a/resources/src/main/java/org/robolectric/res/android/AssetDir.java +++ b/resources/src/main/java/org/robolectric/res/android/AssetDir.java @@ -2,8 +2,8 @@ package org.robolectric.res.android; import org.robolectric.res.android.CppAssetManager.FileType; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/AssetDir.cpp and -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/include/androidfw/AssetDir.h +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/AssetDir.cpp and +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/AssetDir.h public class AssetDir { private SortedVector<FileInfo> mFileInfo; @@ -17,8 +17,8 @@ public class AssetDir { } /* - * Vector-style access. - */ + * Vector-style access. + */ public int getFileCount() { return mFileInfo.size(); } @@ -49,8 +49,8 @@ public class AssetDir { FileInfo() {} FileInfo(String8 path) { // useful for e.g. svect.indexOf - mFileName = path; - mFileType = FileType.kFileTypeUnknown; + mFileName = path; + mFileType = FileType.kFileTypeUnknown; } FileInfo(FileInfo src) { @@ -106,7 +106,7 @@ public class AssetDir { * Returns the index of the matching entry, or -1 if none found. */ static int findEntry(SortedVector<FileInfo> pVector, - String8 fileName) { + String8 fileName) { FileInfo tmpInfo = new FileInfo(); tmpInfo.setFileName(fileName); diff --git a/resources/src/main/java/org/robolectric/res/android/AttributeResolution9.java b/resources/src/main/java/org/robolectric/res/android/AttributeResolution9.java index 33cd5d01c..972f4b6fd 100644 --- a/resources/src/main/java/org/robolectric/res/android/AttributeResolution9.java +++ b/resources/src/main/java/org/robolectric/res/android/AttributeResolution9.java @@ -11,8 +11,8 @@ import org.robolectric.res.android.CppAssetManager2.Theme; import org.robolectric.res.android.ResourceTypes.Res_value; // transliterated from -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/AttributeResolution.cpp and -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/AttributeResolution.h +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/AttributeResolution.cpp and +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/AttributeResolution.h public class AttributeResolution9 { public static final boolean kThrowOnBadId = false; @@ -87,9 +87,9 @@ public class AttributeResolution9 { // `out_values` must NOT be nullptr. // `out_indices` may be nullptr. public static boolean ResolveAttrs(Theme theme, int def_style_attr, - int def_style_res, int[] src_values, - int src_values_length, int[] attrs, - int attrs_length, int[] out_values, int[] out_indices) { + int def_style_res, int[] src_values, + int src_values_length, int[] attrs, + int attrs_length, int[] out_values, int[] out_indices) { if (kDebugStyles) { ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme, def_style_attr, def_style_res); @@ -235,8 +235,8 @@ public class AttributeResolution9 { } public static void ApplyStyle(Theme theme, ResXMLParser xml_parser, int def_style_attr, - int def_style_resid, int[] attrs, int attrs_length, - int[] out_values, int[] out_indices) { + int def_style_resid, int[] attrs, int attrs_length, + int[] out_values, int[] out_indices) { if (kDebugStyles) { ALOGI("APPLY STYLE: theme=%s defStyleAttr=0x%x defStyleRes=0x%x xml=%s", theme, def_style_attr, def_style_resid, xml_parser); @@ -353,7 +353,7 @@ public class AttributeResolution9 { // We found the attribute we were looking for. cookie = entry.cookie; type_set_flags.set(def_style_flags.get()); - + value.set(entry.value); if (kDebugStyles) { ALOGI("-> From def style: type=0x%x, data=0x%08x", value.get().dataType, value.get().data); diff --git a/resources/src/main/java/org/robolectric/res/android/ByteBucketArray.java b/resources/src/main/java/org/robolectric/res/android/ByteBucketArray.java index 2c280eb18..209fb1ee8 100644 --- a/resources/src/main/java/org/robolectric/res/android/ByteBucketArray.java +++ b/resources/src/main/java/org/robolectric/res/android/ByteBucketArray.java @@ -1,11 +1,15 @@ package org.robolectric.res.android; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/ByteBucketArray.h +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/ByteBucketArray.h /** * Stores a sparsely populated array. Has a fixed size of 256 * (number of entries that a byte can represent). */ public abstract class ByteBucketArray<T> { + public ByteBucketArray(T mDefault) { + this.mDefault = mDefault; + } + final int size() { return NUM_BUCKETS * BUCKET_SIZE; } @@ -25,7 +29,8 @@ public abstract class ByteBucketArray<T> { if (bucket == null) { return mDefault; } - return bucket[0x0f & ((byte) index)]; + T t = bucket[0x0f & ((byte) index)]; + return t == null ? mDefault : t; } T editItemAt(int index) { diff --git a/resources/src/main/java/org/robolectric/res/android/Chunk.java b/resources/src/main/java/org/robolectric/res/android/Chunk.java index 131d0365c..823312cea 100644 --- a/resources/src/main/java/org/robolectric/res/android/Chunk.java +++ b/resources/src/main/java/org/robolectric/res/android/Chunk.java @@ -15,8 +15,8 @@ import org.robolectric.res.android.ResourceTypes.ResTable_type; import org.robolectric.res.android.ResourceTypes.WithOffset; // transliterated from -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ChunkIterator.cpp and -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/Chunk.h +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ChunkIterator.cpp and +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/Chunk.h // Helpful wrapper around a ResChunk_header that provides getter methods // that handle endianness conversions and provide access to the data portion diff --git a/resources/src/main/java/org/robolectric/res/android/ConfigDescription.java b/resources/src/main/java/org/robolectric/res/android/ConfigDescription.java index b3951601d..7bf419255 100644 --- a/resources/src/main/java/org/robolectric/res/android/ConfigDescription.java +++ b/resources/src/main/java/org/robolectric/res/android/ConfigDescription.java @@ -12,7 +12,7 @@ import java.util.regex.Pattern; /** * transliterated from - * https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/tools/aapt2/ConfigDescription.cpp + * https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/tools/aapt2/ConfigDescription.cpp */ public class ConfigDescription { public static final int SDK_CUPCAKE = 3; @@ -525,14 +525,14 @@ public class ConfigDescription { if (out != null) { out.screenLayout2 = (byte) ((out.screenLayout2 & ~ResTable_config.MASK_SCREENROUND) | - ResTable_config.SCREENROUND_ANY); + ResTable_config.SCREENROUND_ANY); } return true; } else if (Objects.equals(name, "round")) { if (out != null) { out.screenLayout2 = (byte) ((out.screenLayout2 & ~ResTable_config.MASK_SCREENROUND) | - ResTable_config.SCREENROUND_YES); + ResTable_config.SCREENROUND_YES); } return true; } else if (Objects.equals(name, "notround")) { @@ -551,19 +551,19 @@ public class ConfigDescription { if (out != null) out.colorMode = (byte) ((out.colorMode & ~ResTable_config.MASK_WIDE_COLOR_GAMUT) | - ResTable_config.WIDE_COLOR_GAMUT_ANY); + ResTable_config.WIDE_COLOR_GAMUT_ANY); return true; } else if (Objects.equals(name, "widecg")) { if (out != null) out.colorMode = (byte) ((out.colorMode & ~ResTable_config.MASK_WIDE_COLOR_GAMUT) | - ResTable_config.WIDE_COLOR_GAMUT_YES); + ResTable_config.WIDE_COLOR_GAMUT_YES); return true; } else if (Objects.equals(name, "nowidecg")) { if (out != null) out.colorMode = (byte) ((out.colorMode & ~ResTable_config.MASK_WIDE_COLOR_GAMUT) | - ResTable_config.WIDE_COLOR_GAMUT_NO); + ResTable_config.WIDE_COLOR_GAMUT_NO); return true; } return false; @@ -574,19 +574,19 @@ public class ConfigDescription { if (out != null) out.colorMode = (byte) ((out.colorMode & ~ResTable_config.MASK_HDR) | - ResTable_config.HDR_ANY); + ResTable_config.HDR_ANY); return true; } else if (Objects.equals(name, "highdr")) { if (out != null) out.colorMode = (byte) ((out.colorMode & ~ResTable_config.MASK_HDR) | - ResTable_config.HDR_YES); + ResTable_config.HDR_YES); return true; } else if (Objects.equals(name, "lowdr")) { if (out != null) out.colorMode = (byte) ((out.colorMode & ~ResTable_config.MASK_HDR) | - ResTable_config.HDR_NO); + ResTable_config.HDR_NO); return true; } return false; @@ -980,7 +980,7 @@ public class ConfigDescription { return false; } - // transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/tools/aapt/AaptConfig.cpp + // transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/tools/aapt/AaptConfig.cpp private static void applyVersionForCompatibility(ResTable_config config) { if (config == null) { return; @@ -989,7 +989,7 @@ public class ConfigDescription { if (((config.uiMode & ResTable_config.MASK_UI_MODE_TYPE) == ResTable_config.UI_MODE_TYPE_VR_HEADSET) || (config.colorMode & ResTable_config.MASK_WIDE_COLOR_GAMUT) != 0 || - (config.colorMode & ResTable_config.MASK_HDR) != 0) { + (config.colorMode & ResTable_config.MASK_HDR) != 0) { min_sdk = SDK_O; } else if (isTruthy(config.screenLayout2 & ResTable_config.MASK_SCREENROUND)) { min_sdk = SDK_MNC; diff --git a/resources/src/main/java/org/robolectric/res/android/CppApkAssets.java b/resources/src/main/java/org/robolectric/res/android/CppApkAssets.java index e9285d642..cbe6fa780 100644 --- a/resources/src/main/java/org/robolectric/res/android/CppApkAssets.java +++ b/resources/src/main/java/org/robolectric/res/android/CppApkAssets.java @@ -1,7 +1,7 @@ package org.robolectric.res.android; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/ApkAssets.h -// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ApkAssets.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/ApkAssets.h +// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ApkAssets.cpp import static org.robolectric.res.android.CppAssetManager.FileType.kFileTypeDirectory; import static org.robolectric.res.android.CppAssetManager.FileType.kFileTypeRegular; @@ -253,9 +253,9 @@ public class CppApkAssets { // Must retain ownership of the IDMAP Asset so that all pointers to its mmapped data remain valid. loaded_apk.idmap_asset_ = idmap_asset; - // const StringPiece data( - // reinterpret_cast<const char*>(loaded_apk.resources_asset_.getBuffer(true /*wordAligned*/)), - // loaded_apk.resources_asset_.getLength()); + // const StringPiece data( + // reinterpret_cast<const char*>(loaded_apk.resources_asset_.getBuffer(true /*wordAligned*/)), + // loaded_apk.resources_asset_.getLength()); StringPiece data = new StringPiece( ByteBuffer.wrap(loaded_apk.resources_asset_.getBuffer(true /*wordAligned*/)) .order(ByteOrder.LITTLE_ENDIAN), diff --git a/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java b/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java index 8633b889d..35f970b5b 100644 --- a/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java +++ b/resources/src/main/java/org/robolectric/res/android/CppAssetManager.java @@ -33,7 +33,7 @@ import org.robolectric.res.android.AssetDir.FileInfo; import org.robolectric.res.android.ZipFileRO.ZipEntryRO; import org.robolectric.util.PerfStatsCollector; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/AssetManager.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/AssetManager.cpp @SuppressWarnings("NewApi") public class CppAssetManager { @@ -117,9 +117,9 @@ public class CppAssetManager { static final Asset kExcludedAsset = Asset.EXCLUDED_ASSET; - static volatile int gCount = 0; + static volatile int gCount = 0; -// final char* RESOURCES_FILENAME = "resources.arsc"; + // final char* RESOURCES_FILENAME = "resources.arsc"; // final char* IDMAP_BIN = "/system/bin/idmap"; // final char* OVERLAY_DIR = "/vendor/overlay"; // final char* OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; @@ -838,7 +838,7 @@ public class CppAssetManager { final asset_path ap) { Asset pAsset = null; - /* look at the filesystem on disk */ + /* look at the filesystem on disk */ if (ap.type == kFileTypeDirectory) { String8 path = new String8(ap.path); path.appendPath(fileName); @@ -846,7 +846,7 @@ public class CppAssetManager { pAsset = openAssetFromFileLocked(path, mode); if (pAsset == null) { - /* try again, this time with ".gz" */ + /* try again, this time with ".gz" */ path.append(".gz"); pAsset = openAssetFromFileLocked(path, mode); } @@ -860,7 +860,7 @@ public class CppAssetManager { } else { String8 path = new String8(fileName); - /* check the appropriate Zip file */ + /* check the appropriate Zip file */ ZipFileRO pZip = getZipFileLocked(ap); if (pZip != null) { //printf("GOT zip, checking NA '%s'\n", (final char*) path); @@ -873,7 +873,7 @@ public class CppAssetManager { } if (pAsset != null) { - /* create a "source" name, for debug/display */ + /* create a "source" name, for debug/display */ pAsset.setAssetSource( createZipSourceNameLocked(ap.path, new String8(), new String8(fileName))); } @@ -984,7 +984,7 @@ public class CppAssetManager { pZipFile.mFileName, mode, pAsset); } if (pAsset == null) { - /* unexpected */ + /* unexpected */ ALOGW("create from segment failed\n"); } @@ -1125,11 +1125,11 @@ public class CppAssetManager { // if we wanted to do an incremental cache fill, we would do it here - /* - * Process "exclude" directives. If we find a filename that ends with - * ".EXCLUDE", we look for a matching entry in the "merged" set, and - * remove it if we find it. We also delete the "exclude" entry. - */ + /* + * Process "exclude" directives. If we find a filename that ends with + * ".EXCLUDE", we look for a matching entry in the "merged" set, and + * remove it if we find it. We also delete the "exclude" entry. + */ int i, count, exclExtLen; count = pContents.size(); @@ -1256,7 +1256,7 @@ public class CppAssetManager { zipName = ZipSet.getPathName(ap.path.string()); - /* convert "sounds" to "rootDir/sounds" */ + /* convert "sounds" to "rootDir/sounds" */ if (rootDir != null) { dirName = new String8(rootDir); } @@ -1351,9 +1351,9 @@ public class CppAssetManager { pZip.endIteration(iterationCookie); - /* - * Add the set of unique directories. - */ + /* + * Add the set of unique directories. + */ for (int i = 0; i < dirs.size(); i++) { AssetDir.FileInfo info = new FileInfo(); info.set(dirs.get(i), kFileTypeDirectory); @@ -1379,26 +1379,26 @@ public class CppAssetManager { */ void mergeInfoLocked(Ref<SortedVector<AssetDir.FileInfo>> pMergedInfoRef, final SortedVector<AssetDir.FileInfo> pContents) { - /* - * Merge what we found in this directory with what we found in - * other places. - * - * Two basic approaches: - * (1) Create a new array that holds the unique values of the two - * arrays. - * (2) Take the elements from pContents and shove them into pMergedInfo. - * - * Because these are vectors of complex objects, moving elements around - * inside the vector requires finalructing new objects and allocating - * storage for members. With approach #1, we're always adding to the - * end, whereas with #2 we could be inserting multiple elements at the - * front of the vector. Approach #1 requires a full copy of the - * contents of pMergedInfo, but approach #2 requires the same copy for - * every insertion at the front of pMergedInfo. - * - * (We should probably use a SortedVector interface that allows us to - * just stuff items in, trusting us to maintain the sort order.) - */ + /* + * Merge what we found in this directory with what we found in + * other places. + * + * Two basic approaches: + * (1) Create a new array that holds the unique values of the two + * arrays. + * (2) Take the elements from pContents and shove them into pMergedInfo. + * + * Because these are vectors of complex objects, moving elements around + * inside the vector requires finalructing new objects and allocating + * storage for members. With approach #1, we're always adding to the + * end, whereas with #2 we could be inserting multiple elements at the + * front of the vector. Approach #1 requires a full copy of the + * contents of pMergedInfo, but approach #2 requires the same copy for + * every insertion at the front of pMergedInfo. + * + * (We should probably use a SortedVector interface that allows us to + * just stuff items in, trusting us to maintain the sort order.) + */ SortedVector<AssetDir.FileInfo> pNewSorted; int mergeMax, contMax; int mergeIdx, contIdx; @@ -1411,33 +1411,33 @@ public class CppAssetManager { while (mergeIdx < mergeMax || contIdx < contMax) { if (mergeIdx == mergeMax) { - /* hit end of "merge" list, copy rest of "contents" */ + /* hit end of "merge" list, copy rest of "contents" */ pNewSorted.add(pContents.itemAt(contIdx)); contIdx++; } else if (contIdx == contMax) { - /* hit end of "cont" list, copy rest of "merge" */ + /* hit end of "cont" list, copy rest of "merge" */ pNewSorted.add(pMergedInfo.itemAt(mergeIdx)); mergeIdx++; } else if (pMergedInfo.itemAt(mergeIdx) == pContents.itemAt(contIdx)) { - /* items are identical, add newer and advance both indices */ + /* items are identical, add newer and advance both indices */ pNewSorted.add(pContents.itemAt(contIdx)); mergeIdx++; contIdx++; } else if (pMergedInfo.itemAt(mergeIdx).isLessThan(pContents.itemAt(contIdx))) { - /* "merge" is lower, add that one */ + /* "merge" is lower, add that one */ pNewSorted.add(pMergedInfo.itemAt(mergeIdx)); mergeIdx++; } else { - /* "cont" is lower, add that one */ + /* "cont" is lower, add that one */ assert (pContents.itemAt(contIdx).isLessThan(pMergedInfo.itemAt(mergeIdx))); pNewSorted.add(pContents.itemAt(contIdx)); contIdx++; } } - /* - * Overwrite the "merged" list with the new stuff. - */ + /* + * Overwrite the "merged" list with the new stuff. + */ pMergedInfoRef.set(pNewSorted); // #if 0 // for Vector, rather than SortedVector @@ -1606,22 +1606,22 @@ public class CppAssetManager { /* - * Manage a set of Zip files. For each file we need a pointer to the - * ZipFile and a time_t with the file's modification date. - * - * We currently only have two zip files (current app, "common" app). - * (This was originally written for 8, based on app/locale/vendor.) - */ + * Manage a set of Zip files. For each file we need a pointer to the + * ZipFile and a time_t with the file's modification date. + * + * We currently only have two zip files (current app, "common" app). + * (This was originally written for 8, based on app/locale/vendor.) + */ static class ZipSet { final List<String> mZipPath = new ArrayList<>(); final List<SharedZip> mZipFile = new ArrayList<>(); - /* - * =========================================================================== - * ZipSet - * =========================================================================== - */ + /* + * =========================================================================== + * ZipSet + * =========================================================================== + */ /* * Destructor. Close any open archives. @@ -1728,12 +1728,12 @@ public class CppAssetManager { // return zip.getOverlay(idx, out); // } // - /* - * Compute the zip file's index. - * - * "appName", "locale", and "vendor" should be set to null to indicate the - * default directory. - */ + /* + * Compute the zip file's index. + * + * "appName", "locale", and "vendor" should be set to null to indicate the + * default directory. + */ int getIndex(final String zip) { final int N = mZipPath.size(); for (int i = 0; i < N; i++) { diff --git a/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java b/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java index c1ac70bd2..0802c6dc0 100644 --- a/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java +++ b/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java @@ -40,11 +40,11 @@ import org.robolectric.res.android.ResourceTypes.ResTable_map_entry; import org.robolectric.res.android.ResourceTypes.ResTable_type; import org.robolectric.res.android.ResourceTypes.Res_value; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/AssetManager2.h -// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/AssetManager2.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/AssetManager2.h +// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/AssetManager2.cpp public class CppAssetManager2 { // #define ATRACE_TAG ATRACE_TAG_RESOURCES -// +// // #include "androidfw/AssetManager2.h" //#include <array> @@ -91,6 +91,14 @@ public class CppAssetManager2 { entry.type_pool = type_pool; return entry; } + + @Override + public String toString() { + return "Entry{" + + "key=" + key + + ", value=" + value + + '}'; + } }; // Denotes the configuration axis that this bag varies with. @@ -783,7 +791,7 @@ public class CppAssetManager2 { // out_name.type16 = entry.type_string_ref.string(); // out_name.type_len = out_name.type16 == null ? 0 : out_name.type16.length(); // if (out_name.type16 == null) { - return false; + return false; // } } @@ -794,7 +802,7 @@ public class CppAssetManager2 { // out_name.entry16 = entry.entry_string_ref.string(); // out_name.entry_len = out_name.entry16 == null ? 0 : out_name.entry16.length(); // if (out_name.entry16 == null) { - return false; + return false; // } } return true; @@ -962,10 +970,12 @@ public class CppAssetManager2 { // final ResTable_map map_entry_end = map_entry + dtohl(map.count); final ResTable_map_entry map = new ResTable_map_entry(entry.entry.myBuf(), entry.entry.myOffset()); int curOffset = map.myOffset() + map.size; - ResTable_map map_entry = - new ResTable_map(map.myBuf(), curOffset); + ResTable_map map_entry = null; // = new ResTable_map(map.myBuf(), curOffset); final int map_entry_end = curOffset + dtohl(map.count) * ResTable_map.SIZEOF; + if (curOffset < map_entry_end) { + map_entry = new ResTable_map(map.myBuf(), curOffset); + } // Keep track of ids that have already been seen to prevent infinite loops caused by circular // dependencies between bags @@ -975,7 +985,7 @@ public class CppAssetManager2 { if (parent_resid.get() == 0 || child_resids.contains(parent_resid.get())) { // There is no parent or that a circular dependency exist, meaning there is nothing to // inherit and we can do a simple copy of the entries in the map. - final int entry_count = (map_entry_end - map_entry.myOffset()) / ResTable_map.SIZEOF; + final int entry_count = (map_entry_end - curOffset) / ResTable_map.SIZEOF; // util.unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>( // malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag.Entry))))}; ResolvedBag new_bag = new ResolvedBag(); @@ -1045,13 +1055,13 @@ public class CppAssetManager2 { final ResolvedBag.Entry[] new_entry = new_bag.entries; int newEntryIndex = 0; - // const ResolvedBag::Entry* parent_entry = parent_bag->entries; + // const ResolvedBag::Entry* parent_entry = parent_bag->entries; int parentEntryIndex = 0; // final ResolvedBag.Entry parent_entry_end = parent_entry + parent_bag.entry_count; final int parentEntryCount = parent_bag.entry_count; // The keys are expected to be in sorted order. Merge the two bags. - while (map_entry.myOffset() != map_entry_end && parentEntryIndex != parentEntryCount) { + while (map_entry != null && map_entry.myOffset() != map_entry_end && parentEntryIndex != parentEntryCount) { final Ref<Integer> child_keyRef = new Ref<>(dtohl(map_entry.name.ident)); if (!is_internal_resid(child_keyRef.get())) { if (entry.dynamic_ref_table.lookupResourceId(child_keyRef) != NO_ERROR) { @@ -1106,7 +1116,7 @@ public class CppAssetManager2 { } // Finish the child entries if they exist. - while (map_entry.myOffset() != map_entry_end) { + while (map_entry != null && map_entry.myOffset() != map_entry_end) { final Ref<Integer> new_key = new Ref<>(map_entry.name.ident); if (!is_internal_resid(new_key.get())) { if (entry.dynamic_ref_table.lookupResourceId(new_key) != NO_ERROR) { @@ -1170,6 +1180,15 @@ public class CppAssetManager2 { return result2; } + String GetResourceName(int resid) { + ResourceName out_name = new ResourceName(); + if (GetResourceName(resid, out_name)) { + return out_name.package_ + ":" + out_name.type + "@" + out_name.entry; + } else { + return null; + } + } + static boolean Utf8ToUtf16(final String str, Ref<String> out) { throw new UnsupportedOperationException(); // ssize_t len = @@ -1260,12 +1279,13 @@ public class CppAssetManager2 { // // // Re-create it. // new (impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>(); - impl.filtered_configs_ = new ByteBucketArray<FilteredConfigGroup>() { - @Override - FilteredConfigGroup newInstance() { - return new FilteredConfigGroup(); - } - }; + impl.filtered_configs_ = + new ByteBucketArray<FilteredConfigGroup>(new FilteredConfigGroup()) { + @Override + FilteredConfigGroup newInstance() { + return new FilteredConfigGroup(); + } + }; // Create the filters here. impl.loaded_package_.ForEachTypeSpec((TypeSpec spec, byte type_index) -> { diff --git a/resources/src/main/java/org/robolectric/res/android/DynamicRefTable.java b/resources/src/main/java/org/robolectric/res/android/DynamicRefTable.java index 8836028b7..208075373 100644 --- a/resources/src/main/java/org/robolectric/res/android/DynamicRefTable.java +++ b/resources/src/main/java/org/robolectric/res/android/DynamicRefTable.java @@ -1,6 +1,6 @@ package org.robolectric.res.android; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/include/androidfw/ResourceTypes.h +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h import static org.robolectric.res.android.Errors.NO_ERROR; import static org.robolectric.res.android.Errors.UNKNOWN_ERROR; @@ -92,7 +92,7 @@ public class DynamicRefTable return NO_ERROR; } -// // Performs the actual conversion of build-time resource ID to run-time + // // Performs the actual conversion of build-time resource ID to run-time // // resource ID. int lookupResourceId(Ref<Integer> resId) { int res = resId.get(); @@ -129,7 +129,7 @@ public class DynamicRefTable resId.set((res & 0x00ffffff) | (((int) translatedId) << 24)); return NO_ERROR; } -// + // int lookupResourceValue(Ref<Res_value> value) { byte resolvedType = DataType.REFERENCE.code(); Res_value inValue = value.get(); @@ -163,7 +163,7 @@ public class DynamicRefTable value.set(new Res_value(resolvedType, resIdRef.get())); return NO_ERROR; - } + } public Map<String, Byte> entries() { return mEntries; @@ -175,7 +175,7 @@ public class DynamicRefTable //} // // private: - final byte mAssignedPackageId; + final byte mAssignedPackageId; final byte[] mLookupTable = new byte[256]; final Map<String, Byte> mEntries = new HashMap<>(); boolean mAppAsLib; diff --git a/resources/src/main/java/org/robolectric/res/android/Errors.java b/resources/src/main/java/org/robolectric/res/android/Errors.java index 04fb8942c..0cab2b773 100644 --- a/resources/src/main/java/org/robolectric/res/android/Errors.java +++ b/resources/src/main/java/org/robolectric/res/android/Errors.java @@ -1,6 +1,6 @@ package org.robolectric.res.android; -// transliterated from https://android.googlesource.com/platform/system/core/+/android-9.0.0_r3/include/utils/Errors.h +// transliterated from https://android.googlesource.com/platform/system/core/+/android-9.0.0_r12/include/utils/Errors.h public class Errors { diff --git a/resources/src/main/java/org/robolectric/res/android/Idmap.java b/resources/src/main/java/org/robolectric/res/android/Idmap.java index d71c25069..65a1e0d42 100644 --- a/resources/src/main/java/org/robolectric/res/android/Idmap.java +++ b/resources/src/main/java/org/robolectric/res/android/Idmap.java @@ -1,8 +1,8 @@ package org.robolectric.res.android; // transliterated from -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/Idmap.cpp and -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/Idmap.h +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/Idmap.cpp and +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/Idmap.h import static org.robolectric.res.android.Util.ATRACE_CALL; import static org.robolectric.res.android.Util.SIZEOF_CPTR; @@ -130,7 +130,7 @@ class Idmap { // return true; } -// LoadedIdmap::LoadedIdmap(const Idmap_header* header) : header_(header) { + // LoadedIdmap::LoadedIdmap(const Idmap_header* header) : header_(header) { // size_t length = strnlen(reinterpret_cast<const char*>(header_->overlay_path), // arraysize(header_->overlay_path)); // overlay_apk_path_.assign(reinterpret_cast<const char*>(header_->overlay_path), length); @@ -148,7 +148,7 @@ class Idmap { // Can't use make_unique because LoadedImpl constructor is private. LoadedIdmap loaded_idmap = new LoadedIdmap(header); - // const byte* data_ptr = reinterpret_cast<const byte*>(idmap_data.data()) + sizeof(*header); + // const byte* data_ptr = reinterpret_cast<const byte*>(idmap_data.data()) + sizeof(*header); StringPiece data_ptr = new StringPiece(idmap_data.myBuf(), idmap_data.myOffset() + SIZEOF_CPTR); // int data_size = idmap_data.size() - sizeof(*header); @@ -162,7 +162,7 @@ class Idmap { } // Validate the type IDs. - // IdmapEntry_header entry_header = reinterpret_cast<const IdmapEntry_header*>(data_ptr); + // IdmapEntry_header entry_header = reinterpret_cast<const IdmapEntry_header*>(data_ptr); IdmapEntry_header entry_header = new IdmapEntry_header(data_ptr.myBuf(), data_ptr.myOffset()); if (!is_valid_type_id(dtohs(entry_header.target_type_id)) || !is_valid_type_id(dtohs(entry_header.overlay_type_id))) { logError(String.format("Invalid type map (0x%02x -> 0x%02x)", diff --git a/resources/src/main/java/org/robolectric/res/android/IdmapEntries.java b/resources/src/main/java/org/robolectric/res/android/IdmapEntries.java index 5e394ecf1..0ea0d9a55 100644 --- a/resources/src/main/java/org/robolectric/res/android/IdmapEntries.java +++ b/resources/src/main/java/org/robolectric/res/android/IdmapEntries.java @@ -2,7 +2,7 @@ package org.robolectric.res.android; import static org.robolectric.res.android.Errors.*; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ResourceTypes.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceTypes.cpp public class IdmapEntries { public boolean hasEntries() { diff --git a/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java b/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java index 76a6a6762..3d3df2fa4 100644 --- a/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java +++ b/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java @@ -39,8 +39,8 @@ import org.robolectric.res.android.ResourceTypes.ResTable_type; import org.robolectric.res.android.ResourceTypes.ResTable_typeSpec; import org.robolectric.res.android.ResourceTypes.Res_value; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/LoadedArsc.h -// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/LoadedArsc.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/LoadedArsc.h +// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/LoadedArsc.cpp public class LoadedArsc { //#ifndef LOADEDARSC_H_ @@ -79,7 +79,7 @@ public class LoadedArsc { static class TypeSpec { public static final int SIZEOF = ResTable_typeSpec.SIZEOF + IdmapEntry_header.SIZEOF; - + // Pointer to the mmapped data where flags are kept. // Flags denote whether the resource entry is public // and under which configurations it varies. @@ -205,7 +205,7 @@ public class LoadedArsc { // memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(ElementType)); for (int i = 0; i < type_spec.types.length; i++) { type_spec.types[i] = types_.get(i); - + } return type_spec; } @@ -730,7 +730,7 @@ public class LoadedArsc { String package_name = Util.ReadUtf16StringFromDevice(entry_iter.packageName, entry_iter.packageName.length); - + if (dtohl(entry_iter.packageId) >= 255) { logError(String.format( "Package ID %02x in RES_TABLE_LIBRARY_TYPE too large for package '%s'.", @@ -837,7 +837,7 @@ public class LoadedArsc { } void ForEachTypeSpec(TypeSpecFunc f) { - for (int i = 0; i < type_specs_.size(); i++) { + for (Integer i : type_specs_.keySet()) { TypeSpec ptr = type_specs_.get(i); if (ptr != null) { byte type_id = ptr.type_spec.id; diff --git a/resources/src/main/java/org/robolectric/res/android/LocaleData.java b/resources/src/main/java/org/robolectric/res/android/LocaleData.java index 6d0d96287..0fe00f5da 100644 --- a/resources/src/main/java/org/robolectric/res/android/LocaleData.java +++ b/resources/src/main/java/org/robolectric/res/android/LocaleData.java @@ -9,7 +9,7 @@ import static org.robolectric.res.android.LocaleDataTables.SCRIPT_PARENTS; import java.util.Arrays; import java.util.Map; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/LocaleData.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/LocaleData.cpp public class LocaleData { private static int packLocale(final byte[] language, final byte[] region) { diff --git a/resources/src/main/java/org/robolectric/res/android/LocaleDataTables.java b/resources/src/main/java/org/robolectric/res/android/LocaleDataTables.java index a08e888cb..2cbfce281 100644 --- a/resources/src/main/java/org/robolectric/res/android/LocaleDataTables.java +++ b/resources/src/main/java/org/robolectric/res/android/LocaleDataTables.java @@ -6,100 +6,100 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/LocaleDataTables.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/LocaleDataTables.cpp public class LocaleDataTables { // Auto-generated by ./tools/localedata/extract_icu_data.py static final byte[][] SCRIPT_CODES = { - /* 0 */ {'A', 'h', 'o', 'm'}, - /* 1 */ {'A', 'r', 'a', 'b'}, - /* 2 */ {'A', 'r', 'm', 'i'}, - /* 3 */ {'A', 'r', 'm', 'n'}, - /* 4 */ {'A', 'v', 's', 't'}, - /* 5 */ {'B', 'a', 'm', 'u'}, - /* 6 */ {'B', 'a', 's', 's'}, - /* 7 */ {'B', 'e', 'n', 'g'}, - /* 8 */ {'B', 'r', 'a', 'h'}, - /* 9 */ {'C', 'a', 'n', 's'}, - /* 10 */ {'C', 'a', 'r', 'i'}, - /* 11 */ {'C', 'h', 'a', 'm'}, - /* 12 */ {'C', 'h', 'e', 'r'}, - /* 13 */ {'C', 'o', 'p', 't'}, - /* 14 */ {'C', 'p', 'r', 't'}, - /* 15 */ {'C', 'y', 'r', 'l'}, - /* 16 */ {'D', 'e', 'v', 'a'}, - /* 17 */ {'E', 'g', 'y', 'p'}, - /* 18 */ {'E', 't', 'h', 'i'}, - /* 19 */ {'G', 'e', 'o', 'r'}, - /* 20 */ {'G', 'o', 't', 'h'}, - /* 21 */ {'G', 'r', 'e', 'k'}, - /* 22 */ {'G', 'u', 'j', 'r'}, - /* 23 */ {'G', 'u', 'r', 'u'}, - /* 24 */ {'H', 'a', 'n', 's'}, - /* 25 */ {'H', 'a', 'n', 't'}, - /* 26 */ {'H', 'a', 't', 'r'}, - /* 27 */ {'H', 'e', 'b', 'r'}, - /* 28 */ {'H', 'l', 'u', 'w'}, - /* 29 */ {'H', 'm', 'n', 'g'}, - /* 30 */ {'I', 't', 'a', 'l'}, - /* 31 */ {'J', 'p', 'a', 'n'}, - /* 32 */ {'K', 'a', 'l', 'i'}, - /* 33 */ {'K', 'a', 'n', 'a'}, - /* 34 */ {'K', 'h', 'a', 'r'}, - /* 35 */ {'K', 'h', 'm', 'r'}, - /* 36 */ {'K', 'n', 'd', 'a'}, - /* 37 */ {'K', 'o', 'r', 'e'}, - /* 38 */ {'L', 'a', 'n', 'a'}, - /* 39 */ {'L', 'a', 'o', 'o'}, - /* 40 */ {'L', 'a', 't', 'n'}, - /* 41 */ {'L', 'e', 'p', 'c'}, - /* 42 */ {'L', 'i', 'n', 'a'}, - /* 43 */ {'L', 'i', 's', 'u'}, - /* 44 */ {'L', 'y', 'c', 'i'}, - /* 45 */ {'L', 'y', 'd', 'i'}, - /* 46 */ {'M', 'a', 'n', 'd'}, - /* 47 */ {'M', 'a', 'n', 'i'}, - /* 48 */ {'M', 'e', 'r', 'c'}, - /* 49 */ {'M', 'l', 'y', 'm'}, - /* 50 */ {'M', 'o', 'n', 'g'}, - /* 51 */ {'M', 'r', 'o', 'o'}, - /* 52 */ {'M', 'y', 'm', 'r'}, - /* 53 */ {'N', 'a', 'r', 'b'}, - /* 54 */ {'N', 'k', 'o', 'o'}, - /* 55 */ {'O', 'g', 'a', 'm'}, - /* 56 */ {'O', 'r', 'k', 'h'}, - /* 57 */ {'O', 'r', 'y', 'a'}, - /* 58 */ {'O', 's', 'g', 'e'}, - /* 59 */ {'P', 'a', 'u', 'c'}, - /* 60 */ {'P', 'h', 'l', 'i'}, - /* 61 */ {'P', 'h', 'n', 'x'}, - /* 62 */ {'P', 'l', 'r', 'd'}, - /* 63 */ {'P', 'r', 't', 'i'}, - /* 64 */ {'R', 'u', 'n', 'r'}, - /* 65 */ {'S', 'a', 'm', 'r'}, - /* 66 */ {'S', 'a', 'r', 'b'}, - /* 67 */ {'S', 'a', 'u', 'r'}, - /* 68 */ {'S', 'g', 'n', 'w'}, - /* 69 */ {'S', 'i', 'n', 'h'}, - /* 70 */ {'S', 'o', 'r', 'a'}, - /* 71 */ {'S', 'y', 'r', 'c'}, - /* 72 */ {'T', 'a', 'l', 'e'}, - /* 73 */ {'T', 'a', 'l', 'u'}, - /* 74 */ {'T', 'a', 'm', 'l'}, - /* 75 */ {'T', 'a', 'n', 'g'}, - /* 76 */ {'T', 'a', 'v', 't'}, - /* 77 */ {'T', 'e', 'l', 'u'}, - /* 78 */ {'T', 'f', 'n', 'g'}, - /* 79 */ {'T', 'h', 'a', 'a'}, - /* 80 */ {'T', 'h', 'a', 'i'}, - /* 81 */ {'T', 'i', 'b', 't'}, - /* 82 */ {'U', 'g', 'a', 'r'}, - /* 83 */ {'V', 'a', 'i', 'i'}, - /* 84 */ {'X', 'p', 'e', 'o'}, - /* 85 */ {'X', 's', 'u', 'x'}, - /* 86 */ {'Y', 'i', 'i', 'i'}, - /* 87 */ {'~', '~', '~', 'A'}, - /* 88 */ {'~', '~', '~', 'B'}, + /* 0 */ {'A', 'h', 'o', 'm'}, + /* 1 */ {'A', 'r', 'a', 'b'}, + /* 2 */ {'A', 'r', 'm', 'i'}, + /* 3 */ {'A', 'r', 'm', 'n'}, + /* 4 */ {'A', 'v', 's', 't'}, + /* 5 */ {'B', 'a', 'm', 'u'}, + /* 6 */ {'B', 'a', 's', 's'}, + /* 7 */ {'B', 'e', 'n', 'g'}, + /* 8 */ {'B', 'r', 'a', 'h'}, + /* 9 */ {'C', 'a', 'n', 's'}, + /* 10 */ {'C', 'a', 'r', 'i'}, + /* 11 */ {'C', 'h', 'a', 'm'}, + /* 12 */ {'C', 'h', 'e', 'r'}, + /* 13 */ {'C', 'o', 'p', 't'}, + /* 14 */ {'C', 'p', 'r', 't'}, + /* 15 */ {'C', 'y', 'r', 'l'}, + /* 16 */ {'D', 'e', 'v', 'a'}, + /* 17 */ {'E', 'g', 'y', 'p'}, + /* 18 */ {'E', 't', 'h', 'i'}, + /* 19 */ {'G', 'e', 'o', 'r'}, + /* 20 */ {'G', 'o', 't', 'h'}, + /* 21 */ {'G', 'r', 'e', 'k'}, + /* 22 */ {'G', 'u', 'j', 'r'}, + /* 23 */ {'G', 'u', 'r', 'u'}, + /* 24 */ {'H', 'a', 'n', 's'}, + /* 25 */ {'H', 'a', 'n', 't'}, + /* 26 */ {'H', 'a', 't', 'r'}, + /* 27 */ {'H', 'e', 'b', 'r'}, + /* 28 */ {'H', 'l', 'u', 'w'}, + /* 29 */ {'H', 'm', 'n', 'g'}, + /* 30 */ {'I', 't', 'a', 'l'}, + /* 31 */ {'J', 'p', 'a', 'n'}, + /* 32 */ {'K', 'a', 'l', 'i'}, + /* 33 */ {'K', 'a', 'n', 'a'}, + /* 34 */ {'K', 'h', 'a', 'r'}, + /* 35 */ {'K', 'h', 'm', 'r'}, + /* 36 */ {'K', 'n', 'd', 'a'}, + /* 37 */ {'K', 'o', 'r', 'e'}, + /* 38 */ {'L', 'a', 'n', 'a'}, + /* 39 */ {'L', 'a', 'o', 'o'}, + /* 40 */ {'L', 'a', 't', 'n'}, + /* 41 */ {'L', 'e', 'p', 'c'}, + /* 42 */ {'L', 'i', 'n', 'a'}, + /* 43 */ {'L', 'i', 's', 'u'}, + /* 44 */ {'L', 'y', 'c', 'i'}, + /* 45 */ {'L', 'y', 'd', 'i'}, + /* 46 */ {'M', 'a', 'n', 'd'}, + /* 47 */ {'M', 'a', 'n', 'i'}, + /* 48 */ {'M', 'e', 'r', 'c'}, + /* 49 */ {'M', 'l', 'y', 'm'}, + /* 50 */ {'M', 'o', 'n', 'g'}, + /* 51 */ {'M', 'r', 'o', 'o'}, + /* 52 */ {'M', 'y', 'm', 'r'}, + /* 53 */ {'N', 'a', 'r', 'b'}, + /* 54 */ {'N', 'k', 'o', 'o'}, + /* 55 */ {'O', 'g', 'a', 'm'}, + /* 56 */ {'O', 'r', 'k', 'h'}, + /* 57 */ {'O', 'r', 'y', 'a'}, + /* 58 */ {'O', 's', 'g', 'e'}, + /* 59 */ {'P', 'a', 'u', 'c'}, + /* 60 */ {'P', 'h', 'l', 'i'}, + /* 61 */ {'P', 'h', 'n', 'x'}, + /* 62 */ {'P', 'l', 'r', 'd'}, + /* 63 */ {'P', 'r', 't', 'i'}, + /* 64 */ {'R', 'u', 'n', 'r'}, + /* 65 */ {'S', 'a', 'm', 'r'}, + /* 66 */ {'S', 'a', 'r', 'b'}, + /* 67 */ {'S', 'a', 'u', 'r'}, + /* 68 */ {'S', 'g', 'n', 'w'}, + /* 69 */ {'S', 'i', 'n', 'h'}, + /* 70 */ {'S', 'o', 'r', 'a'}, + /* 71 */ {'S', 'y', 'r', 'c'}, + /* 72 */ {'T', 'a', 'l', 'e'}, + /* 73 */ {'T', 'a', 'l', 'u'}, + /* 74 */ {'T', 'a', 'm', 'l'}, + /* 75 */ {'T', 'a', 'n', 'g'}, + /* 76 */ {'T', 'a', 'v', 't'}, + /* 77 */ {'T', 'e', 'l', 'u'}, + /* 78 */ {'T', 'f', 'n', 'g'}, + /* 79 */ {'T', 'h', 'a', 'a'}, + /* 80 */ {'T', 'h', 'a', 'i'}, + /* 81 */ {'T', 'i', 'b', 't'}, + /* 82 */ {'U', 'g', 'a', 'r'}, + /* 83 */ {'V', 'a', 'i', 'i'}, + /* 84 */ {'X', 'p', 'e', 'o'}, + /* 85 */ {'X', 's', 'u', 'x'}, + /* 86 */ {'Y', 'i', 'i', 'i'}, + /* 87 */ {'~', '~', '~', 'A'}, + /* 88 */ {'~', '~', '~', 'B'}, }; static final Map<Integer, Byte> LIKELY_SCRIPTS; diff --git a/resources/src/main/java/org/robolectric/res/android/ResStringPool.java b/resources/src/main/java/org/robolectric/res/android/ResStringPool.java index d08f5dd98..7180a3328 100644 --- a/resources/src/main/java/org/robolectric/res/android/ResStringPool.java +++ b/resources/src/main/java/org/robolectric/res/android/ResStringPool.java @@ -1,7 +1,7 @@ package org.robolectric.res.android; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ResourceTypes.cpp -// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/include/androidfw/ResourceTypes.h +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceTypes.cpp +// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h import static org.robolectric.res.android.Errors.BAD_TYPE; import static org.robolectric.res.android.Errors.NAME_NOT_FOUND; @@ -38,25 +38,25 @@ public class ResStringPool { private int mError; - byte[] mOwnedData; + byte[] mOwnedData; //private Object mOwnedData; private ResStringPool_header mHeader; private int mSize; -// private mutable Mutex mDecodeLock; + // private mutable Mutex mDecodeLock; // const uint32_t* mEntries; private IntArray mEntries; -// const uint32_t* mEntryStyles; - private IntArray mEntryStyles; -// const void* mStrings; - private int mStrings; + // const uint32_t* mEntryStyles; + private IntArray mEntryStyles; + // const void* mStrings; + private int mStrings; //private List<String> mStrings; //private String[] mCache; //private char16_t mutable** mCache; - private int mStringPoolSize; // number of uint16_t -// const uint32_t* mStyles; - private int mStyles; - private int mStylePoolSize; // number of int + private int mStringPoolSize; // number of uint16_t + // const uint32_t* mStyles; + private int mStyles; + private int mStylePoolSize; // number of int public ResStringPool() { mError = NO_INIT; @@ -242,8 +242,8 @@ public class ResStringPool { if (isTruthy(mHeader.flags&ResStringPool_header.UTF8_FLAG) && (mHeader.getByte(mStrings + mStringPoolSize-1) != 0) || - (!isTruthy(mHeader.flags&ResStringPool_header.UTF8_FLAG) && - ((mHeader.getShort(mStrings + mStringPoolSize*2-2) != 0)))) { + (!isTruthy(mHeader.flags&ResStringPool_header.UTF8_FLAG) && + ((mHeader.getShort(mStrings + mStringPoolSize*2-2) != 0)))) { ALOGW("Bad string block: last string is not 0-terminated\n"); return (mError=BAD_TYPE); } @@ -264,7 +264,7 @@ public class ResStringPool { if ((mEntryStyles.myOffset() - mHeader.myOffset()) > (int)size) { ALOGW("Bad string block: entry of %d styles extends past data size %d\n", (int)(mEntryStyles.myOffset()), - (int)size); + (int)size); return (mError=BAD_TYPE); } mStyles = mHeader.stylesStart; @@ -327,13 +327,13 @@ public class ResStringPool { public String stringAt(int idx) { if (mError == NO_ERROR && idx < mHeader.stringCount) { - final boolean isUTF8 = (mHeader.flags&ResStringPool_header.UTF8_FLAG) != 0; + final boolean isUTF8 = (mHeader.flags&ResStringPool_header.UTF8_FLAG) != 0; // const uint32_t off = mEntries[idx]/(isUTF8?sizeof(uint8_t):sizeof(uint16_t)); ByteBuffer buf = mHeader.myBuf(); int bufOffset = mHeader.myOffset(); // const uint32_t off = mEntries[idx]/(isUTF8?sizeof(uint8_t):sizeof(uint16_t)); final int off = mEntries.get(idx) - /(isUTF8?1/*sizeof(uint8_t)*/:2/*sizeof(uint16_t)*/); + /(isUTF8?1/*sizeof(uint8_t)*/:2/*sizeof(uint16_t)*/); if (off < (mStringPoolSize-1)) { if (!isUTF8) { final int strings = mStrings; @@ -535,18 +535,18 @@ public class ResStringPool { return NAME_NOT_FOUND; } -// - public int size() { - return mError == NO_ERROR ? mHeader.stringCount : 0; - } + // + public int size() { + return mError == NO_ERROR ? mHeader.stringCount : 0; + } - int styleCount() { - return mError == NO_ERROR ? mHeader.styleCount : 0; - } + int styleCount() { + return mError == NO_ERROR ? mHeader.styleCount : 0; + } - int bytes() { - return mError == NO_ERROR ? mHeader.header.size : 0; - } + int bytes() { + return mError == NO_ERROR ? mHeader.header.size : 0; + } public boolean isUTF8() { return true; diff --git a/resources/src/main/java/org/robolectric/res/android/ResStringPoolHeader.java b/resources/src/main/java/org/robolectric/res/android/ResStringPoolHeader.java index 30eb7b1b4..308ab6843 100644 --- a/resources/src/main/java/org/robolectric/res/android/ResStringPoolHeader.java +++ b/resources/src/main/java/org/robolectric/res/android/ResStringPoolHeader.java @@ -17,7 +17,7 @@ import org.robolectric.res.android.ResourceTypes.ResChunk_header; * into a style table starting at stylesStart. Each entry in the * style table is an array of ResStringPool_span structures. */ -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/include/androidfw/ResourceTypes.h#434 +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h#434 public class ResStringPoolHeader { public static final int SIZEOF = ResChunk_header.SIZEOF + 20; diff --git a/resources/src/main/java/org/robolectric/res/android/ResTable.java b/resources/src/main/java/org/robolectric/res/android/ResTable.java index f94c00bad..24e232684 100644 --- a/resources/src/main/java/org/robolectric/res/android/ResTable.java +++ b/resources/src/main/java/org/robolectric/res/android/ResTable.java @@ -46,8 +46,8 @@ import org.robolectric.res.android.ResourceTypes.ResTable_type; import org.robolectric.res.android.ResourceTypes.ResTable_typeSpec; import org.robolectric.res.android.ResourceTypes.Res_value; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ResourceTypes.cpp -// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/include/androidfw/ResourceTypes.h +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceTypes.cpp +// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h @SuppressWarnings("NewApi") public class ResTable { @@ -140,7 +140,7 @@ public class ResTable { // copyData); // } -// status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false, + // status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false, // bool appAsLib=false, bool isSystemAsset=false); int add( Asset asset, Asset idmapAsset, final int cookie, boolean copyData, @@ -216,7 +216,7 @@ public class ResTable { return (mError=NO_ERROR); } -// status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize, + // status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize, // bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false); int addInternal(byte[] data, int dataSize, final Object idmapData, int idmapDataSize, boolean appAsLib, final int cookie, boolean copyData, boolean isSystemAsset) @@ -295,52 +295,52 @@ public class ResTable { // (const ResChunk_header*)(((const uint8_t*)header->header) // + dtohs(header->header->header.headerSize)); ResChunk_header chunk = - new ResChunk_header(buf, dtohs(header.header.header.headerSize)); + new ResChunk_header(buf, dtohs(header.header.header.headerSize)); while (chunk != null && (chunk.myOffset()) <= (header.dataEnd -ResChunk_header.SIZEOF) && - (chunk.myOffset()) <= (header.dataEnd -dtohl(chunk.size))) { - int err = validate_chunk(chunk, ResChunk_header.SIZEOF, header.dataEnd, "ResTable"); - if (err != NO_ERROR) { - return (mError=err); - } - if (kDebugTableNoisy) { - ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n", - dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size), - (Object)((chunk.myOffset()) - (header.header.myOffset()))); - } - final int csize = dtohl(chunk.size); - final int ctype = dtohs(chunk.type); - if (ctype == RES_STRING_POOL_TYPE) { - if (header.values.getError() != NO_ERROR) { - // Only use the first string chunk; ignore any others that - // may appear. - err = header.values.setTo(chunk.myBuf(), chunk.myOffset(), csize, false); - if (err != NO_ERROR) { - return (mError=err); - } - } else { - ALOGW("Multiple string chunks found in resource table."); + (chunk.myOffset()) <= (header.dataEnd -dtohl(chunk.size))) { + int err = validate_chunk(chunk, ResChunk_header.SIZEOF, header.dataEnd, "ResTable"); + if (err != NO_ERROR) { + return (mError=err); } - } else if (ctype == RES_TABLE_PACKAGE_TYPE) { - if (curPackage >= dtohl(header.header.packageCount)) { - ALOGW("More package chunks were found than the %d declared in the header.", - dtohl(header.header.packageCount)); - return (mError=BAD_TYPE); + if (kDebugTableNoisy) { + ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n", + dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size), + (Object)((chunk.myOffset()) - (header.header.myOffset()))); } + final int csize = dtohl(chunk.size); + final int ctype = dtohs(chunk.type); + if (ctype == RES_STRING_POOL_TYPE) { + if (header.values.getError() != NO_ERROR) { + // Only use the first string chunk; ignore any others that + // may appear. + err = header.values.setTo(chunk.myBuf(), chunk.myOffset(), csize, false); + if (err != NO_ERROR) { + return (mError=err); + } + } else { + ALOGW("Multiple string chunks found in resource table."); + } + } else if (ctype == RES_TABLE_PACKAGE_TYPE) { + if (curPackage >= dtohl(header.header.packageCount)) { + ALOGW("More package chunks were found than the %d declared in the header.", + dtohl(header.header.packageCount)); + return (mError=BAD_TYPE); + } - if (parsePackage( - new ResTable_package(chunk.myBuf(), chunk.myOffset()), header, appAsLib, isSystemAsset) != NO_ERROR) { - return mError; + if (parsePackage( + new ResTable_package(chunk.myBuf(), chunk.myOffset()), header, appAsLib, isSystemAsset) != NO_ERROR) { + return mError; + } + curPackage++; + } else { + ALOGW("Unknown chunk type 0x%x in table at 0x%x.\n", + ctype, + (chunk.myOffset()) - (header.header.myOffset())); } - curPackage++; - } else { - ALOGW("Unknown chunk type 0x%x in table at 0x%x.\n", - ctype, - (chunk.myOffset()) - (header.header.myOffset())); + chunk = chunk.myOffset() + csize < header.dataEnd + ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize) + : null; } - chunk = chunk.myOffset() + csize < header.dataEnd - ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize) - : null; - } if (curPackage < dtohl(header.header.packageCount)) { ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.", @@ -436,10 +436,10 @@ public class ResTable { // } if (outSpecFlags != null) { - outSpecFlags.set(entry.specFlags); + outSpecFlags.set(entry.specFlags); } if (outConfig != null) { - outConfig.set(entry.config); + outConfig.set(entry.config); } return entry._package_.header.index; } @@ -495,8 +495,8 @@ public class ResTable { } ResTable_sparseTypeEntry lower_bound(ResTable_sparseTypeEntry first, ResTable_sparseTypeEntry last, - ResTable_sparseTypeEntry value, - Compare comparator) { + ResTable_sparseTypeEntry value, + Compare comparator) { int count = (last.myOffset() - first.myOffset()) / ResTable_sparseTypeEntry.SIZEOF; int itOffset; int step; @@ -705,7 +705,7 @@ public class ResTable { ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry.size)); return BAD_TYPE; } - + if (outEntry != null) { outEntry.entry = entry; outEntry.config = bestConfig; @@ -719,11 +719,11 @@ public class ResTable { } int parsePackage(ResTable_package pkg, - Header header, boolean appAsLib, boolean isSystemAsset) + Header header, boolean appAsLib, boolean isSystemAsset) { int base = pkg.myOffset(); int err = validate_chunk(pkg.header, ResTable_package.SIZEOF - 4 /*sizeof(pkg.typeIdOffset)*/, - header.dataEnd, "ResTable_package"); + header.dataEnd, "ResTable_package"); if (err != NO_ERROR) { return (mError=err); } @@ -778,13 +778,13 @@ public class ResTable { PackageGroup group = null; Package _package = new Package(this, header, pkg); if (_package == NULL) { - return (mError=NO_MEMORY); - } + return (mError=NO_MEMORY); + } // err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings), // header->dataEnd-(base+dtohl(pkg->typeStrings))); err = _package.typeStrings.setTo(pkg.myBuf(), base+dtohl(pkg.typeStrings), - header.dataEnd -(base+dtohl(pkg.typeStrings)), false); + header.dataEnd -(base+dtohl(pkg.typeStrings)), false); if (err != NO_ERROR) { // delete group; // delete _package; @@ -794,7 +794,7 @@ public class ResTable { // err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings), // header->dataEnd-(base+dtohl(pkg->keyStrings))); err = _package.keyStrings.setTo(pkg.myBuf(), base+dtohl(pkg.keyStrings), - header.dataEnd -(base+dtohl(pkg.keyStrings)), false); + header.dataEnd -(base+dtohl(pkg.keyStrings)), false); if (err != NO_ERROR) { // delete group; // delete _package; @@ -841,177 +841,177 @@ public class ResTable { // Iterate through all chunks. ResChunk_header chunk = - new ResChunk_header(pkg.myBuf(), pkg.myOffset() + dtohs(pkg.header.headerSize)); + new ResChunk_header(pkg.myBuf(), pkg.myOffset() + dtohs(pkg.header.headerSize)); // const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size); final int endPos = (pkg.myOffset()) + pkg.header.size; // while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) && // ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) { while (chunk != null && (chunk.myOffset()) <= (endPos-ResChunk_header.SIZEOF) && - (chunk.myOffset()) <= (endPos-dtohl(chunk.size))) { - if (kDebugTableNoisy) { - ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n", - dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size), - ((chunk.myOffset()) - (header.header.myOffset()))); - } - final int csize = dtohl(chunk.size); - final short ctype = dtohs(chunk.type); - if (ctype == RES_TABLE_TYPE_SPEC_TYPE) { - final ResTable_typeSpec typeSpec = new ResTable_typeSpec(chunk.myBuf(), chunk.myOffset()); - err = validate_chunk(typeSpec.header, ResTable_typeSpec.SIZEOF, - endPos, "ResTable_typeSpec"); - if (err != NO_ERROR) { - return (mError=err); + (chunk.myOffset()) <= (endPos-dtohl(chunk.size))) { + if (kDebugTableNoisy) { + ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%s\n", + dtohs(chunk.type), dtohs(chunk.headerSize), dtohl(chunk.size), + ((chunk.myOffset()) - (header.header.myOffset()))); } + final int csize = dtohl(chunk.size); + final short ctype = dtohs(chunk.type); + if (ctype == RES_TABLE_TYPE_SPEC_TYPE) { + final ResTable_typeSpec typeSpec = new ResTable_typeSpec(chunk.myBuf(), chunk.myOffset()); + err = validate_chunk(typeSpec.header, ResTable_typeSpec.SIZEOF, + endPos, "ResTable_typeSpec"); + if (err != NO_ERROR) { + return (mError=err); + } - final int typeSpecSize = dtohl(typeSpec.header.size); - final int newEntryCount = dtohl(typeSpec.entryCount); - - if (kDebugLoadTableNoisy) { - ALOGI("TypeSpec off %s: type=0x%x, headerSize=0x%x, size=%s\n", - (base-chunk.myOffset()), - dtohs(typeSpec.header.type), - dtohs(typeSpec.header.headerSize), - typeSpecSize); - } - // look for block overrun or int overflow when multiplying by 4 - if ((dtohl(typeSpec.entryCount) > (Integer.MAX_VALUE/4 /*sizeof(int)*/) - || dtohs(typeSpec.header.headerSize)+(4 /*sizeof(int)*/*newEntryCount) - > typeSpecSize)) { - ALOGW("ResTable_typeSpec entry index to %s extends beyond chunk end %s.", - (dtohs(typeSpec.header.headerSize) + (4 /*sizeof(int)*/*newEntryCount)), - typeSpecSize); - return (mError=BAD_TYPE); - } + final int typeSpecSize = dtohl(typeSpec.header.size); + final int newEntryCount = dtohl(typeSpec.entryCount); - if (typeSpec.id == 0) { - ALOGW("ResTable_type has an id of 0."); - return (mError=BAD_TYPE); - } + if (kDebugLoadTableNoisy) { + ALOGI("TypeSpec off %s: type=0x%x, headerSize=0x%x, size=%s\n", + (base-chunk.myOffset()), + dtohs(typeSpec.header.type), + dtohs(typeSpec.header.headerSize), + typeSpecSize); + } + // look for block overrun or int overflow when multiplying by 4 + if ((dtohl(typeSpec.entryCount) > (Integer.MAX_VALUE/4 /*sizeof(int)*/) + || dtohs(typeSpec.header.headerSize)+(4 /*sizeof(int)*/*newEntryCount) + > typeSpecSize)) { + ALOGW("ResTable_typeSpec entry index to %s extends beyond chunk end %s.", + (dtohs(typeSpec.header.headerSize) + (4 /*sizeof(int)*/*newEntryCount)), + typeSpecSize); + return (mError=BAD_TYPE); + } - if (newEntryCount > 0) { - boolean addToType = true; - byte typeIndex = (byte) (typeSpec.id - 1); - IdmapEntries idmapEntry = idmapEntries.get(typeSpec.id); - if (idmapEntry != null) { - typeIndex = (byte) (idmapEntry.targetTypeId() - 1); - } else if (header.resourceIDMap != NULL) { - // This is an overlay, but the types in this overlay are not - // overlaying anything according to the idmap. We can skip these - // as they will otherwise conflict with the other resources in the package - // without a mapping. - addToType = false; + if (typeSpec.id == 0) { + ALOGW("ResTable_type has an id of 0."); + return (mError=BAD_TYPE); } - if (addToType) { - List<Type> typeList = computeIfAbsent(group.types, (int) typeIndex, k -> new ArrayList<>()); - if (!typeList.isEmpty()) { - final Type existingType = typeList.get(0); - if (existingType.entryCount != newEntryCount && idmapEntry == null) { - ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d", - (int) newEntryCount, (int) existingType.entryCount); - // We should normally abort here, but some legacy apps declare - // resources in the 'android' package (old bug in AAPT). - } + if (newEntryCount > 0) { + boolean addToType = true; + byte typeIndex = (byte) (typeSpec.id - 1); + IdmapEntries idmapEntry = idmapEntries.get(typeSpec.id); + if (idmapEntry != null) { + typeIndex = (byte) (idmapEntry.targetTypeId() - 1); + } else if (header.resourceIDMap != NULL) { + // This is an overlay, but the types in this overlay are not + // overlaying anything according to the idmap. We can skip these + // as they will otherwise conflict with the other resources in the package + // without a mapping. + addToType = false; } - Type t = new Type(header, _package, newEntryCount); - t.typeSpec = typeSpec; - t.typeSpecFlags = typeSpec.getSpecFlags(); - if (idmapEntry != null) { - t.idmapEntries = idmapEntry; + if (addToType) { + List<Type> typeList = computeIfAbsent(group.types, (int) typeIndex, k -> new ArrayList<>()); + if (!typeList.isEmpty()) { + final Type existingType = typeList.get(0); + if (existingType.entryCount != newEntryCount && idmapEntry == null) { + ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d", + (int) newEntryCount, (int) existingType.entryCount); + // We should normally abort here, but some legacy apps declare + // resources in the 'android' package (old bug in AAPT). + } + } + + Type t = new Type(header, _package, newEntryCount); + t.typeSpec = typeSpec; + t.typeSpecFlags = typeSpec.getSpecFlags(); + if (idmapEntry != null) { + t.idmapEntries = idmapEntry; + } + typeList.add(t); + group.largestTypeId = max(group.largestTypeId, typeSpec.id); } - typeList.add(t); - group.largestTypeId = max(group.largestTypeId, typeSpec.id); + } else { + ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec.id); } - } else { - ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec.id); - } - - } else if (ctype == RES_TABLE_TYPE_TYPE) { - ResTable_type type = new ResTable_type(chunk.myBuf(), chunk.myOffset()); - err = validate_chunk(type.header, ResTable_type.SIZEOF_WITHOUT_CONFIG/*-sizeof(ResTable_config)*/+4, - endPos, "ResTable_type"); - if (err != NO_ERROR) { - return (mError=err); - } - final int typeSize = dtohl(type.header.size); - final int newEntryCount = dtohl(type.entryCount); + } else if (ctype == RES_TABLE_TYPE_TYPE) { + ResTable_type type = new ResTable_type(chunk.myBuf(), chunk.myOffset()); + err = validate_chunk(type.header, ResTable_type.SIZEOF_WITHOUT_CONFIG/*-sizeof(ResTable_config)*/+4, + endPos, "ResTable_type"); + if (err != NO_ERROR) { + return (mError=err); + } - if (kDebugLoadTableNoisy) { - System.out.println(String.format("Type off 0x%x: type=0x%x, headerSize=0x%x, size=%d\n", - base-chunk.myOffset(), - dtohs(type.header.type), - dtohs(type.header.headerSize), - typeSize)); - } - if (dtohs(type.header.headerSize)+(4/*sizeof(int)*/*newEntryCount) > typeSize) { - ALOGW("ResTable_type entry index to %s extends beyond chunk end 0x%x.", - (dtohs(type.header.headerSize) + (4/*sizeof(int)*/*newEntryCount)), - typeSize); - return (mError=BAD_TYPE); - } + final int typeSize = dtohl(type.header.size); + final int newEntryCount = dtohl(type.entryCount); - if (newEntryCount != 0 - && dtohl(type.entriesStart) > (typeSize- ResTable_entry.SIZEOF)) { - ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.", - dtohl(type.entriesStart), typeSize); - return (mError=BAD_TYPE); - } + if (kDebugLoadTableNoisy) { + System.out.println(String.format("Type off 0x%x: type=0x%x, headerSize=0x%x, size=%d\n", + base-chunk.myOffset(), + dtohs(type.header.type), + dtohs(type.header.headerSize), + typeSize)); + } + if (dtohs(type.header.headerSize)+(4/*sizeof(int)*/*newEntryCount) > typeSize) { + ALOGW("ResTable_type entry index to %s extends beyond chunk end 0x%x.", + (dtohs(type.header.headerSize) + (4/*sizeof(int)*/*newEntryCount)), + typeSize); + return (mError=BAD_TYPE); + } - if (type.id == 0) { - ALOGW("ResTable_type has an id of 0."); - return (mError=BAD_TYPE); - } + if (newEntryCount != 0 + && dtohl(type.entriesStart) > (typeSize- ResTable_entry.SIZEOF)) { + ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.", + dtohl(type.entriesStart), typeSize); + return (mError=BAD_TYPE); + } - if (newEntryCount > 0) { - boolean addToType = true; - byte typeIndex = (byte) (type.id - 1); - IdmapEntries idmapEntry = idmapEntries.get(type.id); - if (idmapEntry != null) { - typeIndex = (byte) (idmapEntry.targetTypeId() - 1); - } else if (header.resourceIDMap != NULL) { - // This is an overlay, but the types in this overlay are not - // overlaying anything according to the idmap. We can skip these - // as they will otherwise conflict with the other resources in the package - // without a mapping. - addToType = false; + if (type.id == 0) { + ALOGW("ResTable_type has an id of 0."); + return (mError=BAD_TYPE); } - if (addToType) { - List<Type> typeList = getOrDefault(group.types, (int) typeIndex, Collections.emptyList()); - if (typeList.isEmpty()) { - ALOGE("No TypeSpec for type %d", type.id); - return (mError = BAD_TYPE); + if (newEntryCount > 0) { + boolean addToType = true; + byte typeIndex = (byte) (type.id - 1); + IdmapEntries idmapEntry = idmapEntries.get(type.id); + if (idmapEntry != null) { + typeIndex = (byte) (idmapEntry.targetTypeId() - 1); + } else if (header.resourceIDMap != NULL) { + // This is an overlay, but the types in this overlay are not + // overlaying anything according to the idmap. We can skip these + // as they will otherwise conflict with the other resources in the package + // without a mapping. + addToType = false; } - Type t = typeList.get(typeList.size() - 1); - if (newEntryCount != t.entryCount) { - ALOGE("ResTable_type entry count inconsistent: given %d, previously %d", - (int) newEntryCount, (int) t.entryCount); - return (mError = BAD_TYPE); - } + if (addToType) { + List<Type> typeList = getOrDefault(group.types, (int) typeIndex, Collections.emptyList()); + if (typeList.isEmpty()) { + ALOGE("No TypeSpec for type %d", type.id); + return (mError = BAD_TYPE); + } - if (t._package_ != _package) { - ALOGE("No TypeSpec for type %d", type.id); - return (mError = BAD_TYPE); - } + Type t = typeList.get(typeList.size() - 1); + if (newEntryCount != t.entryCount) { + ALOGE("ResTable_type entry count inconsistent: given %d, previously %d", + (int) newEntryCount, (int) t.entryCount); + return (mError = BAD_TYPE); + } + + if (t._package_ != _package) { + ALOGE("No TypeSpec for type %d", type.id); + return (mError = BAD_TYPE); + } - t.configs.add(type); + t.configs.add(type); - if (kDebugTableGetEntry) { - ResTable_config thisConfig = ResTable_config.fromDtoH(type.config); - ALOGI("Adding config to type %d: %s\n", type.id, - thisConfig.toString()); + if (kDebugTableGetEntry) { + ResTable_config thisConfig = ResTable_config.fromDtoH(type.config); + ALOGI("Adding config to type %d: %s\n", type.id, + thisConfig.toString()); + } } + } else { + ALOGV("Skipping empty ResTable_type for type %d", type.id); } - } else { - ALOGV("Skipping empty ResTable_type for type %d", type.id); - } - } else if (ctype == RES_TABLE_LIBRARY_TYPE) { - if (group.dynamicRefTable.entries().isEmpty()) { - throw new UnsupportedOperationException("libraries not supported yet"); + } else if (ctype == RES_TABLE_LIBRARY_TYPE) { + if (group.dynamicRefTable.entries().isEmpty()) { + throw new UnsupportedOperationException("libraries not supported yet"); // const ResTable_lib_header* lib = (const ResTable_lib_header*) chunk; // status_t err = validate_chunk(&lib->header, sizeof(*lib), // endPos, "ResTable_lib_header"); @@ -1029,18 +1029,18 @@ public class ResTable { // for (size_t i = 0; i < N; i++) { // group.dynamicRefTable.addMapping(mPackageGroups[i].name, mPackageGroups[i].id); // } + } else { + ALOGW("Found multiple library tables, ignoring..."); + } } else { - ALOGW("Found multiple library tables, ignoring..."); - } - } else { - err = validate_chunk(chunk, ResChunk_header.SIZEOF, - endPos, "ResTable_package:unknown"); - if (err != NO_ERROR) { - return (mError=err); + err = validate_chunk(chunk, ResChunk_header.SIZEOF, + endPos, "ResTable_package:unknown"); + if (err != NO_ERROR) { + return (mError=err); + } } - } chunk = chunk.myOffset() + csize < endPos ? new ResChunk_header(chunk.myBuf(), chunk.myOffset() + csize) : null; - } + } return NO_ERROR; } @@ -1068,17 +1068,17 @@ public class ResTable { // Find which configurations match the set of parameters. This allows for a much // faster lookup in getEntry() if the set of values is narrowed down. //for (int t = 0; t < packageGroup.types.size(); t++) { - //if (packageGroup.types.get(t).isEmpty()) { - // continue; - // } - // - // List<Type> typeList = packageGroup.types.get(t); - for (List<Type> typeList : packageGroup.types.values()) { - if (typeList.isEmpty()) { - continue; + //if (packageGroup.types.get(t).isEmpty()) { + // continue; + // } + // + // List<Type> typeList = packageGroup.types.get(t); + for (List<Type> typeList : packageGroup.types.values()) { + if (typeList.isEmpty()) { + continue; } - // Retrieve the cache entry for this type. + // Retrieve the cache entry for this type. //TypeCacheEntry cacheEntry = packageGroup.typeCacheEntries.editItemAt(t); for (int ts = 0; ts < typeList.size(); ts++) { @@ -1195,14 +1195,14 @@ public class ResTable { if (name[nameIndex] == '*') { fakePublic = true; nameIndex++; + } } - } if (nameIndex >= nameEnd) { return 0; } if (packageEnd != -1) { - packageName = nameString.substring(nameIndex, packageEnd); - nameIndex = packageEnd+1; + packageName = nameString.substring(nameIndex, packageEnd); + nameIndex = packageEnd+1; } else if (packageName == null) { return 0; } @@ -1229,7 +1229,7 @@ public class ResTable { for (PackageGroup group : mPackageGroups.values()) { if (!Objects.equals(packageName.trim(), group.name.trim())) { if (kDebugTableNoisy) { - System.out.println(String.format("Skipping package group: %s\n", group.name)); + System.out.println(String.format("Skipping package group: %s\n", group.name)); } continue; } @@ -1245,7 +1245,7 @@ public class ResTable { int identifier = findEntry(group, ti, nameString, outTypeSpecFlags); if (identifier != 0) { if (fakePublic && outTypeSpecFlags != null) { - outTypeSpecFlags.set(outTypeSpecFlags.get() | ResTable_typeSpec.SPEC_PUBLIC); + outTypeSpecFlags.set(outTypeSpecFlags.get() | ResTable_typeSpec.SPEC_PUBLIC); } return identifier; } @@ -2570,12 +2570,13 @@ public class ResTable { // Gets cleared whenever the parameters/configuration changes. // These are stored here in a parallel structure because the data in `types` may // be shared by other ResTable's (framework resources are shared this way). - ByteBucketArray<TypeCacheEntry> typeCacheEntries = new ByteBucketArray<TypeCacheEntry>() { - @Override - TypeCacheEntry newInstance() { - return new TypeCacheEntry(); - } - }; + ByteBucketArray<TypeCacheEntry> typeCacheEntries = + new ByteBucketArray<TypeCacheEntry>(new TypeCacheEntry()) { + @Override + TypeCacheEntry newInstance() { + return new TypeCacheEntry(); + } + }; // The table mapping dynamic references to resolved references for // this package group. @@ -2594,7 +2595,7 @@ public class ResTable { // -------------------------------------------------------------------- // -------------------------------------------------------------------- -// struct ResTable::Header + // struct ResTable::Header public static class Header { // Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL), @@ -2645,8 +2646,8 @@ public class ResTable { public List<ResTable_type> configs; public Type(final Header _header, final Package _package, int count) - // : header(_header), package(_package), entryCount(count), - // typeSpec(NULL), typeSpecFlags(NULL) { } + // : header(_header), package(_package), entryCount(count), + // typeSpec(NULL), typeSpecFlags(NULL) { } { this.header = _header; _package_ = _package; @@ -2657,7 +2658,7 @@ public class ResTable { } } -// struct ResTable::Package + // struct ResTable::Package public static class Package { // Package(ResTable* _owner, final Header* _header, final ResTable_package* _package) // : owner(_owner), header(_header), package(_package), typeIdOffset(0) { @@ -2910,7 +2911,7 @@ public class ResTable { // This is a new attribute... figure out what to do with it. if (set.numAttrs >= set.availAttrs) { // Need to alloc more memory... - final int newAvail = set.availAttrs+N; + final int newAvail = set.availAttrs+N; // set = (bag_set[])realloc(set, // sizeof(bag_set) // + sizeof(bag_entry)*newAvail); diff --git a/resources/src/main/java/org/robolectric/res/android/ResTableTheme.java b/resources/src/main/java/org/robolectric/res/android/ResTableTheme.java index 89954c4c5..3efeca3af 100644 --- a/resources/src/main/java/org/robolectric/res/android/ResTableTheme.java +++ b/resources/src/main/java/org/robolectric/res/android/ResTableTheme.java @@ -23,8 +23,8 @@ import org.robolectric.res.android.ResTable.bag_entry; import org.robolectric.res.android.ResourceTypes.Res_value; // transliterated from -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ResourceTypes.cpp and -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/ResourceTypes.h +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceTypes.cpp and +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/ResourceTypes.h public class ResTableTheme { diff --git a/resources/src/main/java/org/robolectric/res/android/ResTable_config.java b/resources/src/main/java/org/robolectric/res/android/ResTable_config.java index 2815d2e66..e85353af2 100644 --- a/resources/src/main/java/org/robolectric/res/android/ResTable_config.java +++ b/resources/src/main/java/org/robolectric/res/android/ResTable_config.java @@ -76,8 +76,8 @@ import javax.annotation.Nonnull; * Describes a particular resource configuration. * * Transliterated from: - * * https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ResourceTypes.cpp - * * https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/ResourceTypes.h (struct ResTable_config) + * * https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceTypes.cpp + * * https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/ResourceTypes.h (struct ResTable_config) * * Changes from 8.0.0_r4 partially applied. */ @@ -226,7 +226,7 @@ public class ResTable_config { public static final int LAYOUTDIR_RTL = ACONFIGURATION_LAYOUTDIR_RTL << SHIFT_LAYOUTDIR; public static final int SCREENWIDTH_ANY = 0; -// public static final int MASK_SCREENSIZE = 0x0f; + // public static final int MASK_SCREENSIZE = 0x0f; public static final int SCREENSIZE_ANY = ACONFIGURATION_SCREENSIZE_ANY; public static final int SCREENSIZE_SMALL = ACONFIGURATION_SCREENSIZE_SMALL; public static final int SCREENSIZE_NORMAL = ACONFIGURATION_SCREENSIZE_NORMAL; @@ -862,7 +862,7 @@ public class ResTable_config { // screenHeightDp = dtohs(screenHeightDp); // } -// void ResTable_config::copyFromDtoH(const ResTable_config& o) { + // void ResTable_config::copyFromDtoH(const ResTable_config& o) { static ResTable_config fromDtoH(final ResTable_config o) { return new ResTable_config( 0 /*sizeof(ResTable_config)*/, @@ -1017,49 +1017,49 @@ public class ResTable_config { } int compare(final ResTable_config o) { - if (imsi() != o.imsi()) { - return (imsi() > o.imsi()) ? 1 : -1; - } - - int diff = compareLocales(this, o); - if (diff < 0) { - return -1; - } - if (diff > 0) { - return 1; - } - - if (screenType() != o.screenType()) { - return (screenType() > o.screenType()) ? 1 : -1; - } - if (input() != o.input()) { - return (input() > o.input()) ? 1 : -1; - } - if (screenSize() != o.screenSize()) { - return (screenSize() > o.screenSize()) ? 1 : -1; - } - if (version() != o.version()) { - return (version() > o.version()) ? 1 : -1; - } - if (screenLayout != o.screenLayout) { - return (screenLayout > o.screenLayout) ? 1 : -1; - } - if (screenLayout2 != o.screenLayout2) { - return (screenLayout2 > o.screenLayout2) ? 1 : -1; - } - if (colorMode != o.colorMode) { - return (colorMode > o.colorMode) ? 1 : -1; - } - if (uiMode != o.uiMode) { - return (uiMode > o.uiMode) ? 1 : -1; - } - if (smallestScreenWidthDp != o.smallestScreenWidthDp) { - return (smallestScreenWidthDp > o.smallestScreenWidthDp) ? 1 : -1; - } - if (screenSizeDp() != o.screenSizeDp()) { - return (screenSizeDp() > o.screenSizeDp()) ? 1 : -1; - } - return 0; + if (imsi() != o.imsi()) { + return (imsi() > o.imsi()) ? 1 : -1; + } + + int diff = compareLocales(this, o); + if (diff < 0) { + return -1; + } + if (diff > 0) { + return 1; + } + + if (screenType() != o.screenType()) { + return (screenType() > o.screenType()) ? 1 : -1; + } + if (input() != o.input()) { + return (input() > o.input()) ? 1 : -1; + } + if (screenSize() != o.screenSize()) { + return (screenSize() > o.screenSize()) ? 1 : -1; + } + if (version() != o.version()) { + return (version() > o.version()) ? 1 : -1; + } + if (screenLayout != o.screenLayout) { + return (screenLayout > o.screenLayout) ? 1 : -1; + } + if (screenLayout2 != o.screenLayout2) { + return (screenLayout2 > o.screenLayout2) ? 1 : -1; + } + if (colorMode != o.colorMode) { + return (colorMode > o.colorMode) ? 1 : -1; + } + if (uiMode != o.uiMode) { + return (uiMode > o.uiMode) ? 1 : -1; + } + if (smallestScreenWidthDp != o.smallestScreenWidthDp) { + return (smallestScreenWidthDp > o.smallestScreenWidthDp) ? 1 : -1; + } + if (screenSizeDp() != o.screenSizeDp()) { + return (screenSizeDp() > o.screenSizeDp()) ? 1 : -1; + } + return 0; } @@ -1358,10 +1358,10 @@ public class ResTable_config { } if (isTruthy(input()) || isTruthy(o.input())) { - final int keysHidden = inputFlags & MASK_KEYSHIDDEN; - final int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN; + final int keysHidden = inputFlags & MASK_KEYSHIDDEN; + final int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN; if (keysHidden != oKeysHidden) { - final int reqKeysHidden = + final int reqKeysHidden = requested.inputFlags & MASK_KEYSHIDDEN; if (isTruthy(reqKeysHidden)) { @@ -1375,10 +1375,10 @@ public class ResTable_config { } } - final int navHidden = inputFlags & MASK_NAVHIDDEN; - final int oNavHidden = o.inputFlags & MASK_NAVHIDDEN; + final int navHidden = inputFlags & MASK_NAVHIDDEN; + final int oNavHidden = o.inputFlags & MASK_NAVHIDDEN; if (navHidden != oNavHidden) { - final int reqNavHidden = + final int reqNavHidden = requested.inputFlags & MASK_NAVHIDDEN; if (isTruthy(reqNavHidden)) { @@ -1501,34 +1501,34 @@ public class ResTable_config { } if (screenConfig() != 0) { - final int layoutDir = screenLayout&MASK_LAYOUTDIR; - final int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR; + final int layoutDir = screenLayout&MASK_LAYOUTDIR; + final int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR; if (layoutDir != 0 && layoutDir != setLayoutDir) { return false; } - final int screenSize = screenLayout&MASK_SCREENSIZE; - final int setScreenSize = settings.screenLayout&MASK_SCREENSIZE; + final int screenSize = screenLayout&MASK_SCREENSIZE; + final int setScreenSize = settings.screenLayout&MASK_SCREENSIZE; // Any screen sizes for larger screens than the setting do not // match. if (screenSize != 0 && screenSize > setScreenSize) { return false; } - final int screenLong = screenLayout&MASK_SCREENLONG; - final int setScreenLong = settings.screenLayout&MASK_SCREENLONG; + final int screenLong = screenLayout&MASK_SCREENLONG; + final int setScreenLong = settings.screenLayout&MASK_SCREENLONG; if (screenLong != 0 && screenLong != setScreenLong) { return false; } - final int uiModeType = uiMode&MASK_UI_MODE_TYPE; - final int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE; + final int uiModeType = uiMode&MASK_UI_MODE_TYPE; + final int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE; if (uiModeType != 0 && uiModeType != setUiModeType) { return false; } - final int uiModeNight = uiMode&MASK_UI_MODE_NIGHT; - final int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT; + final int uiModeNight = uiMode&MASK_UI_MODE_NIGHT; + final int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT; if (uiModeNight != 0 && uiModeNight != setUiModeNight) { return false; } @@ -1540,8 +1540,8 @@ public class ResTable_config { } if (screenConfig2() != 0) { - final int screenRound = screenLayout2 & MASK_SCREENROUND; - final int setScreenRound = settings.screenLayout2 & MASK_SCREENROUND; + final int screenRound = screenLayout2 & MASK_SCREENROUND; + final int setScreenRound = settings.screenLayout2 & MASK_SCREENROUND; if (screenRound != 0 && screenRound != setScreenRound) { return false; } @@ -1585,8 +1585,8 @@ public class ResTable_config { } } if (input() != 0) { - final int keysHidden = inputFlags&MASK_KEYSHIDDEN; - final int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN; + final int keysHidden = inputFlags&MASK_KEYSHIDDEN; + final int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN; if (keysHidden != 0 && keysHidden != setKeysHidden) { // For compatibility, we count a request for KEYSHIDDEN_NO as also // matching the more recent KEYSHIDDEN_SOFT. Basically @@ -1601,8 +1601,8 @@ public class ResTable_config { return false; } } - final int navHidden = inputFlags&MASK_NAVHIDDEN; - final int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN; + final int navHidden = inputFlags&MASK_NAVHIDDEN; + final int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN; if (navHidden != 0 && navHidden != setNavHidden) { return false; } @@ -1996,14 +1996,14 @@ public class ResTable_config { } /** - union { - struct { - uint8_t orientation; - uint8_t touchscreen; - uint16_t density; - }; - uint32_t screenType; - }; + union { + struct { + uint8_t orientation; + uint8_t touchscreen; + uint16_t density; + }; + uint32_t screenType; + }; */ private int screenType() { return ((orientation & 0xff) << 24) | ((touchscreen & 0xff) << 16) | (density & 0xffff); @@ -2171,14 +2171,14 @@ public class ResTable_config { // The variants are the same, try numbering system. boolean localeNumsysMatches = arrayCompare(localeNumberingSystem, - requested.localeNumberingSystem - ) == 0; + requested.localeNumberingSystem + ) == 0; boolean otherNumsysMatches = arrayCompare(o.localeNumberingSystem, - requested.localeNumberingSystem - ) == 0; + requested.localeNumberingSystem + ) == 0; if (localeNumsysMatches != otherNumsysMatches) { - return localeNumsysMatches; + return localeNumsysMatches; } // Finally, the languages, although equivalent, may still be different diff --git a/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java b/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java index 81a1994a4..4591d7de6 100644 --- a/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java +++ b/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java @@ -16,8 +16,8 @@ import java.util.List; import java.util.Map; import org.robolectric.res.android.ResourceTypes.ResStringPool_header.Writer; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ResourceTypes.cpp -// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/include/androidfw/ResourceTypes.h +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceTypes.cpp +// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h public class ResourceTypes { public static final String ANDROID_NS = "http://schemas.android.com/apk/res/android"; public static final String AUTO_NS = "http://schemas.android.com/apk/res-auto"; @@ -378,33 +378,33 @@ public class ResourceTypes { } } -/** - * This is a reference to a unique entry (a ResTable_entry structure) - * in a resource table. The value is structured as: 0xpptteeee, - * where pp is the package index, tt is the type index in that - * package, and eeee is the entry index in that type. The package - * and type values start at 1 for the first item, to help catch cases - * where they have not been supplied. - */ -public static class ResTable_ref - { - public static final int SIZEOF = 4; - - public int ident; - - public ResTable_ref(ByteBuffer buf, int offset) { - ident = buf.getInt(offset); - } + /** + * This is a reference to a unique entry (a ResTable_entry structure) + * in a resource table. The value is structured as: 0xpptteeee, + * where pp is the package index, tt is the type index in that + * package, and eeee is the entry index in that type. The package + * and type values start at 1 for the first item, to help catch cases + * where they have not been supplied. + */ + public static class ResTable_ref + { + public static final int SIZEOF = 4; - public ResTable_ref() { - ident = 0; - } + public int ident; - @Override - public String toString() { - return "ResTable_ref{ident=" + ident + '}'; - } - }; + public ResTable_ref(ByteBuffer buf, int offset) { + ident = buf.getInt(offset); + } + + public ResTable_ref() { + ident = 0; + } + + @Override + public String toString() { + return "ResTable_ref{ident=" + ident + '}'; + } + }; /** * Reference to a string in a string pool. @@ -441,7 +441,7 @@ public static class ResTable_ref *********************************************************************** */ -/** + /** * Definition for a pool of strings. The data of this chunk is an * array of uint32_t providing indices into the pool, relative to * stringsStart. At stringsStart are all of the UTF-16 strings @@ -476,9 +476,9 @@ public static class ResTable_ref // on strcmp16()). public static final int SORTED_FLAG = 1<<0; - // String pool is encoded in UTF-8 - public static final int UTF8_FLAG = 1<<8; -// }; + // String pool is encoded in UTF-8 + public static final int UTF8_FLAG = 1<<8; + // }; final int flags; // Index from header of the string data. @@ -1253,10 +1253,10 @@ public static class ResTable_ref short idxOrOffset; // struct { - // The index of the entry. + // The index of the entry. // uint16_t idx; - // The offset from ResTable_type::entriesStart, divided by 4. + // The offset from ResTable_type::entriesStart, divided by 4. // uint16_t offset; // }; diff --git a/resources/src/main/java/org/robolectric/res/android/ResourceUtils.java b/resources/src/main/java/org/robolectric/res/android/ResourceUtils.java index 3a5b20e42..66664faff 100644 --- a/resources/src/main/java/org/robolectric/res/android/ResourceUtils.java +++ b/resources/src/main/java/org/robolectric/res/android/ResourceUtils.java @@ -1,8 +1,8 @@ package org.robolectric.res.android; // transliterated from -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/include/androidfw/ResourceUtils.h -// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/libs/androidfw/ResourceUtils.cpp +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/include/androidfw/ResourceUtils.h +// and https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/libs/androidfw/ResourceUtils.cpp class ResourceUtils { // Extracts the package, type, and name from a string of the format: [[package:]type/]name // Validation must be performed on each extracted piece. @@ -72,7 +72,7 @@ class ResourceUtils { // } static boolean ExtractResourceName(String str, Ref<String> out_package, Ref<String> out_type, - final Ref<String> out_entry) { + final Ref<String> out_entry) { out_package.set(""); out_type.set(""); boolean has_package_separator = false; @@ -95,7 +95,7 @@ class ResourceUtils { out_entry.set(str.substring(start, end)); return !(has_package_separator && out_package.get().isEmpty()) && - !(has_type_separator && out_type.get().isEmpty()); + !(has_type_separator && out_type.get().isEmpty()); } } diff --git a/resources/src/main/java/org/robolectric/res/android/String8.java b/resources/src/main/java/org/robolectric/res/android/String8.java index 1da9fc0ab..9dcaa1e83 100644 --- a/resources/src/main/java/org/robolectric/res/android/String8.java +++ b/resources/src/main/java/org/robolectric/res/android/String8.java @@ -2,8 +2,8 @@ package org.robolectric.res.android; import java.io.File; -// transliterated from https://android.googlesource.com/platform/system/core/+/android-9.0.0_r3/libutils/String8.cpp -// and https://android.googlesource.com/platform/system/core/+/android-9.0.0_r3/include/utils/String8.h +// transliterated from https://android.googlesource.com/platform/system/core/+/android-9.0.0_r12/libutils/String8.cpp +// and https://android.googlesource.com/platform/system/core/+/android-9.0.0_r12/include/utils/String8.h public class String8 { private StringBuilder mString; @@ -27,7 +27,7 @@ public class String8 { int length() { return mString.length(); } -//String8 String8::format(const char* fmt, ...) + //String8 String8::format(const char* fmt, ...) //{ // va_list args; // va_start(args, fmt); @@ -98,11 +98,11 @@ public class String8 { // } // return real_append(other.string(), otherLen); //} -public String8 append(final String other) { - mString.append(other); + public String8 append(final String other) { + mString.append(other); return this; -} -//status_t String8::append(const char* other, size_t otherLen) + } + //status_t String8::append(const char* other, size_t otherLen) //{ // if (bytes() == 0) { // return setTo(other, otherLen); @@ -288,16 +288,16 @@ public String8 append(final String other) { // buf[len] = '\0'; // unlockBuffer(len); //} -String8 getPathLeaf() { - final int cp; - final String buf = mString.toString(); - cp = buf.lastIndexOf(File.separatorChar); - if (cp == -1) { - return new String8(this); - } else { - return new String8(buf.substring(cp + 1)); + String8 getPathLeaf() { + final int cp; + final String buf = mString.toString(); + cp = buf.lastIndexOf(File.separatorChar); + if (cp == -1) { + return new String8(this); + } else { + return new String8(buf.substring(cp + 1)); + } } -} //String8 String8::getPathDir(void) const //{ // const char* cp; @@ -329,13 +329,13 @@ String8 getPathLeaf() { // return res; //} -/* - * Helper function for finding the start of an extension in a pathname. - * - * Returns a index inside mString, or -1 if no extension was found. - */ -private int find_extension() -{ + /* + * Helper function for finding the start of an extension in a pathname. + * + * Returns a index inside mString, or -1 if no extension was found. + */ + private int find_extension() + { int lastSlashIndex; final StringBuilder str = mString; @@ -348,10 +348,10 @@ private int find_extension() } // find the last dot return str.lastIndexOf(".", lastSlashIndex); -} + } -public String getPathExtension() -{ + public String getPathExtension() + { int extIndex; extIndex = find_extension(); if (extIndex != -1) { @@ -360,7 +360,7 @@ public String getPathExtension() else { return ""; } -} + } String8 getBasePath() { int extIndex; @@ -382,7 +382,7 @@ public String getPathExtension() } mString.append(name); return this; -} + } //String8& String8::convertToResPath() //{ diff --git a/resources/src/main/java/org/robolectric/res/android/StringPoolRef.java b/resources/src/main/java/org/robolectric/res/android/StringPoolRef.java index 1d4e8e6a0..9c67304b7 100644 --- a/resources/src/main/java/org/robolectric/res/android/StringPoolRef.java +++ b/resources/src/main/java/org/robolectric/res/android/StringPoolRef.java @@ -1,7 +1,7 @@ package org.robolectric.res.android; /** - * transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/include/androidfw/ResourceTypes.h:541 + * transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/include/androidfw/ResourceTypes.h:541 * Wrapper class that allows the caller to retrieve a string from a string pool without knowing * which string pool to look. */ diff --git a/resources/src/test/java/org/robolectric/RoboSettingsTest.java b/resources/src/test/java/org/robolectric/RoboSettingsTest.java index f306b3969..cef8f8538 100644 --- a/resources/src/test/java/org/robolectric/RoboSettingsTest.java +++ b/resources/src/test/java/org/robolectric/RoboSettingsTest.java @@ -15,12 +15,16 @@ public class RoboSettingsTest { private String originalMavenRepositoryId; private String originalMavenRepositoryUrl; + private String originalMavenRepositoryUserName; + private String originalMavenRepositoryPassword; private boolean originalUseGlobalScheduler; @Before public void setUp() { originalMavenRepositoryId = RoboSettings.getMavenRepositoryId(); originalMavenRepositoryUrl = RoboSettings.getMavenRepositoryUrl(); + originalMavenRepositoryUserName = RoboSettings.getMavenRepositoryUserName(); + originalMavenRepositoryPassword = RoboSettings.getMavenRepositoryPassword(); originalUseGlobalScheduler = RoboSettings.isUseGlobalScheduler(); } @@ -28,6 +32,8 @@ public class RoboSettingsTest { public void tearDown() { RoboSettings.setMavenRepositoryId(originalMavenRepositoryId); RoboSettings.setMavenRepositoryUrl(originalMavenRepositoryUrl); + RoboSettings.setMavenRepositoryUserName(originalMavenRepositoryUserName); + RoboSettings.setMavenRepositoryPassword(originalMavenRepositoryPassword); RoboSettings.setUseGlobalScheduler(originalUseGlobalScheduler); } @@ -54,6 +60,18 @@ public class RoboSettingsTest { } @Test + public void setMavenRepositoryUserName() { + RoboSettings.setMavenRepositoryUserName("username"); + assertEquals("username", RoboSettings.getMavenRepositoryUserName()); + } + + @Test + public void setMavenRepositoryPassword() { + RoboSettings.setMavenRepositoryPassword("password"); + assertEquals("password", RoboSettings.getMavenRepositoryPassword()); + } + + @Test public void isUseGlobalScheduler_defaultFalse() { assertFalse(RoboSettings.isUseGlobalScheduler()); } diff --git a/robolectric/Android.mk b/robolectric/Android.mk index 24fc2eaf2..8dcf8e7fa 100644 --- a/robolectric/Android.mk +++ b/robolectric/Android.mk @@ -19,9 +19,10 @@ LOCAL_JAVA_LIBRARIES := \ Robolectric_junit \ Robolectric_utils \ robolectric-host-android_all \ + robolectric-host-androidx-test-ext-junit \ + robolectric-host-androidx-test-monitor \ robolectric-host-monitor-1.0.2-alpha1 \ robolectric-maven-ant-tasks-2.1.3 \ - robolectric-host-androidx-test \ robolectric-bouncycastle-1.46 \ robolectric-asm-commons-6.0 \ robolectric-guava-25.1-jre \ @@ -61,10 +62,12 @@ LOCAL_JAVA_LIBRARIES := \ Robolectric_sandbox \ Robolectric_junit \ Robolectric_utils \ + robolectric-host-androidx-test-ext-junit \ + robolectric-host-androidx-test-monitor \ robolectric-host-monitor-1.0.2-alpha1 \ + robolectric-host-androidx-test-core \ robolectric-maven-ant-tasks-2.1.3 \ robolectric-mockito-core-2.16.0 \ - robolectric-host-androidx-test \ robolectric-bouncycastle-1.46 \ robolectric-hamcrest-core-1.3 \ robolectric-sqlite4java-0.282 \ @@ -98,11 +101,13 @@ test_runtime_libraries := \ Robolectric_sandbox \ Robolectric_junit \ Robolectric_utils \ + robolectric-host-androidx-test-ext-junit \ + robolectric-host-androidx-test-monitor \ robolectric-host-monitor-1.0.2-alpha1 \ + robolectric-host-androidx-test-core \ robolectric-byte-buddy-agent-1.6.5 \ robolectric-maven-ant-tasks-2.1.3 \ robolectric-mockito-core-2.16.0 \ - robolectric-host-androidx-test \ robolectric-bouncycastle-1.46 \ robolectric-hamcrest-core-1.3 \ robolectric-sqlite4java-0.282 \ @@ -128,7 +133,9 @@ include external/robolectric-shadows/run_robolectric_module_tests.mk ########################################### robolectric_target_to_host_jars := \ robolectric-host-android_all:$(call intermediates-dir-for, JAVA_LIBRARIES, robolectric_android-all-stub,,COMMON)/classes-with-res.jar \ - robolectric-host-androidx-test:$(call java-lib-files, androidx.test.monitor) \ + robolectric-host-androidx-test-core:$(call java-lib-files, androidx.test.core) \ + robolectric-host-androidx-test-ext-junit:$(call java-lib-files, androidx.test.ext.junit) \ + robolectric-host-androidx-test-monitor:$(call java-lib-files, androidx.test.monitor) \ robolectric-host-androidx:$(call java-lib-files, androidx.fragment_fragment) \ robolectric-host-android-support-v4:$(call java-lib-files, android-support-v4) \ robolectric-host-android-support-multidex:$(call java-lib-files, android-support-multidex) \ diff --git a/robolectric/build.gradle b/robolectric/build.gradle index e8d2ce2fb..f47118f9f 100644 --- a/robolectric/build.gradle +++ b/robolectric/build.gradle @@ -1,7 +1,3 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) @@ -21,41 +17,38 @@ configurations { project.sourceSets.test.compileClasspath += configurations.shadow dependencies { - // Project dependencies - compile project(":annotations") - compile project(":junit") - compile project(":resources") - compile project(":sandbox") - compile project(":utils") + api project(":annotations") + api project(":junit") + api project(":resources") + api project(":sandbox") + api project(":utils") // We need to have shadows-framework.jar on the runtime system classpath so ServiceLoader // can find its META-INF/services/org.robolectric.shadows.ShadowAdapter. - compile project(":shadows:framework") + api project(":shadows:framework") - // Compile dependencies - compile "org.bouncycastle:bcprov-jdk15on:1.52" - compileOnly "com.google.code.findbugs:jsr305:3.0.1" + api "org.bouncycastle:bcprov-jdk15on:1.52" + compileOnly "com.google.code.findbugs:jsr305:3.0.2" - compile "org.apache.ant:ant:1.8.0" - compile("org.apache.maven:maven-ant-tasks:2.1.3") { + api "org.apache.ant:ant:1.8.0" + api("org.apache.maven:maven-ant-tasks:2.1.3") { exclude group: "junit", module: "junit" } compileOnly AndroidSdk.MAX_SDK.coordinates compileOnly "junit:junit:4.12" - compileOnly "androidx.test:monitor:1.1.0-alpha4" + compile "androidx.test:monitor:1.1.0" - // Testing dependencies - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" - testCompile "androidx.test:core:1.0.0-alpha4" + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" + testImplementation "androidx.test:core:1.0.0" + testImplementation "androidx.test.ext:junit:1.0.0" + testImplementation "androidx.test:runner:1.1.0" testCompileOnly AndroidSdk.MAX_SDK.coordinates // compile against latest Android SDK testRuntime AndroidSdk.MAX_SDK.coordinates // run against whatever this JDK supports } test { - systemProperty 'robolectric.resourcesMode', 'both' - if (project.hasProperty('maxParallelForks')) maxParallelForks = project.maxParallelForks as int if (project.hasProperty('forkEvery')) diff --git a/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java b/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java index 76e89ac96..50d312ecf 100644 --- a/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java +++ b/robolectric/src/main/java/org/robolectric/RobolectricTestRunner.java @@ -359,6 +359,11 @@ public class RobolectricTestRunner extends SandboxTestRunner { + roboMethod.getMethod().getName() + ": sdk=" + sdkConfig.getApiLevel() + "; resources=" + roboMethod.resourcesMode); + if (roboMethod.resourcesMode == ResourcesMode.legacy) { + System.out.println( + "[Robolectric] NOTICE: legacy resources mode is deprecated; see http://robolectric.org/migrating/#migrating-to-40"); + } + roboMethod.parallelUniverseInterface = getHooksInterface(sdkEnvironment); Class<TestLifecycle> cl = sdkEnvironment.bootstrappedClass(getTestLifecycleClass()); roboMethod.testLifecycle = ReflectionHelpers.newInstance(cl); diff --git a/robolectric/src/main/java/org/robolectric/SdkPicker.java b/robolectric/src/main/java/org/robolectric/SdkPicker.java index 64542498e..0acfa142f 100644 --- a/robolectric/src/main/java/org/robolectric/SdkPicker.java +++ b/robolectric/src/main/java/org/robolectric/SdkPicker.java @@ -14,7 +14,6 @@ import javax.annotation.Nullable; import org.robolectric.annotation.Config; import org.robolectric.annotation.internal.ConfigUtils; import org.robolectric.internal.SdkConfig; -import org.robolectric.manifest.AndroidManifest; public class SdkPicker { private final Set<SdkConfig> supportedSdks; @@ -35,25 +34,6 @@ public class SdkPicker { * Enumerate the SDKs to be used for this test. * * @param config a {@link Config} specifying one or more SDKs - * @param appManifest the {@link AndroidManifest} for the test - * @return the list of candidate {@link SdkConfig}s. - * @since 3.2 - * @deprecated Use {@link #selectSdks(Config, UsesSdk)} instead. - */ - @Deprecated - @Nonnull - public List<SdkConfig> selectSdks(Config config, AndroidManifest appManifest) { - Set<SdkConfig> sdks = new TreeSet<>(configuredSdks(config, appManifest)); - if (enabledSdks != null) { - sdks = Sets.intersection(sdks, enabledSdks); - } - return Lists.newArrayList(sdks); - } - - /** - * Enumerate the SDKs to be used for this test. - * - * @param config a {@link Config} specifying one or more SDKs * @param usesSdk the {@link UsesSdk} for the test * @return the list of candidate {@link SdkConfig}s. * @since 3.9 @@ -80,12 +60,6 @@ public class SdkPicker { } } - /** @deprecated Use {@link #configuredSdks(Config, UsesSdk)} instead. */ - @Deprecated - protected Set<SdkConfig> configuredSdks(Config config, AndroidManifest appManifest) { - return configuredSdks(config, (UsesSdk) appManifest); - } - protected Set<SdkConfig> configuredSdks(Config config, UsesSdk usesSdk) { int appMinSdk = Math.max(usesSdk.getMinSdkVersion(), minSupportedSdk.getApiLevel()); int appTargetSdk = Math.max(usesSdk.getTargetSdkVersion(), minSupportedSdk.getApiLevel()); @@ -170,15 +144,6 @@ public class SdkPicker { } @Nonnull - private static List<SdkConfig> map(Collection<Integer> supportedSdks) { - ArrayList<SdkConfig> sdkConfigs = new ArrayList<>(); - for (int supportedSdk : supportedSdks) { - sdkConfigs.add(new SdkConfig(supportedSdk)); - } - return sdkConfigs; - } - - @Nonnull static List<SdkConfig> map(int... supportedSdks) { ArrayList<SdkConfig> sdkConfigs = new ArrayList<>(); for (int supportedSdk : supportedSdks) { diff --git a/robolectric/src/main/java/org/robolectric/android/fakes/RoboMonitoringInstrumentation.java b/robolectric/src/main/java/org/robolectric/android/fakes/RoboMonitoringInstrumentation.java index 8869078c7..15c4a91f8 100644 --- a/robolectric/src/main/java/org/robolectric/android/fakes/RoboMonitoringInstrumentation.java +++ b/robolectric/src/main/java/org/robolectric/android/fakes/RoboMonitoringInstrumentation.java @@ -5,7 +5,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import androidx.test.runner.MonitoringInstrumentation; import org.robolectric.Robolectric; -import org.robolectric.android.controller.ActivityController; import org.robolectric.shadows.ShadowLooper; public class RoboMonitoringInstrumentation extends MonitoringInstrumentation { @@ -35,14 +34,15 @@ public class RoboMonitoringInstrumentation extends MonitoringInstrumentation { ActivityInfo ai = intent.resolveActivityInfo(getTargetContext().getPackageManager(), 0); try { Class<? extends Activity> activityClass = Class.forName(ai.name).asSubclass(Activity.class); - ActivityController<? extends Activity> controller = Robolectric.buildActivity(activityClass, intent); - Activity activity = controller.get(); - callActivityOnCreate(activity, null); - controller.postCreate(null); - callActivityOnStart(activity); - callActivityOnResume(activity); - controller.visible().windowFocusChanged(true); - return activity; + return Robolectric.buildActivity(activityClass, intent) + .create() + .postCreate(null) + .start() + .resume() + .postResume() + .visible() + .windowFocusChanged(true) + .get(); } catch (ClassNotFoundException e) { throw new RuntimeException("Could not load activity " + ai.name, e); } diff --git a/robolectric/src/main/java/org/robolectric/android/internal/LocalActivityInvoker.java b/robolectric/src/main/java/org/robolectric/android/internal/LocalActivityInvoker.java new file mode 100644 index 000000000..c85a71e11 --- /dev/null +++ b/robolectric/src/main/java/org/robolectric/android/internal/LocalActivityInvoker.java @@ -0,0 +1,190 @@ +package org.robolectric.android.internal; + +import static androidx.test.InstrumentationRegistry.getContext; +import static androidx.test.InstrumentationRegistry.getTargetContext; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import android.app.Activity; +import android.app.Instrumentation.ActivityResult; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.Bundle; +import androidx.test.internal.platform.app.ActivityInvoker; +import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; +import androidx.test.runner.lifecycle.Stage; +import javax.annotation.Nullable; +import org.robolectric.Robolectric; +import org.robolectric.android.controller.ActivityController; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowActivity; + +/** + * An {@link ActivityInvoker} that drives {@link Activity} lifecycles manually. + * + * <p>All the methods in this class are blocking API. + */ +public class LocalActivityInvoker implements ActivityInvoker { + + @Nullable private ActivityController<? extends Activity> controller; + + @Override + public void startActivity(Intent intent) { + ActivityInfo ai = intent.resolveActivityInfo(getTargetContext().getPackageManager(), 0); + try { + Class<? extends Activity> activityClass = Class.forName(ai.name).asSubclass(Activity.class); + controller = + Robolectric.buildActivity(activityClass, intent) + .create() + .postCreate(null) + .start() + .resume() + .postResume() + .visible() + .windowFocusChanged(true); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Could not load activity " + ai.name, e); + } + } + + + @Override + public void resumeActivity(Activity activity) { + checkNotNull(controller); + checkState(controller.get() == activity); + Stage stage = ActivityLifecycleMonitorRegistry.getInstance().getLifecycleStageOf(activity); + switch (stage) { + case RESUMED: + return; + case PAUSED: + controller.stop().restart().start().resume().postResume(); + return; + case STOPPED: + controller.restart().start().resume().postResume(); + return; + default: + throw new IllegalStateException( + String.format( + "Activity's stage must be RESUMED, PAUSED or STOPPED but was %s.", stage)); + } + } + + @Override + public void pauseActivity(Activity activity) { + checkNotNull(controller); + checkState(controller.get() == activity); + Stage stage = ActivityLifecycleMonitorRegistry.getInstance().getLifecycleStageOf(activity); + switch (stage) { + case RESUMED: + controller.pause(); + return; + case PAUSED: + return; + default: + throw new IllegalStateException( + String.format("Activity's stage must be RESUMED or PAUSED but was %s.", stage)); + } + } + + @Override + public void stopActivity(Activity activity) { + checkNotNull(controller); + checkState(controller.get() == activity); + Stage stage = ActivityLifecycleMonitorRegistry.getInstance().getLifecycleStageOf(activity); + switch (stage) { + case RESUMED: + controller.pause().stop(); + return; + case PAUSED: + controller.stop(); + return; + case STOPPED: + return; + default: + throw new IllegalStateException( + String.format( + "Activity's stage must be RESUMED, PAUSED or STOPPED but was %s.", stage)); + } + } + + @Override + public void recreateActivity(Activity activity) { + checkNotNull(controller); + checkState(controller.get() == activity); + Stage originalStage = + ActivityLifecycleMonitorRegistry.getInstance().getLifecycleStageOf(activity); + + // Move the activity stage to STOPPED before retrieving saveInstanceState. + stopActivity(activity); + + Bundle outState = new Bundle(); + controller.saveInstanceState(outState); + Object nonConfigInstance = activity.onRetainNonConfigurationInstance(); + controller.destroy(); + + controller = Robolectric.buildActivity(activity.getClass(), activity.getIntent()); + Activity recreatedActivity = controller.get(); + Shadow.<ShadowActivity>extract(recreatedActivity) + .setLastNonConfigurationInstance(nonConfigInstance); + controller + .create(outState) + .postCreate(outState) + .start() + .restoreInstanceState(outState) + .resume() + .postResume() + .visible() + .windowFocusChanged(true); + + // Move to the original stage. + switch (originalStage) { + case RESUMED: + return; + case PAUSED: + pauseActivity(recreatedActivity); + return; + case STOPPED: + stopActivity(recreatedActivity); + return; + default: + throw new IllegalStateException( + String.format( + "Activity's stage must be RESUMED, PAUSED or STOPPED but was %s.", originalStage)); + } + } + + @Override + public void finishActivity(Activity activity) { + checkNotNull(controller); + checkState(controller.get() == activity); + activity.finish(); + Stage stage = ActivityLifecycleMonitorRegistry.getInstance().getLifecycleStageOf(activity); + switch (stage) { + case RESUMED: + controller.pause().stop().destroy(); + return; + case PAUSED: + controller.stop().destroy(); + return; + case STOPPED: + controller.destroy(); + return; + default: + throw new IllegalStateException( + String.format( + "Activity's stage must be RESUMED, PAUSED or STOPPED but was %s.", stage)); + } + } + + // TODO: just copy implementation from super. It looks like 'default' keyword from super is + // getting stripped from androidx.test.monitor maven artifact + @Override + public Intent getIntentForActivity(Class<? extends Activity> activityClass) { + Intent intent = Intent.makeMainActivity(new ComponentName(getTargetContext(), activityClass)); + if (getTargetContext().getPackageManager().resolveActivity(intent, 0) != null) { + return intent; + } + return Intent.makeMainActivity(new ComponentName(getContext(), activityClass)); + } +} diff --git a/robolectric/src/main/java/org/robolectric/android/internal/NoOpThreadChecker.java b/robolectric/src/main/java/org/robolectric/android/internal/NoOpThreadChecker.java new file mode 100644 index 000000000..481009de8 --- /dev/null +++ b/robolectric/src/main/java/org/robolectric/android/internal/NoOpThreadChecker.java @@ -0,0 +1,15 @@ +package org.robolectric.android.internal; + +import androidx.test.internal.platform.ThreadChecker; + +/** + * In Robolectric environment, everything is executed on the main thread except for when you + * manually create and run your code on worker thread. + */ +public class NoOpThreadChecker implements ThreadChecker { + @Override + public void checkMainThread() {} + + @Override + public void checkNotMainThread() {} +} diff --git a/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java b/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java index 94064c44a..3afe6f970 100644 --- a/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java +++ b/robolectric/src/main/java/org/robolectric/android/internal/ParallelUniverse.java @@ -1,6 +1,7 @@ package org.robolectric.android.internal; import static android.location.LocationManager.GPS_PROVIDER; +import static android.os.Build.VERSION_CODES.P; import static org.robolectric.shadow.api.Shadow.newInstanceOf; import static org.robolectric.util.ReflectionHelpers.ClassParameter.from; @@ -130,7 +131,14 @@ public class ParallelUniverse implements ParallelUniverseInterface { parsedPackage = new PackageParser.Package("org.robolectric.default"); parsedPackage.applicationInfo.targetSdkVersion = appManifest.getTargetSdkVersion(); } - + // Support overriding the package name specified in the Manifest. + if (!Config.DEFAULT_PACKAGE_NAME.equals(config.packageName())) { + parsedPackage.packageName = config.packageName(); + parsedPackage.applicationInfo.packageName = config.packageName(); + } else { + parsedPackage.packageName = appManifest.getPackageName(); + parsedPackage.applicationInfo.packageName = appManifest.getPackageName(); + } } else { RuntimeEnvironment.compileTimeSystemResourcesFile = apkLoader.getCompileTimeSystemResourcesFile(sdkEnvironment); @@ -144,14 +152,11 @@ public class ParallelUniverse implements ParallelUniverseInterface { ApplicationInfo applicationInfo = parsedPackage.applicationInfo; - // Support overriding the package name specified in the Manifest. - if (!Config.DEFAULT_PACKAGE_NAME.equals(config.packageName())) { - parsedPackage.packageName = config.packageName(); - parsedPackage.applicationInfo.packageName = config.packageName(); - } else { - parsedPackage.packageName = appManifest.getPackageName(); - parsedPackage.applicationInfo.packageName = appManifest.getPackageName(); + // unclear why, but prior to P the processName wasn't set + if (sdkConfig.getApiLevel() < P && applicationInfo.processName == null) { + applicationInfo.processName = parsedPackage.packageName; } + // TempDirectory tempDirectory = RuntimeEnvironment.getTempDirectory(); // packageInfo.setVolumeUuid(tempDirectory.createIfNotExists(packageInfo.packageName + // "-dataDir").toAbsolutePath().toString()); diff --git a/robolectric/src/main/java/org/robolectric/internal/dependency/MavenDependencyResolver.java b/robolectric/src/main/java/org/robolectric/internal/dependency/MavenDependencyResolver.java index d81f6732e..bee65b5c3 100644 --- a/robolectric/src/main/java/org/robolectric/internal/dependency/MavenDependencyResolver.java +++ b/robolectric/src/main/java/org/robolectric/internal/dependency/MavenDependencyResolver.java @@ -3,6 +3,8 @@ package org.robolectric.internal.dependency; import java.net.MalformedURLException; import java.net.URL; import java.util.Hashtable; + +import org.apache.maven.artifact.ant.Authentication; import org.apache.maven.artifact.ant.DependenciesTask; import org.apache.maven.artifact.ant.RemoteRepository; import org.apache.maven.model.Dependency; @@ -14,14 +16,18 @@ public class MavenDependencyResolver implements DependencyResolver { private final Project project = new Project(); private final String repositoryUrl; private final String repositoryId; + private final String repositoryUserName; + private final String repositoryPassword; public MavenDependencyResolver() { - this(RoboSettings.getMavenRepositoryUrl(), RoboSettings.getMavenRepositoryId()); + this(RoboSettings.getMavenRepositoryUrl(), RoboSettings.getMavenRepositoryId(), RoboSettings.getMavenRepositoryUserName(), RoboSettings.getMavenRepositoryPassword()); } - public MavenDependencyResolver(String repositoryUrl, String repositoryId) { + public MavenDependencyResolver(String repositoryUrl, String repositoryId, String repositoryUserName, String repositoryPassword) { this.repositoryUrl = repositoryUrl; this.repositoryId = repositoryId; + this.repositoryUserName = repositoryUserName; + this.repositoryPassword = repositoryPassword; } @Override @@ -39,6 +45,12 @@ public class MavenDependencyResolver implements DependencyResolver { RemoteRepository remoteRepository = new RemoteRepository(); remoteRepository.setUrl(repositoryUrl); remoteRepository.setId(repositoryId); + if (repositoryUserName != null || repositoryPassword != null) { + Authentication authentication = new Authentication(); + authentication.setUserName(repositoryUserName); + authentication.setPassword(repositoryPassword); + remoteRepository.addAuthentication(authentication); + } dependenciesTask.addConfiguredRemoteRepository(remoteRepository); dependenciesTask.setProject(project); for (DependencyJar dependencyJar : dependencies) { diff --git a/robolectric/src/main/resources/META-INF/services/androidx.test.internal.platform.ThreadChecker b/robolectric/src/main/resources/META-INF/services/androidx.test.internal.platform.ThreadChecker new file mode 100644 index 000000000..55104eac2 --- /dev/null +++ b/robolectric/src/main/resources/META-INF/services/androidx.test.internal.platform.ThreadChecker @@ -0,0 +1 @@ +org.robolectric.android.internal.NoOpThreadChecker diff --git a/robolectric/src/main/resources/META-INF/services/androidx.test.internal.platform.app.ActivityInvoker b/robolectric/src/main/resources/META-INF/services/androidx.test.internal.platform.app.ActivityInvoker new file mode 100644 index 000000000..e9944b51e --- /dev/null +++ b/robolectric/src/main/resources/META-INF/services/androidx.test.internal.platform.app.ActivityInvoker @@ -0,0 +1 @@ +org.robolectric.android.internal.LocalActivityInvoker diff --git a/robolectric/src/test/java/org/robolectric/AttributeSetBuilderTest.java b/robolectric/src/test/java/org/robolectric/AttributeSetBuilderTest.java index 61acac5dd..4531bbb02 100644 --- a/robolectric/src/test/java/org/robolectric/AttributeSetBuilderTest.java +++ b/robolectric/src/test/java/org/robolectric/AttributeSetBuilderTest.java @@ -8,16 +8,15 @@ import static org.robolectric.res.AttributeResource.ANDROID_RES_NS_PREFIX; import static org.robolectric.res.AttributeResource.RES_AUTO_NS_URI; import android.util.AttributeSet; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.res.AttributeResource; -/** - * Tests for {@link Robolectric#buildAttributeSet()} - */ -@RunWith(RobolectricTestRunner.class) +/** Tests for {@link Robolectric#buildAttributeSet()} */ +@RunWith(AndroidJUnit4.class) public class AttributeSetBuilderTest { private static final String APP_NS = RES_AUTO_NS_URI; diff --git a/robolectric/src/test/java/org/robolectric/IncludedDependenciesTest.java b/robolectric/src/test/java/org/robolectric/IncludedDependenciesTest.java index 07f4daffd..8c8dc7398 100644 --- a/robolectric/src/test/java/org/robolectric/IncludedDependenciesTest.java +++ b/robolectric/src/test/java/org/robolectric/IncludedDependenciesTest.java @@ -2,6 +2,7 @@ package org.robolectric; import static org.junit.Assert.assertEquals; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.StringReader; import org.json.JSONObject; import org.junit.Test; @@ -9,7 +10,7 @@ import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserFactory; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class IncludedDependenciesTest { @Test public void jsonShouldWork() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/InvokeDynamicTest.java b/robolectric/src/test/java/org/robolectric/InvokeDynamicTest.java index d65fcee6a..109b52588 100644 --- a/robolectric/src/test/java/org/robolectric/InvokeDynamicTest.java +++ b/robolectric/src/test/java/org/robolectric/InvokeDynamicTest.java @@ -2,6 +2,7 @@ package org.robolectric; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.annotation.Config; @@ -11,7 +12,7 @@ import org.robolectric.annotation.RealObject; import org.robolectric.annotation.internal.Instrument; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(sdk = Config.NEWEST_SDK) public class InvokeDynamicTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/ManifestFactoryTest.java b/robolectric/src/test/java/org/robolectric/ManifestFactoryTest.java index f1ee09812..903a8665e 100644 --- a/robolectric/src/test/java/org/robolectric/ManifestFactoryTest.java +++ b/robolectric/src/test/java/org/robolectric/ManifestFactoryTest.java @@ -41,17 +41,23 @@ public class ManifestFactoryTest { ManifestFactory manifestFactory = testRunner.getManifestFactory(config); assertThat(manifestFactory).isInstanceOf(DefaultManifestFactory.class); ManifestIdentifier manifestIdentifier = manifestFactory.identify(config); - assertThat(manifestIdentifier.getManifestFile()).isEqualTo(Fs.fileFromPath(baseDir + "/path/to/MergedManifest.xml")); - assertThat(manifestIdentifier.getResDir()).isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-resources")); - assertThat(manifestIdentifier.getAssetDir()).isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-assets")); + assertThat(manifestIdentifier.getManifestFile()) + .isEqualTo(Fs.fileFromPath(baseDir + "/path/to/MergedManifest.xml")); + assertThat(manifestIdentifier.getResDir()) + .isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-resources")); + assertThat(manifestIdentifier.getAssetDir()) + .isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-assets")); assertThat(manifestIdentifier.getLibraries()).isEmpty(); assertThat(manifestIdentifier.getPackageName()).isNull(); AndroidManifest androidManifest = RobolectricTestRunner .createAndroidManifest(manifestIdentifier); - assertThat(androidManifest.getAndroidManifestFile()).isEqualTo(Fs.fileFromPath(baseDir + "/path/to/MergedManifest.xml")); - assertThat(androidManifest.getResDirectory()).isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-resources")); - assertThat(androidManifest.getAssetsDirectory()).isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-assets")); + assertThat(androidManifest.getAndroidManifestFile()) + .isEqualTo(Fs.fileFromPath(baseDir + "/path/to/MergedManifest.xml")); + assertThat(androidManifest.getResDirectory()) + .isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-resources")); + assertThat(androidManifest.getAssetsDirectory()) + .isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-assets")); } @Test @@ -71,6 +77,9 @@ public class ManifestFactoryTest { }; String baseDir = System.getProperty("robolectric-tests.base-dir"); + if (baseDir == null) { + baseDir = ""; + } Config.Implementation config = Config.Builder.defaults() .setManifest("TestAndroidManifest.xml") @@ -81,9 +90,11 @@ public class ManifestFactoryTest { ManifestIdentifier manifestIdentifier = manifestFactory.identify(config); assertThat(manifestIdentifier.getManifestFile()) .isEqualTo(Fs.fromURL(getClass().getClassLoader().getResource("TestAndroidManifest.xml"))); - assertThat(manifestIdentifier.getResDir()).isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-resources")); - assertThat(manifestIdentifier.getAssetDir()).isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-assets")); + assertThat(manifestIdentifier.getResDir()) + .isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-resources")); + assertThat(manifestIdentifier.getAssetDir()) + .isEqualTo(Fs.fileFromPath(baseDir + "/path/to/merged-assets")); assertThat(manifestIdentifier.getLibraries()).isEmpty(); assertThat(manifestIdentifier.getPackageName()).isEqualTo("another.package"); } -} +}
\ No newline at end of file diff --git a/robolectric/src/test/java/org/robolectric/QualifiersTest.java b/robolectric/src/test/java/org/robolectric/QualifiersTest.java index bb21af990..f3cca59f9 100644 --- a/robolectric/src/test/java/org/robolectric/QualifiersTest.java +++ b/robolectric/src/test/java/org/robolectric/QualifiersTest.java @@ -1,6 +1,7 @@ package org.robolectric; import static android.os.Build.VERSION_CODES.O; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; @@ -10,20 +11,21 @@ import android.content.res.Resources; import android.os.Build.VERSION_CODES; import android.view.View; import android.widget.TextView; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Locale; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class QualifiersTest { private Resources resources; @Before public void setUp() throws Exception { - resources = RuntimeEnvironment.application.getResources(); + resources = getApplicationContext().getResources(); } @Test @@ -107,7 +109,7 @@ public class QualifiersTest { @Test @Config(qualifiers = "land") public void setQualifiers_updatesSystemAndAppResources() throws Exception { Resources systemResources = Resources.getSystem(); - Resources appResources = RuntimeEnvironment.application.getResources(); + Resources appResources = getApplicationContext().getResources(); assertThat(systemResources.getConfiguration().orientation).isEqualTo( Configuration.ORIENTATION_LANDSCAPE); diff --git a/robolectric/src/test/java/org/robolectric/RobolectricTest.java b/robolectric/src/test/java/org/robolectric/RobolectricTest.java index 0eb6d2edd..5ee979dc9 100644 --- a/robolectric/src/test/java/org/robolectric/RobolectricTest.java +++ b/robolectric/src/test/java/org/robolectric/RobolectricTest.java @@ -17,6 +17,8 @@ import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewParent; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.junit.After; @@ -31,7 +33,7 @@ import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowView; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class RobolectricTest { private PrintStream originalSystemOut; @@ -48,7 +50,7 @@ public class RobolectricTest { buff = new ByteArrayOutputStream(); PrintStream testOut = new PrintStream(buff); System.setOut(testOut); - context = RuntimeEnvironment.application; + context = ApplicationProvider.getApplicationContext(); } @After diff --git a/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerClassLoaderConfigTest.java b/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerClassLoaderConfigTest.java index 5961d0a1f..96df76a8c 100644 --- a/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerClassLoaderConfigTest.java +++ b/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerClassLoaderConfigTest.java @@ -2,13 +2,14 @@ package org.robolectric; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.internal.bytecode.SandboxClassLoader; import org.robolectric.test.DummyClass; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class RobolectricTestRunnerClassLoaderConfigTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerSelfTest.java b/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerSelfTest.java index e15403223..e6eda5b7a 100644 --- a/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerSelfTest.java +++ b/robolectric/src/test/java/org/robolectric/RobolectricTestRunnerSelfTest.java @@ -6,6 +6,8 @@ import static org.junit.Assert.fail; import android.app.Application; import android.content.res.Resources; import android.os.Build; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.hamcrest.CoreMatchers; import org.junit.AfterClass; import org.junit.Test; @@ -13,15 +15,18 @@ import org.junit.runner.RunWith; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(application = RobolectricTestRunnerSelfTest.MyTestApplication.class) public class RobolectricTestRunnerSelfTest { @Test public void shouldInitializeAndBindApplicationButNotCallOnCreate() { - assertThat(RuntimeEnvironment.application).named("application") + assertThat((Application) ApplicationProvider.getApplicationContext()) + .named("application") .isInstanceOf(MyTestApplication.class); - assertThat(((MyTestApplication) RuntimeEnvironment.application).onCreateWasCalled).named("onCreate called").isTrue(); + assertThat(((MyTestApplication) ApplicationProvider.getApplicationContext()).onCreateWasCalled) + .named("onCreate called") + .isTrue(); if (RuntimeEnvironment.useLegacyResources()) { assertThat(RuntimeEnvironment.getAppResourceTable()) .named("Application resource loader") @@ -32,7 +37,7 @@ public class RobolectricTestRunnerSelfTest { @Test public void shouldSetUpSystemResources() { Resources systemResources = Resources.getSystem(); - Resources appResources = RuntimeEnvironment.application.getResources(); + Resources appResources = ApplicationProvider.getApplicationContext().getResources(); assertThat(systemResources).named("system resources").isNotNull(); diff --git a/robolectric/src/test/java/org/robolectric/TemporaryBindingsTest.java b/robolectric/src/test/java/org/robolectric/TemporaryBindingsTest.java index b4fedeb13..de5cf7abb 100644 --- a/robolectric/src/test/java/org/robolectric/TemporaryBindingsTest.java +++ b/robolectric/src/test/java/org/robolectric/TemporaryBindingsTest.java @@ -5,6 +5,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.view.View; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.annotation.Config; @@ -12,20 +14,25 @@ import org.robolectric.annotation.Implements; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowView; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(sdk = O) // running on all SDKs is unnecessary and can cause OOM GC overhead issues public class TemporaryBindingsTest { @Test @Config(shadows = TemporaryShadowView.class) public void overridingShadowBindingsShouldNotAffectBindingsInLaterTests() throws Exception { - TemporaryShadowView shadowView = Shadow.extract(new View(RuntimeEnvironment.application)); + TemporaryShadowView shadowView = + Shadow.extract(new View(ApplicationProvider.getApplicationContext())); assertThat(shadowView.getClass().getSimpleName()).isEqualTo(TemporaryShadowView.class.getSimpleName()); } @Test public void overridingShadowBindingsShouldNotAffectBindingsInLaterTestsAgain() throws Exception { - assertThat(shadowOf(new View(RuntimeEnvironment.application)).getClass().getSimpleName()).isEqualTo(ShadowView.class.getSimpleName()); + assertThat( + shadowOf(new View(ApplicationProvider.getApplicationContext())) + .getClass() + .getSimpleName()) + .isEqualTo(ShadowView.class.getSimpleName()); } @Implements(View.class) diff --git a/robolectric/src/test/java/org/robolectric/TestRunnerSequenceTest.java b/robolectric/src/test/java/org/robolectric/TestRunnerSequenceTest.java index ec79166b4..adf29635c 100644 --- a/robolectric/src/test/java/org/robolectric/TestRunnerSequenceTest.java +++ b/robolectric/src/test/java/org/robolectric/TestRunnerSequenceTest.java @@ -158,7 +158,6 @@ public class TestRunnerSequenceTest { return builder.build(); } - @Override protected AndroidManifest getAppManifest(Config config) { return new AndroidManifest(resourceFile("TestAndroidManifest.xml"), resourceFile("res"), resourceFile("assets")); } diff --git a/robolectric/src/test/java/org/robolectric/android/AndroidInterceptorsIntegrationTest.java b/robolectric/src/test/java/org/robolectric/android/AndroidInterceptorsIntegrationTest.java index 63c3dd2b2..164be091e 100644 --- a/robolectric/src/test/java/org/robolectric/android/AndroidInterceptorsIntegrationTest.java +++ b/robolectric/src/test/java/org/robolectric/android/AndroidInterceptorsIntegrationTest.java @@ -2,6 +2,7 @@ package org.robolectric.android; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.lang.invoke.CallSite; @@ -12,13 +13,12 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.internal.bytecode.InvokeDynamicSupport; import org.robolectric.shadows.ShadowSystemClock; import org.robolectric.util.ReflectionHelpers.ClassParameter; /** Integration tests for Android interceptors. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class AndroidInterceptorsIntegrationTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/android/AndroidTranslatorClassInstrumentedTest.java b/robolectric/src/test/java/org/robolectric/android/AndroidTranslatorClassInstrumentedTest.java index e0ca20b41..0ea650bff 100644 --- a/robolectric/src/test/java/org/robolectric/android/AndroidTranslatorClassInstrumentedTest.java +++ b/robolectric/src/test/java/org/robolectric/android/AndroidTranslatorClassInstrumentedTest.java @@ -4,15 +4,15 @@ import static com.google.common.truth.Truth.assertThat; import android.graphics.Bitmap; import android.graphics.Paint; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.internal.Instrument; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(sdk = Config.NEWEST_SDK) public class AndroidTranslatorClassInstrumentedTest { diff --git a/robolectric/src/test/java/org/robolectric/android/BootstrapTest.java b/robolectric/src/test/java/org/robolectric/android/BootstrapTest.java index 18134803e..81ff41e6a 100644 --- a/robolectric/src/test/java/org/robolectric/android/BootstrapTest.java +++ b/robolectric/src/test/java/org/robolectric/android/BootstrapTest.java @@ -47,15 +47,16 @@ import android.os.Build; import android.util.DisplayMetrics; import android.view.Display; import android.view.DisplayInfo; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Locale; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class BootstrapTest { private Configuration configuration; @@ -76,8 +77,9 @@ public class BootstrapTest { @Config(qualifiers = "w480dp-h640dp") public void shouldSetUpRealisticDisplay() throws Exception { if (Build.VERSION.SDK_INT > JELLY_BEAN) { - DisplayManager displayManager = (DisplayManager) RuntimeEnvironment.application - .getSystemService(Context.DISPLAY_SERVICE); + DisplayManager displayManager = + (DisplayManager) + ApplicationProvider.getApplicationContext().getSystemService(Context.DISPLAY_SERVICE); DisplayInfo displayInfo = new DisplayInfo(); Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); display.getDisplayInfo(displayInfo); @@ -100,8 +102,8 @@ public class BootstrapTest { } } - DisplayMetrics displayMetrics = RuntimeEnvironment.application.getResources() - .getDisplayMetrics(); + DisplayMetrics displayMetrics = + ApplicationProvider.getApplicationContext().getResources().getDisplayMetrics(); assertThat(displayMetrics.widthPixels).isEqualTo(480); assertThat(displayMetrics.heightPixels).isEqualTo(640); } @@ -110,8 +112,9 @@ public class BootstrapTest { @Config(qualifiers = "w480dp-h640dp-land-hdpi") public void shouldSetUpRealisticDisplay_landscapeHighDensity() throws Exception { if (Build.VERSION.SDK_INT > JELLY_BEAN) { - DisplayManager displayManager = (DisplayManager) RuntimeEnvironment.application - .getSystemService(Context.DISPLAY_SERVICE); + DisplayManager displayManager = + (DisplayManager) + ApplicationProvider.getApplicationContext().getSystemService(Context.DISPLAY_SERVICE); DisplayInfo displayInfo = new DisplayInfo(); Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); display.getDisplayInfo(displayInfo); @@ -134,8 +137,8 @@ public class BootstrapTest { } } - DisplayMetrics displayMetrics = RuntimeEnvironment.application.getResources() - .getDisplayMetrics(); + DisplayMetrics displayMetrics = + ApplicationProvider.getApplicationContext().getResources().getDisplayMetrics(); assertThat(displayMetrics.widthPixels).isEqualTo(960); assertThat(displayMetrics.heightPixels).isEqualTo(720); } diff --git a/robolectric/src/test/java/org/robolectric/android/DefaultPackageManagerIntentComparatorTest.java b/robolectric/src/test/java/org/robolectric/android/DefaultPackageManagerIntentComparatorTest.java index 730835257..81bc04c75 100644 --- a/robolectric/src/test/java/org/robolectric/android/DefaultPackageManagerIntentComparatorTest.java +++ b/robolectric/src/test/java/org/robolectric/android/DefaultPackageManagerIntentComparatorTest.java @@ -3,12 +3,12 @@ package org.robolectric.android; import static com.google.common.truth.Truth.assertThat; import android.content.Intent; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowPackageManager.IntentComparator; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class DefaultPackageManagerIntentComparatorTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/android/DeviceConfigTest.java b/robolectric/src/test/java/org/robolectric/android/DeviceConfigTest.java index 95cb4ca6d..03d2d1942 100644 --- a/robolectric/src/test/java/org/robolectric/android/DeviceConfigTest.java +++ b/robolectric/src/test/java/org/robolectric/android/DeviceConfigTest.java @@ -6,16 +6,16 @@ import static com.google.common.truth.Truth.assertThat; import android.content.res.Configuration; import android.os.Build.VERSION_CODES; import android.util.DisplayMetrics; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.res.Qualifiers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class DeviceConfigTest { private Configuration configuration; diff --git a/robolectric/src/test/java/org/robolectric/android/DrawableResourceLoaderTest.java b/robolectric/src/test/java/org/robolectric/android/DrawableResourceLoaderTest.java index 82983114b..5709a73d1 100644 --- a/robolectric/src/test/java/org/robolectric/android/DrawableResourceLoaderTest.java +++ b/robolectric/src/test/java/org/robolectric/android/DrawableResourceLoaderTest.java @@ -17,27 +17,28 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.NinePatchDrawable; import android.graphics.drawable.VectorDrawable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class DrawableResourceLoaderTest { private Resources resources; @Before public void setup() throws Exception { assumeTrue(useLegacy()); - resources = RuntimeEnvironment.application.getResources(); + resources = ApplicationProvider.getApplicationContext().getResources(); } @Test public void testGetDrawable_rainbow() throws Exception { - assertNotNull(RuntimeEnvironment.application.getResources().getDrawable(R.drawable.rainbow)); + assertNotNull( + ApplicationProvider.getApplicationContext().getResources().getDrawable(R.drawable.rainbow)); } @Test @@ -71,12 +72,24 @@ public class DrawableResourceLoaderTest { @Test @Config(qualifiers = "land") public void testLayerDrawable_xlarge() { - assertEquals(6, ((LayerDrawable) RuntimeEnvironment.application.getResources().getDrawable(R.drawable.rainbow)).getNumberOfLayers()); + assertEquals( + 6, + ((LayerDrawable) + ApplicationProvider.getApplicationContext() + .getResources() + .getDrawable(R.drawable.rainbow)) + .getNumberOfLayers()); } @Test public void testLayerDrawable() { - assertEquals(8, ((LayerDrawable) RuntimeEnvironment.application.getResources().getDrawable(R.drawable.rainbow)).getNumberOfLayers()); + assertEquals( + 8, + ((LayerDrawable) + ApplicationProvider.getApplicationContext() + .getResources() + .getDrawable(R.drawable.rainbow)) + .getNumberOfLayers()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/android/FragmentTestUtilTest.java b/robolectric/src/test/java/org/robolectric/android/FragmentTestUtilTest.java index 326e3e476..9512c5f71 100644 --- a/robolectric/src/test/java/org/robolectric/android/FragmentTestUtilTest.java +++ b/robolectric/src/test/java/org/robolectric/android/FragmentTestUtilTest.java @@ -12,12 +12,12 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class FragmentTestUtilTest { @Test public void startFragment_shouldStartFragment() { diff --git a/robolectric/src/test/java/org/robolectric/android/PreferenceIntegrationTest.java b/robolectric/src/test/java/org/robolectric/android/PreferenceIntegrationTest.java index 803e852d4..34cc01416 100644 --- a/robolectric/src/test/java/org/robolectric/android/PreferenceIntegrationTest.java +++ b/robolectric/src/test/java/org/robolectric/android/PreferenceIntegrationTest.java @@ -14,13 +14,13 @@ import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; import android.preference.RingtonePreference; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class PreferenceIntegrationTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/android/ResourceLoaderTest.java b/robolectric/src/test/java/org/robolectric/android/ResourceLoaderTest.java index 2cbebe548..129aa5717 100644 --- a/robolectric/src/test/java/org/robolectric/android/ResourceLoaderTest.java +++ b/robolectric/src/test/java/org/robolectric/android/ResourceLoaderTest.java @@ -12,19 +12,20 @@ import android.os.Build.VERSION_CODES; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Locale; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.res.ResName; import org.robolectric.res.ResourceTable; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ResourceLoaderTest { private String optsForO; @@ -41,13 +42,21 @@ public class ResourceLoaderTest { @Test @Config(qualifiers="w0dp") public void checkDefaultBooleanValue() throws Exception { - assertThat(RuntimeEnvironment.application.getResources().getBoolean(R.bool.different_resource_boolean)).isEqualTo(false); + assertThat( + ApplicationProvider.getApplicationContext() + .getResources() + .getBoolean(R.bool.different_resource_boolean)) + .isEqualTo(false); } @Test @Config(qualifiers="w820dp") public void checkQualifiedBooleanValue() throws Exception { - assertThat(RuntimeEnvironment.application.getResources().getBoolean(R.bool.different_resource_boolean)).isEqualTo(true); + assertThat( + ApplicationProvider.getApplicationContext() + .getResources() + .getBoolean(R.bool.different_resource_boolean)) + .isEqualTo(true); } @Test @@ -64,7 +73,9 @@ public class ResourceLoaderTest { assertThat(RuntimeEnvironment.getQualifiers()) .isEqualTo("en-rUS-ldltr-sw320dp-w320dp-h470dp-normal-notlong-notround-" + optsForO + "port-notnight-mdpi-finger-keyssoft-nokeys-navhidden-nonav-v" + Build.VERSION.RESOURCES_SDK_INT); - View view = LayoutInflater.from(RuntimeEnvironment.application).inflate(R.layout.different_screen_sizes, null); + View view = + LayoutInflater.from(ApplicationProvider.getApplicationContext()) + .inflate(R.layout.different_screen_sizes, null); TextView textView = view.findViewById(android.R.id.text1); assertThat(textView.getText().toString()).isEqualTo("default"); RuntimeEnvironment.setQualifiers("fr-land"); // testing if this pollutes the other test @@ -91,6 +102,7 @@ public class ResourceLoaderTest { internalResourceId = (Integer) internalRIdClass.getDeclaredField(internalResource.name).get(null); assertThat(resId).isEqualTo(internalResourceId); - assertThat(RuntimeEnvironment.application.getResources().getString(resId)).isEqualTo("The old PIN you typed isn't correct."); + assertThat(ApplicationProvider.getApplicationContext().getResources().getString(resId)) + .isEqualTo("The old PIN you typed isn't correct."); } } diff --git a/robolectric/src/test/java/org/robolectric/android/ResourceTableFactoryIntegrationTest.java b/robolectric/src/test/java/org/robolectric/android/ResourceTableFactoryIntegrationTest.java index ceb4f84cf..65b523ad4 100644 --- a/robolectric/src/test/java/org/robolectric/android/ResourceTableFactoryIntegrationTest.java +++ b/robolectric/src/test/java/org/robolectric/android/ResourceTableFactoryIntegrationTest.java @@ -5,14 +5,14 @@ import static org.junit.Assume.assumeTrue; import static org.robolectric.shadows.ShadowAssetManager.useLegacy; import android.os.Build; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.res.ResName; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = Build.VERSION_CODES.L) public class ResourceTableFactoryIntegrationTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/android/ShadowingTest.java b/robolectric/src/test/java/org/robolectric/android/ShadowingTest.java index ba76b21e2..41b91a819 100644 --- a/robolectric/src/test/java/org/robolectric/android/ShadowingTest.java +++ b/robolectric/src/test/java/org/robolectric/android/ShadowingTest.java @@ -4,15 +4,16 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import android.app.Application; import android.util.Log; import android.view.View; import android.widget.Toast; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowingTest { @Test @@ -22,17 +23,19 @@ public class ShadowingTest { @Test public void shouldDelegateToObjectToStringIfShadowHasNone() throws Exception { - assertThat(new Toast(RuntimeEnvironment.application).toString()).startsWith("android.widget.Toast@"); + assertThat(new Toast((Application) ApplicationProvider.getApplicationContext()).toString()) + .startsWith("android.widget.Toast@"); } @Test public void shouldDelegateToObjectHashCodeIfShadowHasNone() throws Exception { - assertFalse(new View(RuntimeEnvironment.application).hashCode() == 0); + assertFalse( + new View((Application) ApplicationProvider.getApplicationContext()).hashCode() == 0); } @Test public void shouldDelegateToObjectEqualsIfShadowHasNone() throws Exception { - View view = new View(RuntimeEnvironment.application); + View view = new View((Application) ApplicationProvider.getApplicationContext()); assertEquals(view, view); } } diff --git a/robolectric/src/test/java/org/robolectric/android/XmlResourceParserImplTest.java b/robolectric/src/test/java/org/robolectric/android/XmlResourceParserImplTest.java index cbd887df2..5f930af8d 100644 --- a/robolectric/src/test/java/org/robolectric/android/XmlResourceParserImplTest.java +++ b/robolectric/src/test/java/org/robolectric/android/XmlResourceParserImplTest.java @@ -7,7 +7,10 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; +import android.app.Application; import android.content.res.XmlResourceParser; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -24,13 +27,12 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.w3c.dom.Document; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class XmlResourceParserImplTest { private static final String RES_AUTO_NS = "http://schemas.android.com/apk/res-auto"; @@ -38,7 +40,10 @@ public class XmlResourceParserImplTest { @Before public void setUp() throws Exception { - parser = RuntimeEnvironment.application.getResources().getXml(R.xml.preferences); + parser = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getXml(R.xml.preferences); } @After @@ -573,7 +578,10 @@ public class XmlResourceParserImplTest { @Test public void testGetAttributeResourceValueIntInt() throws Exception { - parser = RuntimeEnvironment.application.getResources().getXml(R.xml.has_attribute_resource_value); + parser = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getXml(R.xml.has_attribute_resource_value); parseUntilNext(XmlResourceParser.START_TAG); assertThat(parser.getAttributeResourceValue(0, 42)).isEqualTo(R.layout.main); @@ -581,7 +589,10 @@ public class XmlResourceParserImplTest { @Test public void testGetAttributeResourceValueStringStringInt() throws Exception { - parser = RuntimeEnvironment.application.getResources().getXml(R.xml.has_attribute_resource_value); + parser = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getXml(R.xml.has_attribute_resource_value); parseUntilNext(XmlResourceParser.START_TAG); assertThat(parser.getAttributeResourceValue(RES_AUTO_NS, "bar", 42)).isEqualTo(R.layout.main); @@ -705,7 +716,10 @@ public class XmlResourceParserImplTest { public void testGetIdAttributeResourceValue_defaultValue() throws Exception { assertThat(parser.getIdAttributeResourceValue(12)).isEqualTo(12); - parser = RuntimeEnvironment.application.getResources().getXml(R.xml.has_id); + parser = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getXml(R.xml.has_id); parseUntilNext(XmlResourceParser.START_TAG); assertThat(parser.getIdAttributeResourceValue(12)).isEqualTo(R.id.tacos); } @@ -718,14 +732,20 @@ public class XmlResourceParserImplTest { @Test public void getStyleAttribute_allowStyleAttrReference() throws Exception { - parser = RuntimeEnvironment.application.getResources().getXml(R.xml.has_style_attribute_reference); + parser = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getXml(R.xml.has_style_attribute_reference); parseUntilNext(XmlResourceParser.START_TAG); assertThat(parser.getStyleAttribute()).isEqualTo(R.attr.parentStyleReference); } @Test public void getStyleAttribute_allowStyleAttrReferenceLackingExplicitAttrType() throws Exception { - parser = RuntimeEnvironment.application.getResources().getXml(R.xml.has_parent_style_reference); + parser = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getXml(R.xml.has_parent_style_reference); parseUntilNext(XmlResourceParser.START_TAG); assertThat(parser.getStyleAttribute()).isEqualTo(R.attr.parentStyleReference); } diff --git a/robolectric/src/test/java/org/robolectric/android/controller/ActivityControllerTest.java b/robolectric/src/test/java/org/robolectric/android/controller/ActivityControllerTest.java index 99907d772..ea4375763 100644 --- a/robolectric/src/test/java/org/robolectric/android/controller/ActivityControllerTest.java +++ b/robolectric/src/test/java/org/robolectric/android/controller/ActivityControllerTest.java @@ -16,6 +16,8 @@ import android.view.ContextThemeWrapper; import android.view.ViewRootImpl; import android.view.Window; import android.widget.LinearLayout; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; @@ -23,14 +25,13 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowLooper; import org.robolectric.util.Scheduler; import org.robolectric.util.TestRunnable; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ActivityControllerTest { private static final List<String> transcript = new ArrayList<>(); private final ComponentName componentName = new ComponentName("org.robolectric", MyActivity.class.getName()); @@ -220,7 +221,9 @@ public class ActivityControllerTest { @Test public void configurationChange_callsLifecycleMethodsAndAppliesConfig() { - Configuration config = new Configuration(RuntimeEnvironment.application.getResources().getConfiguration()); + Configuration config = + new Configuration( + ApplicationProvider.getApplicationContext().getResources().getConfiguration()); final float newFontScale = config.fontScale *= 2; controller.setup(); @@ -232,7 +235,9 @@ public class ActivityControllerTest { @Test public void configurationChange_callsOnConfigurationChangedAndAppliesConfigWhenAllManaged() { - Configuration config = new Configuration(RuntimeEnvironment.application.getResources().getConfiguration()); + Configuration config = + new Configuration( + ApplicationProvider.getApplicationContext().getResources().getConfiguration()); final float newFontScale = config.fontScale *= 2; ActivityController<ConfigAwareActivity> configController = @@ -245,7 +250,9 @@ public class ActivityControllerTest { @Test public void configurationChange_callsLifecycleMethodsAndAppliesConfigWhenAnyNonManaged() { - Configuration config = new Configuration(RuntimeEnvironment.application.getResources().getConfiguration()); + Configuration config = + new Configuration( + ApplicationProvider.getApplicationContext().getResources().getConfiguration()); final float newFontScale = config.fontScale *= 2; final int newOrientation = config.orientation = (config.orientation + 1) % 3; @@ -272,7 +279,9 @@ public class ActivityControllerTest { @Test @Config(qualifiers = "land") public void configurationChange_restoresTheme() { - Configuration config = new Configuration(RuntimeEnvironment.application.getResources().getConfiguration()); + Configuration config = + new Configuration( + ApplicationProvider.getApplicationContext().getResources().getConfiguration()); config.orientation = Configuration.ORIENTATION_PORTRAIT; controller.get().setTheme(android.R.style.Theme_Black); @@ -286,7 +295,9 @@ public class ActivityControllerTest { @Test @Config(qualifiers = "land") public void configurationChange_reattachesRetainedFragments() { - Configuration config = new Configuration(RuntimeEnvironment.application.getResources().getConfiguration()); + Configuration config = + new Configuration( + ApplicationProvider.getApplicationContext().getResources().getConfiguration()); config.orientation = Configuration.ORIENTATION_PORTRAIT; ActivityController<NonConfigStateActivity> configController = @@ -329,7 +340,7 @@ public class ActivityControllerTest { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_ACTION_BAR); - setContentView(new LinearLayout(RuntimeEnvironment.application)); + setContentView(new LinearLayout(ApplicationProvider.getApplicationContext())); transcribeWhilePaused("onCreate"); transcript.add("finishedOnCreate"); } diff --git a/robolectric/src/test/java/org/robolectric/android/controller/BackupAgentControllerTest.java b/robolectric/src/test/java/org/robolectric/android/controller/BackupAgentControllerTest.java index 313fc20c0..6b90ea93b 100644 --- a/robolectric/src/test/java/org/robolectric/android/controller/BackupAgentControllerTest.java +++ b/robolectric/src/test/java/org/robolectric/android/controller/BackupAgentControllerTest.java @@ -2,25 +2,27 @@ package org.robolectric.android.controller; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.app.backup.BackupAgent; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.os.ParcelFileDescriptor; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.IOException; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class BackupAgentControllerTest { private final BackupAgentController<MyBackupAgent> backupAgentController = Robolectric.buildBackupAgent(MyBackupAgent.class); @Test public void shouldSetBaseContext() throws Exception { MyBackupAgent myBackupAgent = backupAgentController.get(); - assertThat(myBackupAgent.getBaseContext()).isEqualTo(RuntimeEnvironment.application.getBaseContext()); + assertThat(myBackupAgent.getBaseContext()) + .isEqualTo(((Application) ApplicationProvider.getApplicationContext()).getBaseContext()); } public static class MyBackupAgent extends BackupAgent { diff --git a/robolectric/src/test/java/org/robolectric/android/controller/ContentProviderControllerTest.java b/robolectric/src/test/java/org/robolectric/android/controller/ContentProviderControllerTest.java index fecc62f78..190e8878a 100644 --- a/robolectric/src/test/java/org/robolectric/android/controller/ContentProviderControllerTest.java +++ b/robolectric/src/test/java/org/robolectric/android/controller/ContentProviderControllerTest.java @@ -2,33 +2,35 @@ package org.robolectric.android.controller; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.pm.PathPermission; import android.content.pm.ProviderInfo; import android.net.Uri; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.testing.TestContentProvider1; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ContentProviderControllerTest { private final ContentProviderController<TestContentProvider1> controller = Robolectric.buildContentProvider(TestContentProvider1.class); private ContentResolver contentResolver; @Before public void setUp() throws Exception { - contentResolver = RuntimeEnvironment.application.getContentResolver(); + contentResolver = ApplicationProvider.getApplicationContext().getContentResolver(); } @Test public void shouldSetBaseContext() throws Exception { TestContentProvider1 myContentProvider = controller.create().get(); - assertThat(myContentProvider.getContext()).isEqualTo(RuntimeEnvironment.application.getBaseContext()); + assertThat(myContentProvider.getContext()) + .isEqualTo(((Application) ApplicationProvider.getApplicationContext()).getBaseContext()); } @Test @@ -100,8 +102,10 @@ public class ContentProviderControllerTest { static class XContentProvider extends TestContentProvider1 { @Override public boolean onCreate() { - ContentProviderClient contentProviderClient = RuntimeEnvironment.application.getContentResolver() - .acquireContentProviderClient("x-authority"); + ContentProviderClient contentProviderClient = + ApplicationProvider.getApplicationContext() + .getContentResolver() + .acquireContentProviderClient("x-authority"); transcript.add(contentProviderClient == null ? "x-authority not registered yet" : "x-authority is registered"); return false; } diff --git a/robolectric/src/test/java/org/robolectric/android/controller/FragmentControllerTest.java b/robolectric/src/test/java/org/robolectric/android/controller/FragmentControllerTest.java index 5a9b8abd6..b23e522ca 100644 --- a/robolectric/src/test/java/org/robolectric/android/controller/FragmentControllerTest.java +++ b/robolectric/src/test/java/org/robolectric/android/controller/FragmentControllerTest.java @@ -13,12 +13,12 @@ import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class FragmentControllerTest { private static final int VIEW_ID_CUSTOMIZED_LOGIN_ACTIVITY = 123; diff --git a/robolectric/src/test/java/org/robolectric/android/controller/IntentServiceControllerTest.java b/robolectric/src/test/java/org/robolectric/android/controller/IntentServiceControllerTest.java index 5096b7985..67115f8ba 100644 --- a/robolectric/src/test/java/org/robolectric/android/controller/IntentServiceControllerTest.java +++ b/robolectric/src/test/java/org/robolectric/android/controller/IntentServiceControllerTest.java @@ -9,16 +9,16 @@ import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowLooper; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class IntentServiceControllerTest { private static final List<String> transcript = new ArrayList<>(); private final ComponentName componentName = new ComponentName("org.robolectric", MyService.class.getName()); diff --git a/robolectric/src/test/java/org/robolectric/android/controller/ServiceControllerTest.java b/robolectric/src/test/java/org/robolectric/android/controller/ServiceControllerTest.java index 0e919a9cb..e86258f19 100644 --- a/robolectric/src/test/java/org/robolectric/android/controller/ServiceControllerTest.java +++ b/robolectric/src/test/java/org/robolectric/android/controller/ServiceControllerTest.java @@ -9,16 +9,16 @@ import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowLooper; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ServiceControllerTest { private static final List<String> transcript = new ArrayList<>(); private final ComponentName componentName = new ComponentName("org.robolectric", MyService.class.getName()); @@ -112,14 +112,14 @@ public class ServiceControllerTest { private Handler handler = new Handler(Looper.getMainLooper()); public Intent boundIntent; - + public Intent reboundIntent; public Intent startIntent; public int startFlags; public int startId; - + public Intent unboundIntent; - + @Override public IBinder onBind(Intent intent) { boundIntent = intent; diff --git a/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseCreateApplicationTest.java b/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseCreateApplicationTest.java index c49d82d8a..7cc24beef 100644 --- a/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseCreateApplicationTest.java +++ b/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseCreateApplicationTest.java @@ -5,6 +5,8 @@ import static org.robolectric.Shadows.shadowOf; import static org.robolectric.android.internal.ParallelUniverse.registerBroadcastReceivers; import android.app.Application; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.base.Charsets; import com.google.common.io.Files; import java.io.File; @@ -15,7 +17,6 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.robolectric.FakeApp; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.TestFakeApp; import org.robolectric.annotation.Config; @@ -24,7 +25,7 @@ import org.robolectric.res.Fs; import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.testing.TestApplication; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ParallelUniverseCreateApplicationTest { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -49,7 +50,7 @@ public class ParallelUniverseCreateApplicationTest { } @Test public void shouldAssignThePackageNameFromTheManifest() throws Exception { - Application application = RuntimeEnvironment.application; + Application application = ApplicationProvider.getApplicationContext(); assertThat(application.getPackageName()).isEqualTo("org.robolectric"); assertThat(application).isInstanceOf(TestApplication.class); @@ -58,7 +59,9 @@ public class ParallelUniverseCreateApplicationTest { @Test public void shouldRegisterReceiversFromTheManifest() throws Exception { // gross: - shadowOf(RuntimeEnvironment.application).getRegisteredReceivers().clear(); + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .getRegisteredReceivers() + .clear(); AndroidManifest appManifest = newConfigWith( "<application>" diff --git a/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseTest.java b/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseTest.java index c5d9e46b1..db1a46b9a 100644 --- a/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseTest.java +++ b/robolectric/src/test/java/org/robolectric/android/internal/ParallelUniverseTest.java @@ -11,6 +11,7 @@ import android.app.Application; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; +import androidx.test.core.app.ApplicationProvider; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.util.Locale; @@ -61,7 +62,8 @@ public class ParallelUniverseTest { RoboSettings.setUseGlobalScheduler(true); try { bootstrapWrapper.callSetUpApplicationState(); - final ShadowApplication shadowApplication = Shadow.extract(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadow.extract(ApplicationProvider.getApplicationContext()); assertThat(shadowApplication.getBackgroundThreadScheduler()) .isSameAs(shadowApplication.getForegroundThreadScheduler()); assertThat(RuntimeEnvironment.getMasterScheduler()) @@ -74,7 +76,8 @@ public class ParallelUniverseTest { @Test public void setUpApplicationState_setsBackgroundScheduler_toBeDifferentToForeground_byDefault() { bootstrapWrapper.callSetUpApplicationState(); - final ShadowApplication shadowApplication = Shadow.extract(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadow.extract(ApplicationProvider.getApplicationContext()); assertThat(shadowApplication.getBackgroundThreadScheduler()) .isNotSameAs(shadowApplication.getForegroundThreadScheduler()); } diff --git a/robolectric/src/test/java/org/robolectric/android/util/concurrent/RoboExecutorServiceTest.java b/robolectric/src/test/java/org/robolectric/android/util/concurrent/RoboExecutorServiceTest.java index bab7e16a2..b31609947 100644 --- a/robolectric/src/test/java/org/robolectric/android/util/concurrent/RoboExecutorServiceTest.java +++ b/robolectric/src/test/java/org/robolectric/android/util/concurrent/RoboExecutorServiceTest.java @@ -2,6 +2,7 @@ package org.robolectric.android.util.concurrent; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; @@ -11,11 +12,10 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowApplication; import org.robolectric.util.Scheduler; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class RoboExecutorServiceTest { private final List<String> transcript = new ArrayList<>(); private final RoboExecutorService executorService = new RoboExecutorService(); diff --git a/robolectric/src/test/java/org/robolectric/fakes/RoboCursorTest.java b/robolectric/src/test/java/org/robolectric/fakes/RoboCursorTest.java index bdde6e3e2..ba57971cf 100644 --- a/robolectric/src/test/java/org/robolectric/fakes/RoboCursorTest.java +++ b/robolectric/src/test/java/org/robolectric/fakes/RoboCursorTest.java @@ -8,13 +8,13 @@ import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class RoboCursorTest { private static final String STRING_COLUMN = "stringColumn"; private static final String LONG_COLUMN = "longColumn"; @@ -31,7 +31,7 @@ public class RoboCursorTest { @Before public void setup() throws Exception { - contentResolver = RuntimeEnvironment.application.getContentResolver(); + contentResolver = ApplicationProvider.getApplicationContext().getContentResolver(); shadowOf(contentResolver).setCursor(uri, cursor); cursor.setColumnNames(asList( @@ -112,7 +112,7 @@ public class RoboCursorTest { @Test public void get_shouldConvert() throws Exception { cursor.setResults(new Object[][]{new Object[]{ - "aString", 1234L, "42", new byte[]{1, 2, 3}, 255, "1.25", 2.5d, null + "aString", "1234", "42", new byte[]{1, 2, 3}, 255, "1.25", 2.5d, null }}); assertThat(cursor.getCount()).isEqualTo(1); assertThat(cursor.moveToNext()).isTrue(); diff --git a/robolectric/src/test/java/org/robolectric/fakes/RoboMenuItemTest.java b/robolectric/src/test/java/org/robolectric/fakes/RoboMenuItemTest.java index 8fda1b943..e086ffed5 100644 --- a/robolectric/src/test/java/org/robolectric/fakes/RoboMenuItemTest.java +++ b/robolectric/src/test/java/org/robolectric/fakes/RoboMenuItemTest.java @@ -3,24 +3,25 @@ package org.robolectric.fakes; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.graphics.drawable.Drawable; import android.view.MenuItem; import android.view.View; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class RoboMenuItemTest { private MenuItem item; private TestOnActionExpandListener listener; @Before public void setUp() throws Exception { - item = new RoboMenuItem(RuntimeEnvironment.application); + item = new RoboMenuItem((Application) ApplicationProvider.getApplicationContext()); listener = new TestOnActionExpandListener(); item.setOnActionExpandListener(listener); } @@ -54,14 +55,14 @@ public class RoboMenuItemTest { @Test public void expandActionView_shouldSetExpandedTrue() throws Exception { - item.setActionView(new View(RuntimeEnvironment.application)); + item.setActionView(new View((Application) ApplicationProvider.getApplicationContext())); assertThat(item.expandActionView()).isTrue(); assertThat(item.isActionViewExpanded()).isTrue(); } @Test public void expandActionView_shouldInvokeListener() throws Exception { - item.setActionView(new View(RuntimeEnvironment.application)); + item.setActionView(new View((Application) ApplicationProvider.getApplicationContext())); item.expandActionView(); assertThat(listener.expanded).isTrue(); } @@ -74,7 +75,7 @@ public class RoboMenuItemTest { @Test public void collapseActionView_shouldSetExpandedFalse() throws Exception { - item.setActionView(new View(RuntimeEnvironment.application)); + item.setActionView(new View((Application) ApplicationProvider.getApplicationContext())); item.expandActionView(); assertThat(item.collapseActionView()).isTrue(); assertThat(item.isActionViewExpanded()).isFalse(); @@ -82,7 +83,7 @@ public class RoboMenuItemTest { @Test public void collapseActionView_shouldInvokeListener() throws Exception { - item.setActionView(new View(RuntimeEnvironment.application)); + item.setActionView(new View((Application) ApplicationProvider.getApplicationContext())); listener.expanded = true; item.collapseActionView(); assertThat(listener.expanded).isFalse(); @@ -141,7 +142,10 @@ public class RoboMenuItemTest { @Test public void getIcon_shouldReturnDrawableFromSetIconDrawable() throws Exception { - Drawable testDrawable = RuntimeEnvironment.application.getResources().getDrawable(R.drawable.an_image); + Drawable testDrawable = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDrawable(R.drawable.an_image); assertThat(testDrawable).isNotNull(); assertThat(item.getIcon()).isNull(); item.setIcon(testDrawable); diff --git a/robolectric/src/test/java/org/robolectric/fakes/RoboMenuTest.java b/robolectric/src/test/java/org/robolectric/fakes/RoboMenuTest.java index 712fb9a4c..36af367ea 100644 --- a/robolectric/src/test/java/org/robolectric/fakes/RoboMenuTest.java +++ b/robolectric/src/test/java/org/robolectric/fakes/RoboMenuTest.java @@ -5,22 +5,23 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import android.app.Activity; +import android.app.Application; import android.content.Intent; import android.view.MenuItem; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowApplication; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class RoboMenuTest { @Test public void addAndRemoveMenuItems() { - RoboMenu menu = new RoboMenu(RuntimeEnvironment.application); + RoboMenu menu = new RoboMenu((Application) ApplicationProvider.getApplicationContext()); menu.add(9, 10, 0, org.robolectric.R.string.ok); RoboMenuItem item = (RoboMenuItem) menu.findItem(10); @@ -36,7 +37,7 @@ public class RoboMenuTest { @Test public void addSubMenu() { - RoboMenu menu = new RoboMenu(RuntimeEnvironment.application); + RoboMenu menu = new RoboMenu((Application) ApplicationProvider.getApplicationContext()); menu.addSubMenu(9, 10, 0, org.robolectric.R.string.ok); RoboMenuItem item = (RoboMenuItem) menu.findItem(10); @@ -66,7 +67,7 @@ public class RoboMenuTest { @Test public void add_AddsItemsInOrder() { - RoboMenu menu = new RoboMenu(RuntimeEnvironment.application); + RoboMenu menu = new RoboMenu((Application) ApplicationProvider.getApplicationContext()); menu.add(0, 0, 1, "greeting"); menu.add(0, 0, 0, "hell0"); menu.add(0, 0, 0, "hello"); diff --git a/robolectric/src/test/java/org/robolectric/fakes/RoboWebSettingsTest.java b/robolectric/src/test/java/org/robolectric/fakes/RoboWebSettingsTest.java index 9179ecd97..0f76fbcd2 100644 --- a/robolectric/src/test/java/org/robolectric/fakes/RoboWebSettingsTest.java +++ b/robolectric/src/test/java/org/robolectric/fakes/RoboWebSettingsTest.java @@ -3,13 +3,13 @@ package org.robolectric.fakes; import static com.google.common.truth.Truth.assertThat; import android.webkit.WebSettings; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.internal.DoNotInstrument; @DoNotInstrument -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class RoboWebSettingsTest { private final RoboWebSettings webSettings = new RoboWebSettings(); private static final boolean[] TRUE_AND_FALSE = {true, false}; diff --git a/robolectric/src/test/java/org/robolectric/internal/DefaultManifestFactoryTest.java b/robolectric/src/test/java/org/robolectric/internal/DefaultManifestFactoryTest.java index 8b2e6615b..8c6465a14 100644 --- a/robolectric/src/test/java/org/robolectric/internal/DefaultManifestFactoryTest.java +++ b/robolectric/src/test/java/org/robolectric/internal/DefaultManifestFactoryTest.java @@ -137,4 +137,4 @@ public class DefaultManifestFactoryTest { assertThat(manifest.getRClassName()) .isEqualTo("overridden.package.R"); } -} +}
\ No newline at end of file diff --git a/robolectric/src/test/java/org/robolectric/internal/dependency/MavenDependencyResolverTest.java b/robolectric/src/test/java/org/robolectric/internal/dependency/MavenDependencyResolverTest.java index 788e83b72..ec47cdebb 100644 --- a/robolectric/src/test/java/org/robolectric/internal/dependency/MavenDependencyResolverTest.java +++ b/robolectric/src/test/java/org/robolectric/internal/dependency/MavenDependencyResolverTest.java @@ -28,6 +28,10 @@ public class MavenDependencyResolverTest { private static final String REPOSITORY_ID = "remote"; + private static final String REPOSITORY_USERNAME = "username"; + + private static final String REPOSITORY_PASSWORD = "password"; + private DependenciesTask dependenciesTask; private Project project; @@ -114,7 +118,7 @@ public class MavenDependencyResolverTest { } private DependencyResolver createResolver() { - return new MavenDependencyResolver(REPOSITORY_URL, REPOSITORY_ID) { + return new MavenDependencyResolver(REPOSITORY_URL, REPOSITORY_ID, REPOSITORY_USERNAME, REPOSITORY_PASSWORD) { @Override protected DependenciesTask createDependenciesTask() { return dependenciesTask; diff --git a/robolectric/src/test/java/org/robolectric/json/JSONArrayTest.java b/robolectric/src/test/java/org/robolectric/json/JSONArrayTest.java index 7d4ffed63..d6df95a30 100644 --- a/robolectric/src/test/java/org/robolectric/json/JSONArrayTest.java +++ b/robolectric/src/test/java/org/robolectric/json/JSONArrayTest.java @@ -2,13 +2,13 @@ package org.robolectric.json; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Arrays; import org.json.JSONArray; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class JSONArrayTest { @Test public void testEquality() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/junit/rules/ExpectedLogMessagesRuleTest.java b/robolectric/src/test/java/org/robolectric/junit/rules/ExpectedLogMessagesRuleTest.java index 5905ac97b..b642f7909 100644 --- a/robolectric/src/test/java/org/robolectric/junit/rules/ExpectedLogMessagesRuleTest.java +++ b/robolectric/src/test/java/org/robolectric/junit/rules/ExpectedLogMessagesRuleTest.java @@ -1,15 +1,15 @@ package org.robolectric.junit.rules; import android.util.Log; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.RuleChain; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; /** Tests for {@link ExpectedLogMessagesRule}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public final class ExpectedLogMessagesRuleTest { private ExpectedLogMessagesRule rule = new ExpectedLogMessagesRule(); diff --git a/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java b/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java index 398e889c1..80ed5339e 100644 --- a/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java +++ b/robolectric/src/test/java/org/robolectric/manifest/AndroidManifestTest.java @@ -35,10 +35,12 @@ public class AndroidManifestTest { assertThat(config.getContentProviders().get(0).getName()) .isEqualTo("org.robolectric.tester.FullyQualifiedClassName"); assertThat(config.getContentProviders().get(0).getAuthorities()).isEqualTo("org.robolectric.authority1"); + assertThat(config.getContentProviders().get(0).isEnabled()).isTrue(); assertThat(config.getContentProviders().get(1).getName()) .isEqualTo("org.robolectric.tester.PartiallyQualifiedClassName"); assertThat(config.getContentProviders().get(1).getAuthorities()).isEqualTo("org.robolectric.authority2"); + assertThat(config.getContentProviders().get(1).isEnabled()).isFalse(); } @Test @@ -92,6 +94,7 @@ public class AndroidManifestTest { assertThat(config.getBroadcastReceivers().get(4).getName()) .isEqualTo("org.robolectric.test.ConfigTestReceiver"); assertThat(config.getBroadcastReceivers().get(4).getActions()).contains("org.robolectric.ACTION_DOT_SUBPACKAGE"); + assertThat(config.getBroadcastReceivers().get(4).isEnabled()).isFalse(); assertThat(config.getBroadcastReceivers().get(5).getName()).isEqualTo("com.foo.Receiver"); assertThat(config.getBroadcastReceivers().get(5).getActions()).contains("org.robolectric.ACTION_DIFFERENT_PACKAGE"); @@ -126,6 +129,9 @@ public class AndroidManifestTest { assertThat(config.getServiceData("com.bar.ServiceWithoutIntentFilter").getClassName()).isEqualTo("com.bar.ServiceWithoutIntentFilter"); assertThat(config.getServiceData("com.foo.Service").getPermission()) .isEqualTo("com.foo.Permission"); + + assertThat(config.getServiceData("com.foo.Service").isEnabled()).isTrue(); + assertThat(config.getServiceData("com.bar.ServiceWithoutIntentFilter").isEnabled()).isFalse(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/res/ResourceParserTest.java b/robolectric/src/test/java/org/robolectric/res/ResourceParserTest.java index b92c18e71..7b5d59ebe 100644 --- a/robolectric/src/test/java/org/robolectric/res/ResourceParserTest.java +++ b/robolectric/src/test/java/org/robolectric/res/ResourceParserTest.java @@ -22,9 +22,8 @@ public class ResourceParserTest { config = new ResTable_config(); } - @Test - public void shouldLoadDrawableXmlResources() throws Exception { + public void shouldLoadDrawableXmlResources() { TypedResource value = resourceTable.getValue(new ResName("org.robolectric", "drawable", "rainbow"), config); assertThat(value).isNotNull(); assertThat(value.getResType()).isEqualTo(ResType.DRAWABLE); @@ -33,7 +32,7 @@ public class ResourceParserTest { } @Test - public void shouldLoadDrawableBitmapResources() throws Exception { + public void shouldLoadDrawableBitmapResources() { TypedResource value = resourceTable.getValue(new ResName("org.robolectric", "drawable", "an_image"), config); assertThat(value).isNotNull(); assertThat(value.getResType()).isEqualTo(ResType.DRAWABLE); @@ -42,7 +41,7 @@ public class ResourceParserTest { } @Test - public void shouldLoadDrawableBitmapResourcesDefinedByItemTag() throws Exception { + public void shouldLoadDrawableBitmapResourcesDefinedByItemTag() { TypedResource value = resourceTable.getValue(new ResName("org.robolectric", "drawable", "example_item_drawable"), config); assertThat(value).isNotNull(); assertThat(value.getResType()).isEqualTo(ResType.DRAWABLE); @@ -51,18 +50,20 @@ public class ResourceParserTest { } @Test - public void shouldLoadIdResourcesDefinedByItemTag() throws Exception { + public void shouldLoadIdResourcesDefinedByItemTag() { TypedResource value = resourceTable.getValue(new ResName("org.robolectric", "id", "id_declared_in_item_tag"), config); assertThat(value).isNotNull(); assertThat(value.getResType()).isEqualTo(ResType.CHAR_SEQUENCE); assertThat(value.isReference()).isFalse(); - assertThat(value.asString()).isEqualTo(""); - assertThat((String) value.getData()).isEqualTo(""); + assertThat(value.asString()).isEmpty(); + assertThat((String) value.getData()).isEmpty(); } @Test - public void whenIdItemsHaveStringContent_shouldLoadIdResourcesDefinedByItemTag() throws Exception { - TypedResource value2 = resourceTable.getValue(new ResName("org.robolectric", "id", "id_with_string_value"), config); - assertThat(value2.asString()).isEqualTo("string value"); + public void whenIdItemsHaveStringContent_shouldLoadIdResourcesDefinedByItemTag() { + TypedResource value = + resourceTable.getValue( + new ResName("org.robolectric", "id", "id_with_string_value"), config); + assertThat(value.asString()).isEmpty(); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/AdapterViewBehavior.java b/robolectric/src/test/java/org/robolectric/shadows/AdapterViewBehavior.java index 1a8312f0c..a551efa26 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/AdapterViewBehavior.java +++ b/robolectric/src/test/java/org/robolectric/shadows/AdapterViewBehavior.java @@ -7,15 +7,15 @@ import android.os.Looper; import android.view.View; import android.widget.AdapterView; import android.widget.TextView; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) abstract public class AdapterViewBehavior { private AdapterView adapterView; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ConverterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ConverterTest.java index e7b20abb5..ea1f7ec44 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ConverterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ConverterTest.java @@ -2,11 +2,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.res.Fs; import org.robolectric.res.FsFile; import org.robolectric.res.Qualifiers; @@ -14,7 +14,7 @@ import org.robolectric.res.ResType; import org.robolectric.res.TypedResource; import org.robolectric.res.XmlContext; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ConverterTest { private XmlContext xmlContext; diff --git a/robolectric/src/test/java/org/robolectric/shadows/LegacyManifestParserTest.java b/robolectric/src/test/java/org/robolectric/shadows/LegacyManifestParserTest.java index 8bb0b3a0e..7307d9b10 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/LegacyManifestParserTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/LegacyManifestParserTest.java @@ -6,15 +6,15 @@ import static org.robolectric.util.TestUtil.resourceFile; import android.content.pm.PackageParser.Package; import android.content.pm.PackageParser.Permission; import android.content.pm.PermissionInfo; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.manifest.AndroidManifest; /** Unit test for {@link org.robolectric.shadows.LegacyManifestParser}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class LegacyManifestParserTest { private AndroidManifest androidManifest; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ResourceHelperTest.java b/robolectric/src/test/java/org/robolectric/shadows/ResourceHelperTest.java index 32ac135f2..9edaac17a 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ResourceHelperTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ResourceHelperTest.java @@ -3,15 +3,13 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.util.TypedValue; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -/** - * Unit tests for {@link ResourceHelper}. - */ -@RunWith(RobolectricTestRunner.class) +/** Unit tests for {@link ResourceHelper}. */ +@RunWith(AndroidJUnit4.class) public class ResourceHelperTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/SQLiteCursorTest.java b/robolectric/src/test/java/org/robolectric/shadows/SQLiteCursorTest.java index e71dbb945..582e4d744 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/SQLiteCursorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/SQLiteCursorTest.java @@ -7,13 +7,13 @@ import android.database.Cursor; import android.database.sqlite.SQLiteCursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class SQLiteCursorTest { private SQLiteDatabase database; diff --git a/robolectric/src/test/java/org/robolectric/shadows/SQLiteDatabaseTest.java b/robolectric/src/test/java/org/robolectric/shadows/SQLiteDatabaseTest.java index 1adda38bf..f365dfb53 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/SQLiteDatabaseTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/SQLiteDatabaseTest.java @@ -6,12 +6,15 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import android.app.Application; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.os.CancellationSignal; import android.os.OperationCanceledException; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import java.util.ArrayList; import java.util.List; @@ -20,10 +23,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class SQLiteDatabaseTest { private SQLiteDatabase database; private List<SQLiteDatabase> openDatabases = new ArrayList<>(); @@ -32,7 +33,8 @@ public class SQLiteDatabaseTest { @Before public void setUp() throws Exception { - databasePath = RuntimeEnvironment.application.getDatabasePath("database.db"); + databasePath = + ((Application) ApplicationProvider.getApplicationContext()).getDatabasePath("database.db"); databasePath.getParentFile().mkdirs(); database = openOrCreateDatabase(databasePath); @@ -921,7 +923,8 @@ public class SQLiteDatabaseTest { ///////////////////// private SQLiteDatabase openOrCreateDatabase(String name) { - return openOrCreateDatabase(RuntimeEnvironment.application.getDatabasePath(name)); + return openOrCreateDatabase( + ((Application) ApplicationProvider.getApplicationContext()).getDatabasePath(name)); } private SQLiteDatabase openOrCreateDatabase(File databasePath) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/SQLiteOpenHelperTest.java b/robolectric/src/test/java/org/robolectric/shadows/SQLiteOpenHelperTest.java index 478a2ec27..11454b55e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/SQLiteOpenHelperTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/SQLiteOpenHelperTest.java @@ -2,26 +2,29 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class SQLiteOpenHelperTest { private TestOpenHelper helper; @Before public void setUp() throws Exception { - helper = new TestOpenHelper(RuntimeEnvironment.application, "path", null, 1); + helper = + new TestOpenHelper( + (Application) ApplicationProvider.getApplicationContext(), "path", null, 1); } @After @@ -95,18 +98,30 @@ public class SQLiteOpenHelperTest { public void testGetPath() throws Exception { final String path1 = "path1", path2 = "path2"; - TestOpenHelper helper1 = new TestOpenHelper(RuntimeEnvironment.application, path1, null, 1); - String expectedPath1 = RuntimeEnvironment.application.getDatabasePath(path1).getAbsolutePath(); + TestOpenHelper helper1 = + new TestOpenHelper( + (Application) ApplicationProvider.getApplicationContext(), path1, null, 1); + String expectedPath1 = + ((Application) ApplicationProvider.getApplicationContext()) + .getDatabasePath(path1) + .getAbsolutePath(); assertThat(helper1.getReadableDatabase().getPath()).isEqualTo(expectedPath1); - TestOpenHelper helper2 = new TestOpenHelper(RuntimeEnvironment.application, path2, null, 1); - String expectedPath2 = RuntimeEnvironment.application.getDatabasePath(path2).getAbsolutePath(); + TestOpenHelper helper2 = + new TestOpenHelper( + (Application) ApplicationProvider.getApplicationContext(), path2, null, 1); + String expectedPath2 = + ((Application) ApplicationProvider.getApplicationContext()) + .getDatabasePath(path2) + .getAbsolutePath(); assertThat(helper2.getReadableDatabase().getPath()).isEqualTo(expectedPath2); } @Test public void testCloseMultipleDbs() throws Exception { - TestOpenHelper helper2 = new TestOpenHelper(RuntimeEnvironment.application, "path2", null, 1); + TestOpenHelper helper2 = + new TestOpenHelper( + (Application) ApplicationProvider.getApplicationContext(), "path2", null, 1); SQLiteDatabase database1 = helper.getWritableDatabase(); SQLiteDatabase database2 = helper2.getWritableDatabase(); assertThat(database1.isOpen()).isTrue(); @@ -120,7 +135,9 @@ public class SQLiteOpenHelperTest { @Test public void testOpenMultipleDbsOnCreate() throws Exception { - TestOpenHelper helper2 = new TestOpenHelper(RuntimeEnvironment.application, "path2", null, 1); + TestOpenHelper helper2 = + new TestOpenHelper( + (Application) ApplicationProvider.getApplicationContext(), "path2", null, 1); assertThat(helper.onCreateCalled).isFalse(); assertThat(helper2.onCreateCalled).isFalse(); helper.getWritableDatabase(); @@ -149,7 +166,7 @@ public class SQLiteOpenHelperTest { private void verifyData(SQLiteDatabase db, String table, int expectedVals) { assertThat(db.query(table, null, null, null, - null, null, null).getCount()).isEqualTo(expectedVals); + null, null, null).getCount()).isEqualTo(expectedVals); } @Test @@ -158,7 +175,9 @@ public class SQLiteOpenHelperTest { SQLiteDatabase db1 = helper.getWritableDatabase(); setupTable(db1, TABLE_NAME1); insertData(db1, TABLE_NAME1, new int[]{1, 2}); - TestOpenHelper helper2 = new TestOpenHelper(RuntimeEnvironment.application, "path2", null, 1); + TestOpenHelper helper2 = + new TestOpenHelper( + (Application) ApplicationProvider.getApplicationContext(), "path2", null, 1); SQLiteDatabase db2 = helper2.getWritableDatabase(); setupTable(db2, TABLE_NAME2); insertData(db2, TABLE_NAME2, new int[]{4, 5, 6}); @@ -169,7 +188,9 @@ public class SQLiteOpenHelperTest { @Test public void testCloseOneDbKeepsDataForOther() throws Exception { final String TABLE_NAME1 = "fart", TABLE_NAME2 = "fart2"; - TestOpenHelper helper2 = new TestOpenHelper(RuntimeEnvironment.application, "path2", null, 1); + TestOpenHelper helper2 = + new TestOpenHelper( + (Application) ApplicationProvider.getApplicationContext(), "path2", null, 1); SQLiteDatabase db1 = helper.getWritableDatabase(); SQLiteDatabase db2 = helper2.getWritableDatabase(); setupTable(db1, TABLE_NAME1); @@ -231,9 +252,9 @@ public class SQLiteOpenHelperTest { } @Override - public void onCreate(SQLiteDatabase database) { - onCreateCalled = true; - } + public void onCreate(SQLiteDatabase database) { + onCreateCalled = true; + } @Override public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/SQLiteQueryBuilderTest.java b/robolectric/src/test/java/org/robolectric/shadows/SQLiteQueryBuilderTest.java index 972a33754..fbc14077c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/SQLiteQueryBuilderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/SQLiteQueryBuilderTest.java @@ -6,13 +6,13 @@ import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class SQLiteQueryBuilderTest { private static final String TABLE_NAME = "sqlBuilderTest"; diff --git a/robolectric/src/test/java/org/robolectric/shadows/SQLiteStatementTest.java b/robolectric/src/test/java/org/robolectric/shadows/SQLiteStatementTest.java index 50f4511f7..220ab0c0f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/SQLiteStatementTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/SQLiteStatementTest.java @@ -3,25 +3,27 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; +import android.app.Application; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDoneException; import android.database.sqlite.SQLiteStatement; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class SQLiteStatementTest { private SQLiteDatabase database; @Before public void setUp() throws Exception { - final File databasePath = RuntimeEnvironment.application.getDatabasePath("path"); + final File databasePath = + ((Application) ApplicationProvider.getApplicationContext()).getDatabasePath("path"); databasePath.getParentFile().mkdirs(); database = SQLiteDatabase.openOrCreateDatabase(databasePath.getPath(), null); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSeekBarTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSeekBarTest.java index ef3e3e3a3..caecc3330 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSeekBarTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSeekBarTest.java @@ -2,21 +2,23 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.Context; import android.widget.AbsSeekBar; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAbsSeekBarTest { @Test public void testInheritance() { // TODO: this seems to test static typing - compiler enforces this ;) - TestAbsSeekBar seekBar = new TestAbsSeekBar(RuntimeEnvironment.application); + TestAbsSeekBar seekBar = + new TestAbsSeekBar((Application) ApplicationProvider.getApplicationContext()); ShadowAbsSeekBar shadow = Shadows.shadowOf(seekBar); assertThat(shadow).isInstanceOf(ShadowProgressBar.class); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSpinnerAdapterViewBehaviorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSpinnerAdapterViewBehaviorTest.java index 90c325eb0..880a7ec17 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSpinnerAdapterViewBehaviorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSpinnerAdapterViewBehaviorTest.java @@ -1,14 +1,15 @@ package org.robolectric.shadows; +import android.app.Application; import android.widget.AdapterView; import android.widget.Gallery; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAbsSpinnerAdapterViewBehaviorTest extends AdapterViewBehavior { @Override public AdapterView createAdapterView() { - return new Gallery(RuntimeEnvironment.application); + return new Gallery((Application) ApplicationProvider.getApplicationContext()); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSpinnerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSpinnerTest.java index 8609449e5..c4e8e3f63 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSpinnerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsSpinnerTest.java @@ -3,18 +3,19 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.Spinner; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAbsSpinnerTest { private Context context; private Spinner spinner; @@ -23,7 +24,7 @@ public class ShadowAbsSpinnerTest { @Before public void setUp() throws Exception { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); spinner = new Spinner(context); shadowSpinner = shadowOf(spinner); String [] testItems = {"foo", "bar"}; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsoluteLayoutTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsoluteLayoutTest.java index d154a9aba..96aef3b0d 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsoluteLayoutTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbsoluteLayoutTest.java @@ -2,22 +2,26 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.view.ViewGroup; import android.widget.AbsoluteLayout; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAbsoluteLayoutTest { @Test public void getLayoutParams_shouldReturnAbsoluteLayoutParams() throws Exception { - ViewGroup.LayoutParams layoutParams = (new AbsoluteLayout(RuntimeEnvironment.application) { - @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { - return super.generateDefaultLayoutParams(); - } - }).generateDefaultLayoutParams(); + ViewGroup.LayoutParams layoutParams = + (new AbsoluteLayout((Application) ApplicationProvider.getApplicationContext()) { + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return super.generateDefaultLayoutParams(); + } + }) + .generateDefaultLayoutParams(); assertThat(layoutParams).isInstanceOf(AbsoluteLayout.LayoutParams.class); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbstractCursorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbstractCursorTest.java index 00ac8855c..009a70482 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAbstractCursorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAbstractCursorTest.java @@ -2,18 +2,19 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.database.AbstractCursor; import android.net.Uri; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAbstractCursorTest { private TestCursor cursor; @@ -208,7 +209,8 @@ public class ShadowAbstractCursorTest { Uri uri = Uri.parse("content://foo.com"); ShadowAbstractCursor shadow = Shadows.shadowOf(cursor); assertThat(shadow.getNotificationUri_Compatibility()).isNull(); - cursor.setNotificationUri(RuntimeEnvironment.application.getContentResolver(), uri); + cursor.setNotificationUri( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), uri); assertThat(shadow.getNotificationUri_Compatibility()).isEqualTo(uri); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityEventTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityEventTest.java index b9e689375..202480a5c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityEventTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityEventTest.java @@ -3,19 +3,20 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.Notification; import android.os.Parcel; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAccessibilityEventTest { private AccessibilityEvent event; @@ -68,7 +69,7 @@ public class ShadowAccessibilityEventTest { @Test public void shouldHaveCurrentSourceId() { - TextView rootView = new TextView(RuntimeEnvironment.application); + TextView rootView = new TextView((Application) ApplicationProvider.getApplicationContext()); event.setSource(rootView); assertThat(shadowOf(event).getSourceRoot()).isEqualTo(rootView); assertThat(shadowOf(event).getVirtualDescendantId()) diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityManagerTest.java index 43fdca591..93e9f2bd4 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityManagerTest.java @@ -6,28 +6,32 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.accessibilityservice.AccessibilityServiceInfo; +import android.app.Application; import android.content.Context; import android.content.pm.ServiceInfo; import android.view.accessibility.AccessibilityManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAccessibilityManagerTest { private AccessibilityManager accessibilityManager; @Before public void setUp() throws Exception { - accessibilityManager = (AccessibilityManager) RuntimeEnvironment.application.getSystemService(ACCESSIBILITY_SERVICE); + accessibilityManager = + (AccessibilityManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(ACCESSIBILITY_SERVICE); } @Test @@ -40,8 +44,11 @@ public class ShadowAccessibilityManagerTest { // Emulates Android framework behavior, e.g., // AccessibilityManager.getInstance(context).isEnabled(). private static AccessibilityManager getAccessibilityManagerInstance() throws Exception { - return ReflectionHelpers.callStaticMethod(AccessibilityManager.class, "getInstance", - ReflectionHelpers.ClassParameter.from(Context.class, RuntimeEnvironment.application)); + return ReflectionHelpers.callStaticMethod( + AccessibilityManager.class, + "getInstance", + ReflectionHelpers.ClassParameter.from( + Context.class, (Application) ApplicationProvider.getApplicationContext())); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityNodeInfoTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityNodeInfoTest.java index 12a7b1e00..d4c1f68ec 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityNodeInfoTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityNodeInfoTest.java @@ -4,6 +4,7 @@ import static android.os.Build.VERSION_CODES.LOLLIPOP; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.graphics.Rect; import android.os.Bundle; import android.os.Parcel; @@ -11,15 +12,15 @@ import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.AccessibilityWindowInfo; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.After; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class ShadowAccessibilityNodeInfoTest { private AccessibilityNodeInfo node; @@ -169,7 +170,7 @@ public class ShadowAccessibilityNodeInfoTest { @Test public void equalsTest_nodesFromTheSameViewAreEqual() { - View view = new View(RuntimeEnvironment.application); + View view = new View((Application) ApplicationProvider.getApplicationContext()); AccessibilityNodeInfo nodeA = AccessibilityNodeInfo.obtain(view); AccessibilityNodeInfo nodeB = AccessibilityNodeInfo.obtain(view); shadowOf(nodeA).setText("tomato"); @@ -180,8 +181,8 @@ public class ShadowAccessibilityNodeInfoTest { @Test public void equalsTest_nodesFromDifferentViewsAreNotEqual() { - View viewA = new View(RuntimeEnvironment.application); - View viewB = new View(RuntimeEnvironment.application); + View viewA = new View((Application) ApplicationProvider.getApplicationContext()); + View viewB = new View((Application) ApplicationProvider.getApplicationContext()); AccessibilityNodeInfo nodeA = AccessibilityNodeInfo.obtain(viewA); AccessibilityNodeInfo nodeB = AccessibilityNodeInfo.obtain(viewB); shadowOf(nodeA).setText("test"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityServiceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityServiceTest.java index 030b8fbe6..e3a954721 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityServiceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityServiceTest.java @@ -5,13 +5,13 @@ import static org.robolectric.Shadows.shadowOf; import android.accessibilityservice.AccessibilityService; import android.view.accessibility.AccessibilityEvent; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAccessibilityServiceTest { private MyService service ; private ShadowAccessibilityService shadow; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityWindowInfoTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityWindowInfoTest.java index c8e21f45b..36af4e1d5 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityWindowInfoTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccessibilityWindowInfoTest.java @@ -6,13 +6,13 @@ import static org.robolectric.Shadows.shadowOf; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowAccessibilityWindowInfoTest { private AccessibilityWindowInfo window; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccountManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccountManagerTest.java index f84383a9a..6b2655b58 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccountManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccountManagerTest.java @@ -16,21 +16,22 @@ import android.accounts.AuthenticatorException; import android.accounts.OnAccountsUpdateListener; import android.accounts.OperationCanceledException; import android.app.Activity; +import android.app.Application; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.IOException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.Scheduler; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAccountManagerTest { private AccountManager am; private Scheduler scheduler; @@ -38,7 +39,7 @@ public class ShadowAccountManagerTest { @Before public void setUp() throws Exception { - am = AccountManager.get(RuntimeEnvironment.application); + am = AccountManager.get((Application) ApplicationProvider.getApplicationContext()); scheduler = Robolectric.getForegroundThreadScheduler(); activity = new Activity(); } @@ -46,9 +47,11 @@ public class ShadowAccountManagerTest { @Test public void testGet() { assertThat(am).isNotNull(); - assertThat(am).isSameAs(AccountManager.get(RuntimeEnvironment.application)); + assertThat(am) + .isSameAs(AccountManager.get((Application) ApplicationProvider.getApplicationContext())); - AccountManager activityAM = AccountManager.get(RuntimeEnvironment.application); + AccountManager activityAM = + AccountManager.get((Application) ApplicationProvider.getApplicationContext()); assertThat(activityAM).isNotNull(); assertThat(activityAM).isSameAs(am); } @@ -642,7 +645,10 @@ public class ShadowAccountManagerTest { @Test public void testGetAsSystemService() throws Exception { - AccountManager systemService = (AccountManager) RuntimeEnvironment.application.getSystemService(Context.ACCOUNT_SERVICE); + AccountManager systemService = + (AccountManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.ACCOUNT_SERVICE); assertThat(systemService).isNotNull(); assertThat(am).isEqualTo(systemService); } @@ -672,6 +678,31 @@ public class ShadowAccountManagerTest { } @Test + public void getAuthToken_withActivity_returnsAuthIntent() throws Exception { + Account account = new Account("name", "google.com"); + shadowOf(am).addAccount(account); + shadowOf(am).addAuthenticator("google.com"); + + TestAccountManagerCallback<Bundle> callback = new TestAccountManagerCallback<>(); + AccountManagerFuture<Bundle> future = am.getAuthToken(account, + "auth_token_type", + new Bundle(), + activity, + callback, + new Handler()); + + assertThat(future.isDone()).isTrue(); + assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_NAME)) + .isEqualTo(account.name); + assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_TYPE)) + .isEqualTo(account.type); + assertThat(future.getResult().getString(AccountManager.KEY_AUTHTOKEN)).isNull(); + assertThat((Intent) future.getResult().getParcelable(AccountManager.KEY_INTENT)).isNotNull(); + + assertThat(callback.hasBeenCalled()).isTrue(); + } + + @Test public void getAuthToken_withNotifyAuthFailureSetToFalse_returnsCorrectToken() throws Exception { Account account = new Account("name", "google.com"); shadowOf(am).addAccount(account); @@ -700,6 +731,33 @@ public class ShadowAccountManagerTest { } @Test + public void getAuthToken_withNotifyAuthFailureSetToFalse_returnsAuthIntent() throws Exception { + Account account = new Account("name", "google.com"); + shadowOf(am).addAccount(account); + shadowOf(am).addAuthenticator("google.com"); + + TestAccountManagerCallback<Bundle> callback = new TestAccountManagerCallback<>(); + AccountManagerFuture<Bundle> future = + am.getAuthToken( + account, + "auth_token_type", + new Bundle(), + /* notifyAuthFailure= */ false, + callback, + new Handler()); + + assertThat(future.isDone()).isTrue(); + assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_NAME)) + .isEqualTo(account.name); + assertThat(future.getResult().getString(AccountManager.KEY_ACCOUNT_TYPE)) + .isEqualTo(account.type); + assertThat(future.getResult().getString(AccountManager.KEY_AUTHTOKEN)).isNull(); + assertThat((Intent) future.getResult().getParcelable(AccountManager.KEY_INTENT)).isNotNull(); + + assertThat(callback.hasBeenCalled()).isTrue(); + } + + @Test public void getHasFeatures_returnsTrueWhenAllFeaturesSatisfied() throws Exception { Account account = new Account("name", "google.com"); shadowOf(am).addAccount(account); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccountTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccountTest.java index 5e9ae3d22..2f509f367 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAccountTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAccountTest.java @@ -4,11 +4,11 @@ import static com.google.common.truth.Truth.assertThat; import android.accounts.Account; import android.os.Parcel; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAccountTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityGroupTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityGroupTest.java index 3513a0ed8..5a649e928 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityGroupTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityGroupTest.java @@ -5,11 +5,11 @@ import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import android.app.ActivityGroup; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowActivityGroupTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityManagerTest.java index 7e1ed6c4c..9502b2f7e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityManagerTest.java @@ -8,18 +8,19 @@ import static org.robolectric.Shadows.shadowOf; import android.app.ActivityManager; import android.app.ActivityManager.AppTask; +import android.app.Application; import android.content.ComponentName; import android.content.Context; import android.os.Process; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.collect.Lists; import com.google.common.collect.ImmutableList; 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) +@RunWith(AndroidJUnit4.class) public class ShadowActivityManagerTest { @Test @@ -81,7 +82,11 @@ public class ShadowActivityManagerTest { ActivityManager.RunningAppProcessInfo myInfo = activityManager.getRunningAppProcesses().get(0); assertThat(myInfo.pid).isEqualTo(android.os.Process.myPid()); assertThat(myInfo.uid).isEqualTo(android.os.Process.myUid()); - assertThat(myInfo.processName).isEqualTo(RuntimeEnvironment.application.getBaseContext().getPackageName()); + assertThat(myInfo.processName) + .isEqualTo( + ((Application) ApplicationProvider.getApplicationContext()) + .getBaseContext() + .getPackageName()); shadowOf(activityManager).setProcesses(Lists.newArrayList(process1, process2)); assertThat(activityManager.getRunningAppProcesses()).containsExactly(process1, process2); } @@ -165,8 +170,9 @@ public class ShadowActivityManagerTest { /////////////////////// private ActivityManager getActivityManager() { - return (ActivityManager) RuntimeEnvironment.application.getSystemService( - Context.ACTIVITY_SERVICE); + return (ActivityManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.ACTIVITY_SERVICE); } private ActivityManager.RunningTaskInfo buildTaskInfo(ComponentName name) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityTest.java index 714b93304..baee15d35 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowActivityTest.java @@ -48,6 +48,8 @@ import android.view.Window; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.SearchView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -55,14 +57,12 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.util.TestRunnable; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowActivityTest { private Activity activity; @@ -295,7 +295,8 @@ public class ShadowActivityTest { @Test public void shouldRetrievePackageNameFromTheManifest() throws Exception { - assertThat(Robolectric.setupActivity(Activity.class).getPackageName()).isEqualTo(RuntimeEnvironment.application.getPackageName()); + assertThat(Robolectric.setupActivity(Activity.class).getPackageName()) + .isEqualTo(((Application) ApplicationProvider.getApplicationContext()).getPackageName()); } @Test @@ -843,7 +844,8 @@ public class ShadowActivityTest { public void shouldCallActivityLifecycleCallbacks() { final List<String> transcript = new ArrayList<>(); final ActivityController<Activity> controller = buildActivity(Activity.class); - RuntimeEnvironment.application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks(transcript)); + ((Application) ApplicationProvider.getApplicationContext()) + .registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks(transcript)); controller.create(); assertThat(transcript).containsExactly("onActivityCreated"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAlarmManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAlarmManagerTest.java index dd1778fbb..0acaf7816 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAlarmManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAlarmManagerTest.java @@ -14,22 +14,23 @@ import android.app.Activity; import android.app.AlarmManager; import android.app.AlarmManager.AlarmClockInfo; import android.app.AlarmManager.OnAlarmListener; +import android.app.Application; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Build.VERSION_CODES; import android.os.Handler; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Date; import java.util.TimeZone; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAlarmManagerTest { private Context context; @@ -39,7 +40,7 @@ public class ShadowAlarmManagerTest { @Before public void setUp() { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); shadowAlarmManager = shadowOf(alarmManager); activity = Robolectric.setupActivity(Activity.class); @@ -286,12 +287,18 @@ public class ShadowAlarmManagerTest { @Test public void schedule_useRequestCodeToMatchExistingPendingIntents() throws Exception { Intent intent = new Intent("ACTION!"); - PendingIntent pI = PendingIntent.getService(RuntimeEnvironment.application, 1, intent, 0); + PendingIntent pI = + PendingIntent.getService( + (Application) ApplicationProvider.getApplicationContext(), 1, intent, 0); AlarmManager alarmManager = - (AlarmManager) RuntimeEnvironment.application.getSystemService(Context.ALARM_SERVICE); + (AlarmManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.ALARM_SERVICE); alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 10, pI); - PendingIntent pI2 = PendingIntent.getService(RuntimeEnvironment.application, 2, intent, 0); + PendingIntent pI2 = + PendingIntent.getService( + (Application) ApplicationProvider.getApplicationContext(), 2, intent, 0); alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 10, pI2); assertThat(shadowAlarmManager.getScheduledAlarms()).hasSize(2); @@ -300,12 +307,18 @@ public class ShadowAlarmManagerTest { @Test public void cancel_useRequestCodeToMatchExistingPendingIntents() throws Exception { Intent intent = new Intent("ACTION!"); - PendingIntent pI = PendingIntent.getService(RuntimeEnvironment.application, 1, intent, 0); + PendingIntent pI = + PendingIntent.getService( + (Application) ApplicationProvider.getApplicationContext(), 1, intent, 0); AlarmManager alarmManager = - (AlarmManager) RuntimeEnvironment.application.getSystemService(Context.ALARM_SERVICE); + (AlarmManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.ALARM_SERVICE); alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 10, pI); - PendingIntent pI2 = PendingIntent.getService(RuntimeEnvironment.application, 2, intent, 0); + PendingIntent pI2 = + PendingIntent.getService( + (Application) ApplicationProvider.getApplicationContext(), 2, intent, 0); alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 10, pI2); assertThat(shadowAlarmManager.getScheduledAlarms()).hasSize(2); @@ -319,7 +332,9 @@ public class ShadowAlarmManagerTest { @Config(minSdk = N) public void cancel_removesMatchingListeners() { Intent intent = new Intent("ACTION!"); - PendingIntent pI = PendingIntent.getService(RuntimeEnvironment.application, 1, intent, 0); + PendingIntent pI = + PendingIntent.getService( + (Application) ApplicationProvider.getApplicationContext(), 1, intent, 0); OnAlarmListener listener1 = () -> {}; OnAlarmListener listener2 = () -> {}; Handler handler = new Handler(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAlertDialogTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAlertDialogTest.java index 7c7f37d51..8fdb30a9d 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAlertDialogTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAlertDialogTest.java @@ -12,24 +12,25 @@ import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import android.app.AlertDialog; +import android.app.Application; import android.app.Dialog; import android.content.ContextWrapper; import android.content.DialogInterface; import android.view.View; import android.widget.ArrayAdapter; import android.widget.EditText; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.CustomView; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAlertDialogTest { @Test @@ -187,7 +188,9 @@ public class ShadowAlertDialogTest { @Test public void testBuilderWithItemArrayViaResourceId() throws Exception { - AlertDialog.Builder builder = new AlertDialog.Builder(new ContextWrapper(RuntimeEnvironment.application)); + AlertDialog.Builder builder = + new AlertDialog.Builder( + new ContextWrapper((Application) ApplicationProvider.getApplicationContext())); builder.setTitle("title"); builder.setItems(R.array.alertDialogTestItems, new TestDialogOnClickListener()); @@ -210,7 +213,12 @@ public class ShadowAlertDialogTest { list.add(99); list.add(88); list.add(77); - ArrayAdapter<Integer> adapter = new ArrayAdapter<>(RuntimeEnvironment.application, R.layout.main, R.id.title, list); + ArrayAdapter<Integer> adapter = + new ArrayAdapter<>( + (Application) ApplicationProvider.getApplicationContext(), + R.layout.main, + R.id.title, + list); AlertDialog.Builder builder = new AlertDialog.Builder(application); builder.setSingleChoiceItems(adapter, -1, new DialogInterface.OnClickListener() { @@ -230,7 +238,8 @@ public class ShadowAlertDialogTest { @Test public void show_setsLatestAlertDialogAndLatestDialog() { - AlertDialog alertDialog = new AlertDialog.Builder(RuntimeEnvironment.application).create(); + AlertDialog alertDialog = + new AlertDialog.Builder((Application) ApplicationProvider.getApplicationContext()).create(); assertNull(ShadowDialog.getLatestDialog()); assertNull(ShadowAlertDialog.getLatestAlertDialog()); @@ -242,14 +251,21 @@ public class ShadowAlertDialogTest { @Test public void shouldCallTheClickListenerOfTheCheckedAdapterInASingleChoiceDialog() throws Exception { - AlertDialog.Builder builder = new AlertDialog.Builder(new ContextWrapper(RuntimeEnvironment.application)); + AlertDialog.Builder builder = + new AlertDialog.Builder( + new ContextWrapper((Application) ApplicationProvider.getApplicationContext())); TestDialogOnClickListener listener = new TestDialogOnClickListener(); List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); - ArrayAdapter<Integer> arrayAdapter = new ArrayAdapter<>(RuntimeEnvironment.application, R.layout.main, R.id.title, list); + ArrayAdapter<Integer> arrayAdapter = + new ArrayAdapter<>( + (Application) ApplicationProvider.getApplicationContext(), + R.layout.main, + R.id.title, + list); builder.setSingleChoiceItems(arrayAdapter, 1, listener); AlertDialog alert = builder.create(); @@ -267,8 +283,8 @@ public class ShadowAlertDialogTest { @Test public void shouldDelegateToDialogFindViewByIdIfViewIsNull() { - AlertDialog dialog = new AlertDialog(RuntimeEnvironment.application) { - }; + AlertDialog dialog = + new AlertDialog((Application) ApplicationProvider.getApplicationContext()) {}; assertThat((View) dialog.findViewById(99)).isNull(); @@ -307,10 +323,8 @@ public class ShadowAlertDialogTest { AlertDialog.Builder builder = new AlertDialog.Builder(application); builder.setIcon(R.drawable.an_image); - final ShadowAlertDialog alertDialog = shadowOf(builder.create()); - final ShadowAlertController alertController = alertDialog.getShadowAlertController(); - - assertThat(alertController.getIconId()).isEqualTo(R.drawable.an_image); + AlertDialog alertDialog = builder.create(); + assertThat(shadowOf(alertDialog).getIconId()).isEqualTo(R.drawable.an_image); } private static class TestDialogOnClickListener implements DialogInterface.OnClickListener { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAnimationSetTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAnimationSetTest.java index ebd9f8085..c23a27fb1 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAnimationSetTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAnimationSetTest.java @@ -7,13 +7,13 @@ import android.view.animation.Animation; import android.view.animation.AnimationSet; import android.view.animation.RotateAnimation; import android.view.animation.TranslateAnimation; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAnimationSetTest { final Animation.AnimationListener moveListener = mock(Animation.AnimationListener.class); final Animation.AnimationListener spinListener = mock(Animation.AnimationListener.class); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAnimationUtilsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAnimationUtilsTest.java index 0a98de0b5..7ecc1f8bf 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAnimationUtilsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAnimationUtilsTest.java @@ -6,13 +6,13 @@ import android.R; import android.app.Activity; import android.view.animation.AnimationUtils; import android.view.animation.LayoutAnimationController; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAnimationUtilsTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppOpsManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppOpsManagerTest.java index 440f8af66..61f2288a1 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppOpsManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppOpsManagerTest.java @@ -3,31 +3,42 @@ package org.robolectric.shadows; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.MODE_ERRORED; +import static android.app.AppOpsManager.OPSTR_FINE_LOCATION; import static android.app.AppOpsManager.OPSTR_GPS; +import static android.app.AppOpsManager.OP_FINE_LOCATION; import static android.app.AppOpsManager.OP_GPS; import static android.app.AppOpsManager.OP_SEND_SMS; +import static android.app.AppOpsManager.OP_VIBRATE; import static android.os.Build.VERSION_CODES.KITKAT; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.robolectric.Shadows.shadowOf; import android.app.AppOpsManager; +import android.app.AppOpsManager.OnOpChangedListener; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; +import android.app.Application; import android.content.Context; +import android.media.AudioAttributes; +import android.os.Binder; import android.os.Build.VERSION_CODES; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.HashSet; import java.util.List; import java.util.Set; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowAppOpsManager.ModeAndException; -/** - * Unit tests for {@link ShadowAppOpsManager}. - */ -@RunWith(RobolectricTestRunner.class) +/** Unit tests for {@link ShadowAppOpsManager}. */ +@RunWith(AndroidJUnit4.class) @Config(minSdk = KITKAT) public class ShadowAppOpsManagerTest { @@ -43,8 +54,10 @@ public class ShadowAppOpsManagerTest { @Before public void setUp() { - appOps = (AppOpsManager) RuntimeEnvironment.application.getSystemService( - Context.APP_OPS_SERVICE); + appOps = + (AppOpsManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.APP_OPS_SERVICE); } @Test @@ -90,6 +103,40 @@ public class ShadowAppOpsManagerTest { } @Test + @Config(minSdk = VERSION_CODES.O_MR1) + public void noModeSet_atLeastO_noteProxyOpNoThrow_shouldReturnModeAllowed() { + assertThat(appOps.noteProxyOpNoThrow(OP_GPS, PACKAGE_NAME1)).isEqualTo(MODE_ALLOWED); + } + + @Test + @Config(minSdk = VERSION_CODES.O_MR1) + public void setMode_withModeDefault_atLeastO_noteProxyOpNoThrow_shouldReturnModeDefault() { + appOps.setMode(OP_GPS, Binder.getCallingUid(), PACKAGE_NAME1, MODE_DEFAULT); + assertThat(appOps.noteProxyOpNoThrow(OP_GPS, PACKAGE_NAME1)).isEqualTo(MODE_DEFAULT); + } + + @Test + @Config(minSdk = VERSION_CODES.P) + public void setMode_noteProxyOpNoThrow_atLeastO() { + assertThat(appOps.noteProxyOpNoThrow(OP_GPS, PACKAGE_NAME1)).isEqualTo(MODE_ALLOWED); + appOps.setMode(OP_GPS, Binder.getCallingUid(), PACKAGE_NAME1, MODE_ERRORED); + assertThat(appOps.noteProxyOpNoThrow(OP_GPS, PACKAGE_NAME1)).isEqualTo(MODE_ERRORED); + } + + @Test + @Config(minSdk = VERSION_CODES.KITKAT) + public void startStopWatchingMode() { + OnOpChangedListener callback = mock(OnOpChangedListener.class); + appOps.startWatchingMode(OPSTR_FINE_LOCATION, PACKAGE_NAME1, callback); + appOps.setMode(OP_FINE_LOCATION, UID_1, PACKAGE_NAME1, MODE_ERRORED); + verify(callback).onOpChanged(OPSTR_FINE_LOCATION, PACKAGE_NAME1); + + appOps.stopWatchingMode(callback); + appOps.setMode(OP_FINE_LOCATION, UID_1, PACKAGE_NAME1, MODE_ALLOWED); + verifyNoMoreInteractions(callback); + } + + @Test public void noteOp() { assertThat(appOps.noteOp(OP_GPS, UID_1, PACKAGE_NAME1)).isEqualTo(MODE_ALLOWED); // Use same op more than once @@ -120,22 +167,61 @@ public class ShadowAppOpsManagerTest { @Test public void getOpsForPackage_withOpFilter() { - List<PackageOps> results = appOps.getOpsForPackage( - UID_1, PACKAGE_NAME1, new int[]{OP_GPS}); + List<PackageOps> results = appOps.getOpsForPackage(UID_1, PACKAGE_NAME1, new int[] {OP_GPS}); assertOps(results); appOps.noteOp(OP_SEND_SMS, UID_1, PACKAGE_NAME1); - results = appOps.getOpsForPackage(UID_1, PACKAGE_NAME1, new int[]{OP_GPS}); + results = appOps.getOpsForPackage(UID_1, PACKAGE_NAME1, new int[] {OP_GPS}); assertOps(results); appOps.noteOp(OP_GPS, UID_1, PACKAGE_NAME1); - results = appOps.getOpsForPackage(UID_1, PACKAGE_NAME1, new int[]{OP_GPS}); + results = appOps.getOpsForPackage(UID_1, PACKAGE_NAME1, new int[] {OP_GPS}); assertOps(results, OP_GPS); } - /** - * Assert that the results contain the expected op codes. - */ + @Test + @Config(minSdk = VERSION_CODES.LOLLIPOP) + public void setRestrictions() { + appOps.setRestriction( + OP_VIBRATE, AudioAttributes.USAGE_NOTIFICATION, MODE_ERRORED, new String[] {PACKAGE_NAME1}); + + ModeAndException modeAndException = + shadowOf(appOps).getRestriction(OP_VIBRATE, AudioAttributes.USAGE_NOTIFICATION); + assertThat(modeAndException.mode).isEqualTo(MODE_ERRORED); + assertThat(modeAndException.exceptionPackages).containsExactly(PACKAGE_NAME1); + } + + @Test + public void checkPackage_doesntExist() { + try { + appOps.checkPackage(123, PACKAGE_NAME1); + fail(); + } catch (SecurityException e) { + // expected + } + } + + @Test + public void checkPackage_doesntBelong() { + shadowOf(((Application) ApplicationProvider.getApplicationContext()).getPackageManager()) + .setPackagesForUid(111, PACKAGE_NAME1); + try { + appOps.checkPackage(123, PACKAGE_NAME1); + fail(); + } catch (SecurityException e) { + // expected + } + } + + @Test + public void checkPackage_belongs() { + shadowOf(((Application) ApplicationProvider.getApplicationContext()).getPackageManager()) + .setPackagesForUid(123, PACKAGE_NAME1); + appOps.checkPackage(123, PACKAGE_NAME1); + // check passes without exception + } + + /** Assert that the results contain the expected op codes. */ private void assertOps(List<PackageOps> pkgOps, Integer... expectedOps) { Set<Integer> actualOps = new HashSet<>(); for (PackageOps pkgOp : pkgOps) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppTaskTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppTaskTest.java index 975555e8a..e8fcd4e2f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppTaskTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppTaskTest.java @@ -8,13 +8,13 @@ import android.app.Activity; import android.app.ActivityManager.AppTask; import android.app.ActivityManager.RecentTaskInfo; import android.content.Intent; +import androidx.test.ext.junit.runners.AndroidJUnit4; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowAppTaskTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetHostTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetHostTest.java index 2dbaad948..b5ecc9372 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetHostTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetHostTest.java @@ -4,17 +4,18 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNotNull; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAppWidgetHostTest { private AppWidgetHost appWidgetHost; private ShadowAppWidgetHost shadowAppWidgetHost; @@ -22,7 +23,7 @@ public class ShadowAppWidgetHostTest { @Before public void setup() throws Exception { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); appWidgetHost = new AppWidgetHost(context, 404); shadowAppWidgetHost = shadowOf(appWidgetHost); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetHostViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetHostViewTest.java index a89d9a52f..fb6336c75 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetHostViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetHostViewTest.java @@ -3,23 +3,25 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAppWidgetHostViewTest { private AppWidgetHostView appWidgetHostView; private ShadowAppWidgetHostView shadowAppWidgetHostView; @Before public void setUp() throws Exception { - appWidgetHostView = new AppWidgetHostView(RuntimeEnvironment.application); + appWidgetHostView = + new AppWidgetHostView((Application) ApplicationProvider.getApplicationContext()); shadowAppWidgetHostView = shadowOf(appWidgetHostView); } @@ -43,7 +45,8 @@ public class ShadowAppWidgetHostViewTest { @Test public void shouldBeAbleToHaveHostSet() throws Exception { - AppWidgetHost host = new AppWidgetHost(RuntimeEnvironment.application, 0); + AppWidgetHost host = + new AppWidgetHost((Application) ApplicationProvider.getApplicationContext(), 0); shadowAppWidgetHostView.setHost(host); assertThat(shadowAppWidgetHostView.getHost()).isSameAs(host); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetManagerTest.java index bfca125b9..f57efb8c8 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAppWidgetManagerTest.java @@ -8,6 +8,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.appwidget.AppWidgetProviderInfo; @@ -17,30 +18,36 @@ import android.content.ContextWrapper; import android.view.View; import android.widget.RemoteViews; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAppWidgetManagerTest { private AppWidgetManager appWidgetManager; private ShadowAppWidgetManager shadowAppWidgetManager; @Before public void setUp() throws Exception { - appWidgetManager = AppWidgetManager.getInstance(RuntimeEnvironment.application); + appWidgetManager = + AppWidgetManager.getInstance((Application) ApplicationProvider.getApplicationContext()); shadowAppWidgetManager = shadowOf(appWidgetManager); } @Test public void getInstance_shouldReturnSameInstance() throws Exception { assertNotNull(appWidgetManager); - assertSame(AppWidgetManager.getInstance(RuntimeEnvironment.application), appWidgetManager); - assertSame(AppWidgetManager.getInstance(new ContextWrapper(RuntimeEnvironment.application)), appWidgetManager); + assertSame( + AppWidgetManager.getInstance((Application) ApplicationProvider.getApplicationContext()), + appWidgetManager); + assertSame( + AppWidgetManager.getInstance( + new ContextWrapper((Application) ApplicationProvider.getApplicationContext())), + appWidgetManager); } @Test @@ -77,10 +84,18 @@ public class ShadowAppWidgetManagerTest { View originalWidgetView = shadowAppWidgetManager.getViewFor(widgetId); assertContains("Main Layout", originalWidgetView); - appWidgetManager.updateAppWidget(widgetId, new RemoteViews(RuntimeEnvironment.application.getPackageName(), R.layout.main)); + appWidgetManager.updateAppWidget( + widgetId, + new RemoteViews( + ((Application) ApplicationProvider.getApplicationContext()).getPackageName(), + R.layout.main)); assertSame(originalWidgetView, shadowAppWidgetManager.getViewFor(widgetId)); - appWidgetManager.updateAppWidget(widgetId, new RemoteViews(RuntimeEnvironment.application.getPackageName(), R.layout.media)); + appWidgetManager.updateAppWidget( + widgetId, + new RemoteViews( + ((Application) ApplicationProvider.getApplicationContext()).getPackageName(), + R.layout.media)); assertNotSame(originalWidgetView, shadowAppWidgetManager.getViewFor(widgetId)); View mediaWidgetView = shadowAppWidgetManager.getViewFor(widgetId); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowApplicationTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowApplicationTest.java index 9dc804280..44fe4fb1f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowApplicationTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowApplicationTest.java @@ -46,37 +46,34 @@ import android.view.autofill.AutofillManager; import android.view.textclassifier.TextClassificationManager; import android.widget.LinearLayout; import android.widget.PopupWindow; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.util.Scheduler; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowApplicationTest { private Context context; @Before public void setUp() { - context = RuntimeEnvironment.application; - } - - @Test - @Config(packageName = "override.package") - public void shouldOverridePackageWithConfig() { - assertThat(RuntimeEnvironment.application.getPackageName()).isEqualTo("override.package"); + context = (Application) ApplicationProvider.getApplicationContext(); } @Test public void shouldBeAContext() throws Exception { - assertThat(Robolectric.setupActivity(Activity.class).getApplication()).isSameAs(RuntimeEnvironment.application); - assertThat(Robolectric.setupActivity(Activity.class).getApplication().getApplicationContext()).isSameAs(RuntimeEnvironment.application); + assertThat(Robolectric.setupActivity(Activity.class).getApplication()) + .isSameAs((Application) ApplicationProvider.getApplicationContext()); + assertThat(Robolectric.setupActivity(Activity.class).getApplication().getApplicationContext()) + .isSameAs((Application) ApplicationProvider.getApplicationContext()); } @Test @@ -169,9 +166,12 @@ public class ShadowApplicationTest { @Test @Config(minSdk = O) public void shouldProvideServicesIntroducedOreo() throws Exception { - // Context.AUTOFILL_MANAGER_SERVICE is marked @hide and this is the documented way to obtain this + // Context.AUTOFILL_MANAGER_SERVICE is marked @hide and this is the documented way to obtain + // this // service. - AutofillManager autofillManager = RuntimeEnvironment.application.getSystemService(AutofillManager.class); + AutofillManager autofillManager = + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(AutofillManager.class); assertThat(autofillManager).isNotNull(); assertThat(context.getSystemService(Context.TEXT_CLASSIFICATION_SERVICE)) @@ -179,14 +179,19 @@ public class ShadowApplicationTest { } @Test public void shouldProvideLayoutInflater() throws Exception { - Object systemService = RuntimeEnvironment.application.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + Object systemService = + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); assertThat(systemService).isInstanceOf(LayoutInflater.class); } @Test @Config(minSdk = KITKAT) public void shouldCorrectlyInstantiatedAccessibilityService() throws Exception { - AccessibilityManager accessibilityManager = (AccessibilityManager) RuntimeEnvironment.application.getSystemService(Context.ACCESSIBILITY_SERVICE); + AccessibilityManager accessibilityManager = + (AccessibilityManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.ACCESSIBILITY_SERVICE); AccessibilityManager.TouchExplorationStateChangeListener listener = createTouchListener(); assertThat(accessibilityManager.addTouchExplorationStateChangeListener(listener)).isTrue(); @@ -205,19 +210,22 @@ public class ShadowApplicationTest { TestService service = new TestService(); ComponentName expectedComponentName = new ComponentName("", ""); Binder expectedBinder = new Binder(); - Shadows.shadowOf(RuntimeEnvironment.application).setComponentNameAndServiceForBindService(expectedComponentName, expectedBinder); - RuntimeEnvironment.application.bindService(new Intent(""), service, Context.BIND_AUTO_CREATE); + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()) + .setComponentNameAndServiceForBindService(expectedComponentName, expectedBinder); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(new Intent(""), service, Context.BIND_AUTO_CREATE); assertThat(service.name).isEqualTo(expectedComponentName); assertThat(service.service).isEqualTo(expectedBinder); assertThat(service.nameUnbound).isNull(); - RuntimeEnvironment.application.unbindService(service); + ((Application) ApplicationProvider.getApplicationContext()).unbindService(service); assertThat(service.nameUnbound).isEqualTo(expectedComponentName); } @Test public void bindServiceShouldCallOnServiceConnectedWithNullValues() { TestService service = new TestService(); - RuntimeEnvironment.application.bindService(new Intent(""), service, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(new Intent(""), service, Context.BIND_AUTO_CREATE); assertThat(service.name).isNull(); assertThat(service.service).isNull(); } @@ -228,10 +236,15 @@ public class ShadowApplicationTest { ComponentName expectedComponentName = new ComponentName("", ""); Binder expectedBinder = new Binder(); Intent expectedIntent = new Intent("expected"); - Shadows.shadowOf(RuntimeEnvironment.application).setComponentNameAndServiceForBindServiceForIntent(expectedIntent, expectedComponentName, expectedBinder); + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()) + .setComponentNameAndServiceForBindServiceForIntent( + expectedIntent, expectedComponentName, expectedBinder); TestService service = new TestService(); - assertThat(RuntimeEnvironment.application.bindService(expectedIntent, service, Context.BIND_AUTO_CREATE)).isTrue(); + assertThat( + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntent, service, Context.BIND_AUTO_CREATE)) + .isTrue(); assertThat(service.name).isNull(); assertThat(service.service).isNull(); @@ -248,11 +261,14 @@ public class ShadowApplicationTest { ComponentName expectedComponentName = new ComponentName("", ""); Binder expectedBinder = new Binder(); Intent expectedIntent = new Intent("expected"); - Shadows.shadowOf(RuntimeEnvironment.application).setComponentNameAndServiceForBindServiceForIntent(expectedIntent, expectedComponentName, expectedBinder); - RuntimeEnvironment.application.bindService(expectedIntent, service, Context.BIND_AUTO_CREATE); + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()) + .setComponentNameAndServiceForBindServiceForIntent( + expectedIntent, expectedComponentName, expectedBinder); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntent, service, Context.BIND_AUTO_CREATE); ShadowLooper.pauseMainLooper(); - RuntimeEnvironment.application.unbindService(service); + ((Application) ApplicationProvider.getApplicationContext()).unbindService(service); assertThat(service.nameUnbound).isNull(); ShadowLooper.unPauseMainLooper(); assertThat(service.nameUnbound).isEqualTo(expectedComponentName); @@ -264,10 +280,12 @@ public class ShadowApplicationTest { ComponentName expectedComponentName = new ComponentName("", ""); Binder expectedBinder = new Binder(); Intent expectedIntent = new Intent("expected"); - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); shadowApplication.setComponentNameAndServiceForBindServiceForIntent(expectedIntent, expectedComponentName, expectedBinder); - RuntimeEnvironment.application.bindService(expectedIntent, service, Context.BIND_AUTO_CREATE); - RuntimeEnvironment.application.unbindService(service); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntent, service, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()).unbindService(service); assertThat(shadowApplication.getUnboundServiceConnections()).hasSize(1); assertThat(shadowApplication.getUnboundServiceConnections().get(0)).isSameAs(service); } @@ -279,10 +297,13 @@ public class ShadowApplicationTest { ComponentName expectedComponentName = new ComponentName("", ""); Binder expectedBinder = new Binder(); Intent expectedIntent = new Intent("refuseToBind"); - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); shadowApplication.setComponentNameAndServiceForBindServiceForIntent(expectedIntent, expectedComponentName, expectedBinder); shadowApplication.declareActionUnbindable(expectedIntent.getAction()); - assertFalse(RuntimeEnvironment.application.bindService(expectedIntent, service, Context.BIND_AUTO_CREATE)); + assertFalse( + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntent, service, Context.BIND_AUTO_CREATE)); ShadowLooper.unPauseMainLooper(); assertThat(service.name).isNull(); assertThat(service.service).isNull(); @@ -298,13 +319,16 @@ public class ShadowApplicationTest { ComponentName expectedComponentNameTwo = new ComponentName("package", "two"); Binder expectedBinderTwo = new Binder(); Intent expectedIntentTwo = new Intent("expected_two"); - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); shadowApplication.setComponentNameAndServiceForBindServiceForIntent(expectedIntentOne, expectedComponentNameOne, expectedBinderOne); shadowApplication.setComponentNameAndServiceForBindServiceForIntent(expectedIntentTwo, expectedComponentNameTwo, expectedBinderTwo); - RuntimeEnvironment.application.bindService(expectedIntentOne, service, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntentOne, service, Context.BIND_AUTO_CREATE); assertThat(service.name).isEqualTo(expectedComponentNameOne); assertThat(service.service).isEqualTo(expectedBinderOne); - RuntimeEnvironment.application.bindService(expectedIntentTwo, service, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntentTwo, service, Context.BIND_AUTO_CREATE); assertThat(service.name).isEqualTo(expectedComponentNameTwo); assertThat(service.service).isEqualTo(expectedBinderTwo); } @@ -318,16 +342,20 @@ public class ShadowApplicationTest { ComponentName expectedComponentNameTwo = new ComponentName("package", "two"); Binder expectedBinderTwo = new Binder(); Intent expectedIntentTwo = new Intent("expected_two"); - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); shadowApplication.setComponentNameAndServiceForBindServiceForIntent(expectedIntentOne, expectedComponentNameOne, expectedBinderOne); shadowApplication.setComponentNameAndServiceForBindServiceForIntent(expectedIntentTwo, expectedComponentNameTwo, expectedBinderTwo); - RuntimeEnvironment.application.bindService(expectedIntentOne, service, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntentOne, service, Context.BIND_AUTO_CREATE); assertThat(service.name).isEqualTo(expectedComponentNameOne); assertThat(service.service).isEqualTo(expectedBinderOne); - RuntimeEnvironment.application.bindService(expectedIntentTwo, service, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntentTwo, service, Context.BIND_AUTO_CREATE); assertThat(service.name).isEqualTo(expectedComponentNameTwo); assertThat(service.service).isEqualTo(expectedBinderTwo); - RuntimeEnvironment.application.bindService(new Intent("unknown"), service, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(new Intent("unknown"), service, Context.BIND_AUTO_CREATE); assertThat(service.name).isNull(); assertThat(service.service).isNull(); } @@ -342,30 +370,35 @@ public class ShadowApplicationTest { ComponentName expectedComponentNameTwo = new ComponentName("package", "two"); Binder expectedBinderTwo = new Binder(); Intent expectedIntentTwo = new Intent("expected_two"); - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); shadowApplication.setComponentNameAndServiceForBindServiceForIntent(expectedIntentOne, expectedComponentNameOne, expectedBinderOne); shadowApplication.setComponentNameAndServiceForBindServiceForIntent(expectedIntentTwo, expectedComponentNameTwo, expectedBinderTwo); - RuntimeEnvironment.application.bindService(expectedIntentOne, serviceOne, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntentOne, serviceOne, Context.BIND_AUTO_CREATE); assertThat(serviceOne.nameUnbound).isNull(); - RuntimeEnvironment.application.unbindService(serviceOne); + ((Application) ApplicationProvider.getApplicationContext()).unbindService(serviceOne); assertThat(serviceOne.name).isEqualTo(expectedComponentNameOne); - RuntimeEnvironment.application.bindService(expectedIntentTwo, serviceTwo, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(expectedIntentTwo, serviceTwo, Context.BIND_AUTO_CREATE); assertThat(serviceTwo.nameUnbound).isNull(); - RuntimeEnvironment.application.unbindService(serviceTwo); + ((Application) ApplicationProvider.getApplicationContext()).unbindService(serviceTwo); assertThat(serviceTwo.name).isEqualTo(expectedComponentNameTwo); TestService serviceDefault = new TestService(); - RuntimeEnvironment.application.bindService(new Intent("default"), serviceDefault, Context.BIND_AUTO_CREATE); + ((Application) ApplicationProvider.getApplicationContext()) + .bindService(new Intent("default"), serviceDefault, Context.BIND_AUTO_CREATE); assertThat(serviceDefault.nameUnbound).isNull(); - RuntimeEnvironment.application.unbindService(serviceDefault); + ((Application) ApplicationProvider.getApplicationContext()).unbindService(serviceDefault); assertThat(serviceDefault.name).isNull(); } @Test public void shouldHaveStoppedServiceIntentAndIndicateServiceWasntRunning() { - ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); Activity activity = Robolectric.setupActivity(Activity.class); @@ -385,7 +418,8 @@ public class ShadowApplicationTest { @Test public void shouldHaveStoppedServiceIntentAndIndicateServiceWasRunning() { - ShadowApplication shadowApplication = shadowOf(RuntimeEnvironment.application); + ShadowApplication shadowApplication = + shadowOf((Application) ApplicationProvider.getApplicationContext()); Activity activity = Robolectric.setupActivity(Activity.class); @@ -401,7 +435,8 @@ public class ShadowApplicationTest { @Test public void shouldHaveStoppedServiceByStartedComponent() { - ShadowApplication shadowApplication = shadowOf(RuntimeEnvironment.application); + ShadowApplication shadowApplication = + shadowOf((Application) ApplicationProvider.getApplicationContext()); Activity activity = Robolectric.setupActivity(Activity.class); @@ -424,7 +459,7 @@ public class ShadowApplicationTest { @Test public void shouldClearStartedServiceIntents() { - Application application = RuntimeEnvironment.application; + Application application = (Application) ApplicationProvider.getApplicationContext(); application.startService(getSomeActionIntent("some.action")); application.startService(getSomeActionIntent("another.action")); @@ -439,7 +474,8 @@ public class ShadowApplicationTest { activity.registerReceiver(new TestBroadcastReceiver(), new IntentFilter("Foo")); try { - shadowOf(RuntimeEnvironment.application).assertNoBroadcastListenersOfActionRegistered(activity, "Foo"); + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .assertNoBroadcastListenersOfActionRegistered(activity, "Foo"); fail("should have thrown IllegalStateException"); } catch (IllegalStateException e) { @@ -452,15 +488,18 @@ public class ShadowApplicationTest { Activity activity = Robolectric.setupActivity(Activity.class); activity.registerReceiver(new TestBroadcastReceiver(), new IntentFilter("Foo")); - shadowOf(RuntimeEnvironment.application).assertNoBroadcastListenersOfActionRegistered(activity, "Bar"); + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .assertNoBroadcastListenersOfActionRegistered(activity, "Bar"); } @Test public void canAnswerIfReceiverIsRegisteredForIntent() throws Exception { BroadcastReceiver expectedReceiver = new TestBroadcastReceiver(); - ShadowApplication shadowApplication = shadowOf(RuntimeEnvironment.application); + ShadowApplication shadowApplication = + shadowOf((Application) ApplicationProvider.getApplicationContext()); assertFalse(shadowApplication.hasReceiverForIntent(new Intent("Foo"))); - RuntimeEnvironment.application.registerReceiver(expectedReceiver, new IntentFilter("Foo")); + ((Application) ApplicationProvider.getApplicationContext()) + .registerReceiver(expectedReceiver, new IntentFilter("Foo")); assertTrue(shadowApplication.hasReceiverForIntent(new Intent("Foo"))); } @@ -468,10 +507,13 @@ public class ShadowApplicationTest { @Test public void canFindAllReceiversForAnIntent() throws Exception { BroadcastReceiver expectedReceiver = new TestBroadcastReceiver(); - ShadowApplication shadowApplication = shadowOf(RuntimeEnvironment.application); + ShadowApplication shadowApplication = + shadowOf((Application) ApplicationProvider.getApplicationContext()); assertFalse(shadowApplication.hasReceiverForIntent(new Intent("Foo"))); - RuntimeEnvironment.application.registerReceiver(expectedReceiver, new IntentFilter("Foo")); - RuntimeEnvironment.application.registerReceiver(expectedReceiver, new IntentFilter("Foo")); + ((Application) ApplicationProvider.getApplicationContext()) + .registerReceiver(expectedReceiver, new IntentFilter("Foo")); + ((Application) ApplicationProvider.getApplicationContext()) + .registerReceiver(expectedReceiver, new IntentFilter("Foo")); assertTrue(shadowApplication.getReceiversForIntent(new Intent("Foo")).size() == 2); } @@ -479,9 +521,10 @@ public class ShadowApplicationTest { @Test public void broadcasts_shouldBeLogged() { Intent broadcastIntent = new Intent("foo"); - RuntimeEnvironment.application.sendBroadcast(broadcastIntent); + ((Application) ApplicationProvider.getApplicationContext()).sendBroadcast(broadcastIntent); - List<Intent> broadcastIntents = shadowOf(RuntimeEnvironment.application).getBroadcastIntents(); + List<Intent> broadcastIntents = + shadowOf((Application) ApplicationProvider.getApplicationContext()).getBroadcastIntents(); assertTrue(broadcastIntents.size() == 1); assertEquals(broadcastIntent, broadcastIntents.get(0)); } @@ -489,26 +532,31 @@ public class ShadowApplicationTest { @Test public void sendStickyBroadcast() { Intent broadcastIntent = new Intent("Foo"); - RuntimeEnvironment.application.sendStickyBroadcast(broadcastIntent); + ((Application) ApplicationProvider.getApplicationContext()) + .sendStickyBroadcast(broadcastIntent); // Register after the broadcast has fired. We should immediately get a sticky event. TestBroadcastReceiver receiver = new TestBroadcastReceiver(); - RuntimeEnvironment.application.registerReceiver(receiver, new IntentFilter("Foo")); + ((Application) ApplicationProvider.getApplicationContext()) + .registerReceiver(receiver, new IntentFilter("Foo")); assertTrue(receiver.isSticky); // Fire the broadcast again, and we should get a non-sticky event. - RuntimeEnvironment.application.sendStickyBroadcast(broadcastIntent); + ((Application) ApplicationProvider.getApplicationContext()) + .sendStickyBroadcast(broadcastIntent); assertFalse(receiver.isSticky); } @Test public void shouldRememberResourcesAfterLazilyLoading() throws Exception { - assertSame(RuntimeEnvironment.application.getResources(), RuntimeEnvironment.application.getResources()); + assertSame( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + ((Application) ApplicationProvider.getApplicationContext()).getResources()); } @Test public void checkPermission_shouldTrackGrantedAndDeniedPermissions() throws Exception { - Application application = RuntimeEnvironment.application; + Application application = (Application) ApplicationProvider.getApplicationContext(); shadowOf(application).grantPermissions("foo", "bar"); shadowOf(application).denyPermissions("foo", "qux"); assertThat(application.checkPermission("foo", -1, -1)).isEqualTo(PERMISSION_DENIED); @@ -519,7 +567,7 @@ public class ShadowApplicationTest { @Test public void startActivity_whenActivityCheckingEnabled_checksPackageManagerResolveInfo() throws Exception { - Application application = RuntimeEnvironment.application; + Application application = (Application) ApplicationProvider.getApplicationContext(); shadowOf(application).checkActivities(true); String action = "com.does.not.exist.android.app.v2.mobile"; @@ -535,7 +583,7 @@ public class ShadowApplicationTest { @Test public void bindServiceShouldAddServiceConnectionToListOfBoundServiceConnections() { - final Application application = RuntimeEnvironment.application; + final Application application = (Application) ApplicationProvider.getApplicationContext(); final ShadowApplication shadowApplication = Shadows.shadowOf(application); final ServiceConnection expectedServiceConnection = new EmptyServiceConnection(); @@ -549,7 +597,7 @@ public class ShadowApplicationTest { @Test public void bindServiceShouldAddServiceConnectionToListOfBoundServiceConnectionsEvenIfServiceUnboundable() { - final Application application = RuntimeEnvironment.application; + final Application application = (Application) ApplicationProvider.getApplicationContext(); final ShadowApplication shadowApplication = Shadows.shadowOf(application); final ServiceConnection expectedServiceConnection = new EmptyServiceConnection(); final String unboundableAction = "refuse"; @@ -563,7 +611,7 @@ public class ShadowApplicationTest { @Test public void unbindServiceShouldRemoveServiceConnectionFromListOfBoundServiceConnections() { - final Application application = RuntimeEnvironment.application; + final Application application = (Application) ApplicationProvider.getApplicationContext(); final ShadowApplication shadowApplication = Shadows.shadowOf(application); final ServiceConnection expectedServiceConnection = new EmptyServiceConnection(); @@ -580,7 +628,8 @@ public class ShadowApplicationTest { @Test public void getThreadScheduler_shouldMatchRobolectricValue() { - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); assertThat(shadowApplication.getForegroundThreadScheduler()).isSameAs(Robolectric.getForegroundThreadScheduler()); assertThat(shadowApplication.getBackgroundThreadScheduler()).isSameAs(Robolectric.getBackgroundThreadScheduler()); } @@ -589,7 +638,8 @@ public class ShadowApplicationTest { public void getForegroundThreadScheduler_shouldMatchRuntimeEnvironment() { Scheduler s = new Scheduler(); RuntimeEnvironment.setMasterScheduler(s); - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); assertThat(shadowApplication.getForegroundThreadScheduler()).isSameAs(s); } @@ -597,7 +647,8 @@ public class ShadowApplicationTest { public void getBackgroundThreadScheduler_shouldDifferFromRuntimeEnvironment_byDefault() { Scheduler s = new Scheduler(); RuntimeEnvironment.setMasterScheduler(s); - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); assertThat(shadowApplication.getBackgroundThreadScheduler()).isNotSameAs(RuntimeEnvironment.getMasterScheduler()); } @@ -605,15 +656,22 @@ public class ShadowApplicationTest { public void getBackgroundThreadScheduler_shouldDifferFromRuntimeEnvironment_withAdvancedScheduling() { Scheduler s = new Scheduler(); RuntimeEnvironment.setMasterScheduler(s); - final ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application); + final ShadowApplication shadowApplication = + Shadows.shadowOf((Application) ApplicationProvider.getApplicationContext()); assertThat(shadowApplication.getBackgroundThreadScheduler()).isNotSameAs(s); } @Test public void getLatestPopupWindow() { - PopupWindow pw = new PopupWindow(new LinearLayout(RuntimeEnvironment.application)); - - pw.showAtLocation(new LinearLayout(RuntimeEnvironment.application), Gravity.CENTER, 0, 0); + PopupWindow pw = + new PopupWindow( + new LinearLayout((Application) ApplicationProvider.getApplicationContext())); + + pw.showAtLocation( + new LinearLayout((Application) ApplicationProvider.getApplicationContext()), + Gravity.CENTER, + 0, + 0); PopupWindow latestPopupWindow = ShadowApplication.getInstance().getLatestPopupWindow(); assertThat(latestPopupWindow).isSameAs(pw); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowArrayAdapterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowArrayAdapterTest.java index 673bc026c..7067e46b7 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowArrayAdapterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowArrayAdapterTest.java @@ -3,10 +3,13 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import android.app.Application; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -14,11 +17,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowArrayAdapterTest { private ArrayAdapter<Integer> arrayAdapter; @@ -28,12 +29,14 @@ public class ShadowArrayAdapterTest { list.add(2); list.add(3); - arrayAdapter = new ArrayAdapter<>(RuntimeEnvironment.application, 0, list); + arrayAdapter = + new ArrayAdapter<>((Application) ApplicationProvider.getApplicationContext(), 0, list); } @Test public void verifyContext() { - assertThat(arrayAdapter.getContext()).isSameAs(RuntimeEnvironment.application); + assertThat(arrayAdapter.getContext()) + .isSameAs((Application) ApplicationProvider.getApplicationContext()); } @Test @@ -47,8 +50,13 @@ public class ShadowArrayAdapterTest { @Test public void usesTextViewResourceIdToSetTextWithinListItemView() throws Exception { - ListView parent = new ListView(RuntimeEnvironment.application); - ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(RuntimeEnvironment.application, R.layout.main, R.id.title, new String[] { "first value" }); + ListView parent = new ListView((Application) ApplicationProvider.getApplicationContext()); + ArrayAdapter<String> arrayAdapter = + new ArrayAdapter<>( + (Application) ApplicationProvider.getApplicationContext(), + R.layout.main, + R.id.title, + new String[] {"first value"}); View listItemView = arrayAdapter.getView(0, null, parent); TextView titleTextView = listItemView.findViewById(R.id.title); assertEquals("first value", titleTextView.getText().toString()); @@ -56,7 +64,11 @@ public class ShadowArrayAdapterTest { @Test public void hasTheCorrectConstructorResourceIDs() { - ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(RuntimeEnvironment.application, R.id.title, new String[] { "first value" }); + ArrayAdapter<String> arrayAdapter = + new ArrayAdapter<>( + (Application) ApplicationProvider.getApplicationContext(), + R.id.title, + new String[] {"first value"}); //this assertion may look a little backwards since R.id.title is labeled //textViewResourceId in the constructor parameter list, but the output is correct. @@ -64,7 +76,8 @@ public class ShadowArrayAdapterTest { assertThat(Shadows.shadowOf(arrayAdapter).getTextViewResourceId()).isNotEqualTo(R.id.title); assertThat(Shadows.shadowOf(arrayAdapter).getTextViewResourceId()).isEqualTo(0); - ArrayAdapter<String> arrayAdapter2 = new ArrayAdapter<>(RuntimeEnvironment.application, R.id.title); + ArrayAdapter<String> arrayAdapter2 = + new ArrayAdapter<>((Application) ApplicationProvider.getApplicationContext(), R.id.title); //this assertion may look a little backwards since R.id.title is labeled //textViewResourceId in the constructor parameter list, but the output is correct. @@ -72,7 +85,11 @@ public class ShadowArrayAdapterTest { assertThat(Shadows.shadowOf(arrayAdapter2).getTextViewResourceId()).isNotEqualTo(R.id.title); assertThat(Shadows.shadowOf(arrayAdapter2).getTextViewResourceId()).isEqualTo(0); - ArrayAdapter<String> arrayAdapter3 = new ArrayAdapter<>(RuntimeEnvironment.application, R.id.title, Arrays.asList(new String[] { "first value" })); + ArrayAdapter<String> arrayAdapter3 = + new ArrayAdapter<>( + (Application) ApplicationProvider.getApplicationContext(), + R.id.title, + Arrays.asList(new String[] {"first value"})); //this assertion may look a little backwards since R.id.title is labeled //textViewResourceId in the constructor parameter list, but the output is correct. diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAssetManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAssetManagerTest.java index 10d284f0c..45edb625b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAssetManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAssetManagerTest.java @@ -8,11 +8,14 @@ import static org.mockito.Mockito.when; import static org.robolectric.shadows.ShadowAssetManager.legacyShadowOf; import static org.robolectric.shadows.ShadowAssetManager.useLegacy; +import android.app.Application; import android.content.res.AssetManager; import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.TypedValue; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -23,13 +26,11 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowResources.ShadowLegacyTheme; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAssetManagerTest { @Rule @@ -40,7 +41,7 @@ public class ShadowAssetManagerTest { @Before public void setUp() throws Exception { - resources = RuntimeEnvironment.application.getResources(); + resources = ((Application) ApplicationProvider.getApplicationContext()).getResources(); assetManager = resources.getAssets(); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncQueryHandlerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncQueryHandlerTest.java index 3e34f5e76..74a0b3720 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncQueryHandlerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncQueryHandlerTest.java @@ -4,21 +4,22 @@ import static android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.AsyncQueryHandler; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.fakes.RoboCursor; /** Unit tests for {@link ShadowAsyncQueryHandler}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public final class ShadowAsyncQueryHandlerTest { private static final int TOKEN = 22; @@ -29,7 +30,8 @@ public final class ShadowAsyncQueryHandlerTest { @Before public void setUp() { - contentResolver = RuntimeEnvironment.application.getContentResolver(); + contentResolver = + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskLoaderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskLoaderTest.java index 006db88a9..c09082b78 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskLoaderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskLoaderTest.java @@ -2,17 +2,18 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.AsyncTaskLoader; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAsyncTaskLoaderTest { private final List<String> transcript = new ArrayList<>(); @@ -64,7 +65,7 @@ public class ShadowAsyncTaskLoaderTest { private Integer data; public TestLoader(Integer data) { - super(RuntimeEnvironment.application); + super((Application) ApplicationProvider.getApplicationContext()); this.data = data; } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskTest.java index b5d2d8098..51c4ee128 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAsyncTaskTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.os.AsyncTask; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; @@ -15,10 +16,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.util.Join; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAsyncTaskTest { private List<String> transcript; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAudioEffectTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAudioEffectTest.java index c21a876b8..81bf92d40 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAudioEffectTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAudioEffectTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.media.audiofx.AudioEffect; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAudioEffectTest { @Test public void queryEffects() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAudioManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAudioManagerTest.java index ed5750b6a..6b2114bdf 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAudioManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAudioManagerTest.java @@ -4,20 +4,22 @@ import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioPlaybackConfiguration; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Arrays; import java.util.List; 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) +@RunWith(AndroidJUnit4.class) public class ShadowAudioManagerTest { - private final AudioManager audioManager = new AudioManager(RuntimeEnvironment.application); + private final AudioManager audioManager = + new AudioManager((Application) ApplicationProvider.getApplicationContext()); private final AudioManager.OnAudioFocusChangeListener listener = new AudioManager.OnAudioFocusChangeListener() { @Override public void onAudioFocusChange(int focusChange) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowAutoCompleteTextViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowAutoCompleteTextViewTest.java index 7215cce0c..490afc613 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowAutoCompleteTextViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowAutoCompleteTextViewTest.java @@ -2,28 +2,31 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.Context; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Filter; import android.widget.Filterable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowAutoCompleteTextViewTest { - private final AutoCompleteAdapter adapter = new AutoCompleteAdapter(RuntimeEnvironment.application); + private final AutoCompleteAdapter adapter = + new AutoCompleteAdapter((Application) ApplicationProvider.getApplicationContext()); @Test public void shouldInvokeFilter() throws Exception { Robolectric.getForegroundThreadScheduler().pause(); - AutoCompleteTextView view = new AutoCompleteTextView(RuntimeEnvironment.application); + AutoCompleteTextView view = + new AutoCompleteTextView((Application) ApplicationProvider.getApplicationContext()); view.setAdapter(adapter); view.setText("Foo"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBackupManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBackupManagerTest.java index b715c7cd1..afca18559 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBackupManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBackupManagerTest.java @@ -7,10 +7,13 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.backup.BackupManager; import android.app.backup.RestoreObserver; import android.app.backup.RestoreSession; import android.app.backup.RestoreSet; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.truth.Correspondence; import java.util.Arrays; import java.util.Objects; @@ -22,13 +25,11 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; /** Unit tests for {@link ShadowBackupManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBackupManagerTest { private BackupManager backupManager; @Mock private TestRestoreObserver restoreObserver; @@ -39,8 +40,9 @@ public class ShadowBackupManagerTest { ShadowLooper.pauseMainLooper(); - shadowOf(RuntimeEnvironment.application).grantPermissions(android.Manifest.permission.BACKUP); - backupManager = new BackupManager(RuntimeEnvironment.application); + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .grantPermissions(android.Manifest.permission.BACKUP); + backupManager = new BackupManager((Application) ApplicationProvider.getApplicationContext()); shadowOf(backupManager).addAvailableRestoreSets(123L, Arrays.asList("foo.bar", "bar.baz")); shadowOf(backupManager).addAvailableRestoreSets(456L, Arrays.asList("hello.world")); @@ -59,7 +61,10 @@ public class ShadowBackupManagerTest { // BackupManager is used by creating new instances, but all of them talk to the same // BackupManagerService in Android, so methods that route through the service will share states. backupManager.setBackupEnabled(true); - assertThat(new BackupManager(RuntimeEnvironment.application).isBackupEnabled()).isTrue(); + assertThat( + new BackupManager((Application) ApplicationProvider.getApplicationContext()) + .isBackupEnabled()) + .isTrue(); } @Test @@ -72,7 +77,8 @@ public class ShadowBackupManagerTest { @Test @Config(minSdk = LOLLIPOP) public void isBackupEnabled_noPermission_shouldThrowSecurityException() { - shadowOf(RuntimeEnvironment.application).denyPermissions(android.Manifest.permission.BACKUP); + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .denyPermissions(android.Manifest.permission.BACKUP); try { backupManager.isBackupEnabled(); fail("SecurityException should be thrown"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBaseAdapterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBaseAdapterTest.java index 9e6c60f73..d0ce5bbea 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBaseAdapterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBaseAdapterTest.java @@ -7,11 +7,11 @@ import static org.robolectric.Shadows.shadowOf; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBaseAdapterTest { @Test public void shouldRecordNotifyDataSetChanged() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBatteryManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBatteryManagerTest.java index 20e4d5270..894f83e75 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBatteryManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBatteryManagerTest.java @@ -5,16 +5,17 @@ import static android.os.Build.VERSION_CODES.M; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.os.BatteryManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowBatteryManagerTest { private BatteryManager batteryManager; @@ -23,8 +24,10 @@ public class ShadowBatteryManagerTest { @Before public void before() { - batteryManager = (BatteryManager) RuntimeEnvironment.application.getSystemService( - Context.BATTERY_SERVICE); + batteryManager = + (BatteryManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.BATTERY_SERVICE); shadowBatteryManager = shadowOf(batteryManager); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBinderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBinderTest.java index 14bc47072..009a495b2 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBinderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBinderTest.java @@ -7,11 +7,11 @@ import static org.junit.Assert.fail; import android.os.Binder; import android.os.Parcel; import android.os.RemoteException; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBinderTest { @Test public void transactCallsOnTransact() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapDrawableTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapDrawableTest.java index 96ff2eb4e..f6fafd552 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapDrawableTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapDrawableTest.java @@ -4,6 +4,7 @@ import static com.google.common.truth.Truth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -12,19 +13,20 @@ import android.graphics.ColorMatrixColorFilter; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.ByteArrayInputStream; import java.io.InputStream; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBitmapDrawableTest { - private final Resources resources = RuntimeEnvironment.application.getResources(); + private final Resources resources = + ((Application) ApplicationProvider.getApplicationContext()).getResources(); @Test public void constructors_shouldSetBitmap() throws Exception { @@ -96,13 +98,19 @@ public class ShadowBitmapDrawableTest { @Test public void constructor_shouldSetTheIntrinsicWidthAndHeightToTheWidthAndHeightOfTheBitmap() throws Exception { Bitmap bitmap = Bitmap.createBitmap(5, 10, Bitmap.Config.ARGB_8888); - BitmapDrawable drawable = new BitmapDrawable(RuntimeEnvironment.application.getResources(), bitmap); + BitmapDrawable drawable = + new BitmapDrawable( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), bitmap); assertThat(drawable.getIntrinsicWidth()).isEqualTo(5); assertThat(drawable.getIntrinsicHeight()).isEqualTo(10); } @Test public void constructor_shouldAcceptNullBitmap() throws Exception { - assertThat(new BitmapDrawable(RuntimeEnvironment.application.getResources(), (Bitmap) null)).isNotNull(); + assertThat( + new BitmapDrawable( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + (Bitmap) null)) + .isNotNull(); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapFactoryTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapFactoryTest.java index 1a9dcdd7d..ae8e71c7c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapFactoryTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapFactoryTest.java @@ -5,11 +5,14 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; import android.net.Uri; import android.provider.MediaStore; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -17,14 +20,15 @@ import java.io.InputStream; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBitmapFactoryTest { @Test public void decodeResource_shouldSetDescriptionAndCreatedFrom() throws Exception { - Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image); + Bitmap bitmap = + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.an_image); ShadowBitmap shadowBitmap = shadowOf(bitmap); assertEquals("Bitmap for resource:org.robolectric:drawable/an_image", shadowBitmap.getDescription()); assertEquals(R.drawable.an_image, shadowBitmap.getCreatedFromResId()); @@ -34,21 +38,31 @@ public class ShadowBitmapFactoryTest { @Test public void decodeResource_shouldSetDefaultBitmapConfig() throws Exception { - Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image); + Bitmap bitmap = + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.an_image); assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ARGB_8888); assertThat(bitmap.getRowBytes()).isNotEqualTo(0); } @Test public void withResId0_decodeResource_shouldReturnNull() throws Exception { - assertThat(BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), 0)).isNull(); + assertThat( + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), 0)) + .isNull(); } @Test public void decodeResource_shouldPassABitmapConfig() throws Exception { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ALPHA_8; - Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image, options); + Bitmap bitmap = + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.an_image, + options); assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ALPHA_8); } @@ -64,7 +78,10 @@ public class ShadowBitmapFactoryTest { @Test public void decodeStream_shouldSetDescriptionAndCreatedFrom() throws Exception { - InputStream inputStream = RuntimeEnvironment.application.getContentResolver().openInputStream(Uri.parse("content:/path")); + InputStream inputStream = + ((Application) ApplicationProvider.getApplicationContext()) + .getContentResolver() + .openInputStream(Uri.parse("content:/path")); Bitmap bitmap = BitmapFactory.decodeStream(inputStream); ShadowBitmap shadowBitmap = shadowOf(bitmap); assertEquals("Bitmap for content:/path", shadowBitmap.getDescription()); @@ -87,7 +104,10 @@ public class ShadowBitmapFactoryTest { @Test public void decodeStream_shouldSetDescriptionWithNullOptions() throws Exception { - InputStream inputStream = RuntimeEnvironment.application.getContentResolver().openInputStream(Uri.parse("content:/path")); + InputStream inputStream = + ((Application) ApplicationProvider.getApplicationContext()) + .getContentResolver() + .openInputStream(Uri.parse("content:/path")); Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, null); assertEquals("Bitmap for content:/path", shadowOf(bitmap).getDescription()); assertEquals(100, bitmap.getWidth()); @@ -98,7 +118,10 @@ public class ShadowBitmapFactoryTest { public void decodeResource_shouldGetWidthAndHeightFromHints() throws Exception { ShadowBitmapFactory.provideWidthAndHeightHints(R.drawable.an_image, 123, 456); - Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image); + Bitmap bitmap = + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.an_image); assertEquals("Bitmap for resource:org.robolectric:drawable/an_image", shadowOf(bitmap).getDescription()); assertEquals(123, bitmap.getWidth()); assertEquals(456, bitmap.getHeight()); @@ -108,16 +131,29 @@ public class ShadowBitmapFactoryTest { public void decodeResource_canTakeOptions() throws Exception { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 100; - Bitmap bitmap = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image, options); + Bitmap bitmap = + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.an_image, + options); assertEquals(true, shadowOf(bitmap).getDescription().contains("inSampleSize=100")); } @Test public void decodeResourceStream_canTakeOptions() throws Exception { BitmapFactory.Options options = new BitmapFactory.Options(); - InputStream inputStream = RuntimeEnvironment.application.getContentResolver().openInputStream(Uri.parse("content:/path")); + InputStream inputStream = + ((Application) ApplicationProvider.getApplicationContext()) + .getContentResolver() + .openInputStream(Uri.parse("content:/path")); options.inSampleSize = 100; - Bitmap bitmap = BitmapFactory.decodeResourceStream(RuntimeEnvironment.application.getResources(), null, inputStream, null, options); + Bitmap bitmap = + BitmapFactory.decodeResourceStream( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + null, + inputStream, + null, + options); assertEquals(true, shadowOf(bitmap).getDescription().contains("inSampleSize=100")); } @@ -145,7 +181,10 @@ public class ShadowBitmapFactoryTest { public void decodeUri_shouldGetWidthAndHeightFromHints() throws Exception { ShadowBitmapFactory.provideWidthAndHeightHints(Uri.parse("content:/path"), 123, 456); - Bitmap bitmap = MediaStore.Images.Media.getBitmap(RuntimeEnvironment.application.getContentResolver(), Uri.parse("content:/path")); + Bitmap bitmap = + MediaStore.Images.Media.getBitmap( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Uri.parse("content:/path")); assertEquals("Bitmap for content:/path", shadowOf(bitmap).getDescription()); assertEquals(123, bitmap.getWidth()); assertEquals(456, bitmap.getHeight()); @@ -199,7 +238,10 @@ public class ShadowBitmapFactoryTest { public void decodeStream_shouldGetWidthAndHeightFromHints() throws Exception { ShadowBitmapFactory.provideWidthAndHeightHints(Uri.parse("content:/path"), 123, 456); - InputStream inputStream = RuntimeEnvironment.application.getContentResolver().openInputStream(Uri.parse("content:/path")); + InputStream inputStream = + ((Application) ApplicationProvider.getApplicationContext()) + .getContentResolver() + .openInputStream(Uri.parse("content:/path")); Bitmap bitmap = BitmapFactory.decodeStream(inputStream); assertEquals("Bitmap for content:/path", shadowOf(bitmap).getDescription()); assertEquals(123, bitmap.getWidth()); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapRegionDecoderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapRegionDecoderTest.java index 9b2644752..c502811e9 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapRegionDecoderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapRegionDecoderTest.java @@ -2,10 +2,13 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; import android.graphics.Rect; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.io.ByteStreams; import java.awt.image.BufferedImage; import java.io.File; @@ -18,11 +21,9 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(qualifiers = "hdpi") public class ShadowBitmapRegionDecoderTest { @@ -73,11 +74,17 @@ public class ShadowBitmapRegionDecoderTest { } private static InputStream getImageInputStream() { - return RuntimeEnvironment.application.getResources().openRawResource(R.drawable.robolectric); + return ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .openRawResource(R.drawable.robolectric); } private static FileDescriptor getImageFd() throws Exception { - return RuntimeEnvironment.application.getResources().getAssets().openFd("robolectric.png").getFileDescriptor(); + return ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getAssets() + .openFd("robolectric.png") + .getFileDescriptor(); } private String getGeneratedImageFile() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapTest.java index 45405fc98..b6e672454 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBitmapTest.java @@ -15,6 +15,7 @@ import android.graphics.Paint; import android.os.Build; import android.os.Parcel; import android.util.DisplayMetrics; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; @@ -22,11 +23,10 @@ import java.nio.ShortBuffer; import java.util.Arrays; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBitmapTest { @Test public void shouldCreateScaledBitmap() throws Exception { @@ -580,6 +580,61 @@ public class ShadowBitmapTest { original.reconfigure(100, 100, Bitmap.Config.ARGB_8888); } + @Config(sdk = Build.VERSION_CODES.KITKAT) + @Test + public void setPremultiplied() { + Bitmap original = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + assertThat(original.isPremultiplied()).isFalse(); + original.setPremultiplied(true); + assertThat(original.isPremultiplied()).isTrue(); + original.setPremultiplied(false); + assertThat(original.isPremultiplied()).isFalse(); + } + + @Test + public void sameAs_bitmapsDifferentWidth() { + Bitmap original1 = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + Bitmap original2 = Bitmap.createBitmap(101, 100, Bitmap.Config.ARGB_8888); + assertThat(original1.sameAs(original2)).isFalse(); + } + + @Test + public void sameAs_bitmapsDifferentHeight() { + Bitmap original1 = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + Bitmap original2 = Bitmap.createBitmap(100, 101, Bitmap.Config.ARGB_8888); + assertThat(original1.sameAs(original2)).isFalse(); + } + + @Test + public void sameAs_bitmapsDifferentConfig() { + Bitmap original1 = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); + Bitmap original2 = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_4444); + assertThat(original1.sameAs(original2)).isFalse(); + } + + @Test + public void sameAs_bitmapsDifferentPixels() { + int[] pixels1 = new int[] {0, 1, 2, 3}; + Bitmap original1 = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); + original1.setPixels(pixels1, 0, 1, 0, 0, 2, 2); + + int[] pixels2 = new int[] {3, 2, 1, 0}; + Bitmap original2 = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); + original2.setPixels(pixels2, 0, 1, 0, 0, 2, 2); + assertThat(original1.sameAs(original2)).isFalse(); + } + + @Test + public void sameAs_bitmapsSamePixels() { + int[] pixels = new int[] {0, 1, 2, 3}; + Bitmap original1 = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); + original1.setPixels(pixels, 0, 1, 0, 0, 2, 2); + + Bitmap original2 = Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888); + original2.setPixels(pixels, 0, 1, 0, 0, 2, 2); + assertThat(original1.sameAs(original2)).isTrue(); + } + private static Bitmap create(String name) { Bitmap bitmap = Shadow.newInstanceOf(Bitmap.class); shadowOf(bitmap).appendDescription(name); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java index f3b931e4c..88fdf8a35 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothAdapterTest.java @@ -7,17 +7,18 @@ import static org.robolectric.Shadows.shadowOf; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.UUID; 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.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBluetoothAdapterTest { private BluetoothAdapter bluetoothAdapter; private ShadowBluetoothAdapter shadowBluetoothAdapter; @@ -144,11 +145,24 @@ public class ShadowBluetoothAdapterTest { @Test public void insecureRfcomm_notNull() throws Exception { assertThat( - bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord( - "serviceName", UUID.randomUUID())) + bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord( + "serviceName", UUID.randomUUID())) .isNotNull(); } + @Test + public void canGetProfileConnectionState() throws Exception { + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + assertThat(adapter.getProfileConnectionState(BluetoothProfile.HEADSET)) + .isEqualTo(BluetoothProfile.STATE_DISCONNECTED); + shadowOf(adapter) + .setProfileConnectionState(BluetoothProfile.HEADSET, BluetoothProfile.STATE_CONNECTED); + assertThat(adapter.getProfileConnectionState(BluetoothProfile.HEADSET)) + .isEqualTo(BluetoothProfile.STATE_CONNECTED); + assertThat(adapter.getProfileConnectionState(BluetoothProfile.A2DP)) + .isEqualTo(BluetoothProfile.STATE_DISCONNECTED); + } + private BluetoothAdapter.LeScanCallback newLeScanCallback() { return new BluetoothAdapter.LeScanCallback() { @Override diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothDeviceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothDeviceTest.java index 48caf1627..cd65a6d93 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothDeviceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothDeviceTest.java @@ -6,17 +6,18 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGattCallback; import android.os.ParcelUuid; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; 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) +@RunWith(AndroidJUnit4.class) public class ShadowBluetoothDeviceTest { private static final String MOCK_MAC_ADDRESS = "00:11:22:33:AA:BB"; @@ -34,8 +35,8 @@ public class ShadowBluetoothDeviceTest { BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(MOCK_MAC_ADDRESS); ParcelUuid[] uuids = new ParcelUuid[] { - ParcelUuid.fromString("00000000-1111-2222-3333-000000000011"), - ParcelUuid.fromString("00000000-1111-2222-3333-0000000000aa") + ParcelUuid.fromString("00000000-1111-2222-3333-000000000011"), + ParcelUuid.fromString("00000000-1111-2222-3333-0000000000aa") }; shadowOf(device).setUuids(uuids); @@ -94,8 +95,10 @@ public class ShadowBluetoothDeviceTest { public void connectGatt_doesntCrash() throws Exception { BluetoothDevice bluetoothDevice = ShadowBluetoothDevice.newInstance(MOCK_MAC_ADDRESS); assertThat( - bluetoothDevice.connectGatt( - RuntimeEnvironment.application, false, new BluetoothGattCallback() {})) + bluetoothDevice.connectGatt( + (Application) ApplicationProvider.getApplicationContext(), + false, + new BluetoothGattCallback() {})) .isNotNull(); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothGattTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothGattTest.java index 96594d70c..90d5f2810 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothGattTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothGattTest.java @@ -5,13 +5,13 @@ import static com.google.common.truth.Truth.assertThat; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; /** Tests for {@link ShadowBluetoothGatt}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = JELLY_BEAN_MR2) public class ShadowBluetoothGattTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothManagerTest.java index 1793012ad..50bccaa05 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothManagerTest.java @@ -3,22 +3,26 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.content.Context; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = JELLY_BEAN_MR2) public class ShadowBluetoothManagerTest { - private final BluetoothManager manager = (BluetoothManager) RuntimeEnvironment.application.getSystemService(Context.BLUETOOTH_SERVICE); + private final BluetoothManager manager = + (BluetoothManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.BLUETOOTH_SERVICE); - @Test - public void getAdapter_shouldReturnBluetoothAdapter() { - assertThat(manager.getAdapter()).isSameAs(BluetoothAdapter.getDefaultAdapter()); - } + @Test + public void getAdapter_shouldReturnBluetoothAdapter() { + assertThat(manager.getAdapter()).isSameAs(BluetoothAdapter.getDefaultAdapter()); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothSocketTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothSocketTest.java new file mode 100644 index 000000000..22560ca46 --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBluetoothSocketTest.java @@ -0,0 +1,44 @@ +package org.robolectric.shadows; + +import static com.google.common.truth.Truth.assertThat; +import static org.robolectric.Shadows.shadowOf; + +import android.bluetooth.BluetoothSocket; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import java.io.InputStream; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.shadow.api.Shadow; + +@RunWith(AndroidJUnit4.class) +public class ShadowBluetoothSocketTest { + BluetoothSocket bluetoothSocket; + + private static final byte[] DATA = new byte[] {1, 2, 3, 42, 96, 127}; + + @Before + public void setUp() throws Exception { + bluetoothSocket = Shadow.newInstanceOf(BluetoothSocket.class); + } + + @Test + public void getInputStreamFeeder() throws Exception { + shadowOf(bluetoothSocket).getInputStreamFeeder().write(DATA); + + InputStream inputStream = bluetoothSocket.getInputStream(); + byte[] b = new byte[1024]; + int len = inputStream.read(b); + assertThat(Arrays.copyOf(b, len)).isEqualTo(DATA); + } + + @Test + public void getOutputStreamSink() throws Exception { + bluetoothSocket.getOutputStream().write(DATA); + + byte[] b = new byte[1024]; + int len = shadowOf(bluetoothSocket).getOutputStreamSink().read(b); + assertThat(Arrays.copyOf(b, len)).isEqualTo(DATA); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBroadcastPendingResultTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBroadcastPendingResultTest.java index 0bccec86f..16a1c4861 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBroadcastPendingResultTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBroadcastPendingResultTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.os.Bundle; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBroadcastPendingResultTest { @Test public void testCreate() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBuildTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBuildTest.java index dd4108b57..9688830fb 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBuildTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBuildTest.java @@ -5,12 +5,12 @@ import static com.google.common.truth.Truth.assertThat; import android.os.Build; import android.os.Build.VERSION; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBuildTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowBundleTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowBundleTest.java index e809abe5a..4a079c0c4 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowBundleTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowBundleTest.java @@ -4,12 +4,12 @@ import static com.google.common.truth.Truth.assertThat; import android.os.Bundle; import android.os.Parcelable; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowBundleTest { private final Bundle bundle = new Bundle(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraCharacteristicsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraCharacteristicsTest.java new file mode 100644 index 000000000..195b6394f --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraCharacteristicsTest.java @@ -0,0 +1,47 @@ +package org.robolectric.shadows; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +import static org.robolectric.Shadows.shadowOf; + +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraCharacteristics.Key; +import android.os.Build.VERSION_CODES; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +/** Tests for {@link ShadowCameraCharacteristics}. */ +@Config(minSdk = VERSION_CODES.LOLLIPOP) +@RunWith(AndroidJUnit4.class) +public class ShadowCameraCharacteristicsTest { + + private final Key key0 = new Key("key0", Integer.class); + private final CameraCharacteristics cameraCharacteristics = + ShadowCameraCharacteristics.newCameraCharacteristics(); + + @Test + public void testSetExistingKey() { + shadowOf(cameraCharacteristics).set(key0, 1); + + try { + shadowOf(cameraCharacteristics).set(key0, 1); + fail(); + } catch (IllegalArgumentException e) { + // Expected + } + } + + @Test + public void testGetUnrecognizedKey() { + assertThat(cameraCharacteristics.get(key0)).isNull(); + } + + @Test + public void testGetRecognizedKey() { + shadowOf(cameraCharacteristics).set(key0, 1); + + assertThat(cameraCharacteristics.get(key0)).isEqualTo(1); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraManagerTest.java new file mode 100644 index 000000000..6c6a9f320 --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraManagerTest.java @@ -0,0 +1,114 @@ +package org.robolectric.shadows; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; +import static org.robolectric.Shadows.shadowOf; + +import android.app.Application; +import android.content.Context; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraManager; +import android.os.Build.VERSION_CODES; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +/** Tests for {@link ShadowCameraManager}. */ +@Config(minSdk = VERSION_CODES.LOLLIPOP) +@RunWith(AndroidJUnit4.class) +public class ShadowCameraManagerTest { + + private static final String CAMERA_ID_0 = "cameraId0"; + private static final String CAMERA_ID_1 = "cameraId1"; + + private final CameraManager cameraManager = + (CameraManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.CAMERA_SERVICE); + + private final CameraCharacteristics characteristics = + ShadowCameraCharacteristics.newCameraCharacteristics(); + + @Test + public void testAddCameraNullCameraId() { + try { + shadowOf(cameraManager).addCamera(null, characteristics); + fail(); + } catch (NullPointerException e) { + // Expected + } + } + + @Test + public void testAddCameraNullCharacteristics() { + try { + shadowOf(cameraManager).addCamera(CAMERA_ID_0, null); + fail(); + } catch (NullPointerException e) { + // Expected + } + } + + @Test + public void testAddCameraExistingId() { + shadowOf(cameraManager).addCamera(CAMERA_ID_0, characteristics); + + try { + shadowOf(cameraManager).addCamera(CAMERA_ID_0, characteristics); + fail(); + } catch (IllegalArgumentException e) { + // Expected + } + } + + @Test + public void testGetCameraIdListNoCameras() throws CameraAccessException { + assertThat(cameraManager.getCameraIdList()).isEmpty(); + } + + @Test + public void testGetCameraIdListSingleCamera() throws CameraAccessException { + shadowOf(cameraManager).addCamera(CAMERA_ID_0, characteristics); + + assertThat(cameraManager.getCameraIdList()).asList().containsExactly(CAMERA_ID_0); + } + + @Test + public void testGetCameraIdListInOrderOfAdd() throws CameraAccessException { + shadowOf(cameraManager).addCamera(CAMERA_ID_0, characteristics); + shadowOf(cameraManager).addCamera(CAMERA_ID_1, characteristics); + + assertThat(cameraManager.getCameraIdList()[0]).isEqualTo(CAMERA_ID_0); + assertThat(cameraManager.getCameraIdList()[1]).isEqualTo(CAMERA_ID_1); + } + + @Test + public void testGetCameraCharacteristicsNullCameraId() throws CameraAccessException { + try { + cameraManager.getCameraCharacteristics(null); + fail(); + } catch (NullPointerException e) { + // Expected + } + } + + @Test + public void testGetCameraCharacteristicsUnrecognizedCameraId() throws CameraAccessException { + try { + cameraManager.getCameraCharacteristics(CAMERA_ID_0); + fail(); + } catch (IllegalArgumentException e) { + // Expected + } + } + + @Test + public void testGetCameraCharacteristicsRecognizedCameraId() throws CameraAccessException { + shadowOf(cameraManager).addCamera(CAMERA_ID_0, characteristics); + + assertThat(cameraManager.getCameraCharacteristics(CAMERA_ID_0)).isSameAs(characteristics); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraParametersTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraParametersTest.java index 56cc9072d..f69619c34 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraParametersTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraParametersTest.java @@ -4,37 +4,35 @@ import static com.google.common.truth.Truth.assertThat; import android.graphics.ImageFormat; import android.hardware.Camera; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.Lists; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCameraParametersTest { private Camera.Parameters parameters; - private ShadowCamera.ShadowParameters shadowParameters; @Before public void setUp() throws Exception { parameters = Shadow.newInstanceOf(Camera.Parameters.class); - shadowParameters = Shadows.shadowOf(parameters); } @Test public void testPictureSize() throws Exception { - assertThat(shadowParameters.getPictureHeight()).isNotEqualTo((600)); - assertThat(shadowParameters.getPictureWidth()).isNotEqualTo((800)); + assertThat(Shadows.shadowOf(parameters).getPictureHeight()).isNotEqualTo(600); + assertThat(Shadows.shadowOf(parameters).getPictureWidth()).isNotEqualTo(800); parameters.setPictureSize(800, 600); Camera.Size pictureSize = parameters.getPictureSize(); assertThat(pictureSize.width).isEqualTo(800); assertThat(pictureSize.height).isEqualTo(600); - assertThat(shadowParameters.getPictureHeight()).isEqualTo(600); - assertThat(shadowParameters.getPictureWidth()).isEqualTo(800); + assertThat(Shadows.shadowOf(parameters).getPictureHeight()).isEqualTo(600); + assertThat(Shadows.shadowOf(parameters).getPictureWidth()).isEqualTo(800); } @Test @@ -58,21 +56,21 @@ public class ShadowCameraParametersTest { @Test public void testPreviewSize() throws Exception { - assertThat(shadowParameters.getPreviewWidth()).isNotEqualTo((320)); - assertThat(shadowParameters.getPreviewHeight()).isNotEqualTo((240)); + assertThat(Shadows.shadowOf(parameters).getPreviewWidth()).isNotEqualTo(320); + assertThat(Shadows.shadowOf(parameters).getPreviewHeight()).isNotEqualTo(240); parameters.setPreviewSize(320, 240); Camera.Size size = parameters.getPreviewSize(); assertThat(size.width).isEqualTo(320); assertThat(size.height).isEqualTo(240); - assertThat(shadowParameters.getPreviewWidth()).isEqualTo(320); - assertThat(shadowParameters.getPreviewHeight()).isEqualTo(240); + assertThat(Shadows.shadowOf(parameters).getPreviewWidth()).isEqualTo(320); + assertThat(Shadows.shadowOf(parameters).getPreviewHeight()).isEqualTo(240); } @Test public void testPreviewFormat() throws Exception { - assertThat(shadowParameters.getPreviewFormat()).isEqualTo(ImageFormat.NV21); + assertThat(parameters.getPreviewFormat()).isEqualTo(ImageFormat.NV21); parameters.setPreviewFormat(ImageFormat.JPEG); - assertThat(shadowParameters.getPreviewFormat()).isEqualTo(ImageFormat.JPEG); + assertThat(parameters.getPreviewFormat()).isEqualTo(ImageFormat.JPEG); } @Test @@ -110,6 +108,24 @@ public class ShadowCameraParametersTest { } @Test + public void testInitSupportedPreviewSizes() throws Exception { + Shadows.shadowOf(parameters).initSupportedPreviewSizes(); + assertThat(parameters.getSupportedPreviewSizes()).isNotNull(); + assertThat(parameters.getSupportedPreviewSizes()).isEmpty(); + } + + @Test + public void testAddSupportedPreviewSizes() throws Exception { + Shadows.shadowOf(parameters).initSupportedPreviewSizes(); + Shadows.shadowOf(parameters).addSupportedPreviewSize(320, 240); + List<Camera.Size> supportedSizes = parameters.getSupportedPreviewSizes(); + assertThat(supportedSizes).isNotNull(); + assertThat(supportedSizes).hasSize(1); + assertThat(supportedSizes.get(0).width).isEqualTo(320); + assertThat(supportedSizes.get(0).height).isEqualTo(240); + } + + @Test public void testGetSupportedPreviewFpsRange() throws Exception { List<int[]> supportedRanges = parameters.getSupportedPreviewFpsRange(); assertThat(supportedRanges).isNotNull(); @@ -150,9 +166,9 @@ public class ShadowCameraParametersTest { @Test public void testSetSupportedFocusModes() { - shadowParameters.setSupportedFocusModes("foo", "bar"); + Shadows.shadowOf(parameters).setSupportedFocusModes("foo", "bar"); assertThat(parameters.getSupportedFocusModes()).isEqualTo(Lists.newArrayList("foo", "bar")); - shadowParameters.setSupportedFocusModes("baz"); + Shadows.shadowOf(parameters).setSupportedFocusModes("baz"); assertThat(parameters.getSupportedFocusModes()).isEqualTo(Lists.newArrayList("baz")); } @@ -161,4 +177,24 @@ public class ShadowCameraParametersTest { parameters.setFocusMode("foo"); assertThat(parameters.getFocusMode()).isEqualTo("foo"); } + + @Test + public void testGetSupportedFlashModesDefaultValue() { + List<String> supportedFlashModes = parameters.getSupportedFlashModes(); + assertThat(supportedFlashModes).isEmpty(); + } + + @Test + public void testSetSupportedFlashModes() { + Shadows.shadowOf(parameters).setSupportedFlashModes("foo", "bar"); + assertThat(parameters.getSupportedFlashModes()).containsExactly("foo", "bar").inOrder(); + Shadows.shadowOf(parameters).setSupportedFlashModes("baz"); + assertThat(parameters.getSupportedFlashModes()).containsExactly("baz"); + } + + @Test + public void testSetAndGetFlashMode() { + parameters.setFlashMode("foo"); + assertThat(parameters.getFlashMode()).isEqualTo("foo"); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraSizeTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraSizeTest.java index adf764864..fbec34866 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraSizeTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraSizeTest.java @@ -3,13 +3,13 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.hardware.Camera; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCameraSizeTest { private Camera.Size cameraSize; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraTest.java index 658c5f683..a7687e4da 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCameraTest.java @@ -10,14 +10,14 @@ import android.graphics.Rect; import android.hardware.Camera; import android.view.Surface; import android.view.SurfaceHolder; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCameraTest { private Camera camera; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCanvasTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCanvasTest.java index 1f37b44db..6aae0dd30 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCanvasTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCanvasTest.java @@ -14,13 +14,13 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCanvasTest { private Bitmap targetBitmap; private Bitmap imageBitmap; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCaptioningManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCaptioningManagerTest.java index 03f32ad55..210849c73 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCaptioningManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCaptioningManagerTest.java @@ -1,53 +1,93 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.view.accessibility.CaptioningManager; +import android.view.accessibility.CaptioningManager.CaptioningChangeListener; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; /** Tests for the ShadowCaptioningManager. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = 19) public final class ShadowCaptioningManagerTest { + + @Mock private CaptioningChangeListener captioningChangeListener; + private CaptioningManager captioningManager; - private ShadowCaptioningManager shadowCaptioningManager; @Before public void setUp() { + MockitoAnnotations.initMocks(this); captioningManager = (CaptioningManager) - RuntimeEnvironment.application.getSystemService(Context.CAPTIONING_SERVICE); - shadowCaptioningManager = shadowOf(captioningManager); + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.CAPTIONING_SERVICE); } @Test public void setEnabled_true() { assertThat(captioningManager.isEnabled()).isFalse(); - shadowCaptioningManager.setEnabled(true); + shadowOf(captioningManager).setEnabled(true); assertThat(captioningManager.isEnabled()).isTrue(); } @Test public void setEnabled_false() { - shadowCaptioningManager.setEnabled(false); + shadowOf(captioningManager).setEnabled(false); assertThat(captioningManager.isEnabled()).isFalse(); } @Test - public void setFontScale() { + public void setFontScale_changesValueOfGetFontScale() { float fontScale = 1.5f; - shadowCaptioningManager.setFontScale(fontScale); + shadowOf(captioningManager).setFontScale(fontScale); assertThat(captioningManager.getFontScale()).isWithin(0.001f).of(fontScale); } + + @Test + public void setFontScale_notifiesObservers() { + float fontScale = 1.5f; + captioningManager.addCaptioningChangeListener(captioningChangeListener); + + shadowOf(captioningManager).setFontScale(fontScale); + + verify(captioningChangeListener).onFontScaleChanged(fontScale); + } + + @Test + public void addCaptioningChangeListener_doesNotRegisterSameListenerTwice() { + float fontScale = 1.5f; + captioningManager.addCaptioningChangeListener(captioningChangeListener); + + captioningManager.addCaptioningChangeListener(captioningChangeListener); + + shadowOf(captioningManager).setFontScale(fontScale); + verify(captioningChangeListener).onFontScaleChanged(fontScale); + } + + @Test + public void removeCaptioningChangeListener_unregistersFontScaleListener() { + captioningManager.addCaptioningChangeListener(captioningChangeListener); + + captioningManager.removeCaptioningChangeListener(captioningChangeListener); + + shadowOf(captioningManager).setFontScale(1.5f); + verifyZeroInteractions(captioningChangeListener); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCarrierConfigManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCarrierConfigManagerTest.java new file mode 100644 index 000000000..24336eeb6 --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCarrierConfigManagerTest.java @@ -0,0 +1,57 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.M; +import static com.google.common.truth.Truth.assertThat; +import static org.robolectric.Shadows.shadowOf; + +import android.app.Application; +import android.content.Context; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +/** Junit test for {@link ShadowCarrierConfigManager}. */ +@RunWith(AndroidJUnit4.class) +@Config(minSdk = M) +public class ShadowCarrierConfigManagerTest { + + private CarrierConfigManager carrierConfigManager; + + private static final int TEST_ID = 123; + + @Before + public void setUp() { + carrierConfigManager = + (CarrierConfigManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + } + + @Test + public void getConfigForSubId_shouldReturnNonNullValue() throws Exception { + PersistableBundle persistableBundle = carrierConfigManager.getConfigForSubId(-1); + assertThat(persistableBundle).isNotNull(); + } + + @Test + public void testGetConfigForSubId() throws Exception { + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putString("key1", "test"); + persistableBundle.putInt("key2", 100); + persistableBundle.putBoolean("key3", true); + + shadowOf(carrierConfigManager).setConfigForSubId(TEST_ID, persistableBundle); + + PersistableBundle verifyBundle = carrierConfigManager.getConfigForSubId(TEST_ID); + assertThat(verifyBundle).isNotNull(); + + assertThat(verifyBundle.get("key1")).isEqualTo("test"); + assertThat(verifyBundle.getInt("key2")).isEqualTo(100); + assertThat(verifyBundle.getBoolean("key3")).isTrue(); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCheckBoxTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCheckBoxTest.java index 462fcc755..b3a92f2cf 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCheckBoxTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCheckBoxTest.java @@ -2,17 +2,18 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.widget.CheckBox; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCheckBoxTest { @Test public void testWorks() throws Exception { - CheckBox checkBox = new CheckBox(RuntimeEnvironment.application); + CheckBox checkBox = new CheckBox((Application) ApplicationProvider.getApplicationContext()); assertThat(checkBox.isChecked()).isFalse(); checkBox.setChecked(true); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCheckedTextViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCheckedTextViewTest.java index 02a8bc357..851ce30a9 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCheckedTextViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCheckedTextViewTest.java @@ -3,21 +3,23 @@ package org.robolectric.shadows; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import android.app.Application; import android.widget.CheckedTextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCheckedTextViewTest { private CheckedTextView checkedTextView; @Before public void beforeTests() { - checkedTextView = new CheckedTextView(RuntimeEnvironment.application); + checkedTextView = + new CheckedTextView((Application) ApplicationProvider.getApplicationContext()); } @Test @@ -39,7 +41,8 @@ public class ShadowCheckedTextViewTest { } @Test public void toggle_shouldChangeCheckedness() throws Exception { - CheckedTextView view = new CheckedTextView(RuntimeEnvironment.application); + CheckedTextView view = + new CheckedTextView((Application) ApplicationProvider.getApplicationContext()); assertFalse(view.isChecked()); view.toggle(); assertTrue(view.isChecked()); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowChoreographerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowChoreographerTest.java index e543034f2..1cfec00f3 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowChoreographerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowChoreographerTest.java @@ -7,12 +7,12 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.view.Choreographer; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.util.TimeUtils; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowChoreographerTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowClipboardManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowClipboardManagerTest.java index 9a0359f45..1c1840714 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowClipboardManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowClipboardManagerTest.java @@ -6,22 +6,26 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import android.app.Application; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowClipboardManagerTest { private ClipboardManager clipboardManager; @Before public void setUp() throws Exception { - clipboardManager = (ClipboardManager) RuntimeEnvironment.application.getSystemService(Context.CLIPBOARD_SERVICE); + clipboardManager = + (ClipboardManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.CLIPBOARD_SERVICE); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowColorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowColorTest.java index 5edf1a15d..e39743d55 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowColorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowColorTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.graphics.Color; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowColorTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowConfigurationTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowConfigurationTest.java index ef9b7fc0f..5d7513710 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowConfigurationTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowConfigurationTest.java @@ -5,14 +5,14 @@ import static com.google.common.truth.Truth.assertThat; import android.content.res.Configuration; import android.os.Build; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Locale; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowConfigurationTest { private Configuration configuration; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowConnectivityManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowConnectivityManagerTest.java index b9bc649ab..9ab11fe57 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowConnectivityManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowConnectivityManagerTest.java @@ -1,9 +1,11 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.KITKAT; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.os.Build.VERSION_CODES.M; +import static android.os.Build.VERSION_CODES.N; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -12,29 +14,30 @@ import static org.robolectric.Shadows.shadowOf; import android.content.Context; import android.net.ConnectivityManager; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; +import android.provider.Settings; import android.telephony.TelephonyManager; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; +import org.robolectric.util.ReflectionHelpers.ClassParameter; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowConnectivityManagerTest { private ConnectivityManager connectivityManager; private ShadowNetworkInfo shadowOfActiveNetworkInfo; - private ShadowConnectivityManager shadowConnectivityManager; @Before public void setUp() throws Exception { connectivityManager = (ConnectivityManager) - RuntimeEnvironment.application.getSystemService(Context.CONNECTIVITY_SERVICE); - shadowConnectivityManager = shadowOf(connectivityManager); + getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); shadowOfActiveNetworkInfo = shadowOf(connectivityManager.getActiveNetworkInfo()); } @@ -86,7 +89,7 @@ public class ShadowConnectivityManagerTest { 0, true, NetworkInfo.State.CONNECTED); - shadowConnectivityManager.addNetwork(vpnNetwork, vpnNetworkInfo); + shadowOf(connectivityManager).addNetwork(vpnNetwork, vpnNetworkInfo); NetworkInfo returnedNetworkInfo = connectivityManager.getNetworkInfo(vpnNetwork); assertThat(returnedNetworkInfo).isSameAs(vpnNetworkInfo); @@ -95,7 +98,7 @@ public class ShadowConnectivityManagerTest { @Test @Config(minSdk = LOLLIPOP) public void getNetworkInfo_shouldNotReturnRemovedNetwork() throws Exception { Network wifiNetwork = ShadowNetwork.newInstance(ShadowConnectivityManager.NET_ID_WIFI); - shadowConnectivityManager.removeNetwork(wifiNetwork); + shadowOf(connectivityManager).removeNetwork(wifiNetwork); NetworkInfo returnedNetworkInfo = connectivityManager.getNetworkInfo(wifiNetwork); assertThat(returnedNetworkInfo).isNull(); @@ -113,21 +116,22 @@ public class ShadowConnectivityManagerTest { @Test public void shouldGetAndSetBackgroundDataSetting() throws Exception { assertThat(connectivityManager.getBackgroundDataSetting()).isFalse(); - shadowConnectivityManager.setBackgroundDataSetting(true); + shadowOf(connectivityManager).setBackgroundDataSetting(true); assertThat(connectivityManager.getBackgroundDataSetting()).isTrue(); } @Test public void setActiveNetworkInfo_shouldSetActiveNetworkInfo() throws Exception { - shadowConnectivityManager.setActiveNetworkInfo(null); + shadowOf(connectivityManager).setActiveNetworkInfo(null); assertThat(connectivityManager.getActiveNetworkInfo()).isNull(); - shadowConnectivityManager.setActiveNetworkInfo( - ShadowNetworkInfo.newInstance( - null, - ConnectivityManager.TYPE_MOBILE_HIPRI, - TelephonyManager.NETWORK_TYPE_EDGE, - true, - NetworkInfo.State.DISCONNECTED)); + shadowOf(connectivityManager) + .setActiveNetworkInfo( + ShadowNetworkInfo.newInstance( + null, + ConnectivityManager.TYPE_MOBILE_HIPRI, + TelephonyManager.NETWORK_TYPE_EDGE, + true, + NetworkInfo.State.DISCONNECTED)); NetworkInfo info = connectivityManager.getActiveNetworkInfo(); @@ -146,22 +150,23 @@ public class ShadowConnectivityManagerTest { @Test @Config(minSdk = M) public void getActiveNetwork_nullIfNetworkNotActive() { - shadowConnectivityManager.setDefaultNetworkActive(false); + shadowOf(connectivityManager).setDefaultNetworkActive(false); assertThat(connectivityManager.getActiveNetwork()).isNull(); } @Test @Config(minSdk = M) public void setActiveNetworkInfo_shouldSetActiveNetwork() throws Exception { - shadowConnectivityManager.setActiveNetworkInfo(null); + shadowOf(connectivityManager).setActiveNetworkInfo(null); assertThat(connectivityManager.getActiveNetworkInfo()).isNull(); - shadowConnectivityManager.setActiveNetworkInfo( - ShadowNetworkInfo.newInstance( - null, - ConnectivityManager.TYPE_MOBILE_HIPRI, - TelephonyManager.NETWORK_TYPE_EDGE, - true, - NetworkInfo.State.DISCONNECTED)); + shadowOf(connectivityManager) + .setActiveNetworkInfo( + ShadowNetworkInfo.newInstance( + null, + ConnectivityManager.TYPE_MOBILE_HIPRI, + TelephonyManager.NETWORK_TYPE_EDGE, + true, + NetworkInfo.State.DISCONNECTED)); NetworkInfo info = connectivityManager.getActiveNetworkInfo(); @@ -178,7 +183,7 @@ public class ShadowConnectivityManagerTest { assertThat(infos).asList().hasSize(2); assertThat(infos).asList().contains(connectivityManager.getActiveNetworkInfo()); - shadowConnectivityManager.setActiveNetworkInfo(null); + shadowOf(connectivityManager).setActiveNetworkInfo(null); assertThat(connectivityManager.getAllNetworkInfo()).isEmpty(); } @@ -193,7 +198,7 @@ public class ShadowConnectivityManagerTest { 0 /* subType */, true /* isAvailable */, true /* isConnected */); - shadowConnectivityManager.setActiveNetworkInfo(networkInfo); + shadowOf(connectivityManager).setActiveNetworkInfo(networkInfo); // Verify that getAllNetworks and getAllNetworkInfo match. Network[] networks = connectivityManager.getAllNetworks(); @@ -208,7 +213,7 @@ public class ShadowConnectivityManagerTest { @Test @Config(minSdk = LOLLIPOP) public void getAllNetworkInfo_nullIfNetworkNotActive() { - shadowConnectivityManager.setDefaultNetworkActive(false); + shadowOf(connectivityManager).setDefaultNetworkActive(false); assertThat(connectivityManager.getAllNetworkInfo()).isNull(); } @@ -220,7 +225,7 @@ public class ShadowConnectivityManagerTest { @Test @Config(minSdk = LOLLIPOP) public void getAllNetworks_shouldReturnNoNetworksWhenCleared() throws Exception { - shadowConnectivityManager.clearAllNetworks(); + shadowOf(connectivityManager).clearAllNetworks(); Network[] networks = connectivityManager.getAllNetworks(); assertThat(networks).isEmpty(); } @@ -228,7 +233,7 @@ public class ShadowConnectivityManagerTest { @Test @Config(minSdk = LOLLIPOP) public void getAllNetworks_shouldReturnAddedNetworks() throws Exception { // Let's start clear. - shadowConnectivityManager.clearAllNetworks(); + shadowOf(connectivityManager).clearAllNetworks(); // Add a "VPN network". Network vpnNetwork = ShadowNetwork.newInstance(123); @@ -239,7 +244,7 @@ public class ShadowConnectivityManagerTest { 0, true, NetworkInfo.State.CONNECTED); - shadowConnectivityManager.addNetwork(vpnNetwork, vpnNetworkInfo); + shadowOf(connectivityManager).addNetwork(vpnNetwork, vpnNetworkInfo); Network[] networks = connectivityManager.getAllNetworks(); assertThat(networks).asList().hasSize(1); @@ -254,7 +259,7 @@ public class ShadowConnectivityManagerTest { @Test @Config(minSdk = LOLLIPOP) public void getAllNetworks_shouldNotReturnRemovedNetworks() throws Exception { Network wifiNetwork = ShadowNetwork.newInstance(ShadowConnectivityManager.NET_ID_WIFI); - shadowConnectivityManager.removeNetwork(wifiNetwork); + shadowOf(connectivityManager).removeNetwork(wifiNetwork); Network[] networks = connectivityManager.getAllNetworks(); assertThat(networks).asList().hasSize(1); @@ -276,13 +281,13 @@ public class ShadowConnectivityManagerTest { connectivityManager.reportNetworkConnectivity(wifiNetwork, true); Map<Network, Boolean> reportedNetworks = - shadowConnectivityManager.getReportedNetworkConnectivity(); + shadowOf(connectivityManager).getReportedNetworkConnectivity(); assertThat(reportedNetworks.size()).isEqualTo(1); assertThat(reportedNetworks.get(wifiNetwork)).isTrue(); // Update the status. connectivityManager.reportNetworkConnectivity(wifiNetwork, false); - reportedNetworks = shadowConnectivityManager.getReportedNetworkConnectivity(); + reportedNetworks = shadowOf(connectivityManager).getReportedNetworkConnectivity(); assertThat(reportedNetworks.size()).isEqualTo(1); assertThat(reportedNetworks.get(wifiNetwork)).isFalse(); } @@ -297,7 +302,7 @@ public class ShadowConnectivityManagerTest { @Test @Config(minSdk = LOLLIPOP) public void getNetworkCallbacks_shouldHaveEmptyDefault() throws Exception { - assertEquals(0, shadowConnectivityManager.getNetworkCallbacks().size()); + assertThat(shadowOf(connectivityManager).getNetworkCallbacks()).isEmpty(); } private static ConnectivityManager.NetworkCallback createSimpleCallback() { @@ -315,7 +320,7 @@ public class ShadowConnectivityManagerTest { NetworkRequest.Builder builder = new NetworkRequest.Builder(); ConnectivityManager.NetworkCallback callback = createSimpleCallback(); connectivityManager.requestNetwork(builder.build(), callback); - assertThat(shadowConnectivityManager.getNetworkCallbacks()).hasSize(1); + assertThat(shadowOf(connectivityManager).getNetworkCallbacks()).hasSize(1); } @Test @Config(minSdk = LOLLIPOP) @@ -323,7 +328,7 @@ public class ShadowConnectivityManagerTest { NetworkRequest.Builder builder = new NetworkRequest.Builder(); ConnectivityManager.NetworkCallback callback = createSimpleCallback(); connectivityManager.registerNetworkCallback(builder.build(), callback); - assertEquals(1, shadowConnectivityManager.getNetworkCallbacks().size()); + assertThat(shadowOf(connectivityManager).getNetworkCallbacks()).hasSize(1); } @Test @Config(minSdk = LOLLIPOP) @@ -335,11 +340,11 @@ public class ShadowConnectivityManagerTest { connectivityManager.registerNetworkCallback(builder.build(), callback1); connectivityManager.registerNetworkCallback(builder.build(), callback2); // Remove one at the time. - assertEquals(2, shadowConnectivityManager.getNetworkCallbacks().size()); + assertThat(shadowOf(connectivityManager).getNetworkCallbacks()).hasSize(2); connectivityManager.unregisterNetworkCallback(callback2); - assertEquals(1, shadowConnectivityManager.getNetworkCallbacks().size()); + assertThat(shadowOf(connectivityManager).getNetworkCallbacks()).hasSize(1); connectivityManager.unregisterNetworkCallback(callback1); - assertEquals(0, shadowConnectivityManager.getNetworkCallbacks().size()); + assertThat(shadowOf(connectivityManager).getNetworkCallbacks()).isEmpty(); } @Test(expected=IllegalArgumentException.class) @Config(minSdk = LOLLIPOP) @@ -355,33 +360,33 @@ public class ShadowConnectivityManagerTest { @Test public void isActiveNetworkMetered_mobileIsMetered() { - shadowConnectivityManager.setActiveNetworkInfo( - connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)); + shadowOf(connectivityManager) + .setActiveNetworkInfo(connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)); assertThat(connectivityManager.isActiveNetworkMetered()).isTrue(); } @Test public void isActiveNetworkMetered_nonMobileIsUnmetered() { - shadowConnectivityManager.setActiveNetworkInfo( - connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)); + shadowOf(connectivityManager) + .setActiveNetworkInfo(connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)); assertThat(connectivityManager.isActiveNetworkMetered()).isFalse(); } @Test public void isActiveNetworkMetered_noActiveNetwork() { - shadowConnectivityManager.setActiveNetworkInfo(null); + shadowOf(connectivityManager).setActiveNetworkInfo(null); assertThat(connectivityManager.isActiveNetworkMetered()).isFalse(); } @Test public void isActiveNetworkMetered_noDefaultNetworkActive() { - shadowConnectivityManager.setDefaultNetworkActive(false); + shadowOf(connectivityManager).setDefaultNetworkActive(false); assertThat(connectivityManager.isActiveNetworkMetered()).isFalse(); } @Test @Config(minSdk = M) - public void bindProcessToNetwork_should() { + public void bindProcessToNetwork_shouldGetBoundNetworkForProcess() { Network network = ShadowNetwork.newInstance(789); connectivityManager.bindProcessToNetwork(network); assertThat(connectivityManager.getBoundNetworkForProcess()).isSameAs(network); @@ -390,14 +395,14 @@ public class ShadowConnectivityManagerTest { @Test @Config(minSdk = LOLLIPOP) public void isDefaultNetworkActive_defaultActive() { - assertThat(shadowConnectivityManager.isDefaultNetworkActive()).isTrue(); + assertThat(shadowOf(connectivityManager).isDefaultNetworkActive()).isTrue(); } @Test @Config(minSdk = LOLLIPOP) public void isDefaultNetworkActive_notActive() { - shadowConnectivityManager.setDefaultNetworkActive(false); - assertThat(shadowConnectivityManager.isDefaultNetworkActive()).isFalse(); + shadowOf(connectivityManager).setDefaultNetworkActive(false); + assertThat(shadowOf(connectivityManager).isDefaultNetworkActive()).isFalse(); } private static ConnectivityManager.OnNetworkActiveListener createSimpleOnNetworkActiveListener() { @@ -417,7 +422,7 @@ public class ShadowConnectivityManagerTest { connectivityManager.addDefaultNetworkActiveListener(listener1); connectivityManager.addDefaultNetworkActiveListener(listener2); - shadowConnectivityManager.setDefaultNetworkActive(true); + shadowOf(connectivityManager).setDefaultNetworkActive(true); verify(listener1).onNetworkActive(); verify(listener2).onNetworkActive(); @@ -434,21 +439,21 @@ public class ShadowConnectivityManagerTest { connectivityManager.addDefaultNetworkActiveListener(listener1); connectivityManager.addDefaultNetworkActiveListener(listener2); - shadowConnectivityManager.setDefaultNetworkActive(true); + shadowOf(connectivityManager).setDefaultNetworkActive(true); verify(listener1).onNetworkActive(); verify(listener2).onNetworkActive(); // Remove one at the time. connectivityManager.removeDefaultNetworkActiveListener(listener2); - shadowConnectivityManager.setDefaultNetworkActive(true); + shadowOf(connectivityManager).setDefaultNetworkActive(true); verify(listener1, times(2)).onNetworkActive(); verify(listener2).onNetworkActive(); connectivityManager.removeDefaultNetworkActiveListener(listener1); - shadowConnectivityManager.setDefaultNetworkActive(true); + shadowOf(connectivityManager).setDefaultNetworkActive(true); verify(listener1, times(2)).onNetworkActive(); verify(listener2).onNetworkActive(); @@ -460,5 +465,50 @@ public class ShadowConnectivityManagerTest { // Verify that exception is thrown. connectivityManager.removeDefaultNetworkActiveListener(null); } -} + @Test + @Config(minSdk = LOLLIPOP) + public void getNetworkCapabilities() throws Exception { + NetworkCapabilities nc = new NetworkCapabilities(null); + ReflectionHelpers.callInstanceMethod( + nc, + "addCapability", + ClassParameter.from(int.class, NetworkCapabilities.NET_CAPABILITY_MMS)); + + shadowOf(connectivityManager).setNetworkCapabilities( + shadowOf(connectivityManager).getActiveNetwork(), nc); + + assertThat( + shadowOf(connectivityManager) + .getNetworkCapabilities(shadowOf(connectivityManager).getActiveNetwork()) + .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) + .isTrue(); + } + + @Test + @Config(minSdk = N) + public void getCaptivePortalServerUrl_shouldReturnAddedUrl() { + assertThat(connectivityManager.getCaptivePortalServerUrl()).isEqualTo("http://10.0.0.2"); + + shadowOf(connectivityManager).setCaptivePortalServerUrl("http://10.0.0.1"); + assertThat(connectivityManager.getCaptivePortalServerUrl()).isEqualTo("http://10.0.0.1"); + + shadowOf(connectivityManager).setCaptivePortalServerUrl("http://10.0.0.2"); + assertThat(connectivityManager.getCaptivePortalServerUrl()).isEqualTo("http://10.0.0.2"); + } + + @Test + @Config(minSdk = KITKAT) + public void setAirplaneMode() { + connectivityManager.setAirplaneMode(false); + assertThat( + Settings.Global.getInt( + getApplicationContext().getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, -1)) + .isEqualTo(0); + connectivityManager.setAirplaneMode(true); + assertThat( + Settings.Global.getInt( + getApplicationContext().getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, -1)) + .isEqualTo(1); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentObserverTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentObserverTest.java index 7e464512f..f51c7c827 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentObserverTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentObserverTest.java @@ -5,12 +5,12 @@ import static com.google.common.truth.Truth.assertThat; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContentObserverTest { private TestContentObserver observer; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderClientTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderClientTest.java index 622f0e1fd..47a94b905 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderClientTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderClientTest.java @@ -7,6 +7,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.MockitoAnnotations.initMocks; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.ContentProvider; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; @@ -15,16 +16,16 @@ import android.content.ContentValues; import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContentProviderClientTest { private static final String AUTHORITY = "org.robolectric"; @@ -37,7 +38,8 @@ public class ShadowContentProviderClientTest { private static final String MIME_TYPE = "application/octet-stream"; @Mock ContentProvider provider; - ContentResolver contentResolver = RuntimeEnvironment.application.getContentResolver(); + ContentResolver contentResolver = + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(); @Before public void setUp() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderOperationBuilderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderOperationBuilderTest.java index a7c3137ee..32175b400 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderOperationBuilderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderOperationBuilderTest.java @@ -8,11 +8,11 @@ import android.content.ContentProviderOperation.Builder; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContentProviderOperationBuilderTest { private Builder builder; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderOperationTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderOperationTest.java index b2f39c813..bb8e1157e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderOperationTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderOperationTest.java @@ -4,16 +4,14 @@ import static com.google.common.truth.Truth.assertThat; import android.content.ContentProviderOperation; import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Collections; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -/** - * Tests for {@link ShadowContentProviderOperation}. - */ -@RunWith(RobolectricTestRunner.class) +/** Tests for {@link ShadowContentProviderOperation}. */ +@RunWith(AndroidJUnit4.class) public class ShadowContentProviderOperationTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderResultTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderResultTest.java index 4ab8bc715..40a47b993 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderResultTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderResultTest.java @@ -4,11 +4,11 @@ import static com.google.common.truth.Truth.assertThat; import android.content.ContentProviderResult; import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContentProviderResultTest { @Test public void count() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderTest.java index 87d7f575f..fd3869501 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentProviderTest.java @@ -5,13 +5,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.content.ContentProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadows.testing.TestContentProvider1; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContentProviderTest { @Config(minSdk = KITKAT) @Test public void testSetCallingPackage() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentResolverTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentResolverTest.java index 6a947dcf8..5d0d8db2d 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentResolverTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentResolverTest.java @@ -35,6 +35,8 @@ import android.os.CancellationSignal; import android.os.Handler; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; @@ -50,12 +52,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.fakes.BaseCursor; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContentResolverTest { private static final String AUTHORITY = "org.robolectric"; @@ -67,7 +68,8 @@ public class ShadowContentResolverTest { @Before public void setUp() { - contentResolver = RuntimeEnvironment.application.getContentResolver(); + contentResolver = + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(); shadowContentResolver = shadowOf(contentResolver); uri21 = Uri.parse(EXTERNAL_CONTENT_URI.toString() + "/21"); uri22 = Uri.parse(EXTERNAL_CONTENT_URI.toString() + "/22"); @@ -286,11 +288,13 @@ public class ShadowContentResolverTest { ProviderInfo providerInfo0 = new ProviderInfo(); providerInfo0.authority = "the-authority"; // todo: support multiple authorities providerInfo0.grantUriPermissions = true; - mock.attachInfo(RuntimeEnvironment.application, providerInfo0); + mock.attachInfo((Application) ApplicationProvider.getApplicationContext(), providerInfo0); mock.onCreate(); ArgumentCaptor<ProviderInfo> captor = ArgumentCaptor.forClass(ProviderInfo.class); - verify(mock).attachInfo(same(RuntimeEnvironment.application), captor.capture()); + verify(mock) + .attachInfo( + same((Application) ApplicationProvider.getApplicationContext()), captor.capture()); ProviderInfo providerInfo = captor.getValue(); assertThat(providerInfo.authority).isEqualTo("the-authority"); @@ -674,7 +678,7 @@ public class ShadowContentResolverTest { contentResolver.notifyChange(EXTERNAL_CONTENT_URI, null); assertThat(co.changed).isTrue(); - scr.clearContentObservers(); + contentResolver.unregisterContentObserver(co); assertThat(scr.getContentObservers(EXTERNAL_CONTENT_URI)).isEmpty(); } @@ -874,7 +878,10 @@ public class ShadowContentResolverTest { @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { - final File file = new File(RuntimeEnvironment.application.getFilesDir(), "test_file"); + final File file = + new File( + ((Application) ApplicationProvider.getApplicationContext()).getFilesDir(), + "test_file"); try { file.createNewFile(); } catch (IOException e) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentUrisTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentUrisTest.java index 92fbbb1fd..99f3c045b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentUrisTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentUrisTest.java @@ -4,12 +4,12 @@ import static com.google.common.truth.Truth.assertThat; import android.content.ContentUris; import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContentUrisTest { Uri URI; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentValuesTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentValuesTest.java index d4e1dfb09..7e2e5cdce 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContentValuesTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContentValuesTest.java @@ -3,12 +3,12 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.content.ContentValues; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContentValuesTest { private static final String KEY = "key"; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContextImplTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContextImplTest.java index 230edf48e..6c276d10b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContextImplTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContextImplTest.java @@ -7,6 +7,7 @@ import static android.os.Build.VERSION_CODES.N; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.PendingIntent; import android.app.WallpaperManager; import android.bluetooth.BluetoothManager; @@ -21,18 +22,18 @@ import android.os.Process; import android.view.LayoutInflater; import android.widget.FrameLayout; import android.widget.RemoteViews; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContextImplTest { - private final ContextWrapper context = RuntimeEnvironment.application; + private final ContextWrapper context = (Application) ApplicationProvider.getApplicationContext(); private final ShadowContextImpl shadowContext = Shadow.extract(context.getBaseContext()); @Test @@ -57,13 +58,13 @@ public class ShadowContextImplTest { public void testMoveSharedPreferencesFrom() throws Exception { String PREFS = "PREFS"; String PREF_NAME = "TOKEN_PREF"; - RuntimeEnvironment.application + ((Application) ApplicationProvider.getApplicationContext()) .getSharedPreferences(PREFS, Context.MODE_PRIVATE) .edit() .putString(PREF_NAME, "token") .commit(); - Context context = RuntimeEnvironment.application; + Context context = (Application) ApplicationProvider.getApplicationContext(); Context dpContext = context.createDeviceProtectedStorageContext(); assertThat(dpContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE).contains(PREF_NAME)) @@ -115,14 +116,15 @@ public class ShadowContextImplTest { context, 0, new Intent() - .setClassName(RuntimeEnvironment.application, "ActivityIntent") + .setClassName( + (Application) ApplicationProvider.getApplicationContext(), "ActivityIntent") .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), PendingIntent.FLAG_UPDATE_CURRENT); context.startIntentSender(intent.getIntentSender(), null, 0, 0, 0); assertThat( - shadowOf(RuntimeEnvironment.application) + shadowOf((Application) ApplicationProvider.getApplicationContext()) .getNextStartedActivity() .getComponent() .getClassName()) @@ -135,13 +137,15 @@ public class ShadowContextImplTest { PendingIntent.getBroadcast( context, 0, - new Intent().setClassName(RuntimeEnvironment.application, "BroadcastIntent"), + new Intent() + .setClassName( + (Application) ApplicationProvider.getApplicationContext(), "BroadcastIntent"), PendingIntent.FLAG_UPDATE_CURRENT); context.startIntentSender(intent.getIntentSender(), null, 0, 0, 0); assertThat( - shadowOf(RuntimeEnvironment.application) + shadowOf((Application) ApplicationProvider.getApplicationContext()) .getBroadcastIntents() .get(0) .getComponent() @@ -155,13 +159,15 @@ public class ShadowContextImplTest { PendingIntent.getService( context, 0, - new Intent().setClassName(RuntimeEnvironment.application, "ServiceIntent"), + new Intent() + .setClassName( + (Application) ApplicationProvider.getApplicationContext(), "ServiceIntent"), PendingIntent.FLAG_UPDATE_CURRENT); context.startIntentSender(intent.getIntentSender(), null, 0, 0, 0); assertThat( - shadowOf(RuntimeEnvironment.application) + shadowOf((Application) ApplicationProvider.getApplicationContext()) .getNextStartedService() .getComponent() .getClassName()) @@ -171,22 +177,30 @@ public class ShadowContextImplTest { @Test public void createPackageContext() throws Exception { Context packageContext = - context.createPackageContext(RuntimeEnvironment.application.getPackageName(), 0); + context.createPackageContext( + ((Application) ApplicationProvider.getApplicationContext()).getPackageName(), 0); LayoutInflater inflater = (LayoutInflater) - RuntimeEnvironment.application.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.cloneInContext(packageContext); - inflater.inflate(R.layout.remote_views, new FrameLayout(RuntimeEnvironment.application), false); + inflater.inflate( + R.layout.remote_views, + new FrameLayout((Application) ApplicationProvider.getApplicationContext()), + false); } @Test public void createPackageContextRemoteViews() throws Exception { RemoteViews remoteViews = - new RemoteViews(RuntimeEnvironment.application.getPackageName(), R.layout.remote_views); + new RemoteViews( + ((Application) ApplicationProvider.getApplicationContext()).getPackageName(), + R.layout.remote_views); remoteViews.apply( - RuntimeEnvironment.application, new FrameLayout(RuntimeEnvironment.application)); + (Application) ApplicationProvider.getApplicationContext(), + new FrameLayout((Application) ApplicationProvider.getApplicationContext())); } @Test @@ -201,7 +215,10 @@ public class ShadowContextImplTest { serviceIntent, serviceConnection, flags, Process.myUserHandle())) .isTrue(); - assertThat(shadowOf(RuntimeEnvironment.application).getBoundServiceConnections()).hasSize(1); + assertThat( + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .getBoundServiceConnections()) + .hasSize(1); } @Test @@ -212,7 +229,10 @@ public class ShadowContextImplTest { assertThat(context.bindService(serviceIntent, serviceConnection, flags)).isTrue(); - assertThat(shadowOf(RuntimeEnvironment.application).getBoundServiceConnections()).hasSize(1); + assertThat( + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .getBoundServiceConnections()) + .hasSize(1); } @Test @@ -221,7 +241,8 @@ public class ShadowContextImplTest { Intent serviceIntent = new Intent(action); ServiceConnection serviceConnection = buildServiceConnection(); int flags = 0; - shadowOf(RuntimeEnvironment.application).declareActionUnbindable(action); + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .declareActionUnbindable(action); assertThat(context.bindService(serviceIntent, serviceConnection, flags)).isFalse(); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContextTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContextTest.java index 897ceccde..15c8ce552 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContextTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContextTest.java @@ -4,12 +4,15 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static com.google.common.truth.Truth.assertThat; import static java.nio.charset.StandardCharsets.UTF_8; +import android.app.Application; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.content.res.TypedArray; import android.os.Build.VERSION_CODES; import android.util.AttributeSet; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -20,13 +23,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContextTest { - private final Context context = RuntimeEnvironment.application; + private final Context context = (Application) ApplicationProvider.getApplicationContext(); @Test @Config(minSdk = JELLY_BEAN_MR1) @@ -43,7 +44,7 @@ public class ShadowContextTest { @Config(minSdk = VERSION_CODES.O) public void startForegroundService() { Intent intent = new Intent(); - RuntimeEnvironment.application.startForegroundService(intent); + ((Application) ApplicationProvider.getApplicationContext()).startForegroundService(intent); assertThat(ShadowApplication.getInstance().getNextStartedService()).isEqualTo(intent); } @@ -88,7 +89,7 @@ public class ShadowContextTest { File cacheTest = new File(context.getCacheDir(), "__test__"); assertThat(cacheTest.getAbsolutePath()) - .startsWith(System.getProperty("java.io.tmpdir")); + .startsWith(System.getProperty("java.io.tmpdir")); assertThat(cacheTest.getAbsolutePath()) .endsWith(File.separator + "__test__"); @@ -104,9 +105,9 @@ public class ShadowContextTest { File cacheTest = new File(context.getExternalCacheDir(), "__test__"); assertThat(cacheTest.getAbsolutePath()) - .startsWith(System.getProperty("java.io.tmpdir")); + .startsWith(System.getProperty("java.io.tmpdir")); assertThat(cacheTest.getAbsolutePath()) - .endsWith(File.separator + "__test__"); + .endsWith(File.separator + "__test__"); try (FileOutputStream fos = new FileOutputStream(cacheTest)) { fos.write("test".getBytes(UTF_8)); @@ -139,15 +140,15 @@ public class ShadowContextTest { @Test public void getDatabasePath_shouldAllowAbsolutePaths() throws Exception { - String testDbName; - - if (System.getProperty("os.name").startsWith("Windows")) { - testDbName = "C:\\absolute\\full\\path\\to\\db\\abc.db"; - } else { - testDbName = "/absolute/full/path/to/db/abc.db"; - } - File dbFile = context.getDatabasePath(testDbName); - assertThat(dbFile).isEqualTo(new File(testDbName)); + String testDbName; + + if (System.getProperty("os.name").startsWith("Windows")) { + testDbName = "C:\\absolute\\full\\path\\to\\db\\abc.db"; + } else { + testDbName = "/absolute/full/path/to/db/abc.db"; + } + File dbFile = context.getDatabasePath(testDbName); + assertThat(dbFile).isEqualTo(new File(testDbName)); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowContextWrapperTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowContextWrapperTest.java index 7c33a71d1..ef485e173 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowContextWrapperTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowContextWrapperTest.java @@ -10,6 +10,7 @@ import static org.robolectric.Robolectric.buildActivity; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.Application; import android.appwidget.AppWidgetProvider; import android.content.BroadcastReceiver; import android.content.Context; @@ -24,6 +25,8 @@ import android.os.HandlerThread; import android.os.Looper; import android.view.LayoutInflater; import android.view.View; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.util.concurrent.SettableFuture; import java.util.ArrayList; import java.util.List; @@ -33,16 +36,14 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowContextWrapperTest { public ArrayList<String> transcript; private ContextWrapper contextWrapper; - private final Context context = RuntimeEnvironment.application; + private final Context context = (Application) ApplicationProvider.getApplicationContext(); private final ShadowContextWrapper shadowContextWrapper = Shadow.extract(context); @Before public void setUp() throws Exception { @@ -263,12 +264,15 @@ public class ShadowContextWrapperTest { public void broadcastReceivers_shouldBeSharedAcrossContextsPerApplicationContext() throws Exception { BroadcastReceiver receiver = broadcastReceiver("Larry"); - new ContextWrapper(RuntimeEnvironment.application).registerReceiver(receiver, intentFilter("foo", "baz")); - new ContextWrapper(RuntimeEnvironment.application).sendBroadcast(new Intent("foo")); - RuntimeEnvironment.application.sendBroadcast(new Intent("baz")); + new ContextWrapper((Application) ApplicationProvider.getApplicationContext()) + .registerReceiver(receiver, intentFilter("foo", "baz")); + new ContextWrapper((Application) ApplicationProvider.getApplicationContext()) + .sendBroadcast(new Intent("foo")); + ((Application) ApplicationProvider.getApplicationContext()).sendBroadcast(new Intent("baz")); assertThat(transcript).containsExactly("Larry notified of foo", "Larry notified of baz"); - new ContextWrapper(RuntimeEnvironment.application).unregisterReceiver(receiver); + new ContextWrapper((Application) ApplicationProvider.getApplicationContext()) + .unregisterReceiver(receiver); } @Test @@ -343,9 +347,12 @@ public class ShadowContextWrapperTest { @Test public void shouldReturnApplicationContext_forViewContextInflatedWithApplicationContext() throws Exception { - View view = LayoutInflater.from(RuntimeEnvironment.application).inflate(R.layout.custom_layout, null); + View view = + LayoutInflater.from((Application) ApplicationProvider.getApplicationContext()) + .inflate(R.layout.custom_layout, null); Context viewContext = new ContextWrapper(view.getContext()); - assertThat(viewContext.getApplicationContext()).isEqualTo(RuntimeEnvironment.application); + assertThat(viewContext.getApplicationContext()) + .isEqualTo((Application) ApplicationProvider.getApplicationContext()); } @Test @@ -389,7 +396,11 @@ public class ShadowContextWrapperTest { @Test public void bindServiceDelegatesToShadowApplication() { contextWrapper.bindService(new Intent("foo"), new TestService(), Context.BIND_AUTO_CREATE); - assertEquals("foo", shadowOf(RuntimeEnvironment.application).getNextStartedService().getAction()); + assertEquals( + "foo", + shadowOf((Application) ApplicationProvider.getApplicationContext()) + .getNextStartedService() + .getAction()); } @Test @@ -430,7 +441,8 @@ public class ShadowContextWrapperTest { @Test public void packageManagerShouldNotBeNullWhenWrappingAnApplication() { - assertThat(RuntimeEnvironment.application.getPackageManager()).isNotNull(); + assertThat(((Application) ApplicationProvider.getApplicationContext()).getPackageManager()) + .isNotNull(); } @Test @@ -487,7 +499,7 @@ public class ShadowContextWrapperTest { @Test public void sendBroadcast_shouldOnlySendIntentWithTypeWhenReceiverMatchesType() - throws IntentFilter.MalformedMimeTypeException { + throws IntentFilter.MalformedMimeTypeException { final BroadcastReceiver viewAllTypesReceiver = broadcastReceiver("ViewActionWithAnyTypeReceiver"); final IntentFilter allTypesIntentFilter = intentFilter("view"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCookieManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCookieManagerTest.java index 1b03ede58..79fb9b480 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCookieManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCookieManagerTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.webkit.CookieManager; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCookieManagerTest { private final String url = "robolectric.org/"; private final String httpUrl = "http://robolectric.org/"; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCookieSyncManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCookieSyncManagerTest.java index 83ba8bcd8..3beee3c15 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCookieSyncManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCookieSyncManagerTest.java @@ -4,11 +4,11 @@ import static com.google.common.truth.Truth.assertThat; import android.app.Activity; import android.webkit.CookieSyncManager; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCookieSyncManagerTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCornerPathEffectTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCornerPathEffectTest.java index 5f1717ca7..9df505fa7 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCornerPathEffectTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCornerPathEffectTest.java @@ -4,11 +4,11 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.graphics.CornerPathEffect; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCornerPathEffectTest { @Test public void shouldGetRadius() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCountDownTimerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCountDownTimerTest.java index 166ff66a8..1238b396c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCountDownTimerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCountDownTimerTest.java @@ -3,13 +3,13 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.os.CountDownTimer; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCountDownTimerTest { private ShadowCountDownTimer shadowCountDownTimer; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCountingAdapter.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCountingAdapter.java index c4be209c3..249f36df3 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCountingAdapter.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCountingAdapter.java @@ -1,10 +1,11 @@ package org.robolectric.shadows; +import android.app.Application; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; -import org.robolectric.RuntimeEnvironment; +import androidx.test.core.app.ApplicationProvider; class ShadowCountingAdapter extends BaseAdapter { private int itemCount; @@ -35,7 +36,7 @@ class ShadowCountingAdapter extends BaseAdapter { @Override public View getView(int position, View convertView, ViewGroup parent) { - TextView textView = new TextView(RuntimeEnvironment.application); + TextView textView = new TextView((Application) ApplicationProvider.getApplicationContext()); textView.setText("Item " + position); return textView; } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorAdapterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorAdapterTest.java index 56d59266b..8480ddb7d 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorAdapterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorAdapterTest.java @@ -2,19 +2,20 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.view.View; import android.view.ViewGroup; import android.widget.CursorAdapter; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCursorAdapterTest { private Cursor curs; @@ -89,7 +90,7 @@ public class ShadowCursorAdapterTest { private static class TestAdapter extends CursorAdapter { public TestAdapter(Cursor curs) { - super(RuntimeEnvironment.application, curs, false); + super((Application) ApplicationProvider.getApplicationContext(), curs, false); } @Override @@ -104,7 +105,7 @@ public class ShadowCursorAdapterTest { private static class TestAdapterWithFlags extends CursorAdapter { public TestAdapterWithFlags(Cursor c, int flags) { - super(RuntimeEnvironment.application, c, flags); + super((Application) ApplicationProvider.getApplicationContext(), c, flags); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorWindowTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorWindowTest.java index 6fa73237b..5c24fa4dd 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorWindowTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorWindowTest.java @@ -5,11 +5,11 @@ import static com.google.common.truth.Truth.assertThat; import android.database.CursorWindow; import android.database.DatabaseUtils; import android.database.MatrixCursor; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCursorWindowTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorWrapperTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorWrapperTest.java index 29abc453f..786b35dd0 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorWrapperTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCursorWrapperTest.java @@ -13,15 +13,15 @@ import android.database.CursorWrapper; import android.database.DataSetObserver; import android.net.Uri; import android.os.Bundle; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.lang.reflect.Method; import java.util.HashMap; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowCursorWrapperTest { private static class ForwardVerifier { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDatabaseUtilsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDatabaseUtilsTest.java index b632ba015..f19a7f8ce 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDatabaseUtilsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDatabaseUtilsTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.database.DatabaseUtils; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDatabaseUtilsTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDateFormatTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDateFormatTest.java index 4a58d2e78..1e780d9f5 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDateFormatTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDateFormatTest.java @@ -3,13 +3,13 @@ package org.robolectric.shadows; import static org.junit.Assert.assertEquals; import android.text.format.DateFormat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Calendar; import java.util.Date; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDateFormatTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDateIntervalFormatTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDateIntervalFormatTest.java index 157f60bb5..bde0e7263 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDateIntervalFormatTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDateIntervalFormatTest.java @@ -8,16 +8,16 @@ import android.icu.text.SimpleDateFormat; import android.icu.util.TimeZone; import android.icu.util.ULocale; import android.text.format.DateUtils; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.text.ParseException; import java.util.Calendar; import java.util.Date; import libcore.icu.DateIntervalFormat; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = M) public class ShadowDateIntervalFormatTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDatePickerDialogTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDatePickerDialogTest.java index 10f7029a5..0ef7a9be0 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDatePickerDialogTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDatePickerDialogTest.java @@ -3,21 +3,24 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.DatePickerDialog; import android.widget.DatePicker; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Locale; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDatePickerDialogTest { @Test public void returnsTheInitialYearMonthAndDayPassedIntoTheDatePickerDialog() throws Exception { Locale.setDefault(Locale.US); - DatePickerDialog datePickerDialog = new DatePickerDialog(RuntimeEnvironment.application, null, 2012, 6, 7); + DatePickerDialog datePickerDialog = + new DatePickerDialog( + (Application) ApplicationProvider.getApplicationContext(), null, 2012, 6, 7); assertThat(shadowOf(datePickerDialog).getYear()).isEqualTo(2012); assertThat(shadowOf(datePickerDialog).getMonthOfYear()).isEqualTo(6); assertThat(shadowOf(datePickerDialog).getDayOfMonth()).isEqualTo(7); @@ -32,7 +35,13 @@ public class ShadowDatePickerDialogTest { } }; - DatePickerDialog datePickerDialog = new DatePickerDialog(RuntimeEnvironment.application, expectedDateSetListener, 2012, 6, 7); + DatePickerDialog datePickerDialog = + new DatePickerDialog( + (Application) ApplicationProvider.getApplicationContext(), + expectedDateSetListener, + 2012, + 6, + 7); ShadowDatePickerDialog shadowDatePickerDialog = shadowOf(datePickerDialog); assertThat(shadowDatePickerDialog.getOnDateSetListenerCallback()).isEqualTo(expectedDateSetListener); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDateUtilsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDateUtilsTest.java index db5adc5cc..f07fab63e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDateUtilsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDateUtilsTest.java @@ -6,16 +6,17 @@ import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; import static android.os.Build.VERSION_CODES.M; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.text.format.DateUtils; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Calendar; import java.util.TimeZone; 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) +@RunWith(AndroidJUnit4.class) public class ShadowDateUtilsTest { @Test @@ -23,7 +24,11 @@ public class ShadowDateUtilsTest { public void formatDateTime_withCurrentYear_worksSinceKitKat() { final long millisAtStartOfYear = getMillisAtStartOfYear(); - String actual = DateUtils.formatDateTime(RuntimeEnvironment.application, millisAtStartOfYear, DateUtils.FORMAT_NUMERIC_DATE); + String actual = + DateUtils.formatDateTime( + (Application) ApplicationProvider.getApplicationContext(), + millisAtStartOfYear, + DateUtils.FORMAT_NUMERIC_DATE); assertThat(actual).isEqualTo("1/1"); } @@ -32,8 +37,13 @@ public class ShadowDateUtilsTest { public void formatDateTime_withCurrentYear_worksSinceM() { final long millisAtStartOfYear = getMillisAtStartOfYear(); - // starting with M, sometimes the year is there, sometimes it's missing, unless you specify FORMAT_SHOW_YEAR - String actual = DateUtils.formatDateTime(RuntimeEnvironment.application, millisAtStartOfYear, DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_NUMERIC_DATE); + // starting with M, sometimes the year is there, sometimes it's missing, unless you specify + // FORMAT_SHOW_YEAR + String actual = + DateUtils.formatDateTime( + (Application) ApplicationProvider.getApplicationContext(), + millisAtStartOfYear, + DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_NUMERIC_DATE); final int currentYear = Calendar.getInstance().get(Calendar.YEAR); assertThat(actual).isEqualTo("1/1/" + currentYear); } @@ -45,14 +55,22 @@ public class ShadowDateUtilsTest { final int currentYear = calendar.get(Calendar.YEAR); final long millisAtStartOfYear = getMillisAtStartOfYear(); - String actual = DateUtils.formatDateTime(RuntimeEnvironment.application, millisAtStartOfYear, DateUtils.FORMAT_NUMERIC_DATE); + String actual = + DateUtils.formatDateTime( + (Application) ApplicationProvider.getApplicationContext(), + millisAtStartOfYear, + DateUtils.FORMAT_NUMERIC_DATE); assertThat(actual).isEqualTo("1/1/" + currentYear); } @Test public void formatDateTime_withPastYear() { - String actual = DateUtils.formatDateTime(RuntimeEnvironment.application, 1420099200000L, DateUtils.FORMAT_NUMERIC_DATE); - assertThat(actual).isEqualTo("1/1/2015"); + String actual = + DateUtils.formatDateTime( + (Application) ApplicationProvider.getApplicationContext(), + 1420099200000L, + DateUtils.FORMAT_NUMERIC_DATE); + assertThat(actual).isEqualTo("1/1/2015"); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDebugTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDebugTest.java index 9613cae39..9abcd68b1 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDebugTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDebugTest.java @@ -5,15 +5,16 @@ import static android.os.Build.VERSION_CODES.M; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; +import android.app.Application; import android.os.Debug; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; 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) +@RunWith(AndroidJUnit4.class) public class ShadowDebugTest { private static final String TRACE_FILENAME = "dmtrace.trace"; @@ -35,8 +36,11 @@ public class ShadowDebugTest { Debug.stopMethodTracing(); assertThat( - new File(RuntimeEnvironment.application.getExternalFilesDir(null), TRACE_FILENAME) - .exists()) + new File( + ((Application) ApplicationProvider.getApplicationContext()) + .getExternalFilesDir(null), + TRACE_FILENAME) + .exists()) .isTrue(); } @@ -47,8 +51,11 @@ public class ShadowDebugTest { Debug.stopMethodTracing(); assertThat( - new File(RuntimeEnvironment.application.getExternalFilesDir(null), TRACE_FILENAME) - .exists()) + new File( + ((Application) ApplicationProvider.getApplicationContext()) + .getExternalFilesDir(null), + TRACE_FILENAME) + .exists()) .isTrue(); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDevicePolicyManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDevicePolicyManagerTest.java index 5757faf2c..11ab65bdb 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDevicePolicyManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDevicePolicyManagerTest.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; @@ -25,18 +26,18 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.UserManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; /** Unit tests for {@link ShadowDevicePolicyManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public final class ShadowDevicePolicyManagerTest { private DevicePolicyManager devicePolicyManager; @@ -48,14 +49,18 @@ public final class ShadowDevicePolicyManagerTest { public void setUp() { devicePolicyManager = (DevicePolicyManager) - RuntimeEnvironment.application.getSystemService(Context.DEVICE_POLICY_SERVICE); + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.DEVICE_POLICY_SERVICE); userManager = - (UserManager) RuntimeEnvironment.application.getSystemService(Context.USER_SERVICE); + (UserManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.USER_SERVICE); testComponent = new ComponentName("com.example.app", "DeviceAdminReceiver"); - packageManager = RuntimeEnvironment.application.getPackageManager(); + packageManager = + ((Application) ApplicationProvider.getApplicationContext()).getPackageManager(); } @Test @@ -576,7 +581,8 @@ public final class ShadowDevicePolicyManagerTest { devicePolicyManager.setOrganizationName(testComponent, organizationName); // THEN the name should be set properly - assertThat(devicePolicyManager.getOrganizationName(testComponent)).isEqualTo(organizationName); + assertThat(devicePolicyManager.getOrganizationName(testComponent).toString()) + .isEqualTo(organizationName); } @Test @@ -623,7 +629,8 @@ public final class ShadowDevicePolicyManagerTest { devicePolicyManager.setOrganizationName(testComponent, organizationName); // THEN the name should be set properly - assertThat(devicePolicyManager.getOrganizationName(testComponent)).isEqualTo(organizationName); + assertThat(devicePolicyManager.getOrganizationName(testComponent).toString()) + .isEqualTo(organizationName); } @Test @@ -958,4 +965,16 @@ public final class ShadowDevicePolicyManagerTest { shadowOf(devicePolicyManager).setUserProvisioningState(STATE_USER_UNMANAGED); assertThat(devicePolicyManager.getUserProvisioningState()).isEqualTo(STATE_USER_UNMANAGED); } + + @Test + @Config(minSdk = LOLLIPOP) + public void getProfileOwnerNameAsUser() { + int userId = 0; + String orgName = "organization"; + assertThat(devicePolicyManager.getProfileOwnerNameAsUser(userId)).isNull(); + + shadowOf(devicePolicyManager).setProfileOwnerName(userId, orgName); + + assertThat(devicePolicyManager.getProfileOwnerNameAsUser(userId)).isEqualTo(orgName); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDialogPreferenceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDialogPreferenceTest.java index cc10a6bcf..cd4a4fd8a 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDialogPreferenceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDialogPreferenceTest.java @@ -6,13 +6,13 @@ import android.os.Bundle; import android.preference.DialogPreference; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDialogPreferenceTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDialogTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDialogTest.java index 2629a524f..9ca224a6d 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDialogTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDialogTest.java @@ -9,28 +9,29 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.view.View; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDialogTest { @Test public void shouldCallOnDismissListener() throws Exception { final List<String> transcript = new ArrayList<>(); - final Dialog dialog = new Dialog(RuntimeEnvironment.application); + final Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); dialog.show(); dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override @@ -48,7 +49,7 @@ public class ShadowDialogTest { @Test public void setContentViewWithViewAllowsFindById() throws Exception { final int viewId = 1234; - Context context = RuntimeEnvironment.application; + Context context = (Application) ApplicationProvider.getApplicationContext(); final Dialog dialog = new Dialog(context); final View view = new View(context); view.setId(viewId); @@ -59,13 +60,13 @@ public class ShadowDialogTest { @Test public void shouldGetLayoutInflater() { - Dialog dialog = new Dialog(RuntimeEnvironment.application); + Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); assertNotNull(dialog.getLayoutInflater()); } @Test public void shouldCallOnStartFromShow() { - TestDialog dialog = new TestDialog(RuntimeEnvironment.application); + TestDialog dialog = new TestDialog((Application) ApplicationProvider.getApplicationContext()); dialog.show(); assertTrue(dialog.onStartCalled); @@ -73,7 +74,7 @@ public class ShadowDialogTest { @Test public void shouldSetCancelable() { - Dialog dialog = new Dialog(RuntimeEnvironment.application); + Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); ShadowDialog shadow = shadowOf(dialog); dialog.setCancelable(false); @@ -82,14 +83,14 @@ public class ShadowDialogTest { @Test public void shouldDismissTheRealDialogWhenCancelled() throws Exception { - TestDialog dialog = new TestDialog(RuntimeEnvironment.application); + TestDialog dialog = new TestDialog((Application) ApplicationProvider.getApplicationContext()); dialog.cancel(); assertThat(dialog.wasDismissed).isTrue(); } @Test public void shouldDefaultCancelableToTrueAsTheSDKDoes() throws Exception { - Dialog dialog = new Dialog(RuntimeEnvironment.application); + Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); ShadowDialog shadow = shadowOf(dialog); assertThat(shadow.isCancelable()).isTrue(); @@ -99,13 +100,14 @@ public class ShadowDialogTest { public void shouldOnlyCallOnCreateOnce() { final List<String> transcript = new ArrayList<>(); - Dialog dialog = new Dialog(RuntimeEnvironment.application) { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - transcript.add("onCreate called"); - } - }; + Dialog dialog = + new Dialog((Application) ApplicationProvider.getApplicationContext()) { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + transcript.add("onCreate called"); + } + }; dialog.show(); assertThat(transcript).containsExactly("onCreate called"); @@ -118,7 +120,7 @@ public class ShadowDialogTest { @Test public void show_setsLatestDialog() { - Dialog dialog = new Dialog(RuntimeEnvironment.application); + Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); assertNull(ShadowDialog.getLatestDialog()); dialog.show(); @@ -131,7 +133,7 @@ public class ShadowDialogTest { public void getLatestDialog_shouldReturnARealDialog() throws Exception { assertThat(ShadowDialog.getLatestDialog()).isNull(); - Dialog dialog = new Dialog(RuntimeEnvironment.application); + Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); dialog.show(); assertThat(ShadowDialog.getLatestDialog()).isSameAs(dialog); } @@ -140,13 +142,13 @@ public class ShadowDialogTest { public void shouldKeepListOfOpenedDialogs() throws Exception { assertEquals(0, ShadowDialog.getShownDialogs().size()); - TestDialog dialog = new TestDialog(RuntimeEnvironment.application); + TestDialog dialog = new TestDialog((Application) ApplicationProvider.getApplicationContext()); dialog.show(); assertEquals(1, ShadowDialog.getShownDialogs().size()); assertEquals(dialog, ShadowDialog.getShownDialogs().get(0)); - TestDialog dialog2 = new TestDialog(RuntimeEnvironment.application); + TestDialog dialog2 = new TestDialog((Application) ApplicationProvider.getApplicationContext()); dialog2.show(); assertEquals(2, ShadowDialog.getShownDialogs().size()); @@ -170,7 +172,7 @@ public class ShadowDialogTest { @Test public void shouldFindViewsWithinAContentViewThatWasPreviouslySet() throws Exception { - Dialog dialog = new Dialog(RuntimeEnvironment.application); + Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); dialog.setContentView(dialog.getLayoutInflater().inflate(R.layout.main, null)); assertThat(dialog.<TextView>findViewById(R.id.title)).isInstanceOf((Class<? extends TextView>) TextView.class); } @@ -178,13 +180,13 @@ public class ShadowDialogTest { @Test @Config(minSdk = KITKAT) public void show_shouldWorkWithAPI19() { - Dialog dialog = new Dialog(RuntimeEnvironment.application); + Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); dialog.show(); } @Test public void canSetAndGetOnCancelListener() { - Dialog dialog = new Dialog(RuntimeEnvironment.application); + Dialog dialog = new Dialog((Application) ApplicationProvider.getApplicationContext()); DialogInterface.OnCancelListener onCancelListener = new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { @@ -216,7 +218,7 @@ public class ShadowDialogTest { private static class NestingTestDialog extends Dialog { public NestingTestDialog() { - super(RuntimeEnvironment.application); + super((Application) ApplicationProvider.getApplicationContext()); } @Override diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDiscoverySessionTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDiscoverySessionTest.java index 52d1127ea..ff6fe22eb 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDiscoverySessionTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDiscoverySessionTest.java @@ -4,13 +4,13 @@ import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; import android.net.wifi.aware.DiscoverySession; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; /** Tests for {@link ShadowDiscoverySession}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = O) public class ShadowDiscoverySessionTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDisplayManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDisplayManagerTest.java index 000b159f7..89595bc68 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDisplayManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDisplayManagerTest.java @@ -7,6 +7,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.robolectric.shadows.ShadowDisplayManagerTest.HideFromJB.getGlobal; +import android.app.Application; import android.content.Context; import android.graphics.Point; import android.hardware.display.DisplayManager; @@ -14,25 +15,27 @@ import android.hardware.display.DisplayManagerGlobal; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDisplayManagerTest { private DisplayManager instance; @Before public void setUp() throws Exception { - instance = (DisplayManager) RuntimeEnvironment.application - .getSystemService(Context.DISPLAY_SERVICE); + instance = + (DisplayManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.DISPLAY_SERVICE); } @Test @Config(maxSdk = JELLY_BEAN) diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDisplayTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDisplayTest.java index ed26fac86..a4be75c2b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDisplayTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDisplayTest.java @@ -9,14 +9,14 @@ import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.util.DisplayMetrics; import android.view.Display; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = JELLY_BEAN_MR1) public class ShadowDisplayTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDownloadManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDownloadManagerTest.java index 91bb34700..68fad1b5d 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDownloadManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDownloadManagerTest.java @@ -9,12 +9,12 @@ import android.app.DownloadManager; import android.database.Cursor; import android.net.Uri; import android.util.Pair; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDownloadManagerTest { private final Uri uri = Uri.parse("http://example.com/foo.mp4"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDrawableTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDrawableTest.java index e2378d98c..aa9aed7af 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDrawableTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDrawableTest.java @@ -10,6 +10,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.ColorFilter; @@ -17,16 +18,16 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.VectorDrawable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.ByteArrayInputStream; import java.io.InputStream; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDrawableTest { @Test public void createFromStream__shouldReturnNullWhenAskedToCreateADrawableFromACorruptedSourceStream() throws Exception { @@ -37,8 +38,13 @@ public class ShadowDrawableTest { @Test public void createFromResourceStream_shouldWorkWithoutSourceName() { - Drawable drawable = Drawable.createFromResourceStream(RuntimeEnvironment.application.getResources(), - null, new ByteArrayInputStream(new byte[0]), null, new BitmapFactory.Options()); + Drawable drawable = + Drawable.createFromResourceStream( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + null, + new ByteArrayInputStream(new byte[0]), + null, + new BitmapFactory.Options()); assertNotNull(drawable); } @@ -118,8 +124,11 @@ public class ShadowDrawableTest { } @Test public void shouldLoadNinePatchFromDrawableXml() throws Exception { - assertThat(RuntimeEnvironment.application.getResources() - .getDrawable(R.drawable.drawable_with_nine_patch)).isNotNull(); + assertThat( + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDrawable(R.drawable.drawable_with_nine_patch)) + .isNotNull(); } @Test public void settingBoundsShouldInvokeCallback() { @@ -131,7 +140,10 @@ public class ShadowDrawableTest { @Test public void drawableIntrinsicWidthAndHeightShouldBeCorrect() { - final Drawable anImage = RuntimeEnvironment.application.getResources().getDrawable(R.drawable.an_image); + final Drawable anImage = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDrawable(R.drawable.an_image); assertThat(anImage.getIntrinsicHeight()).isEqualTo(53); assertThat(anImage.getIntrinsicWidth()).isEqualTo(64); @@ -140,7 +152,10 @@ public class ShadowDrawableTest { @Test @Config(qualifiers = "mdpi") public void drawableShouldLoadImageOfCorrectSizeWithMdpiQualifier() { - final Drawable anImage = RuntimeEnvironment.application.getResources().getDrawable(R.drawable.robolectric); + final Drawable anImage = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDrawable(R.drawable.robolectric); assertThat(anImage.getIntrinsicHeight()).isEqualTo(167); assertThat(anImage.getIntrinsicWidth()).isEqualTo(198); @@ -149,7 +164,10 @@ public class ShadowDrawableTest { @Test @Config(qualifiers = "hdpi") public void drawableShouldLoadImageOfCorrectSizeWithHdpiQualifier() { - final Drawable anImage = RuntimeEnvironment.application.getResources().getDrawable(R.drawable.robolectric); + final Drawable anImage = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDrawable(R.drawable.robolectric); assertThat(anImage.getIntrinsicHeight()).isEqualTo(251); assertThat(anImage.getIntrinsicWidth()).isEqualTo(297); @@ -160,16 +178,20 @@ public class ShadowDrawableTest { public void testGetBitmapOrVectorDrawableAt19() { // at API 21+ and mdpi, the drawable-anydpi-v21/image_or_vector.xml should be loaded instead // of drawable/image_or_vector.png - final Drawable aDrawable = RuntimeEnvironment.application.getResources() - .getDrawable(R.drawable.an_image_or_vector); + final Drawable aDrawable = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDrawable(R.drawable.an_image_or_vector); assertThat(aDrawable).isInstanceOf(BitmapDrawable.class); } @Test @Config(minSdk = LOLLIPOP) public void testGetBitmapOrVectorDrawableAt21() { - final Drawable aDrawable = RuntimeEnvironment.application.getResources() - .getDrawable(R.drawable.an_image_or_vector); + final Drawable aDrawable = + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDrawable(R.drawable.an_image_or_vector); assertThat(aDrawable).isInstanceOf(VectorDrawable.class); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowDropBoxManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowDropBoxManagerTest.java index bab467c44..189c2ebe7 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowDropBoxManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowDropBoxManagerTest.java @@ -3,19 +3,20 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.os.DropBoxManager; import android.os.DropBoxManager.Entry; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.BufferedReader; import java.io.InputStreamReader; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; /** Unit tests for {@see ShadowDropboxManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowDropBoxManagerTest { private static final String TAG = "TAG"; @@ -28,7 +29,9 @@ public class ShadowDropBoxManagerTest { @Before public void setup() { manager = - (DropBoxManager) RuntimeEnvironment.application.getSystemService(Context.DROPBOX_SERVICE); + (DropBoxManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.DROPBOX_SERVICE); shadowDropBoxManager = shadowOf(manager); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowEditTextPreferenceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowEditTextPreferenceTest.java index 9fb0aaa1c..e414e3be7 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowEditTextPreferenceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowEditTextPreferenceTest.java @@ -4,16 +4,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import android.app.Application; import android.content.Context; import android.preference.EditTextPreference; import android.widget.EditText; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowEditTextPreferenceTest { private static final String SOME_TEXT = "some text"; @@ -23,7 +24,7 @@ public class ShadowEditTextPreferenceTest { @Before public void setup() { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); preference = new EditTextPreference(context); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowEditTextTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowEditTextTest.java index 8a6077c43..606750f9e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowEditTextTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowEditTextTest.java @@ -3,20 +3,21 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.RuntimeEnvironment.application; +import android.app.Application; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.widget.EditText; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Random; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowEditTextTest { private EditText editText; @@ -48,7 +49,8 @@ public class ShadowEditTextTest { .addAttribute(android.R.attr.maxLength, maxLength + "") .build(); - EditText editText = new EditText(RuntimeEnvironment.application, attrs); + EditText editText = + new EditText((Application) ApplicationProvider.getApplicationContext(), attrs); String excessiveInput = stringOfLength(maxLength * 2); editText.setText(excessiveInput); @@ -59,7 +61,8 @@ public class ShadowEditTextTest { @Test public void givenInitializingWithAttributeSet_whenMaxLengthNotDefined_thenTextLengthShouldHaveNoRestrictions() { AttributeSet attrs = Robolectric.buildAttributeSet().build(); - EditText editText = new EditText(RuntimeEnvironment.application, attrs); + EditText editText = + new EditText((Application) ApplicationProvider.getApplicationContext(), attrs); String input = anyString(); editText.setText(input); @@ -69,7 +72,7 @@ public class ShadowEditTextTest { @Test public void whenInitializingWithoutAttributeSet_thenTextLengthShouldHaveNoRestrictions() { - EditText editText = new EditText(RuntimeEnvironment.application); + EditText editText = new EditText((Application) ApplicationProvider.getApplicationContext()); String input = anyString(); editText.setText(input); @@ -79,7 +82,7 @@ public class ShadowEditTextTest { @Test public void testSelectAll() { - EditText editText = new EditText(RuntimeEnvironment.application); + EditText editText = new EditText((Application) ApplicationProvider.getApplicationContext()); editText.setText("foo"); editText.selectAll(); @@ -90,7 +93,7 @@ public class ShadowEditTextTest { @Test public void shouldGetHintFromXml() { - Context context = RuntimeEnvironment.application; + Context context = (Application) ApplicationProvider.getApplicationContext(); LayoutInflater inflater = LayoutInflater.from(context); EditText editText = (EditText) inflater.inflate(R.layout.edit_text, null); assertThat(editText.getHint().toString()).isEqualTo("Hello, Hint"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowEnvironmentTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowEnvironmentTest.java index 9733b6d97..5230bd5af 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowEnvironmentTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowEnvironmentTest.java @@ -9,18 +9,19 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import android.app.Application; import android.os.Environment; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import org.junit.After; import org.junit.Ignore; 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) -public class ShadowEnvironmentTest { +@RunWith(AndroidJUnit4.class) +public class ShadowEnvironmentTest { @After public void tearDown() throws Exception { @@ -132,7 +133,8 @@ public class ShadowEnvironmentTest { ShadowEnvironment.addExternalDir("external_dir_2"); File[] externalFilesDirs = - RuntimeEnvironment.application.getExternalFilesDirs(Environment.DIRECTORY_MOVIES); + ((Application) ApplicationProvider.getApplicationContext()) + .getExternalFilesDirs(Environment.DIRECTORY_MOVIES); assertThat(externalFilesDirs).isNotEmpty(); assertThat(externalFilesDirs[0].getCanonicalPath()).contains("external_dir_1"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowEuiccManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowEuiccManagerTest.java index 8ff76a139..05918ea70 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowEuiccManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowEuiccManagerTest.java @@ -5,15 +5,15 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.RuntimeEnvironment.application; import android.telephony.euicc.EuiccManager; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; import org.robolectric.annotation.Config; /** Junit test for {@link ShadowEuiccManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = P) public class ShadowEuiccManagerTest { private EuiccManager euiccManager; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowEventLogTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowEventLogTest.java index f6529a474..fe20c45ad 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowEventLogTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowEventLogTest.java @@ -5,14 +5,14 @@ import static org.robolectric.shadows.ShadowEventLog.NULL_PLACE_HOLDER; import android.os.Build.VERSION_CODES; import android.util.EventLog; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; /** Test ShadowEventLog */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowEventLogTest { private static final String TEST_STRING1 = "hello"; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowExpandableListViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowExpandableListViewTest.java index 4474ec4ea..997440832 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowExpandableListViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowExpandableListViewTest.java @@ -1,20 +1,22 @@ package org.robolectric.shadows; +import android.app.Application; import android.widget.ExpandableListView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowExpandableListViewTest { private ExpandableListView expandableListView; @Before public void setUp() { - expandableListView = new ExpandableListView(RuntimeEnvironment.application); + expandableListView = + new ExpandableListView((Application) ApplicationProvider.getApplicationContext()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowFilterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowFilterTest.java index 8a396d16a..fb30b1daa 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowFilterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowFilterTest.java @@ -3,12 +3,12 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.widget.Filter; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowFilterTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowFingerprintManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowFingerprintManagerTest.java index 5e6aae34b..3d8fde52c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowFingerprintManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowFingerprintManagerTest.java @@ -6,21 +6,22 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; import android.hardware.fingerprint.FingerprintManager.CryptoObject; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.security.Signature; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = M) public class ShadowFingerprintManagerTest { @@ -28,8 +29,10 @@ public class ShadowFingerprintManagerTest { @Before public void setUp() { - manager = (FingerprintManager) RuntimeEnvironment.application - .getSystemService(Context.FINGERPRINT_SERVICE); + manager = + (FingerprintManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.FINGERPRINT_SERVICE); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowFrameLayoutTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowFrameLayoutTest.java index 77c2e7655..bf8207a41 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowFrameLayoutTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowFrameLayoutTest.java @@ -3,22 +3,23 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNotNull; +import android.app.Application; import android.view.View; import android.widget.FrameLayout; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowFrameLayoutTest { private FrameLayout frameLayout; @Before public void setUp() throws Exception { - frameLayout = new FrameLayout(RuntimeEnvironment.application); + frameLayout = new FrameLayout((Application) ApplicationProvider.getApplicationContext()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowGLES20Test.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowGLES20Test.java index a5b89e224..0ac6d8141 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowGLES20Test.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowGLES20Test.java @@ -3,18 +3,22 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.opengl.GLES20; - +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -/** - * Test for {@link GLES20} - */ -@RunWith(RobolectricTestRunner.class) +/** Test for {@link GLES20} */ +@RunWith(AndroidJUnit4.class) public final class ShadowGLES20Test { @Test + public void glGenFramebuffers() { + int[] framebuffers = new int[1]; + GLES20.glGenFramebuffers(1, framebuffers, 0); + assertThat(framebuffers[0]).isAtLeast(1); + } + + @Test public void glGenTextures() { int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); @@ -35,4 +39,18 @@ public final class ShadowGLES20Test { public void glCreateProgram() { assertThat(GLES20.glCreateProgram()).isAtLeast(1); } + + @Test + public void glGetShaderiv_compileStatus() { + int[] params = new int[1]; + GLES20.glGetShaderiv(1, GLES20.GL_COMPILE_STATUS, params, 0); + assertThat(params[0]).isEqualTo(GLES20.GL_TRUE); + } + + @Test + public void glGetProgramiv_compileStatus() { + int[] params = new int[1]; + GLES20.glGetProgramiv(1, GLES20.GL_LINK_STATUS, params, 0); + assertThat(params[0]).isEqualTo(GLES20.GL_TRUE); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowGeocoderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowGeocoderTest.java index 79c08d7c1..f298d9e40 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowGeocoderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowGeocoderTest.java @@ -4,19 +4,20 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.location.Address; import android.location.Geocoder; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Locale; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; /** Unit test for {@link ShadowGeocoder}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowGeocoderTest { @Test @@ -33,13 +34,17 @@ public class ShadowGeocoderTest { @Test public void getFromLocationReturnsAnEmptyArrayByDefault() throws IOException { - Geocoder geocoder = new Geocoder(RuntimeEnvironment.application.getApplicationContext()); + Geocoder geocoder = + new Geocoder( + ((Application) ApplicationProvider.getApplicationContext()).getApplicationContext()); assertThat(geocoder.getFromLocation(90.0,90.0,1)).hasSize(0); } @Test public void getFromLocationReturnsTheOverwrittenListLimitingByMaxResults() throws IOException { - Geocoder geocoder = new Geocoder(RuntimeEnvironment.application.getApplicationContext()); + Geocoder geocoder = + new Geocoder( + ((Application) ApplicationProvider.getApplicationContext()).getApplicationContext()); ShadowGeocoder shadowGeocoder = shadowOf(geocoder); List<Address> list = Arrays.asList(new Address(Locale.getDefault()), new Address(Locale.CANADA)); @@ -57,7 +62,9 @@ public class ShadowGeocoderTest { @Test public void getFromLocation_throwsExceptionForInvalidLatitude() throws IOException { - Geocoder geocoder = new Geocoder(RuntimeEnvironment.application.getApplicationContext()); + Geocoder geocoder = + new Geocoder( + ((Application) ApplicationProvider.getApplicationContext()).getApplicationContext()); try { geocoder.getFromLocation(91.0, 90.0, 1); @@ -69,7 +76,9 @@ public class ShadowGeocoderTest { @Test public void getFromLocation_throwsExceptionForInvalidLongitude() throws IOException { - Geocoder geocoder = new Geocoder(RuntimeEnvironment.application.getApplicationContext()); + Geocoder geocoder = + new Geocoder( + ((Application) ApplicationProvider.getApplicationContext()).getApplicationContext()); try { geocoder.getFromLocation(15.0, -211.0, 1); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowGestureDetectorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowGestureDetectorTest.java new file mode 100644 index 000000000..c3316bccb --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowGestureDetectorTest.java @@ -0,0 +1,130 @@ +package org.robolectric.shadows; + +import static androidx.test.core.view.MotionEventBuilder.newBuilder; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.robolectric.Shadows.shadowOf; + +import android.app.Application; +import android.view.GestureDetector; +import android.view.MotionEvent; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class ShadowGestureDetectorTest { + + private GestureDetector detector; + private MotionEvent motionEvent; + + @Before + public void setUp() throws Exception { + detector = new GestureDetector(new TestOnGestureListener()); + motionEvent = newBuilder().setAction(MotionEvent.ACTION_UP).setPointer(100, 30).build(); + } + + @Test + public void test_getOnTouchEventMotionEvent() throws Exception { + detector.onTouchEvent(motionEvent); + assertSame(motionEvent, shadowOf(detector).getOnTouchEventMotionEvent()); + } + + @Test + public void test_reset() throws Exception { + detector.onTouchEvent(motionEvent); + assertSame(motionEvent, shadowOf(detector).getOnTouchEventMotionEvent()); + + shadowOf(detector).reset(); + assertNull(shadowOf(detector).getOnTouchEventMotionEvent()); + } + + @Test + public void test_getListener() throws Exception { + TestOnGestureListener listener = new TestOnGestureListener(); + assertSame(listener, shadowOf(new GestureDetector(listener)).getListener()); + assertSame(listener, shadowOf(new GestureDetector(null, listener)).getListener()); + } + + @Test + public void canAnswerLastGestureDetector() throws Exception { + GestureDetector newDetector = + new GestureDetector( + (Application) ApplicationProvider.getApplicationContext(), new TestOnGestureListener()); + assertNotSame(newDetector, ShadowGestureDetector.getLastActiveDetector()); + newDetector.onTouchEvent(motionEvent); + assertSame(newDetector, ShadowGestureDetector.getLastActiveDetector()); + } + + @Test + public void getOnDoubleTapListener_shouldReturnSetDoubleTapListener() throws Exception { + GestureDetector subject = + new GestureDetector( + (Application) ApplicationProvider.getApplicationContext(), new TestOnGestureListener()); + GestureDetector.OnDoubleTapListener onDoubleTapListener = new GestureDetector.OnDoubleTapListener() { + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + return false; + } + + @Override + public boolean onDoubleTap(MotionEvent e) { + return false; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent e) { + return false; + } + }; + + subject.setOnDoubleTapListener(onDoubleTapListener); + assertEquals(shadowOf(subject).getOnDoubleTapListener(), onDoubleTapListener); + + subject.setOnDoubleTapListener(null); + assertEquals(shadowOf(subject).getOnDoubleTapListener(), null); + } + + @Test + public void getOnDoubleTapListener_shouldReturnOnGestureListenerFromConstructor() throws Exception { + GestureDetector.OnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener(); + GestureDetector subject = + new GestureDetector( + (Application) ApplicationProvider.getApplicationContext(), onGestureListener); + assertEquals(shadowOf(subject).getOnDoubleTapListener(), onGestureListener); + } + + private static class TestOnGestureListener implements GestureDetector.OnGestureListener { + @Override + public boolean onDown(MotionEvent e) { + return false; + } + + @Override + public void onShowPress(MotionEvent e) { + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + return false; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + return false; + } + + @Override + public void onLongPress(MotionEvent e) { + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + return false; + } + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowGradientDrawableTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowGradientDrawableTest.java index f249f7f30..d56b3c5da 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowGradientDrawableTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowGradientDrawableTest.java @@ -4,11 +4,11 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.graphics.drawable.GradientDrawable; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowGradientDrawableTest { @Test public void testGetColor_returnsColor() throws Exception { @@ -16,6 +16,6 @@ public class ShadowGradientDrawableTest { ShadowGradientDrawable shadowGradientDrawable = shadowOf(gradientDrawable); int color = 123; gradientDrawable.setColor(color); - assertThat(shadowGradientDrawable.getColor()).isEqualTo(color); + assertThat(shadowGradientDrawable.getLastSetColor()).isEqualTo(color); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowHandlerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowHandlerTest.java index e0c3d039e..ac8d3a2fd 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowHandlerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowHandlerTest.java @@ -9,18 +9,18 @@ import static org.robolectric.util.ReflectionHelpers.ClassParameter.from; import android.os.Handler; import android.os.Looper; import android.os.Message; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.Scheduler; import org.robolectric.util.TestRunnable; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowHandlerTest { private List<String> transcript; TestRunnable scratchRunnable = new TestRunnable(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowHandlerThreadTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowHandlerThreadTest.java index a33b046b1..cde9f6bf1 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowHandlerThreadTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowHandlerThreadTest.java @@ -7,17 +7,18 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.os.HandlerThread; import android.os.Looper; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowHandlerThreadTest { private HandlerThread handlerThread; @@ -36,7 +37,9 @@ public class ShadowHandlerThreadTest { handlerThread = new HandlerThread("test"); handlerThread.start(); assertNotNull(handlerThread.getLooper()); - assertNotSame(handlerThread.getLooper(), RuntimeEnvironment.application.getMainLooper()); + assertNotSame( + handlerThread.getLooper(), + ((Application) ApplicationProvider.getApplicationContext()).getMainLooper()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowHtmlTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowHtmlTest.java index 5f253e974..1005063e8 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowHtmlTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowHtmlTest.java @@ -5,20 +5,21 @@ import static android.os.Build.VERSION_CODES.N; import static com.google.common.truth.Truth.assertThat; import android.annotation.TargetApi; +import android.app.Application; import android.content.Context; import android.text.Html; import android.text.Spanned; import android.widget.EditText; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Collections; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class ShadowHtmlTest { private static final String HTML_SHORT = "<img src='foo.png'>"; private static final String HTML_LONG = String.format("<img src='%s.png'>", @@ -28,7 +29,7 @@ public class ShadowHtmlTest { @Before public void setUp() throws Exception { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowHttpResponseCacheTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowHttpResponseCacheTest.java index aa33cb543..48ee23120 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowHttpResponseCacheTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowHttpResponseCacheTest.java @@ -3,14 +3,14 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.net.http.HttpResponseCache; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowHttpResponseCacheTest { @Before public void setUp() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowICUTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowICUTest.java index cbe7fee70..c84c56a39 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowICUTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowICUTest.java @@ -7,16 +7,16 @@ import android.app.Activity; import android.os.Bundle; import android.widget.DatePicker; import android.widget.LinearLayout; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Locale; import libcore.icu.ICU; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowICUTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowIconTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowIconTest.java index 49d706b5c..75e8b264f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowIconTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowIconTest.java @@ -4,16 +4,17 @@ import static android.os.Build.VERSION_CODES.M; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.graphics.Bitmap; import android.graphics.drawable.Icon; import android.net.Uri; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = M) public class ShadowIconTest { public static final int TYPE_BITMAP = 1; @@ -23,7 +24,10 @@ public class ShadowIconTest { @Test public void testGetRes() { - Icon icon = Icon.createWithResource(RuntimeEnvironment.application, android.R.drawable.ic_delete); + Icon icon = + Icon.createWithResource( + (Application) ApplicationProvider.getApplicationContext(), + android.R.drawable.ic_delete); assertThat(shadowOf(icon).getType()).isEqualTo(TYPE_RESOURCE); assertThat(shadowOf(icon).getResId()).isEqualTo(android.R.drawable.ic_delete); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowImageViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowImageViewTest.java index 81afe343b..de4eec30a 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowImageViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowImageViewTest.java @@ -3,25 +3,27 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.widget.ImageView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowImageViewTest { @Test public void getDrawableResourceId_shouldWorkWhenTheDrawableWasCreatedFromAResource() throws Exception { - Resources resources = RuntimeEnvironment.application.getResources(); + Resources resources = + ((Application) ApplicationProvider.getApplicationContext()).getResources(); Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.an_image); - ImageView imageView = new ImageView(RuntimeEnvironment.application); + ImageView imageView = new ImageView((Application) ApplicationProvider.getApplicationContext()); imageView.setImageBitmap(bitmap); imageView.setImageResource(R.drawable.an_image); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowInputDeviceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowInputDeviceTest.java index 43e14b5f1..ad1d22698 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowInputDeviceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowInputDeviceTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.view.InputDevice; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowInputDeviceTest { @Test public void canConstructInputDeviceWithName() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowInputEventTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowInputEventTest.java index bf8f884be..2fa4f8c89 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowInputEventTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowInputEventTest.java @@ -5,11 +5,11 @@ import static org.robolectric.Shadows.shadowOf; import android.view.InputDevice; import android.view.KeyEvent; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowInputEventTest { @Test public void canSetInputDeviceOnKeyEvent() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowInputMethodManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowInputMethodManagerTest.java index 08917313e..d85c2b6ff 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowInputMethodManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowInputMethodManagerTest.java @@ -5,15 +5,16 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.app.Activity; +import android.app.Application; import android.view.inputmethod.InputMethodManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowInputMethodManagerTest { private InputMethodManager manager; @@ -21,7 +22,10 @@ public class ShadowInputMethodManagerTest { @Before public void setUp() throws Exception { - manager = (InputMethodManager) RuntimeEnvironment.application.getSystemService(Activity.INPUT_METHOD_SERVICE); + manager = + (InputMethodManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Activity.INPUT_METHOD_SERVICE); shadow = Shadows.shadowOf(manager); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentFilterAuthorityEntryTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentFilterAuthorityEntryTest.java index 48e7161cb..11fb70392 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentFilterAuthorityEntryTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentFilterAuthorityEntryTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.content.IntentFilter; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowIntentFilterAuthorityEntryTest { @Test(expected = NumberFormatException.class) public void constructor_shouldThrowAnExceptionIfPortIsNotAValidNumber() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentFilterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentFilterTest.java index fbf795157..132c3727c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentFilterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentFilterTest.java @@ -4,11 +4,11 @@ import static com.google.common.truth.Truth.assertThat; import android.content.IntentFilter; import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowIntentFilterTest { @Test public void copyConstructorTest() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentServiceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentServiceTest.java index 8dec5d017..86d6bf46e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentServiceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentServiceTest.java @@ -5,11 +5,11 @@ import static org.robolectric.Shadows.shadowOf; import android.app.IntentService; import android.content.Intent; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowIntentServiceTest { @Test public void shouldSetIntentRedelivery() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentTest.java index 3000d5247..532863b67 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowIntentTest.java @@ -8,6 +8,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import android.app.Activity; +import android.app.Application; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -17,28 +18,28 @@ import android.net.Uri; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowIntentTest { private static final String TEST_ACTIVITY_CLASS_NAME = "org.robolectric.shadows.TestActivity"; @Test public void resolveActivityInfo_shouldReturnActivityInfoForExistingActivity() { - Context context = RuntimeEnvironment.application; - PackageManager packageManager = context.getPackageManager(); + Context context = (Application) ApplicationProvider.getApplicationContext(); + PackageManager packageManager = context.getPackageManager(); - Intent intent = new Intent(); - intent.setClassName(context, TEST_ACTIVITY_CLASS_NAME); - ActivityInfo activityInfo = intent.resolveActivityInfo(packageManager, PackageManager.GET_ACTIVITIES); - assertThat(activityInfo).isNotNull(); + Intent intent = new Intent(); + intent.setClassName(context, TEST_ACTIVITY_CLASS_NAME); + ActivityInfo activityInfo = intent.resolveActivityInfo(packageManager, PackageManager.GET_ACTIVITIES); + assertThat(activityInfo).isNotNull(); } @Test @@ -205,7 +206,7 @@ public class ShadowIntentTest { assertSame(uri, intent.getData()); assertNull(intent.getType()); } - + @Test public void testGetScheme() throws Exception { Intent intent = new Intent(); @@ -237,7 +238,8 @@ public class ShadowIntentTest { public void testSetClass() throws Exception { Intent intent = new Intent(); Class<? extends ShadowIntentTest> thisClass = getClass(); - Intent output = intent.setClass(RuntimeEnvironment.application, thisClass); + Intent output = + intent.setClass((Application) ApplicationProvider.getApplicationContext(), thisClass); assertSame(output, intent); assertThat(intent.getComponent().getClassName()).isEqualTo(thisClass.getName()); @@ -255,7 +257,8 @@ public class ShadowIntentTest { @Test public void testSetClassThroughConstructor() throws Exception { - Intent intent = new Intent(RuntimeEnvironment.application, getClass()); + Intent intent = + new Intent((Application) ApplicationProvider.getApplicationContext(), getClass()); assertThat(intent.getComponent().getClassName()).isEqualTo(getClass().getName()); } @@ -393,7 +396,12 @@ public class ShadowIntentTest { @Test public void constructor_shouldSetComponentAndActionAndData() { - Intent intent = new Intent("roboaction", Uri.parse("http://www.robolectric.org"), RuntimeEnvironment.application, Activity.class); + Intent intent = + new Intent( + "roboaction", + Uri.parse("http://www.robolectric.org"), + (Application) ApplicationProvider.getApplicationContext(), + Activity.class); assertThat(intent.getComponent()).isEqualTo(new ComponentName("org.robolectric", "android.app.Activity")); assertThat(intent.getAction()).isEqualTo("roboaction"); assertThat(intent.getData()).isEqualTo(Uri.parse("http://www.robolectric.org")); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowIoUtilsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowIoUtilsTest.java index d8c4b7e50..f75203c86 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowIoUtilsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowIoUtilsTest.java @@ -2,6 +2,7 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.io.Files; import java.io.File; import java.nio.charset.StandardCharsets; @@ -10,9 +11,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowIoUtilsTest { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowJobSchedulerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowJobSchedulerTest.java index e5faee422..4901f4872 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowJobSchedulerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowJobSchedulerTest.java @@ -6,20 +6,21 @@ import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.job.JobInfo; import android.app.job.JobScheduler; import android.app.job.JobWorkItem; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowJobSchedulerTest { @@ -27,15 +28,22 @@ public class ShadowJobSchedulerTest { @Before public void setUp() { - jobScheduler = (JobScheduler) RuntimeEnvironment.application.getSystemService(Context.JOB_SCHEDULER_SERVICE); + jobScheduler = + (JobScheduler) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.JOB_SCHEDULER_SERVICE); } @Test public void getAllPendingJobs() { - JobInfo jobInfo = new JobInfo.Builder(99, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build(); + JobInfo jobInfo = + new JobInfo.Builder( + 99, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build(); jobScheduler.schedule(jobInfo); assertThat(jobScheduler.getAllPendingJobs()).contains(jobInfo); @@ -43,14 +51,22 @@ public class ShadowJobSchedulerTest { @Test public void cancelAll() { - jobScheduler.schedule(new JobInfo.Builder(99, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build()); - jobScheduler.schedule(new JobInfo.Builder(33, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build()); + jobScheduler.schedule( + new JobInfo.Builder( + 99, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build()); + jobScheduler.schedule( + new JobInfo.Builder( + 33, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build()); assertThat(jobScheduler.getAllPendingJobs()).hasSize(2); @@ -61,10 +77,14 @@ public class ShadowJobSchedulerTest { @Test public void cancelSingleJob() { - jobScheduler.schedule(new JobInfo.Builder(99, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build()); + jobScheduler.schedule( + new JobInfo.Builder( + 99, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build()); assertThat(jobScheduler.getAllPendingJobs()).isNotEmpty(); @@ -75,10 +95,14 @@ public class ShadowJobSchedulerTest { @Test public void cancelNonExistentJob() { - jobScheduler.schedule(new JobInfo.Builder(99, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build()); + jobScheduler.schedule( + new JobInfo.Builder( + 99, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build()); assertThat(jobScheduler.getAllPendingJobs()).isNotEmpty(); @@ -89,10 +113,15 @@ public class ShadowJobSchedulerTest { @Test public void schedule_success() { - int result = jobScheduler.schedule(new JobInfo.Builder(99, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build()); + int result = + jobScheduler.schedule( + new JobInfo.Builder( + 99, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build()); assertThat(result).isEqualTo(JobScheduler.RESULT_SUCCESS); } @@ -100,10 +129,15 @@ public class ShadowJobSchedulerTest { public void schedule_fail() { shadowOf(jobScheduler).failOnJob(99); - int result = jobScheduler.schedule(new JobInfo.Builder(99, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build()); + int result = + jobScheduler.schedule( + new JobInfo.Builder( + 99, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build()); assertThat(result).isEqualTo(JobScheduler.RESULT_FAILURE); } @@ -112,10 +146,14 @@ public class ShadowJobSchedulerTest { @Config(minSdk = N) public void getPendingJob_withValidId() { int jobId = 99; - JobInfo originalJobInfo = new JobInfo.Builder(jobId, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build(); + JobInfo originalJobInfo = + new JobInfo.Builder( + jobId, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build(); jobScheduler.schedule(originalJobInfo); @@ -129,10 +167,14 @@ public class ShadowJobSchedulerTest { public void getPendingJob_withInvalidId() { int jobId = 99; int invalidJobId = 100; - JobInfo originalJobInfo = new JobInfo.Builder(jobId, - new ComponentName(RuntimeEnvironment.application, "component_class_name")) - .setPeriodic(1000) - .build(); + JobInfo originalJobInfo = + new JobInfo.Builder( + jobId, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) + .setPeriodic(1000) + .build(); jobScheduler.schedule(originalJobInfo); @@ -147,7 +189,10 @@ public class ShadowJobSchedulerTest { int result = jobScheduler.enqueue( new JobInfo.Builder( - 99, new ComponentName(RuntimeEnvironment.application, "component_class_name")) + 99, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) .setPeriodic(1000) .build(), new JobWorkItem(new Intent())); @@ -162,7 +207,10 @@ public class ShadowJobSchedulerTest { int result = jobScheduler.enqueue( new JobInfo.Builder( - 99, new ComponentName(RuntimeEnvironment.application, "component_class_name")) + 99, + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), + "component_class_name")) .setPeriodic(1000) .build(), new JobWorkItem(new Intent())); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowJobServiceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowJobServiceTest.java index b157593ce..8fca386d0 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowJobServiceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowJobServiceTest.java @@ -6,18 +6,16 @@ import static org.robolectric.Shadows.shadowOf; import android.app.job.JobParameters; import android.app.job.JobService; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -/** - * Robolectric test for {@link ShadowJobService}. - */ -@RunWith(RobolectricTestRunner.class) +/** Robolectric test for {@link ShadowJobService}. */ +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowJobServiceTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowJsPromptResultTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowJsPromptResultTest.java index 7f841e85b..f4a619adc 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowJsPromptResultTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowJsPromptResultTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static org.junit.Assert.assertNotNull; import android.webkit.JsPromptResult; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowJsPromptResultTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowJsResultTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowJsResultTest.java index 245ce5e61..3128d6d87 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowJsResultTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowJsResultTest.java @@ -5,12 +5,12 @@ import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; import android.webkit.JsResult; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowJsResultTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowJsonReaderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowJsonReaderTest.java index b79b7228b..8a6f716cf 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowJsonReaderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowJsonReaderTest.java @@ -3,12 +3,12 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.util.JsonReader; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.StringReader; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowJsonReaderTest { @Test public void shouldWork() throws Exception { JsonReader jsonReader = new JsonReader(new StringReader("{\"abc\": \"def\"}")); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowKeyCharacterMapTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowKeyCharacterMapTest.java index 8920fcce2..92c181548 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowKeyCharacterMapTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowKeyCharacterMapTest.java @@ -2,21 +2,22 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.widget.EditText; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowKeyCharacterMapTest { private final KeyCharacterMap keyMap = ShadowKeyCharacterMap.load(0); @Test public void dispatchKeyEvent_shouldSetText() throws Exception { - EditText editText = new EditText(RuntimeEnvironment.application); + EditText editText = new EditText((Application) ApplicationProvider.getApplicationContext()); editText.requestFocus(); for (KeyEvent evt : keyMap.getEvents("string".toCharArray())) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowKeyguardManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowKeyguardManagerTest.java index 464a11d67..11d066f26 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowKeyguardManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowKeyguardManagerTest.java @@ -10,17 +10,18 @@ import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.Application; import android.app.KeyguardManager; import android.app.KeyguardManager.KeyguardDismissCallback; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowKeyguardManagerTest { private static final int USER_ID = 1001; @@ -28,7 +29,10 @@ public class ShadowKeyguardManagerTest { @Before public void setUp() { - manager = (KeyguardManager) RuntimeEnvironment.application.getSystemService(KEYGUARD_SERVICE); + manager = + (KeyguardManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(KEYGUARD_SERVICE); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLayerDrawableTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLayerDrawableTest.java index 1e7ee9027..fa347d0b4 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLayerDrawableTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLayerDrawableTest.java @@ -5,18 +5,19 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLayerDrawableTest { /** * drawables @@ -33,14 +34,26 @@ public class ShadowLayerDrawableTest { @Before public void setUp() { - drawable1000 = new BitmapDrawable(BitmapFactory.decodeResource( - RuntimeEnvironment.application.getResources(), R.drawable.an_image)); - drawable2000 = new BitmapDrawable(BitmapFactory.decodeResource( - RuntimeEnvironment.application.getResources(), R.drawable.an_other_image)); - drawable3000 = new BitmapDrawable(BitmapFactory.decodeResource( - RuntimeEnvironment.application.getResources(), R.drawable.third_image)); - drawable4000 = new BitmapDrawable(BitmapFactory.decodeResource( - RuntimeEnvironment.application.getResources(), R.drawable.fourth_image)); + drawable1000 = + new BitmapDrawable( + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.an_image)); + drawable2000 = + new BitmapDrawable( + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.an_other_image)); + drawable3000 = + new BitmapDrawable( + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.third_image)); + drawable4000 = + new BitmapDrawable( + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.fourth_image)); drawables = new Drawable[]{drawable1000, drawable2000, drawable3000}; } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutAnimationControllerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutAnimationControllerTest.java index 3086197b7..541ca1e3f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutAnimationControllerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutAnimationControllerTest.java @@ -2,21 +2,24 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.view.animation.LayoutAnimationController; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLayoutAnimationControllerTest { private ShadowLayoutAnimationController shadow; @Before public void setup() { - LayoutAnimationController controller = new LayoutAnimationController(RuntimeEnvironment.application, null); + LayoutAnimationController controller = + new LayoutAnimationController( + (Application) ApplicationProvider.getApplicationContext(), null); shadow = Shadows.shadowOf(controller); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutInflaterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutInflaterTest.java index daf59fabf..403468e4c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutInflaterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutInflaterTest.java @@ -11,6 +11,7 @@ import static org.robolectric.Robolectric.buildActivity; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.Application; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.drawable.BitmapDrawable; @@ -30,26 +31,26 @@ import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.R.layout; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.CustomStateView; import org.robolectric.android.CustomView; import org.robolectric.android.CustomView2; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLayoutInflaterTest { private Context context; @Before public void setUp() throws Exception { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutParamsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutParamsTest.java index 5e24edaad..81c5c1847 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutParamsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLayoutParamsTest.java @@ -5,11 +5,11 @@ import static com.google.common.truth.Truth.assertThat; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.Gallery; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLayoutParamsTest { @Test public void testConstructor() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLinearLayoutTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLinearLayoutTest.java index 1f683636a..75df1238c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLinearLayoutTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLinearLayoutTest.java @@ -4,22 +4,23 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertSame; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.view.Gravity; import android.widget.LinearLayout; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLinearLayoutTest { private LinearLayout linearLayout; private ShadowLinearLayout shadow; @Before public void setup() throws Exception { - linearLayout = new LinearLayout(RuntimeEnvironment.application); + linearLayout = new LinearLayout((Application) ApplicationProvider.getApplicationContext()); shadow = shadowOf(linearLayout); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLinkMovementMethodTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLinkMovementMethodTest.java index b35270b3e..cc26fd537 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLinkMovementMethodTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLinkMovementMethodTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.text.method.LinkMovementMethod; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLinkMovementMethodTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowListPopupWindowTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowListPopupWindowTest.java index b41966a01..5bdca66e3 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowListPopupWindowTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowListPopupWindowTest.java @@ -2,19 +2,20 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.Context; import android.view.View; import android.widget.ListPopupWindow; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowListPopupWindowTest { @Test public void show_setsLastListPopupWindow() throws Exception { - Context context = RuntimeEnvironment.application; + Context context = (Application) ApplicationProvider.getApplicationContext(); ListPopupWindow popupWindow = new ListPopupWindow(context); assertThat(ShadowListPopupWindow.getLatestListPopupWindow()).isNull(); popupWindow.setAnchorView(new View(context)); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowListPreferenceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowListPreferenceTest.java index 4adb1f9a7..36a6f2f3b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowListPreferenceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowListPreferenceTest.java @@ -5,13 +5,13 @@ import static org.robolectric.Robolectric.buildActivity; import android.app.Activity; import android.preference.ListPreference; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowListPreferenceTest { private ListPreference listPreference; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowListViewAdapterViewBehaviorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowListViewAdapterViewBehaviorTest.java index 92bd3bfc5..72b992988 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowListViewAdapterViewBehaviorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowListViewAdapterViewBehaviorTest.java @@ -1,14 +1,15 @@ package org.robolectric.shadows; +import android.app.Application; import android.widget.AdapterView; import android.widget.ListView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowListViewAdapterViewBehaviorTest extends AdapterViewBehavior { @Override public AdapterView createAdapterView() { - return new ListView(RuntimeEnvironment.application); + return new ListView((Application) ApplicationProvider.getApplicationContext()); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowListViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowListViewTest.java index 3b5642817..f45e4cffa 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowListViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowListViewTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertNull; import static org.robolectric.RuntimeEnvironment.application; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.util.SparseBooleanArray; import android.view.View; import android.view.ViewGroup; @@ -16,17 +17,17 @@ import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.ListView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowListViewTest { private List<String> transcript; @@ -38,18 +39,18 @@ public class ShadowListViewTest { @Before public void setUp() throws Exception { transcript = new ArrayList<>(); - listView = new ListView(RuntimeEnvironment.application); + listView = new ListView((Application) ApplicationProvider.getApplicationContext()); } @Test public void addHeaderView_ShouldRecordHeaders() throws Exception { - View view0 = new View(RuntimeEnvironment.application); + View view0 = new View((Application) ApplicationProvider.getApplicationContext()); view0.setId(0); - View view1 = new View(RuntimeEnvironment.application); + View view1 = new View((Application) ApplicationProvider.getApplicationContext()); view1.setId(1); - View view2 = new View(RuntimeEnvironment.application); + View view2 = new View((Application) ApplicationProvider.getApplicationContext()); view2.setId(2); - View view3 = new View(RuntimeEnvironment.application); + View view3 = new View((Application) ApplicationProvider.getApplicationContext()); view3.setId(3); listView.addHeaderView(view0); listView.addHeaderView(view1); @@ -70,7 +71,7 @@ public class ShadowListViewTest { @Test public void addHeaderView_shouldAttachTheViewToTheList() throws Exception { - View view = new View(RuntimeEnvironment.application); + View view = new View((Application) ApplicationProvider.getApplicationContext()); view.setId(42); listView.addHeaderView(view); @@ -80,8 +81,8 @@ public class ShadowListViewTest { @Test public void addFooterView_ShouldRecordFooters() throws Exception { - View view0 = new View(RuntimeEnvironment.application); - View view1 = new View(RuntimeEnvironment.application); + View view0 = new View((Application) ApplicationProvider.getApplicationContext()); + View view1 = new View((Application) ApplicationProvider.getApplicationContext()); listView.addFooterView(view0); listView.addFooterView(view1); listView.setAdapter(new ShadowCountingAdapter(3)); @@ -91,7 +92,7 @@ public class ShadowListViewTest { @Test public void addFooterView_shouldAttachTheViewToTheList() throws Exception { - View view = new View(RuntimeEnvironment.application); + View view = new View((Application) ApplicationProvider.getApplicationContext()); view.setId(42); listView.addFooterView(view); @@ -101,9 +102,9 @@ public class ShadowListViewTest { @Test public void setAdapter_shouldNotClearHeaderOrFooterViews() throws Exception { - View header = new View(RuntimeEnvironment.application); + View header = new View((Application) ApplicationProvider.getApplicationContext()); listView.addHeaderView(header); - View footer = new View(RuntimeEnvironment.application); + View footer = new View((Application) ApplicationProvider.getApplicationContext()); listView.addFooterView(footer); prepareListWithThreeItems(); @@ -115,9 +116,9 @@ public class ShadowListViewTest { @Test public void testGetFooterViewsCount() throws Exception { - listView.addHeaderView(new View(RuntimeEnvironment.application)); - listView.addFooterView(new View(RuntimeEnvironment.application)); - listView.addFooterView(new View(RuntimeEnvironment.application)); + listView.addHeaderView(new View((Application) ApplicationProvider.getApplicationContext())); + listView.addFooterView(new View((Application) ApplicationProvider.getApplicationContext())); + listView.addFooterView(new View((Application) ApplicationProvider.getApplicationContext())); prepareListWithThreeItems(); @@ -208,7 +209,7 @@ public class ShadowListViewTest { @Test(expected = UnsupportedOperationException.class) public void removeView_shouldThrowAnException() throws Exception { - listView.removeView(new View(RuntimeEnvironment.application)); + listView.removeView(new View((Application) ApplicationProvider.getApplicationContext())); } @Test(expected = UnsupportedOperationException.class) @@ -226,7 +227,7 @@ public class ShadowListViewTest { @Test public void getPositionForView_shouldReturnInvalidPositionForViewThatIsNotFound() throws Exception { prepareWithListAdapter(); - View view = new View(RuntimeEnvironment.application); + View view = new View((Application) ApplicationProvider.getApplicationContext()); shadowOf(view).setMyParent(ReflectionHelpers.createNullProxy(ViewParent.class)); // Android implementation requires the item have a parent assertThat(listView.getPositionForView(view)).isEqualTo(AdapterView.INVALID_POSITION); } @@ -384,8 +385,9 @@ public class ShadowListViewTest { @Override public View getView(int position, View convertView, ViewGroup parent) { - LinearLayout linearLayout = new LinearLayout(RuntimeEnvironment.application); - linearLayout.addView(new View(RuntimeEnvironment.application)); + LinearLayout linearLayout = + new LinearLayout((Application) ApplicationProvider.getApplicationContext()); + linearLayout.addView(new View((Application) ApplicationProvider.getApplicationContext())); return linearLayout; } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLocaleDataTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLocaleDataTest.java index 88e36fab1..7df2e9018 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLocaleDataTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLocaleDataTest.java @@ -7,15 +7,15 @@ import static android.os.Build.VERSION_CODES.M; import static com.google.common.truth.Truth.assertThat; import android.os.Build; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Locale; import libcore.icu.LocaleData; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLocaleDataTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLocationManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLocationManagerTest.java index 87b57498a..358cbf389 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLocationManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLocationManagerTest.java @@ -10,6 +10,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -21,6 +22,8 @@ import android.location.LocationManager; import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Process; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -31,18 +34,19 @@ import org.junit.Assert; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class ShadowLocationManagerTest { private LocationManager locationManager; private ShadowLocationManager shadowLocationManager; @Before public void setUp() { - locationManager = (LocationManager) RuntimeEnvironment.application.getSystemService(Context.LOCATION_SERVICE); + locationManager = + (LocationManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.LOCATION_SERVICE); shadowLocationManager = shadowOf(locationManager); } @@ -190,12 +194,19 @@ public class ShadowLocationManagerTest { @Test public void shouldRemovePendingIntentsWhenRequestingLocationUpdatesUsingCriteria() throws Exception { Intent someIntent = new Intent("some_action"); - PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, someIntent, - PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent someLocationListenerPendingIntent = + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), + 0, + someIntent, + PendingIntent.FLAG_UPDATE_CURRENT); Intent someOtherIntent = new Intent("some_other_action"); - PendingIntent someOtherLocationListenerPendingIntent = PendingIntent.getBroadcast( - RuntimeEnvironment.application, 0, someOtherIntent, - PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent someOtherLocationListenerPendingIntent = + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), + 0, + someOtherIntent, + PendingIntent.FLAG_UPDATE_CURRENT); shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true); @@ -227,11 +238,19 @@ public class ShadowLocationManagerTest { @Test public void shouldRemovePendingIntentsWhenRequestingLocationUpdatesUsingLocationListeners() throws Exception { Intent someIntent = new Intent("some_action"); - PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, - someIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent someLocationListenerPendingIntent = + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), + 0, + someIntent, + PendingIntent.FLAG_UPDATE_CURRENT); Intent someOtherIntent = new Intent("some_other_action"); - PendingIntent someOtherLocationListenerPendingIntent = PendingIntent.getBroadcast(RuntimeEnvironment.application, - 0, someOtherIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent someOtherLocationListenerPendingIntent = + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), + 0, + someOtherIntent, + PendingIntent.FLAG_UPDATE_CURRENT); shadowLocationManager.setProviderEnabled(GPS_PROVIDER, true); shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true); @@ -278,8 +297,12 @@ public class ShadowLocationManagerTest { @Test public void shouldThrowExceptionWhenRequestingLocationUpdatesAndNoProviderIsFound() throws Exception { Intent someIntent = new Intent("some_action"); - PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, - someIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent someLocationListenerPendingIntent = + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), + 0, + someIntent, + PendingIntent.FLAG_UPDATE_CURRENT); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); try { @@ -376,8 +399,12 @@ public class ShadowLocationManagerTest { shadowLocationManager.setBestProvider(LocationManager.GPS_PROVIDER, true); Intent someIntent = new Intent("some_action"); - PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, - someIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent someLocationListenerPendingIntent = + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), + 0, + someIntent, + PendingIntent.FLAG_UPDATE_CURRENT); locationManager.requestLocationUpdates(GPS_PROVIDER, 0, 0, someLocationListenerPendingIntent); assertThat(shadowLocationManager.getRequestLocationUdpateProviderPendingIntents().get(someLocationListenerPendingIntent)).isEqualTo(GPS_PROVIDER); @@ -391,8 +418,12 @@ public class ShadowLocationManagerTest { criteria.setAccuracy(Criteria.ACCURACY_COARSE); Intent someIntent = new Intent("some_action"); - PendingIntent someLocationListenerPendingIntent = PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, - someIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent someLocationListenerPendingIntent = + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), + 0, + someIntent, + PendingIntent.FLAG_UPDATE_CURRENT); Criteria someCriteria = new Criteria(); someCriteria.setAccuracy(Criteria.ACCURACY_COARSE); locationManager.requestLocationUpdates(0, 0, someCriteria, someLocationListenerPendingIntent); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLogTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLogTest.java index 7639e6116..ace202301 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLogTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLogTest.java @@ -8,16 +8,16 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.util.Log; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.Iterables; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.ShadowLog.LogItem; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLogTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLooperTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLooperTest.java index 015c7532c..11d997891 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLooperTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLooperTest.java @@ -8,6 +8,8 @@ import android.content.Context; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; @@ -17,12 +19,11 @@ import org.junit.Test; import org.junit.rules.TestName; import org.junit.runner.RunWith; import org.robolectric.RoboSettings; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.Scheduler; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLooperTest { // testName is used when creating background threads. Makes it @@ -45,11 +46,11 @@ public class ShadowLooperTest { private boolean hasContinued = false; private Looper looper; private CountDownLatch started = new CountDownLatch(1); - + public QuitThread() { super(testName.getMethodName()); } - + @Override public void run() { Looper.prepare(); @@ -59,14 +60,14 @@ public class ShadowLooperTest { hasContinued = true; } } - + private QuitThread getQuitThread() throws InterruptedException { QuitThread qt = new QuitThread(); qt.start(); qt.started.await(); return qt; } - + @Test public void mainLooper_andMyLooper_shouldBeSame_onMainThread() { assertThat(Looper.myLooper()).isSameAs(Looper.getMainLooper()); @@ -87,18 +88,18 @@ public class ShadowLooperTest { public void shadowMainLooper_shouldBeShadowOfMainLooper() { assertThat(ShadowLooper.getShadowMainLooper()).isSameAs(shadowOf(Looper.getMainLooper())); } - + @Test public void getLooperForThread_returnsLooperForAThreadThatHasOne() throws InterruptedException { QuitThread qt = getQuitThread(); assertThat(ShadowLooper.getLooperForThread(qt)).isSameAs(qt.looper); } - + @Test public void getLooperForThread_returnsLooperForMainThread() { assertThat(ShadowLooper.getLooperForThread(Thread.currentThread())).isSameAs(Looper.getMainLooper()); } - + @Test public void idleMainLooper_executesScheduledTasks() { final boolean[] wasRun = new boolean[]{false}; @@ -216,12 +217,12 @@ public class ShadowLooperTest { test.join(5000); assertThat(test.hasContinued).named("hasContinued:after").isTrue(); } - + @Test(timeout = 1000) public void whenTestHarnessUsesDifferentThread_shouldStillHaveMainLooper() { assertThat(Looper.myLooper()).isSameAs(Looper.getMainLooper()); } - + @Test public void resetThreadLoopers_fromNonMainThread_shouldThrowISE() throws InterruptedException { final AtomicReference<Throwable> ex = new AtomicReference<>(); @@ -239,18 +240,23 @@ public class ShadowLooperTest { t.join(); assertThat(ex.get()).isInstanceOf(IllegalStateException.class); } - + @Test public void soStaticRefsToLoopersInAppWorksAcrossTests_shouldRetainSameLooperForMainThreadBetweenResetsButGiveItAFreshScheduler() throws Exception { Looper mainLooper = Looper.getMainLooper(); Scheduler scheduler = shadowOf(mainLooper).getScheduler(); shadowOf(mainLooper).quit = true; - assertThat(RuntimeEnvironment.application.getMainLooper()).isSameAs(mainLooper); + assertThat(ApplicationProvider.getApplicationContext().getMainLooper()).isSameAs(mainLooper); Scheduler s = new Scheduler(); RuntimeEnvironment.setMasterScheduler(s); ShadowLooper.resetThreadLoopers(); Application application = new Application(); - ReflectionHelpers.callInstanceMethod(application, "attach", ReflectionHelpers.ClassParameter.from(Context.class, RuntimeEnvironment.application.getBaseContext())); + ReflectionHelpers.callInstanceMethod( + application, + "attach", + ReflectionHelpers.ClassParameter.from( + Context.class, + ((Application) ApplicationProvider.getApplicationContext()).getBaseContext())); assertThat(Looper.getMainLooper()).named("Looper.getMainLooper()").isSameAs(mainLooper); assertThat(application.getMainLooper()).named("app.getMainLooper()").isSameAs(mainLooper); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLruTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLruTest.java index 81182a41a..cecf93e09 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowLruTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLruTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.util.LruCache; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowLruTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMarginLayoutParamsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMarginLayoutParamsTest.java index ca9c322fd..e9aedf4b5 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMarginLayoutParamsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMarginLayoutParamsTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.view.ViewGroup; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMarginLayoutParamsTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMatrixCursorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMatrixCursorTest.java index 248f8415c..d38d7825e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMatrixCursorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMatrixCursorTest.java @@ -6,13 +6,13 @@ import static org.junit.Assert.assertTrue; import android.database.CursorIndexOutOfBoundsException; import android.database.MatrixCursor; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Arrays; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMatrixCursorTest { private MatrixCursor singleColumnSingleNullValueMatrixCursor; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMatrixTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMatrixTest.java index 892c2c84f..9ac75226c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMatrixTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMatrixTest.java @@ -7,12 +7,12 @@ import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.RectF; import android.os.Build; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMatrixTest { private static final float EPSILON = 1e-7f; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaMetadataRetrieverTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaMetadataRetrieverTest.java index c590b5d3d..b9e85e007 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaMetadataRetrieverTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaMetadataRetrieverTest.java @@ -10,19 +10,20 @@ import static org.robolectric.shadows.ShadowMediaMetadataRetriever.addFrame; import static org.robolectric.shadows.ShadowMediaMetadataRetriever.addMetadata; import static org.robolectric.shadows.util.DataSource.toDataSource; +import android.app.Application; import android.content.Context; import android.graphics.Bitmap; import android.media.MediaMetadataRetriever; import android.net.Uri; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.FileDescriptor; import java.util.HashMap; import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMediaMetadataRetrieverTest { private final String path = "/media/foo.mp3"; private final String path2 = "/media/foo2.mp3"; @@ -78,7 +79,7 @@ public class ShadowMediaMetadataRetrieverTest { @Test public void getFrameAtTime_shouldDependOnTime() { - Context context = RuntimeEnvironment.application; + Context context = (Application) ApplicationProvider.getApplicationContext(); Uri uri = Uri.parse(path); addFrame(context, uri, 12, bitmap); addFrame(context, uri, 13, bitmap2); @@ -91,7 +92,7 @@ public class ShadowMediaMetadataRetrieverTest { @Test public void setDataSource_ignoresHeadersWhenShadowed() { - Context context = RuntimeEnvironment.application; + Context context = (Application) ApplicationProvider.getApplicationContext(); Uri uri = Uri.parse(path); Map<String, String> headers = new HashMap<>(); headers.put("cookie", "nomnomnom"); @@ -126,7 +127,7 @@ public class ShadowMediaMetadataRetrieverTest { throw new RuntimeException("Shouldn't throw exception after reset", e); } } - + @Test public void setDataSourceException_withAllowedException() { RuntimeException e = new RuntimeException("some dummy message"); @@ -137,8 +138,8 @@ public class ShadowMediaMetadataRetrieverTest { } catch (Exception caught) { assertThat(caught).isSameAs(e); assertThat(e.getStackTrace()[0].getClassName()) - .named("Stack trace should originate in Shadow") - .isEqualTo(ShadowMediaMetadataRetriever.class.getName()); + .named("Stack trace should originate in Shadow") + .isEqualTo(ShadowMediaMetadataRetriever.class.getName()); } } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaPlayerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaPlayerTest.java index 105239099..a741a2689 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaPlayerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaPlayerTest.java @@ -17,10 +17,13 @@ import static org.robolectric.shadows.ShadowMediaPlayer.State.STOPPED; import static org.robolectric.shadows.ShadowMediaPlayer.addException; import static org.robolectric.shadows.util.DataSource.toDataSource; +import android.app.Application; import android.media.AudioManager; import android.media.MediaPlayer; import android.net.Uri; import android.os.Looper; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -38,8 +41,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowMediaPlayer.InvalidStateBehavior; @@ -50,7 +51,7 @@ import org.robolectric.shadows.util.DataSource; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.Scheduler; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMediaPlayerTest { private static final String DUMMY_SOURCE = "dummy-source"; @@ -101,15 +102,20 @@ public class ShadowMediaPlayerTest { public void create_withResourceId_shouldSetDataSource() { ShadowMediaPlayer.addMediaInfo( DataSource.toDataSource( - "android.resource://" + RuntimeEnvironment.application.getPackageName() + "/123"), + "android.resource://" + + ((Application) ApplicationProvider.getApplicationContext()).getPackageName() + + "/123"), new ShadowMediaPlayer.MediaInfo(100, 10)); - MediaPlayer mp = MediaPlayer.create(RuntimeEnvironment.application, 123); + MediaPlayer mp = + MediaPlayer.create((Application) ApplicationProvider.getApplicationContext(), 123); ShadowMediaPlayer shadow = shadowOf(mp); assertThat(shadow.getDataSource()) .isEqualTo( DataSource.toDataSource( - "android.resource://" + RuntimeEnvironment.application.getPackageName() + "/123")); + "android.resource://" + + ((Application) ApplicationProvider.getApplicationContext()).getPackageName() + + "/123")); } @Test @@ -164,10 +170,12 @@ public class ShadowMediaPlayerTest { public void testSetDataSourceUri() throws IOException { Map<String, String> headers = new HashMap<>(); Uri uri = Uri.parse("file:/test"); - DataSource ds = toDataSource(RuntimeEnvironment.application, uri, headers); + DataSource ds = + toDataSource((Application) ApplicationProvider.getApplicationContext(), uri, headers); ShadowMediaPlayer.addMediaInfo(ds, info); - mediaPlayer.setDataSource(RuntimeEnvironment.application, uri, headers); + mediaPlayer.setDataSource( + (Application) ApplicationProvider.getApplicationContext(), uri, headers); assertThat(shadowMediaPlayer.getSourceUri()).named("sourceUri").isSameAs(uri); assertThat(shadowMediaPlayer.getDataSource()).named("dataSource").isEqualTo(ds); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaRecorderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaRecorderTest.java index cbba30a5a..85b02fa61 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaRecorderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaRecorderTest.java @@ -5,14 +5,14 @@ import static com.google.common.truth.Truth.assertThat; import android.hardware.Camera; import android.media.MediaRecorder; import android.view.Surface; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMediaRecorderTest { private MediaRecorder mediaRecorder; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaRouterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaRouterTest.java index 71dec9ebd..3a81bd151 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaRouterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaRouterTest.java @@ -8,25 +8,29 @@ import static android.os.Build.VERSION_CODES.N; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.media.MediaRouter; import android.media.MediaRouter.RouteInfo; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; /** Tests for {@link ShadowMediaRouter}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public final class ShadowMediaRouterTest { private MediaRouter mediaRouter; @Before public void setUp() throws Exception { mediaRouter = - (MediaRouter) RuntimeEnvironment.application.getSystemService(Context.MEDIA_ROUTER_SERVICE); + (MediaRouter) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.MEDIA_ROUTER_SERVICE); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaSessionTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaSessionTest.java new file mode 100644 index 000000000..6c86aa040 --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaSessionTest.java @@ -0,0 +1,21 @@ +package org.robolectric.shadows; + +import android.app.Application; +import android.media.session.MediaSession; +import android.os.Build; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +/** Tests for robolectric functionality around {@link MediaSession}. */ +@RunWith(AndroidJUnit4.class) +@Config(minSdk = Build.VERSION_CODES.LOLLIPOP) +public class ShadowMediaSessionTest { + @Test + public void mediaSessionCompat_creation() throws Exception { + // Should not result in an exception. + new MediaSession((Application) ApplicationProvider.getApplicationContext(), "test"); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaStoreTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaStoreTest.java index bc0726531..1196fbfb2 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaStoreTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMediaStoreTest.java @@ -4,11 +4,11 @@ import static android.provider.MediaStore.Images; import static android.provider.MediaStore.Video; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMediaStoreTest { @Test public void shouldInitializeFields() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMergeCursorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMergeCursorTest.java index 7680d5f1b..49510b2fe 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMergeCursorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMergeCursorTest.java @@ -6,12 +6,12 @@ import android.database.Cursor; import android.database.MergeCursor; import android.database.sqlite.SQLiteCursor; import android.database.sqlite.SQLiteDatabase; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMergeCursorTest { private SQLiteDatabase database; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMessageQueueTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMessageQueueTest.java index 492f238c2..98d7597d2 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMessageQueueTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMessageQueueTest.java @@ -16,18 +16,18 @@ import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.os.SystemClock; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.Scheduler; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMessageQueueTest { private Looper looper; private MessageQueue queue; @@ -36,34 +36,34 @@ public class ShadowMessageQueueTest { private TestHandler handler; private Scheduler scheduler; private String quitField; - + private static class TestHandler extends Handler { public List<Message> handled = new ArrayList<>(); - + public TestHandler(Looper looper) { super(looper); } - + @Override public void handleMessage(Message msg) { handled.add(msg); } } - + private static Looper newLooper() { return newLooper(true); } - + private static Looper newLooper(boolean canQuit) { return callConstructor(Looper.class, from(boolean.class, canQuit)); } - + @Before public void setUp() throws Exception { // Queues and loopers are closely linked; can't easily test one without the other. looper = newLooper(); handler = new TestHandler(looper); - queue = looper.getQueue(); + queue = looper.getQueue(); shadowQueue = shadowOf(queue); scheduler = shadowQueue.getScheduler(); scheduler.pause(); @@ -81,7 +81,7 @@ public class ShadowMessageQueueTest { return callInstanceMethod(queue, "enqueueMessage", from(Message.class, msg), from(long.class, when) - ); + ); } private void removeMessages(Handler handler, int what, Object token) { @@ -91,7 +91,7 @@ public class ShadowMessageQueueTest { from(Object.class, token) ); } - + @Test public void enqueueMessage_setsHead() { enqueueMessage(testMessage, 100); @@ -108,7 +108,7 @@ public class ShadowMessageQueueTest { enqueueMessage(testMessage, 123); assertThat(testMessage.getWhen()).named("when").isEqualTo(123); } - + @Test public void enqueueMessage_returnsFalse_whenQuitting() { setField(queue, quitField, true); @@ -121,7 +121,7 @@ public class ShadowMessageQueueTest { enqueueMessage(testMessage, 1); assertThat(scheduler.size()).named("scheduler_size").isEqualTo(0); } - + @Test public void enqueuedMessage_isSentToHandler() { enqueueMessage(testMessage, 200); @@ -130,7 +130,7 @@ public class ShadowMessageQueueTest { scheduler.advanceTo(200); assertThat(handler.handled).named("handled:after").containsExactly(testMessage); } - + @Test public void removedMessage_isNotSentToHandler() { enqueueMessage(testMessage, 200); @@ -149,7 +149,7 @@ public class ShadowMessageQueueTest { scheduler.advanceToLastPostedRunnable(); assertThat(handler.handled).named("handled").containsExactly(m2, testMessage); } - + @Test public void dispatchedMessage_isMarkedInUse_andRecycled() { Handler handler = new Handler(looper) { @@ -166,16 +166,16 @@ public class ShadowMessageQueueTest { Message msg2 = handler.obtainMessage(2); enqueueMessage(msg2, 205); scheduler.advanceToNextPostedRunnable(); - + // Check that it's been properly recycled. assertThat(msg.what).named("msg.what").isEqualTo(0); - + scheduler.advanceToNextPostedRunnable(); assertThat(msg2.what).named("msg2.what").isEqualTo(0); } - - @Test + + @Test public void reset_shouldClearMessageQueue() { Message msg = handler.obtainMessage(1234); Message msg2 = handler.obtainMessage(5678); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMessageTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMessageTest.java index 8d647c154..8699bd549 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMessageTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMessageTest.java @@ -8,15 +8,15 @@ import static org.robolectric.Shadows.shadowOf; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.Scheduler; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMessageTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMessengerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMessengerTest.java index dbf5c722e..7d1a64c7b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMessengerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMessengerTest.java @@ -5,11 +5,11 @@ import static com.google.common.truth.Truth.assertThat; import android.os.Handler; import android.os.Message; import android.os.Messenger; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMessengerTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMimeTypeMapTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMimeTypeMapTest.java index 61bc58e5f..7e4060b58 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMimeTypeMapTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMimeTypeMapTest.java @@ -8,12 +8,12 @@ import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; import android.webkit.MimeTypeMap; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMimeTypeMapTest { private static final String IMAGE_EXTENSION = "jpg"; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowMotionEventTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowMotionEventTest.java index 33d21b70a..03c8afb60 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowMotionEventTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowMotionEventTest.java @@ -5,12 +5,12 @@ import static org.junit.Assert.assertEquals; import static org.robolectric.Shadows.shadowOf; import android.view.MotionEvent; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowMotionEventTest { private MotionEvent event; private ShadowMotionEvent shadowMotionEvent; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkInfoTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkInfoTest.java index 6e46c336b..6b23f09d6 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkInfoTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkInfoTest.java @@ -4,12 +4,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.net.NetworkInfo; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowNetworkInfoTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkScoreManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkScoreManagerTest.java index 81a11439a..915a024e0 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkScoreManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkScoreManagerTest.java @@ -3,16 +3,17 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.Context; import android.net.NetworkScoreManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; /** ShadowNetworkScoreManagerTest tests {@link ShadowNetworkScoreManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public final class ShadowNetworkScoreManagerTest { @Test @@ -20,7 +21,8 @@ public final class ShadowNetworkScoreManagerTest { public void testGetActiveScorerPackage() throws Exception { NetworkScoreManager networkScoreManager = (NetworkScoreManager) - RuntimeEnvironment.application.getSystemService(Context.NETWORK_SCORE_SERVICE); + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.NETWORK_SCORE_SERVICE); String testPackage = "com.package.test"; networkScoreManager.setActiveScorer(testPackage); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkTest.java index 0afaed41f..bc5a473a9 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNetworkTest.java @@ -6,16 +6,16 @@ import static android.os.Build.VERSION_CODES.M; import static com.google.common.truth.Truth.assertThat; import android.net.Network; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.FileDescriptor; import java.net.DatagramSocket; import java.net.Socket; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowNetworkTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNfcAdapterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNfcAdapterTest.java index 5f881de9e..5d24cea9b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNfcAdapterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNfcAdapterTest.java @@ -5,18 +5,19 @@ import static org.mockito.Mockito.mock; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.Application; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowNfcAdapterTest { @Rule public ExpectedException expectedException = ExpectedException.none(); @@ -71,7 +72,8 @@ public class ShadowNfcAdapterTest { @Test public void isEnabled_shouldReturnEnabledState() { - final NfcAdapter adapter = NfcAdapter.getDefaultAdapter(RuntimeEnvironment.application); + final NfcAdapter adapter = + NfcAdapter.getDefaultAdapter((Application) ApplicationProvider.getApplicationContext()); assertThat(adapter.isEnabled()).isFalse(); shadowOf(adapter).setEnabled(true); @@ -83,21 +85,24 @@ public class ShadowNfcAdapterTest { @Test public void getNfcAdapter_returnsNonNull() { - NfcAdapter adapter = NfcAdapter.getDefaultAdapter(RuntimeEnvironment.application); + NfcAdapter adapter = + NfcAdapter.getDefaultAdapter((Application) ApplicationProvider.getApplicationContext()); assertThat(adapter).isNotNull(); } @Test public void getNfcAdapter_hardwareExists_returnsNonNull() { ShadowNfcAdapter.setNfcHardwareExists(true); - NfcAdapter adapter = NfcAdapter.getDefaultAdapter(RuntimeEnvironment.application); + NfcAdapter adapter = + NfcAdapter.getDefaultAdapter((Application) ApplicationProvider.getApplicationContext()); assertThat(adapter).isNotNull(); } @Test public void getNfcAdapter_hardwareDoesNotExist_returnsNull() { ShadowNfcAdapter.setNfcHardwareExists(false); - NfcAdapter adapter = NfcAdapter.getDefaultAdapter(RuntimeEnvironment.application); + NfcAdapter adapter = + NfcAdapter.getDefaultAdapter((Application) ApplicationProvider.getApplicationContext()); assertThat(adapter).isNull(); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationBuilder25Test.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationBuilder25Test.java index 6e023b483..d43b0c173 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationBuilder25Test.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationBuilder25Test.java @@ -1,12 +1,13 @@ package org.robolectric.shadows; +import android.app.Application; import android.os.Build; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowNotificationBuilder25Test extends ShadowNotificationBuilderTest { /** @@ -15,7 +16,12 @@ public class ShadowNotificationBuilder25Test extends ShadowNotificationBuilderTe */ @Before public void setup() throws Exception { - RuntimeEnvironment.application.getPackageManager().getPackageInfo("org.robolectric", 0).applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; + ((Application) ApplicationProvider.getApplicationContext()) + .getPackageManager() + .getPackageInfo("org.robolectric", 0) + .applicationInfo + .targetSdkVersion = + Build.VERSION_CODES.N_MR1; } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationBuilderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationBuilderTest.java index 01eaed708..2f231a576 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationBuilderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationBuilderTest.java @@ -7,22 +7,24 @@ import static android.os.Build.VERSION_CODES.N; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.Notification; import android.app.PendingIntent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Icon; import android.text.SpannableString; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowNotificationBuilderTest { - private final Notification.Builder builder = new Notification.Builder(RuntimeEnvironment.application); + private final Notification.Builder builder = + new Notification.Builder((Application) ApplicationProvider.getApplicationContext()); @Test public void build_setsContentTitleOnNotification() throws Exception { @@ -210,7 +212,9 @@ public class ShadowNotificationBuilderTest { @Test @Config(minSdk = JELLY_BEAN_MR2) public void build_addsActionToNotification() throws Exception { - PendingIntent action = PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, null, 0); + PendingIntent action = + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, null, 0); Notification notification = builder.addAction(0, "Action", action).build(); assertThat(notification.actions[0].actionIntent).isEqualTo(action); @@ -233,7 +237,10 @@ public class ShadowNotificationBuilderTest { @Test @Config(minSdk = M) public void withBigPictureStyle() { - Bitmap bigPicture = BitmapFactory.decodeResource(RuntimeEnvironment.application.getResources(), R.drawable.an_image); + Bitmap bigPicture = + BitmapFactory.decodeResource( + ((Application) ApplicationProvider.getApplicationContext()).getResources(), + R.drawable.an_image); Icon bigLargeIcon = Icon.createWithBitmap(bigPicture); Notification notification = builder.setStyle(new Notification.BigPictureStyle(builder) diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationManagerTest.java index ec98f5d1f..26bf9e6fb 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationManagerTest.java @@ -8,6 +8,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.AutomaticZenRule; import android.app.Notification; import android.app.NotificationChannel; @@ -19,24 +20,27 @@ import android.content.Context; import android.net.Uri; import android.os.Build; import android.service.notification.StatusBarNotification; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class ShadowNotificationManagerTest { private NotificationManager notificationManager; private Notification notification1 = new Notification(); private Notification notification2 = new Notification(); @Before public void setUp() { - notificationManager = (NotificationManager) RuntimeEnvironment.application.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager = + (NotificationManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.NOTIFICATION_SERVICE); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationTest.java index ae3b673ee..e7e51163e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNotificationTest.java @@ -6,11 +6,11 @@ import static org.robolectric.RuntimeEnvironment.application; import android.app.Notification; import android.app.PendingIntent; import android.content.Intent; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowNotificationTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowNumberPickerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowNumberPickerTest.java index 7eb996a55..9044a0dd9 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowNumberPickerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowNumberPickerTest.java @@ -3,19 +3,21 @@ package org.robolectric.shadows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import android.app.Application; import android.widget.NumberPicker; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowNumberPickerTest { @Test public void shouldFireListeners() { - NumberPicker picker = new NumberPicker(RuntimeEnvironment.application); + NumberPicker picker = + new NumberPicker((Application) ApplicationProvider.getApplicationContext()); NumberPicker.OnValueChangeListener listener = mock(NumberPicker.OnValueChangeListener.class); picker.setOnValueChangedListener(listener); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowObjectAnimatorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowObjectAnimatorTest.java index 89720f107..736f73352 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowObjectAnimatorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowObjectAnimatorTest.java @@ -4,14 +4,14 @@ import static com.google.common.truth.Truth.assertThat; import android.animation.Animator; import android.animation.ObjectAnimator; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowObjectAnimatorTest { private final AnimatorTarget target = new AnimatorTarget(); private List<String> listenerEvents = new ArrayList<>(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowOpenGLMatrixTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowOpenGLMatrixTest.java index cce37507a..c4429fb89 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowOpenGLMatrixTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowOpenGLMatrixTest.java @@ -5,12 +5,12 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static com.google.common.truth.Truth.assertThat; import android.opengl.Matrix; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowOpenGLMatrixTest { @Test(expected = IllegalArgumentException.class) public void multiplyMM_failIfResIsNull() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowOutlineTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowOutlineTest.java index 045141725..7870d7ca2 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowOutlineTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowOutlineTest.java @@ -4,12 +4,12 @@ import static android.os.Build.VERSION_CODES.LOLLIPOP; import android.graphics.Outline; import android.graphics.Path; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowOutlineTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowOverScrollerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowOverScrollerTest.java index 38e7d1e1e..b4c0724ba 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowOverScrollerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowOverScrollerTest.java @@ -2,21 +2,24 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.view.animation.LinearInterpolator; import android.widget.OverScroller; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowOverScrollerTest { private OverScroller overScroller; @Before public void setUp() { - overScroller = new OverScroller(RuntimeEnvironment.application, new LinearInterpolator()); + overScroller = + new OverScroller( + (Application) ApplicationProvider.getApplicationContext(), new LinearInterpolator()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageInstallerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageInstallerTest.java index 7ccff19af..47bff61cf 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageInstallerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageInstallerTest.java @@ -6,20 +6,21 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.IIntentSender; import android.content.IntentSender; import android.content.pm.PackageInstaller; import android.os.Handler; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.OutputStream; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowPackageInstallerTest { @@ -30,7 +31,10 @@ public class ShadowPackageInstallerTest { @Before public void setUp() { - packageInstaller = RuntimeEnvironment.application.getPackageManager().getPackageInstaller(); + packageInstaller = + ((Application) ApplicationProvider.getApplicationContext()) + .getPackageManager() + .getPackageInstaller(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java index 327f3eedf..3be41a2ff 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPackageManagerTest.java @@ -33,9 +33,6 @@ import static android.os.Build.VERSION_CODES.N_MR1; import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -81,6 +78,8 @@ import android.os.Bundle; import android.os.PersistableBundle; import android.os.Process; import android.provider.DocumentsContract; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.base.Function; import com.google.common.collect.Iterables; import java.io.ByteArrayInputStream; @@ -96,12 +95,10 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowPackageManager.PackageSetting; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPackageManagerTest { private static final String TEST_PACKAGE_NAME = "com.some.other.package"; @@ -119,14 +116,18 @@ public class ShadowPackageManagerTest { @Before public void setUp() { - packageManager = RuntimeEnvironment.application.getPackageManager(); + packageManager = + ApplicationProvider.getApplicationContext().getPackageManager(); shadowPackageManager = shadowOf(packageManager); } @Test @Config(minSdk = LOLLIPOP) public void packageInstallerCreateSession() throws Exception { - PackageInstaller packageInstaller = RuntimeEnvironment.application.getPackageManager().getPackageInstaller(); + PackageInstaller packageInstaller = + ApplicationProvider.getApplicationContext() + .getPackageManager() + .getPackageInstaller(); int sessionId = packageInstaller.createSession(createSessionParams("packageName")); PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId); @@ -142,7 +143,10 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void packageInstallerOpenSession() throws Exception { - PackageInstaller packageInstaller = RuntimeEnvironment.application.getPackageManager().getPackageInstaller(); + PackageInstaller packageInstaller = + ApplicationProvider.getApplicationContext() + .getPackageManager() + .getPackageInstaller(); int sessionId = packageInstaller.createSession(createSessionParams("packageName")); PackageInstaller.Session session = packageInstaller.openSession(sessionId); @@ -159,7 +163,7 @@ public class ShadowPackageManagerTest { @Test public void packageInstallerAndGetPackageArchiveInfo() { ApplicationInfo appInfo = new ApplicationInfo(); - appInfo.flags = 0; + appInfo.flags = ApplicationInfo.FLAG_INSTALLED; appInfo.packageName = TEST_PACKAGE_NAME; appInfo.sourceDir = TEST_APP_PATH; appInfo.name = TEST_PACKAGE_LABEL; @@ -200,7 +204,8 @@ public class ShadowPackageManagerTest { */ @Test public void testCheckPermission_thisPackage() throws Exception { - String thisPackage = RuntimeEnvironment.application.getPackageName(); + String thisPackage = + ApplicationProvider.getApplicationContext().getPackageName(); assertEquals(PERMISSION_GRANTED, packageManager.checkPermission( "android.permission.INTERNET", thisPackage)); assertEquals(PERMISSION_GRANTED, packageManager.checkPermission( @@ -340,7 +345,7 @@ public class ShadowPackageManagerTest { @Test public void testQueryBroadcastReceiverSucceeds() { Intent intent = new Intent("org.robolectric.ACTION_RECEIVER_PERMISSION_PACKAGE"); - intent.setPackage(RuntimeEnvironment.application.getPackageName()); + intent.setPackage(ApplicationProvider.getApplicationContext().getPackageName()); List<ResolveInfo> receiverInfos = packageManager.queryBroadcastReceivers(intent, PackageManager.GET_INTENT_FILTERS); assertThat(receiverInfos).isNotEmpty(); @@ -356,13 +361,13 @@ public class ShadowPackageManagerTest { public void testQueryBroadcastReceiverFailsForMissingPackageName() { Intent intent = new Intent("org.robolectric.ACTION_ONE_MORE_PACKAGE"); List<ResolveInfo> receiverInfos = packageManager.queryBroadcastReceivers(intent, PackageManager.GET_INTENT_FILTERS); - assertTrue(receiverInfos.size() == 0); + assertThat(receiverInfos).hasSize(0); } @Test public void testQueryBroadcastReceiver_matchAllWithoutIntentFilter() { Intent intent = new Intent(); - intent.setPackage(RuntimeEnvironment.application.getPackageName()); + intent.setPackage(ApplicationProvider.getApplicationContext().getPackageName()); List<ResolveInfo> receiverInfos = packageManager.queryBroadcastReceivers(intent, PackageManager.GET_INTENT_FILTERS); assertThat(receiverInfos).hasSize(7); @@ -374,7 +379,10 @@ public class ShadowPackageManagerTest { @Test public void testGetPackageInfo_ForReceiversSucceeds() throws Exception { - PackageInfo receiverInfos = packageManager.getPackageInfo(RuntimeEnvironment.application.getPackageName(), PackageManager.GET_RECEIVERS); + PackageInfo receiverInfos = + packageManager.getPackageInfo( + ApplicationProvider.getApplicationContext().getPackageName(), + PackageManager.GET_RECEIVERS); assertThat(receiverInfos.receivers).isNotEmpty(); assertThat(receiverInfos.receivers[0].name).isEqualTo("org.robolectric.ConfigTestReceiver.InnerReceiver"); @@ -433,7 +441,7 @@ public class ShadowPackageManagerTest { @Test public void getPermissionGroupInfo_fromManifest() throws Exception { PermissionGroupInfo permissionGroupInfo = - RuntimeEnvironment.application + ApplicationProvider.getApplicationContext() .getPackageManager() .getPermissionGroupInfo("org.robolectric.package_permission_group", 0); assertThat(permissionGroupInfo.name).isEqualTo("org.robolectric.package_permission_group"); @@ -478,7 +486,7 @@ public class ShadowPackageManagerTest { // Package 1 Package pkg = new Package(TEST_PACKAGE_NAME); ApplicationInfo appInfo = pkg.applicationInfo; - appInfo.flags = 0; + appInfo.flags = ApplicationInfo.FLAG_INSTALLED; appInfo.packageName = TEST_PACKAGE_NAME; appInfo.sourceDir = TEST_APP_PATH; appInfo.name = TEST_PACKAGE_LABEL; @@ -498,7 +506,7 @@ public class ShadowPackageManagerTest { // Package 2, contains one permission group that is the same Package pkg2 = new Package(TEST_PACKAGE2_NAME); ApplicationInfo appInfo2 = pkg2.applicationInfo; - appInfo2.flags = 0; + appInfo2.flags = ApplicationInfo.FLAG_INSTALLED; appInfo2.packageName = TEST_PACKAGE2_NAME; appInfo2.sourceDir = TEST_APP2_PATH; appInfo2.name = TEST_PACKAGE2_LABEL; @@ -524,7 +532,7 @@ public class ShadowPackageManagerTest { @Test public void getPackageArchiveInfo() { ApplicationInfo appInfo = new ApplicationInfo(); - appInfo.flags = 0; + appInfo.flags = ApplicationInfo.FLAG_INSTALLED; appInfo.packageName = TEST_PACKAGE_NAME; appInfo.sourceDir = TEST_APP_PATH; appInfo.name = TEST_PACKAGE_LABEL; @@ -544,27 +552,39 @@ public class ShadowPackageManagerTest { @Test public void getApplicationInfo_ThisApplication() throws Exception { - ApplicationInfo info = packageManager.getApplicationInfo(RuntimeEnvironment.application.getPackageName(), 0); + ApplicationInfo info = + packageManager.getApplicationInfo( + ApplicationProvider.getApplicationContext().getPackageName(), 0); assertThat(info).isNotNull(); - assertThat(info.packageName).isEqualTo(RuntimeEnvironment.application.getPackageName()); + assertThat(info.packageName) + .isEqualTo(ApplicationProvider.getApplicationContext().getPackageName()); } @Test public void getApplicationInfo_uninstalledApplication_includeUninstalled() throws Exception { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); - ApplicationInfo info = packageManager.getApplicationInfo(RuntimeEnvironment.application.getPackageName(), MATCH_UNINSTALLED_PACKAGES); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); + ApplicationInfo info = + packageManager.getApplicationInfo( + ApplicationProvider.getApplicationContext().getPackageName(), + MATCH_UNINSTALLED_PACKAGES); assertThat(info).isNotNull(); - assertThat(info.packageName).isEqualTo(RuntimeEnvironment.application.getPackageName()); + assertThat(info.packageName) + .isEqualTo(ApplicationProvider.getApplicationContext().getPackageName()); } @Test public void getApplicationInfo_uninstalledApplication_dontIncludeUninstalled() throws Exception { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); try { - packageManager.getApplicationInfo(RuntimeEnvironment.application.getPackageName(), 0); + packageManager.getApplicationInfo( + ApplicationProvider.getApplicationContext().getPackageName(), 0); fail("PackageManager.NameNotFoundException not thrown"); } catch (PackageManager.NameNotFoundException e) { // expected @@ -574,11 +594,16 @@ public class ShadowPackageManagerTest { @Test public void getApplicationInfo_disabledApplication_includeDisabled() throws Exception { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); - ApplicationInfo info = packageManager.getApplicationInfo( - RuntimeEnvironment.application.getPackageName(), MATCH_DISABLED_COMPONENTS); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); + ApplicationInfo info = + packageManager.getApplicationInfo( + ApplicationProvider.getApplicationContext().getPackageName(), + MATCH_DISABLED_COMPONENTS); assertThat(info).isNotNull(); - assertThat(info.packageName).isEqualTo(RuntimeEnvironment.application.getPackageName()); + assertThat(info.packageName) + .isEqualTo(ApplicationProvider.getApplicationContext().getPackageName()); } @Test(expected = PackageManager.NameNotFoundException.class) @@ -654,6 +679,23 @@ public class ShadowPackageManagerTest { } @Test + public void queryIntentActivities_ServiceMatch() throws Exception { + Intent i = new Intent("SomeStrangeAction"); + + ResolveInfo info = new ResolveInfo(); + info.nonLocalizedLabel = TEST_PACKAGE_LABEL; + info.serviceInfo = new ServiceInfo(); + info.serviceInfo.name = "name"; + info.serviceInfo.packageName = TEST_PACKAGE_NAME; + + shadowPackageManager.addResolveInfoForIntent(i, info); + + List<ResolveInfo> activities = packageManager.queryIntentActivities(i, 0); + assertThat(activities).isNotNull(); + assertThat(activities).isEmpty(); + } + + @Test @Config(minSdk = JELLY_BEAN_MR1) public void queryIntentActivitiesAsUser_EmptyResult() throws Exception { Intent i = new Intent(Intent.ACTION_APP_ERROR, null); @@ -727,7 +769,9 @@ public class ShadowPackageManagerTest { @Test public void queryIntentActivities_MatchWithExplicitIntent() throws Exception { Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "org.robolectric.shadows.TestActivity"); + i.setClassName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.TestActivity"); List<ResolveInfo> activities = packageManager.queryIntentActivities(i, 0); assertThat(activities).isNotNull(); @@ -768,10 +812,14 @@ public class ShadowPackageManagerTest { @Test public void queryIntentActivities_DisabledComponentExplicitIntent() throws Exception { Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "org.robolectric.shadows.TestActivity"); + i.setClassName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.TestActivity"); ComponentName componentToDisable = - new ComponentName(RuntimeEnvironment.application, "org.robolectric.shadows.TestActivity"); + new ComponentName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.TestActivity"); packageManager.setComponentEnabledSetting( componentToDisable, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, @@ -789,7 +837,9 @@ public class ShadowPackageManagerTest { i.setDataAndType(uri, "image/jpeg"); ComponentName componentToDisable = - new ComponentName(RuntimeEnvironment.application, "org.robolectric.shadows.TestActivity"); + new ComponentName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.TestActivity"); packageManager.setComponentEnabledSetting( componentToDisable, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, @@ -807,7 +857,9 @@ public class ShadowPackageManagerTest { i.setDataAndType(uri, "image/jpeg"); ComponentName componentToDisable = - new ComponentName(RuntimeEnvironment.application, "org.robolectric.shadows.TestActivity"); + new ComponentName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.TestActivity"); packageManager.setComponentEnabledSetting( componentToDisable, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, @@ -822,12 +874,15 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void queryIntentActivities_appHidden_includeUninstalled() { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "org.robolectric.shadows.TestActivity"); + i.setClassName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.TestActivity"); List<ResolveInfo> activities = packageManager.queryIntentActivities(i, MATCH_UNINSTALLED_PACKAGES); @@ -840,12 +895,15 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void queryIntentActivities_appHidden_dontIncludeUninstalled() { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "org.robolectric.shadows.TestActivity"); + i.setClassName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.TestActivity"); assertThat(packageManager.queryIntentActivities(i, /* flags= */ 0)).isEmpty(); } @@ -882,7 +940,7 @@ public class ShadowPackageManagerTest { @Test public void queryIntentServices_MatchWithExplicitIntent() throws Exception { Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "com.foo.Service"); + i.setClassName(ApplicationProvider.getApplicationContext(), "com.foo.Service"); List<ResolveInfo> services = packageManager.queryIntentServices(i, 0); assertThat(services).isNotNull(); @@ -917,12 +975,13 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void queryIntentServices_appHidden_includeUninstalled() { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "com.foo.Service"); + i.setClassName(ApplicationProvider.getApplicationContext(), "com.foo.Service"); List<ResolveInfo> services = packageManager.queryIntentServices(i, MATCH_UNINSTALLED_PACKAGES); assertThat(services).hasSize(1); @@ -933,12 +992,13 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void queryIntentServices_appHidden_dontIncludeUninstalled() { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "com.foo.Service"); + i.setClassName(ApplicationProvider.getApplicationContext(), "com.foo.Service"); assertThat(packageManager.queryIntentServices(i, /* flags= */ 0)).isEmpty(); } @@ -980,7 +1040,9 @@ public class ShadowPackageManagerTest { @Test public void queryBroadcastReceivers_MatchWithExplicitIntent() throws Exception { Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "org.robolectric.fakes.ConfigTestReceiver"); + i.setClassName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.fakes.ConfigTestReceiver"); List<ResolveInfo> receivers = packageManager.queryBroadcastReceivers(i, 0); assertThat(receivers).isNotNull(); @@ -993,12 +1055,15 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void queryBroadcastReceivers_appHidden_includeUninstalled() { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "org.robolectric.fakes.ConfigTestReceiver"); + i.setClassName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.fakes.ConfigTestReceiver"); List<ResolveInfo> activities = packageManager.queryBroadcastReceivers(i, MATCH_UNINSTALLED_PACKAGES); @@ -1011,12 +1076,15 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void queryBroadcastReceivers_appHidden_dontIncludeUninstalled() { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); Intent i = new Intent(); - i.setClassName(RuntimeEnvironment.application, "org.robolectric.fakes.ConfigTestReceiver"); + i.setClassName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.fakes.ConfigTestReceiver"); assertThat(packageManager.queryBroadcastReceivers(i, /* flags= */ 0)).isEmpty(); } @@ -1106,12 +1174,15 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void queryIntentContentProviders_appHidden_includeUninstalled() { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); Intent i = new Intent(DocumentsContract.PROVIDER_INTERFACE); - i.setClassName(RuntimeEnvironment.application, "org.robolectric.shadows.TestActivity"); + i.setClassName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.TestActivity"); ResolveInfo resolveInfo = new ResolveInfo(); resolveInfo.providerInfo = new ProviderInfo(); @@ -1225,7 +1296,8 @@ public class ShadowPackageManagerTest { public void getPackageInfo_shouldReturnActivityInfos() throws Exception { PackageInfo packageInfo = packageManager.getPackageInfo( - RuntimeEnvironment.application.getPackageName(), PackageManager.GET_ACTIVITIES); + ApplicationProvider.getApplicationContext().getPackageName(), + PackageManager.GET_ACTIVITIES); ActivityInfo activityInfoWithFilters = findActivity(packageInfo.activities, ActivityWithFilters.class.getName()); assertThat(activityInfoWithFilters.packageName).isEqualTo("org.robolectric"); @@ -1244,7 +1316,10 @@ public class ShadowPackageManagerTest { @Test public void getPackageInfo_getProvidersShouldReturnProviderInfos() throws Exception { - PackageInfo packageInfo = packageManager.getPackageInfo(RuntimeEnvironment.application.getPackageName(), PackageManager.GET_PROVIDERS); + PackageInfo packageInfo = + packageManager.getPackageInfo( + ApplicationProvider.getApplicationContext().getPackageName(), + PackageManager.GET_PROVIDERS); ProviderInfo[] providers = packageInfo.providers; assertThat(providers).isNotEmpty(); assertThat(providers.length).isEqualTo(2); @@ -1254,11 +1329,21 @@ public class ShadowPackageManagerTest { @Test public void getProviderInfo_shouldReturnProviderInfos() throws Exception { - ProviderInfo providerInfo1 = packageManager.getProviderInfo(new ComponentName(RuntimeEnvironment.application, ".shadows.testing.TestContentProvider1"), 0); + ProviderInfo providerInfo1 = + packageManager.getProviderInfo( + new ComponentName( + ApplicationProvider.getApplicationContext(), + ".shadows.testing.TestContentProvider1"), + 0); assertThat(providerInfo1.packageName).isEqualTo("org.robolectric"); assertThat(providerInfo1.authority).isEqualTo("org.robolectric.authority1"); - ProviderInfo providerInfo2 = packageManager.getProviderInfo(new ComponentName(RuntimeEnvironment.application, "org.robolectric.shadows.testing.TestContentProvider2"), 0); + ProviderInfo providerInfo2 = + packageManager.getProviderInfo( + new ComponentName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.testing.TestContentProvider2"), + 0); assertThat(providerInfo2.packageName).isEqualTo("org.robolectric"); assertThat(providerInfo2.authority).isEqualTo("org.robolectric.authority2"); } @@ -1275,7 +1360,12 @@ public class ShadowPackageManagerTest { @Test public void getProviderInfo_shouldPopulatePermissionsInProviderInfos() throws Exception { - ProviderInfo providerInfo = packageManager.getProviderInfo(new ComponentName(RuntimeEnvironment.application, "org.robolectric.shadows.testing.TestContentProvider1"), 0); + ProviderInfo providerInfo = + packageManager.getProviderInfo( + new ComponentName( + ApplicationProvider.getApplicationContext(), + "org.robolectric.shadows.testing.TestContentProvider1"), + 0); assertThat(providerInfo.authority).isEqualTo("org.robolectric.authority1"); assertThat(providerInfo.readPermission).isEqualTo("READ_PERMISSION"); @@ -1294,7 +1384,7 @@ public class ShadowPackageManagerTest { ProviderInfo providerInfo = packageManager.getProviderInfo( new ComponentName( - RuntimeEnvironment.application, + ApplicationProvider.getApplicationContext(), "org.robolectric.shadows.testing.TestContentProvider1"), PackageManager.GET_META_DATA); assertThat(providerInfo.authority).isEqualTo("org.robolectric.authority1"); @@ -1311,7 +1401,12 @@ public class ShadowPackageManagerTest { @Test public void testReceiverInfo() throws Exception { - ActivityInfo info = packageManager.getReceiverInfo(new ComponentName(RuntimeEnvironment.application, ".test.ConfigTestReceiver"), PackageManager.GET_META_DATA); + ActivityInfo info = + packageManager.getReceiverInfo( + new ComponentName( + ApplicationProvider.getApplicationContext(), + ".test.ConfigTestReceiver"), + PackageManager.GET_META_DATA); assertThat(info.metaData.getInt("numberOfSheep")).isEqualTo(42); } @@ -1327,7 +1422,10 @@ public class ShadowPackageManagerTest { @Test public void getPackageInfo_shouldReturnRequestedPermissions() throws Exception { - PackageInfo packageInfo = packageManager.getPackageInfo(RuntimeEnvironment.application.getPackageName(), PackageManager.GET_PERMISSIONS); + PackageInfo packageInfo = + packageManager.getPackageInfo( + ApplicationProvider.getApplicationContext().getPackageName(), + PackageManager.GET_PERMISSIONS); String[] permissions = packageInfo.requestedPermissions; assertThat(permissions).isNotNull(); assertThat(permissions.length).isEqualTo(4); @@ -1336,19 +1434,28 @@ public class ShadowPackageManagerTest { @Test public void getPackageInfo_uninstalledPackage_includeUninstalled() throws Exception { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); - PackageInfo info = packageManager.getPackageInfo(RuntimeEnvironment.application.getPackageName(), MATCH_UNINSTALLED_PACKAGES); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); + PackageInfo info = + packageManager.getPackageInfo( + ApplicationProvider.getApplicationContext().getPackageName(), + MATCH_UNINSTALLED_PACKAGES); assertThat(info).isNotNull(); - assertThat(info.packageName).isEqualTo(RuntimeEnvironment.application.getPackageName()); + assertThat(info.packageName) + .isEqualTo(ApplicationProvider.getApplicationContext().getPackageName()); } @Test public void getPackageInfo_uninstalledPackage_dontIncludeUninstalled() { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); try { - packageManager.getPackageInfo(RuntimeEnvironment.application.getPackageName(), 0); + packageManager.getPackageInfo( + ApplicationProvider.getApplicationContext().getPackageName(), 0); fail("should have thrown NameNotFoundException"); } catch (NameNotFoundException e) { // expected @@ -1358,26 +1465,36 @@ public class ShadowPackageManagerTest { @Test public void getPackageInfo_disabledPackage_includeDisabled() throws Exception { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); - PackageInfo info = packageManager.getPackageInfo( - RuntimeEnvironment.application.getPackageName(), MATCH_DISABLED_COMPONENTS); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); + PackageInfo info = + packageManager.getPackageInfo( + ApplicationProvider.getApplicationContext().getPackageName(), + MATCH_DISABLED_COMPONENTS); assertThat(info).isNotNull(); - assertThat(info.packageName).isEqualTo(RuntimeEnvironment.application.getPackageName()); + assertThat(info.packageName) + .isEqualTo(ApplicationProvider.getApplicationContext().getPackageName()); } @Test public void getInstalledPackages_uninstalledPackage_includeUninstalled() throws Exception { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); assertThat(packageManager.getInstalledPackages(MATCH_UNINSTALLED_PACKAGES)).isNotEmpty(); - assertThat(packageManager.getInstalledPackages(MATCH_UNINSTALLED_PACKAGES).get(0).packageName).isEqualTo(RuntimeEnvironment.application.getPackageName()); + assertThat(packageManager.getInstalledPackages(MATCH_UNINSTALLED_PACKAGES).get(0).packageName) + .isEqualTo(ApplicationProvider.getApplicationContext().getPackageName()); } @Test public void getInstalledPackages_uninstalledPackage_dontIncludeUninstalled() throws Exception { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); assertThat(packageManager.getInstalledPackages(0)).isEmpty(); } @@ -1385,11 +1502,13 @@ public class ShadowPackageManagerTest { @Test public void getInstalledPackages_disabledPackage_includeDisabled() throws Exception { packageManager.setApplicationEnabledSetting( - RuntimeEnvironment.application.getPackageName(), COMPONENT_ENABLED_STATE_DISABLED, 0); + ApplicationProvider.getApplicationContext().getPackageName(), + COMPONENT_ENABLED_STATE_DISABLED, + 0); assertThat(packageManager.getInstalledPackages(MATCH_DISABLED_COMPONENTS)).isNotEmpty(); assertThat(packageManager.getInstalledPackages(MATCH_DISABLED_COMPONENTS).get(0).packageName) - .isEqualTo(RuntimeEnvironment.application.getPackageName()); + .isEqualTo(ApplicationProvider.getApplicationContext().getPackageName()); } @Test @@ -1466,7 +1585,8 @@ public class ShadowPackageManagerTest { @Test public void shouldAssignTheAppMetaDataFromTheManifest() throws Exception { ApplicationInfo info = - packageManager.getApplicationInfo(RuntimeEnvironment.application.getPackageName(), 0); + packageManager.getApplicationInfo( + ApplicationProvider.getApplicationContext().getPackageName(), 0); Bundle meta = info.metaData; assertThat(meta.getString("org.robolectric.metaName1")).isEqualTo("metaValue1"); @@ -1482,20 +1602,31 @@ public class ShadowPackageManagerTest { assertThat(meta.getBoolean("org.robolectric.metaBooleanFromRes")) .isEqualTo( - RuntimeEnvironment.application.getResources().getBoolean(R.bool.false_bool_value)); + ApplicationProvider.getApplicationContext() + .getResources() + .getBoolean(R.bool.false_bool_value)); assertThat(meta.getInt("org.robolectric.metaIntFromRes")) .isEqualTo( - RuntimeEnvironment.application.getResources().getInteger(R.integer.test_integer1)); + ApplicationProvider.getApplicationContext() + .getResources() + .getInteger(R.integer.test_integer1)); assertThat(meta.getInt("org.robolectric.metaColorFromRes")) - .isEqualTo(RuntimeEnvironment.application.getResources().getColor(R.color.clear)); + .isEqualTo( + ApplicationProvider.getApplicationContext() + .getResources() + .getColor(R.color.clear)); assertThat(meta.getString("org.robolectric.metaStringFromRes")) - .isEqualTo(RuntimeEnvironment.application.getString(R.string.app_name)); + .isEqualTo( + ApplicationProvider.getApplicationContext() + .getString(R.string.app_name)); assertThat(meta.getString("org.robolectric.metaStringOfIntFromRes")) - .isEqualTo(RuntimeEnvironment.application.getString(R.string.str_int)); + .isEqualTo( + ApplicationProvider.getApplicationContext() + .getString(R.string.str_int)); assertThat(meta.getInt("org.robolectric.metaStringRes")).isEqualTo(R.string.app_name); } @@ -1572,7 +1703,9 @@ public class ShadowPackageManagerTest { @Test public void testSetComponentEnabledSetting() { - ComponentName componentName = new ComponentName(RuntimeEnvironment.application, "org.robolectric.component"); + ComponentName componentName = + new ComponentName( + ApplicationProvider.getApplicationContext(), "org.robolectric.component"); assertThat(packageManager.getComponentEnabledSetting(componentName)).isEqualTo(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0); @@ -1583,6 +1716,28 @@ public class ShadowPackageManagerTest { public static class ActivityWithMetadata extends Activity { } @Test + public void getActivityInfo_disabledActivity() throws Exception { + ActivityInfo activityInfo = + packageManager.getActivityInfo( + new ComponentName("org.robolectric", "org.robolectric.shadows.DisabledActivity"), + PackageManager.MATCH_DISABLED_COMPONENTS); + + assertThat(activityInfo).isNotNull(); + assertThat(activityInfo.enabled).isFalse(); + } + + @Test + public void getServiceInfo_disabledService() throws Exception { + ServiceInfo activityInfo = + packageManager.getServiceInfo( + new ComponentName("org.robolectric", "org.robolectric.shadows.DisabledService"), + PackageManager.MATCH_DISABLED_COMPONENTS); + + assertThat(activityInfo).isNotNull(); + assertThat(activityInfo.enabled).isFalse(); + } + + @Test public void getActivityMetaData() throws Exception { Activity activity = setupActivity(ActivityWithMetadata.class); @@ -1599,23 +1754,27 @@ public class ShadowPackageManagerTest { @Test public void getServiceInfo_shouldReturnServiceInfoIfExists() throws Exception { - ServiceInfo serviceInfo = packageManager.getServiceInfo(new ComponentName("org.robolectric", "com.foo.Service"), PackageManager.GET_SERVICES); - assertEquals("org.robolectric", serviceInfo.packageName); - assertEquals("com.foo.Service", serviceInfo.name); - assertEquals("com.foo.MY_PERMISSION", serviceInfo.permission); - assertNotNull(serviceInfo.applicationInfo); + ComponentName component = new ComponentName("org.robolectric", "com.foo.Service"); + ServiceInfo serviceInfo = packageManager.getServiceInfo(component, 0); + assertThat(serviceInfo.packageName).isEqualTo("org.robolectric"); + assertThat(serviceInfo.processName).isEqualTo("org.robolectric"); + assertThat(serviceInfo.name).isEqualTo("com.foo.Service"); + assertThat(serviceInfo.permission).isEqualTo("com.foo.MY_PERMISSION"); + assertThat(serviceInfo.applicationInfo).isNotNull(); } @Test public void getServiceInfo_shouldReturnServiceInfoWithMetaDataWhenFlagsSet() throws Exception { - ServiceInfo serviceInfo = packageManager.getServiceInfo(new ComponentName("org.robolectric", "com.foo.Service"), PackageManager.GET_META_DATA); - assertNotNull(serviceInfo.metaData); + ComponentName component = new ComponentName("org.robolectric", "com.foo.Service"); + ServiceInfo serviceInfo = packageManager.getServiceInfo(component, PackageManager.GET_META_DATA); + assertThat(serviceInfo.metaData).isNotNull(); } @Test public void getServiceInfo_shouldReturnServiceInfoWithoutMetaDataWhenFlagsNotSet() throws Exception { - ServiceInfo serviceInfo = packageManager.getServiceInfo(new ComponentName("org.robolectric", "com.foo.Service"), PackageManager.GET_SERVICES); - assertNull(serviceInfo.metaData); + ComponentName component = new ComponentName("org.robolectric", "com.foo.Service"); + ServiceInfo serviceInfo = packageManager.getServiceInfo(component, 0); + assertThat(serviceInfo.metaData).isNull(); } @Test @@ -1667,8 +1826,13 @@ public class ShadowPackageManagerTest { @Test public void getResourcesForApplication_currentApplication() throws Exception { - assertThat(packageManager.getResourcesForApplication("org.robolectric").getString(R.string.app_name)) - .isEqualTo(RuntimeEnvironment.application.getString(R.string.app_name)); + assertThat( + packageManager + .getResourcesForApplication("org.robolectric") + .getString(R.string.app_name)) + .isEqualTo( + ApplicationProvider.getApplicationContext() + .getString(R.string.app_name)); } @Test @@ -1692,7 +1856,8 @@ public class ShadowPackageManagerTest { shadowPackageManager.addPackage(packageInfo); assertThat(packageManager.getResourcesForApplication("another.package")).isNotNull(); - assertThat(packageManager.getResourcesForApplication("another.package")).isNotEqualTo(RuntimeEnvironment.application.getResources()); + assertThat(packageManager.getResourcesForApplication("another.package")) + .isNotEqualTo(ApplicationProvider.getApplicationContext().getResources()); } @Test @Config(minSdk = M) @@ -1846,7 +2011,7 @@ public class ShadowPackageManagerTest { @Test public void getPermissionInfo() throws Exception { PermissionInfo permission = - RuntimeEnvironment.application + ApplicationProvider.getApplicationContext() .getPackageManager() .getPermissionInfo("org.robolectric.some_permission", 0); assertThat(permission.labelRes).isEqualTo(R.string.test_permission_label); @@ -2053,9 +2218,11 @@ public class ShadowPackageManagerTest { @Test public void getXml() throws Exception { - XmlResourceParser in = packageManager.getXml(RuntimeEnvironment.application.getPackageName(), - R.xml.dialog_preferences, - RuntimeEnvironment.application.getApplicationInfo()); + XmlResourceParser in = + packageManager.getXml( + ApplicationProvider.getApplicationContext().getPackageName(), + R.xml.dialog_preferences, + ApplicationProvider.getApplicationContext().getApplicationInfo()); assertThat(in).isNotNull(); } @@ -2091,9 +2258,12 @@ public class ShadowPackageManagerTest { @Test public void deletePackage() throws Exception { // Apps must have the android.permission.DELETE_PACKAGES set to delete packages. - PackageManager packageManager = RuntimeEnvironment.application.getPackageManager(); - packageManager.getPackageInfo(RuntimeEnvironment.application.getPackageName(), 0).requestedPermissions = - new String[] { android.Manifest.permission.DELETE_PACKAGES }; + PackageManager packageManager = + ApplicationProvider.getApplicationContext().getPackageManager(); + packageManager.getPackageInfo( + ApplicationProvider.getApplicationContext().getPackageName(), 0) + .requestedPermissions = + new String[] {android.Manifest.permission.DELETE_PACKAGES}; PackageInfo packageInfo = new PackageInfo(); packageInfo.packageName = "test.package"; @@ -2129,7 +2299,9 @@ public class ShadowPackageManagerTest { public void getIntentFiltersForActivity() throws NameNotFoundException { List<IntentFilter> intentFilters = shadowPackageManager.getIntentFiltersForActivity( - new ComponentName(RuntimeEnvironment.application, ActivityWithFilters.class)); + new ComponentName( + ApplicationProvider.getApplicationContext(), + ActivityWithFilters.class)); assertThat(intentFilters).hasSize(1); IntentFilter intentFilter = intentFilters.get(0); assertThat(intentFilter.getCategory(0)).isEqualTo(Intent.CATEGORY_DEFAULT); @@ -2140,7 +2312,8 @@ public class ShadowPackageManagerTest { @Test public void getPackageInfo_shouldHaveWritableDataDirs() throws Exception { PackageInfo packageInfo = - packageManager.getPackageInfo(RuntimeEnvironment.application.getPackageName(), 0); + packageManager.getPackageInfo( + ApplicationProvider.getApplicationContext().getPackageName(), 0); File dataDir = new File(packageInfo.applicationInfo.dataDir); assertThat(dataDir.isDirectory()).isTrue(); @@ -2160,7 +2333,8 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void getApplicationHiddenSettingAsUser_hidden() throws Exception { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); @@ -2172,7 +2346,8 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void getApplicationHiddenSettingAsUser_notHidden() throws Exception { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); assertThat(packageManager.getApplicationHiddenSettingAsUser(packageName, /* user= */ null)) .isFalse(); @@ -2188,7 +2363,8 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void setApplicationHiddenSettingAsUser_includeUninstalled() throws Exception { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); @@ -2205,7 +2381,8 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP) public void setApplicationHiddenSettingAsUser_dontIncludeUninstalled() throws Exception { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); packageManager.setApplicationHiddenSettingAsUser( packageName, /* hidden= */ true, /* user= */ null); @@ -2230,7 +2407,8 @@ public class ShadowPackageManagerTest { @Test @Config(minSdk = LOLLIPOP_MR1) public void setUnbadgedApplicationIcon() throws Exception { - String packageName = RuntimeEnvironment.application.getPackageName(); + String packageName = + ApplicationProvider.getApplicationContext().getPackageName(); Drawable d = new BitmapDrawable(); shadowPackageManager.setUnbadgedApplicationIcon(packageName, d); @@ -2256,9 +2434,10 @@ public class ShadowPackageManagerTest { } @Test - @Config(minSdk = android.os.Build.VERSION_CODES.P, packageName = "com.self.package") + @Config(minSdk = android.os.Build.VERSION_CODES.P) public void isPackageSuspended_callersPackage_shouldReturnFalse() throws NameNotFoundException { - assertThat(packageManager.isPackageSuspended("com.self.package")).isFalse(); + assertThat(packageManager.isPackageSuspended(ApplicationProvider.getApplicationContext().getPackageName())) + .isFalse(); } @Test @@ -2308,7 +2487,8 @@ public class ShadowPackageManagerTest { public void setPackagesSuspended_withProfileOwner_shouldThrow() { DevicePolicyManager devicePolicyManager = (DevicePolicyManager) - RuntimeEnvironment.application.getSystemService(Context.DEVICE_POLICY_SERVICE); + ApplicationProvider.getApplicationContext() + .getSystemService(Context.DEVICE_POLICY_SERVICE); shadowOf(devicePolicyManager) .setProfileOwner(new ComponentName("com.profile.owner", "ProfileOwnerClass")); try { @@ -2328,7 +2508,8 @@ public class ShadowPackageManagerTest { public void setPackagesSuspended_withDeviceOwner_shouldThrow() { DevicePolicyManager devicePolicyManager = (DevicePolicyManager) - RuntimeEnvironment.application.getSystemService(Context.DEVICE_POLICY_SERVICE); + ApplicationProvider.getApplicationContext() + .getSystemService(Context.DEVICE_POLICY_SERVICE); shadowOf(devicePolicyManager) .setDeviceOwner(new ComponentName("com.device.owner", "DeviceOwnerClass")); // Robolectric uses a random UID (see ShadowProcess#getRandomApplicationUid) that falls within @@ -2347,7 +2528,7 @@ public class ShadowPackageManagerTest { } @Test - @Config(minSdk = android.os.Build.VERSION_CODES.P, packageName = "com.self.package") + @Config(minSdk = android.os.Build.VERSION_CODES.P) public void setPackagesSuspended_shouldSuspendSuspendablePackagesAndReturnTheRest() throws NameNotFoundException { shadowPackageManager.addPackage(createPackageInfoWithPackageName("android")); @@ -2361,19 +2542,24 @@ public class ShadowPackageManagerTest { "com.suspendable.package1", "android", // Unsuspendable (platform package). "com.suspendable.package2", - "com.self.package" // Unsuspendable (caller's package). + ApplicationProvider.getApplicationContext() + .getPackageName() // Unsuspendable (caller's package). }, /* suspended= */ true, /* appExtras= */ null, /* launcherExtras= */ null, /* dialogMessage= */ (String) null)) .asList() - .containsExactly("com.nonexistent.package", "android", "com.self.package"); + .containsExactly( + "com.nonexistent.package", "android", + ApplicationProvider.getApplicationContext().getPackageName()); assertThat(packageManager.isPackageSuspended("com.suspendable.package1")).isTrue(); assertThat(packageManager.isPackageSuspended("android")).isFalse(); assertThat(packageManager.isPackageSuspended("com.suspendable.package2")).isTrue(); - assertThat(packageManager.isPackageSuspended("com.self.package")).isFalse(); + assertThat(packageManager.isPackageSuspended( + ApplicationProvider.getApplicationContext().getPackageName())) + .isFalse(); } @Test @@ -2404,7 +2590,7 @@ public class ShadowPackageManagerTest { } @Test - @Config(minSdk = android.os.Build.VERSION_CODES.P, packageName = "com.self.package") + @Config(minSdk = android.os.Build.VERSION_CODES.P) public void setPackagesSuspended_shouldUnsuspendSuspendablePackagesAndReturnTheRest() throws NameNotFoundException { shadowPackageManager.addPackage(createPackageInfoWithPackageName("android")); @@ -2426,19 +2612,22 @@ public class ShadowPackageManagerTest { "com.suspendable.package1", "android", // Unsuspendable (platform package). "com.suspendable.package2", - "com.self.package" // Unsuspendable (caller's package). + ApplicationProvider.getApplicationContext() + .getPackageName() // Unsuspendable (caller's package). }, /* suspended= */ false, /* appExtras= */ null, /* launcherExtras= */ null, /* dialogMessage= */ (String) null)) .asList() - .containsExactly("com.nonexistent.package", "android", "com.self.package"); + .containsExactly( + "com.nonexistent.package", "android", ApplicationProvider.getApplicationContext().getPackageName()); assertThat(packageManager.isPackageSuspended("com.suspendable.package1")).isFalse(); assertThat(packageManager.isPackageSuspended("android")).isFalse(); assertThat(packageManager.isPackageSuspended("com.suspendable.package2")).isFalse(); - assertThat(packageManager.isPackageSuspended("com.self.package")).isFalse(); + assertThat(packageManager.isPackageSuspended(ApplicationProvider.getApplicationContext().getPackageName())) + .isFalse(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPaintTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPaintTest.java index 64a6f8941..7921b6fa8 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPaintTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPaintTest.java @@ -7,12 +7,12 @@ import static org.robolectric.Shadows.shadowOf; import android.graphics.Color; import android.graphics.Paint; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPaintTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPairTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPairTest.java index 346063908..20929e114 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPairTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPairTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.util.Pair; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPairTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowParcelFileDescriptorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowParcelFileDescriptorTest.java index 0831dfc1f..3d023f750 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowParcelFileDescriptorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowParcelFileDescriptorTest.java @@ -1,55 +1,63 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assume.assumeTrue; -import static org.robolectric.shadows.ShadowAssetManager.useLegacy; import android.os.ParcelFileDescriptor; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowParcelFileDescriptorTest { + + private static final int READ_ONLY_FILE_CONTENTS = 42; + private File file; private File readOnlyFile; @Before - public void setup() throws Exception { - assumeTrue(useLegacy()); - file = new File(RuntimeEnvironment.application.getFilesDir(), "test"); + public void setUp() throws Exception { + file = new File(ApplicationProvider.getApplicationContext().getFilesDir(), "test"); FileOutputStream os = new FileOutputStream(file); os.close(); - readOnlyFile = new File(RuntimeEnvironment.application.getFilesDir(), "test_readonly"); + readOnlyFile = + new File(ApplicationProvider.getApplicationContext().getFilesDir(), "test_readonly"); os = new FileOutputStream(readOnlyFile); + os.write(READ_ONLY_FILE_CONTENTS); os.close(); - readOnlyFile.setReadOnly(); + assertThat(readOnlyFile.setReadOnly()).isTrue(); } @Test public void testOpens() throws Exception { - ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); + ParcelFileDescriptor pfd = + ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); assertThat(pfd).isNotNull(); assertThat(pfd.getFileDescriptor().valid()).isTrue(); pfd.close(); } @Test - public void testOpens_readOnlyFile() throws Exception { - ParcelFileDescriptor pfd = ParcelFileDescriptor.open(readOnlyFile, ParcelFileDescriptor.MODE_READ_ONLY); + public void testOpens_canReadReadOnlyFile() throws Exception { + ParcelFileDescriptor pfd = + ParcelFileDescriptor.open(readOnlyFile, ParcelFileDescriptor.MODE_READ_ONLY); assertThat(pfd).isNotNull(); assertThat(pfd.getFileDescriptor().valid()).isTrue(); + FileInputStream is = new FileInputStream(pfd.getFileDescriptor()); + assertThat(is.read()).isEqualTo(READ_ONLY_FILE_CONTENTS); pfd.close(); } @Test public void testOpens_canWriteWritableFile() throws Exception { - ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); + ParcelFileDescriptor pfd = + ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); assertThat(pfd).isNotNull(); assertThat(pfd.getFileDescriptor().valid()).isTrue(); FileOutputStream os = new FileOutputStream(pfd.getFileDescriptor()); @@ -59,7 +67,8 @@ public class ShadowParcelFileDescriptorTest { @Test public void testStatSize_emptyFile() throws Exception { - ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); + ParcelFileDescriptor pfd = + ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); assertThat(pfd).isNotNull(); assertThat(pfd.getFileDescriptor().valid()).isTrue(); assertThat(pfd.getStatSize()).isEqualTo(0); @@ -68,12 +77,13 @@ public class ShadowParcelFileDescriptorTest { @Test public void testStatSize_writtenFile() throws Exception { - ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); + ParcelFileDescriptor pfd = + ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE); assertThat(pfd).isNotNull(); assertThat(pfd.getFileDescriptor().valid()).isTrue(); FileOutputStream os = new FileOutputStream(pfd.getFileDescriptor()); os.write(5); - assertThat(pfd.getStatSize()).isEqualTo(1); // One byte. + assertThat(pfd.getStatSize()).isEqualTo(1); // One byte. os.close(); } @@ -82,21 +92,24 @@ public class ShadowParcelFileDescriptorTest { ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, -1); pfd.close(); assertThat(pfd.getFileDescriptor().valid()).isFalse(); + assertThat(pfd.getFd()).isEqualTo(-1); } @Test public void testAutoCloseInputStream() throws Exception { ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, -1); - ParcelFileDescriptor.AutoCloseInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd); + ParcelFileDescriptor.AutoCloseInputStream is = + new ParcelFileDescriptor.AutoCloseInputStream(pfd); is.close(); assertThat(pfd.getFileDescriptor().valid()).isFalse(); } @Test public void testAutoCloseOutputStream() throws Exception { - File f = new File(RuntimeEnvironment.application.getFilesDir(), "outfile"); + File f = new File(ApplicationProvider.getApplicationContext().getFilesDir(), "outfile"); ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, -1); - ParcelFileDescriptor.AutoCloseOutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(pfd); + ParcelFileDescriptor.AutoCloseOutputStream os = + new ParcelFileDescriptor.AutoCloseOutputStream(pfd); os.close(); assertThat(pfd.getFileDescriptor().valid()).isFalse(); } @@ -106,9 +119,11 @@ public class ShadowParcelFileDescriptorTest { ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); ParcelFileDescriptor readSide = pipe[0]; ParcelFileDescriptor writeSide = pipe[1]; - byte[] dataToWrite = new byte[] {0,1,2,3,4}; - ParcelFileDescriptor.AutoCloseInputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(readSide); - ParcelFileDescriptor.AutoCloseOutputStream outputStream = new ParcelFileDescriptor.AutoCloseOutputStream(writeSide); + byte[] dataToWrite = new byte[] {0, 1, 2, 3, 4}; + ParcelFileDescriptor.AutoCloseInputStream inputStream = + new ParcelFileDescriptor.AutoCloseInputStream(readSide); + ParcelFileDescriptor.AutoCloseOutputStream outputStream = + new ParcelFileDescriptor.AutoCloseOutputStream(writeSide); outputStream.write(dataToWrite); byte[] read = new byte[dataToWrite.length]; int byteCount = inputStream.read(read); @@ -117,4 +132,15 @@ public class ShadowParcelFileDescriptorTest { assertThat(byteCount).isEqualTo(dataToWrite.length); assertThat(read).isEqualTo(dataToWrite); } + + @Test + public void testGetFd_canRead() throws IOException { + ParcelFileDescriptor pfd = + ParcelFileDescriptor.open(readOnlyFile, ParcelFileDescriptor.MODE_READ_ONLY); + int fd = pfd.getFd(); + assertThat(fd).isGreaterThan(0); + FileInputStream is = new FileInputStream(new File("/proc/self/fd/" + fd)); + assertThat(is.read()).isEqualTo(READ_ONLY_FILE_CONTENTS); + is.close(); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowParcelTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowParcelTest.java index 2e22f5d16..b6e15eb77 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowParcelTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowParcelTest.java @@ -11,6 +11,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -20,10 +21,9 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowParcelTest { private Parcel parcel; @@ -639,7 +639,7 @@ public class ShadowParcelTest { parcel.setDataCapacity(8); assertThat(parcel.dataCapacity()).isEqualTo(8); } - + @Test public void testWriteAndEnforceCompatibleInterface() { parcel.writeInterfaceToken("com.example.IMyInterface"); @@ -647,7 +647,7 @@ public class ShadowParcelTest { parcel.enforceInterface("com.example.IMyInterface"); // Nothing explodes } - + @Test public void testWriteAndEnforceIncompatibleInterface() { parcel.writeInterfaceToken("com.example.Derp"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPasswordTransformationMethodTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPasswordTransformationMethodTest.java index cf8c7e877..452b7ccd3 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPasswordTransformationMethodTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPasswordTransformationMethodTest.java @@ -3,12 +3,12 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.text.method.PasswordTransformationMethod; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPasswordTransformationMethodTest { private PasswordTransformationMethod transformationMethod; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPathTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPathTest.java index 3664ec2f9..617650b42 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPathTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPathTest.java @@ -1,32 +1,22 @@ package org.robolectric.shadows; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.robolectric.Shadows.shadowOf; import static org.robolectric.shadows.ShadowPath.Point.Type.LINE_TO; import static org.robolectric.shadows.ShadowPath.Point.Type.MOVE_TO; import android.graphics.Path; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPathTest { @Test - public void testGradTo() { - Path path = Shadow.newInstanceOf(Path.class); - path.quadTo(0, 5, 10, 15); - ShadowPath shadowPath = shadowOf(path); - assertEquals(shadowPath.getQuadDescription(), "Add a quadratic bezier from last point, approaching (0.0,5.0), ending at (10.0,15.0)"); - } - - @Test public void testMoveTo() throws Exception { - Path path = Shadow.newInstanceOf(Path.class); + Path path = new Path(); path.moveTo(2, 3); path.moveTo(3, 4); @@ -38,7 +28,7 @@ public class ShadowPathTest { @Test public void testLineTo() throws Exception { - Path path = Shadow.newInstanceOf(Path.class); + Path path = new Path(); path.lineTo(2, 3); path.lineTo(3, 4); @@ -50,7 +40,7 @@ public class ShadowPathTest { @Test public void testReset() throws Exception { - Path path = Shadow.newInstanceOf(Path.class); + Path path = new Path(); path.moveTo(0, 3); path.lineTo(2, 3); path.quadTo(2, 3, 4, 5); @@ -59,20 +49,16 @@ public class ShadowPathTest { ShadowPath shadowPath = shadowOf(path); List<ShadowPath.Point> points = shadowPath.getPoints(); assertEquals(0, points.size()); - assertNull(shadowPath.getWasMovedTo()); - assertEquals("", shadowPath.getQuadDescription()); } @Test public void test_copyConstructor() throws Exception { - Path path = Shadow.newInstanceOf(Path.class); + Path path = new Path(); path.moveTo(0, 3); path.lineTo(2, 3); path.quadTo(2, 3, 4, 5); Path copiedPath = new Path(path); assertEquals(shadowOf(path).getPoints(), shadowOf(copiedPath).getPoints()); - assertEquals(shadowOf(path).getWasMovedTo(), shadowOf(copiedPath).getWasMovedTo()); - assertEquals(shadowOf(path).getQuadDescription(), shadowOf(copiedPath).getQuadDescription()); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPeerHandleTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPeerHandleTest.java index 7e7f8ba38..c172cd415 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPeerHandleTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPeerHandleTest.java @@ -4,13 +4,13 @@ import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; import android.net.wifi.aware.PeerHandle; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; /** Tests for {@link ShadowPeerHandle}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = O) public class ShadowPeerHandleTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPendingIntentTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPendingIntentTest.java index b11179739..a65f30162 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPendingIntentTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPendingIntentTest.java @@ -10,28 +10,29 @@ import static org.junit.Assert.fail; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.Application; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPendingIntentTest { private Context context; @Before public void setUp() { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); } @Test @@ -75,7 +76,8 @@ public class ShadowPendingIntentTest { assertThat(shadow.getSavedIntents()).isEqualTo(intents); pendingIntent.send(); - ShadowApplication application = shadowOf(RuntimeEnvironment.application); + ShadowApplication application = + shadowOf((Application) ApplicationProvider.getApplicationContext()); assertThat(application.getNextStartedActivity()).isEqualTo(intents[1]); assertThat(application.getNextStartedActivity()).isEqualTo(intents[0]); } @@ -90,7 +92,8 @@ public class ShadowPendingIntentTest { assertThat(shadow.getSavedIntents()).isEqualTo(intents); pendingIntent.send(); - ShadowApplication application = shadowOf(RuntimeEnvironment.application); + ShadowApplication application = + shadowOf((Application) ApplicationProvider.getApplicationContext()); assertThat(application.getNextStartedActivity()).isEqualTo(intents[1]); assertThat(application.getNextStartedActivity()).isEqualTo(intents[0]); } @@ -320,7 +323,8 @@ public class ShadowPendingIntentTest { @Test public void getActivities_withFlagNoCreate_shouldReturnExistingIntent() { Intent[] intents = {new Intent(Intent.ACTION_VIEW), new Intent(Intent.ACTION_PICK)}; - PendingIntent.getActivities(RuntimeEnvironment.application, 99, intents, 100); + PendingIntent.getActivities( + (Application) ApplicationProvider.getApplicationContext(), 99, intents, 100); Intent[] identicalIntents = {new Intent(Intent.ACTION_VIEW), new Intent(Intent.ACTION_PICK)}; PendingIntent saved = @@ -332,7 +336,8 @@ public class ShadowPendingIntentTest { @Test public void getActivities_withNoFlags_shouldReturnExistingIntent() { Intent[] intents = {new Intent(Intent.ACTION_VIEW), new Intent(Intent.ACTION_PICK)}; - PendingIntent.getActivities(RuntimeEnvironment.application, 99, intents, 100); + PendingIntent.getActivities( + (Application) ApplicationProvider.getApplicationContext(), 99, intents, 100); Intent[] identicalIntents = {new Intent(Intent.ACTION_VIEW), new Intent(Intent.ACTION_PICK)}; PendingIntent saved = PendingIntent.getActivities(context, 99, identicalIntents, 0); @@ -625,7 +630,7 @@ public class ShadowPendingIntentTest { @Test public void testHashCode() { - Context ctx = RuntimeEnvironment.application; + Context ctx = (Application) ApplicationProvider.getApplicationContext(); PendingIntent pendingIntent1 = PendingIntent.getActivity(ctx, 99, new Intent("activity"), 100); assertThat(pendingIntent1.hashCode()) diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPhoneWindowTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPhoneWindowTest.java index 2fb624b15..b534341fa 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPhoneWindowTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPhoneWindowTest.java @@ -6,13 +6,13 @@ import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import android.graphics.drawable.Drawable; import android.view.Window; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPhoneWindowTest { private Window window; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPictureTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPictureTest.java index 74f0c3990..6aaaa2604 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPictureTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPictureTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.graphics.Picture; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPictureTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPopupMenuTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPopupMenuTest.java index 4642eafef..46e8cafbf 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPopupMenuTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPopupMenuTest.java @@ -3,16 +3,17 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.view.MenuItem; import android.view.View; import android.widget.PopupMenu; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPopupMenuTest { private PopupMenu popupMenu; @@ -20,8 +21,9 @@ public class ShadowPopupMenuTest { @Before public void setUp() { - View anchorView = new View(RuntimeEnvironment.application); - popupMenu = new PopupMenu(RuntimeEnvironment.application, anchorView); + View anchorView = new View((Application) ApplicationProvider.getApplicationContext()); + popupMenu = + new PopupMenu((Application) ApplicationProvider.getApplicationContext(), anchorView); shadowPopupMenu = shadowOf(popupMenu); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPorterDuffColorFilterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPorterDuffColorFilterTest.java index b2789d5ef..d144019e3 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPorterDuffColorFilterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPorterDuffColorFilterTest.java @@ -1,17 +1,18 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowPorterDuffColorFilterTest { @Test @@ -21,6 +22,13 @@ public class ShadowPorterDuffColorFilterTest { assertThat(filter.getMode()).isEqualTo(PorterDuff.Mode.ADD); } + @Config(minSdk = O) + @Test + public void createNativeInstance_shouldWork() { + final PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.ADD); + assertThat(filter.getNativeInstance()).isEqualTo(0L); + } + @Test public void hashCode_returnsDifferentValuesForDifferentModes() { PorterDuffColorFilter addFilter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.ADD); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPowerManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPowerManagerTest.java index 4b72b2c4d..b2d217ccc 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPowerManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPowerManagerTest.java @@ -5,24 +5,28 @@ import static android.os.Build.VERSION_CODES.M; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.os.PowerManager; import android.os.WorkSource; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class ShadowPowerManagerTest { private PowerManager powerManager; private ShadowPowerManager shadowPowerManager; @Before public void before() { - powerManager = (PowerManager) RuntimeEnvironment.application.getSystemService(Context.POWER_SERVICE); + powerManager = + (PowerManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.POWER_SERVICE); shadowPowerManager = shadowOf(powerManager); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceActivityTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceActivityTest.java index 105f3c828..9eefefc7b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceActivityTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceActivityTest.java @@ -4,14 +4,14 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNotNull; import android.preference.PreferenceActivity; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPreferenceActivityTest { private TestPreferenceActivity activity; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceActivityTestWithFragment.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceActivityTestWithFragment.java index d7554fb90..3b139a6cd 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceActivityTestWithFragment.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceActivityTestWithFragment.java @@ -7,20 +7,19 @@ import android.app.FragmentManager; import android.os.Bundle; import android.preference.Preference; import android.preference.PreferenceFragment; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; /** - * Current Android examples show adding a PreferenceFragment as part of the - * hosting Activity lifecycle. This resulted in a null pointer exception when - * trying to access a Context while inflating the Preference objects defined in - * xml. This class tests that path. + * Current Android examples show adding a PreferenceFragment as part of the hosting Activity + * lifecycle. This resulted in a null pointer exception when trying to access a Context while + * inflating the Preference objects defined in xml. This class tests that path. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPreferenceActivityTestWithFragment { private TestPreferenceActivity activity = Robolectric.setupActivity(TestPreferenceActivity.class); private TestPreferenceFragment fragment; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceGroupTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceGroupTest.java index e95ed13af..5decabda6 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceGroupTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowPreferenceGroupTest.java @@ -10,13 +10,13 @@ import android.preference.Preference; import android.preference.PreferenceGroup; import android.preference.PreferenceManager; import android.util.AttributeSet; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowPreferenceGroupTest { private TestPreferenceGroup group; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowProcessTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowProcessTest.java index e0d2cfed4..a443314ed 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowProcessTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowProcessTest.java @@ -2,14 +2,14 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; /** Test ShadowProcess */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowProcessTest { @Test public void shouldBeZeroWhenNotSet() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowProgressBarTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowProgressBarTest.java index 0c0fb0681..5f15836ef 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowProgressBarTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowProgressBarTest.java @@ -8,13 +8,13 @@ import static org.robolectric.RuntimeEnvironment.application; import android.util.AttributeSet; import android.widget.ProgressBar; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowProgressBarTest { private int[] testValues = {0, 1, 2, 100}; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowProgressDialogTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowProgressDialogTest.java index a820388b0..0dabde28f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowProgressDialogTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowProgressDialogTest.java @@ -3,16 +3,17 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.ProgressDialog; import android.view.View; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowProgressDialogTest { private ProgressDialog dialog; @@ -20,7 +21,7 @@ public class ShadowProgressDialogTest { @Before public void setUp() { - dialog = new ProgressDialog(RuntimeEnvironment.application); + dialog = new ProgressDialog((Application) ApplicationProvider.getApplicationContext()); shadow = Shadows.shadowOf(dialog); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowRadioButtonTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowRadioButtonTest.java index 09483abe2..59a9fc690 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowRadioButtonTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowRadioButtonTest.java @@ -5,20 +5,22 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.graphics.drawable.ColorDrawable; import android.widget.RadioButton; import android.widget.RadioGroup; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowRadioButtonTest { @Test public void canBeExplicitlyChecked() throws Exception { - RadioButton radioButton = new RadioButton(RuntimeEnvironment.application); + RadioButton radioButton = + new RadioButton((Application) ApplicationProvider.getApplicationContext()); assertFalse(radioButton.isChecked()); radioButton.setChecked(true); @@ -30,7 +32,8 @@ public class ShadowRadioButtonTest { @Test public void canBeToggledBetweenCheckedState() throws Exception { - RadioButton radioButton = new RadioButton(RuntimeEnvironment.application); + RadioButton radioButton = + new RadioButton((Application) ApplicationProvider.getApplicationContext()); assertFalse(radioButton.isChecked()); radioButton.toggle(); @@ -42,7 +45,8 @@ public class ShadowRadioButtonTest { @Test public void canBeClickedToToggleCheckedState() throws Exception { - RadioButton radioButton = new RadioButton(RuntimeEnvironment.application); + RadioButton radioButton = + new RadioButton((Application) ApplicationProvider.getApplicationContext()); assertFalse(radioButton.isChecked()); radioButton.performClick(); @@ -54,12 +58,15 @@ public class ShadowRadioButtonTest { @Test public void shouldInformRadioGroupThatItIsChecked() throws Exception { - RadioButton radioButton1 = new RadioButton(RuntimeEnvironment.application); + RadioButton radioButton1 = + new RadioButton((Application) ApplicationProvider.getApplicationContext()); radioButton1.setId(99); - RadioButton radioButton2 = new RadioButton(RuntimeEnvironment.application); + RadioButton radioButton2 = + new RadioButton((Application) ApplicationProvider.getApplicationContext()); radioButton2.setId(100); - RadioGroup radioGroup = new RadioGroup(RuntimeEnvironment.application); + RadioGroup radioGroup = + new RadioGroup((Application) ApplicationProvider.getApplicationContext()); radioGroup.addView(radioButton1); radioGroup.addView(radioButton2); @@ -72,7 +79,8 @@ public class ShadowRadioButtonTest { @Test public void getButtonDrawableId() { - RadioButton radioButton = new RadioButton(RuntimeEnvironment.application); + RadioButton radioButton = + new RadioButton((Application) ApplicationProvider.getApplicationContext()); radioButton.setButtonDrawable(R.drawable.an_image); assertThat(shadowOf(radioButton).getButtonDrawableId()).isEqualTo(R.drawable.an_image); @@ -80,7 +88,8 @@ public class ShadowRadioButtonTest { @Test public void getButtonDrawable() { - RadioButton radioButton = new RadioButton(RuntimeEnvironment.application); + RadioButton radioButton = + new RadioButton((Application) ApplicationProvider.getApplicationContext()); ColorDrawable drawable = new ColorDrawable(); radioButton.setButtonDrawable(drawable); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowRadioGroupTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowRadioGroupTest.java index bb9ae2b26..f8eee250a 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowRadioGroupTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowRadioGroupTest.java @@ -3,21 +3,23 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import android.app.Application; import android.widget.RadioGroup; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.Arrays; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowRadioGroupTest { private static final int BUTTON_ID = 3245; @Test public void checkedRadioButtonId() throws Exception { - RadioGroup radioGroup = new RadioGroup(RuntimeEnvironment.application); + RadioGroup radioGroup = + new RadioGroup((Application) ApplicationProvider.getApplicationContext()); assertThat(radioGroup.getCheckedRadioButtonId()).isEqualTo(-1); radioGroup.check(99); assertThat(radioGroup.getCheckedRadioButtonId()).isEqualTo(99); @@ -25,7 +27,8 @@ public class ShadowRadioGroupTest { @Test public void check_shouldCallOnCheckedChangeListener() throws Exception { - RadioGroup radioGroup = new RadioGroup(RuntimeEnvironment.application); + RadioGroup radioGroup = + new RadioGroup((Application) ApplicationProvider.getApplicationContext()); TestOnCheckedChangeListener listener = new TestOnCheckedChangeListener(); radioGroup.setOnCheckedChangeListener(listener); @@ -37,7 +40,8 @@ public class ShadowRadioGroupTest { @Test public void clearCheck_shouldCallOnCheckedChangeListenerTwice() throws Exception { - RadioGroup radioGroup = new RadioGroup(RuntimeEnvironment.application); + RadioGroup radioGroup = + new RadioGroup((Application) ApplicationProvider.getApplicationContext()); TestOnCheckedChangeListener listener = new TestOnCheckedChangeListener(); radioGroup.check(BUTTON_ID); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowRatingBarTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowRatingBarTest.java index 102c5023b..6d688e9b7 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowRatingBarTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowRatingBarTest.java @@ -2,16 +2,17 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.widget.RatingBar; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowRatingBarTest { private RatingBar ratingBar; @@ -20,7 +21,7 @@ public class ShadowRatingBarTest { @Before public void setup() { - ratingBar = new RatingBar(RuntimeEnvironment.application); + ratingBar = new RatingBar((Application) ApplicationProvider.getApplicationContext()); listener = new TestRatingBarChangedListener(); transcript = new ArrayList<>(); ratingBar.setOnRatingBarChangeListener(listener); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowRectTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowRectTest.java index feed080d7..37951fd84 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowRectTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowRectTest.java @@ -3,12 +3,12 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.graphics.Rect; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowRectTest { @Before public void setUp() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowRelativeLayoutTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowRelativeLayoutTest.java index a25819a14..03560ea8b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowRelativeLayoutTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowRelativeLayoutTest.java @@ -4,23 +4,25 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.RelativeLayout; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; 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) +@RunWith(AndroidJUnit4.class) public class ShadowRelativeLayoutTest { @Test @Config(minSdk = JELLY_BEAN_MR1) public void getRules_shouldShowAddRuleData_sinceApiLevel17() throws Exception { - ImageView imageView = new ImageView(RuntimeEnvironment.application); - RelativeLayout layout = new RelativeLayout(RuntimeEnvironment.application); + ImageView imageView = new ImageView((Application) ApplicationProvider.getApplicationContext()); + RelativeLayout layout = + new RelativeLayout((Application) ApplicationProvider.getApplicationContext()); layout.addView(imageView, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) imageView.getLayoutParams(); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); @@ -32,8 +34,9 @@ public class ShadowRelativeLayoutTest { @Test @Config(maxSdk = JELLY_BEAN) public void getRules_shouldShowAddRuleData_uptoApiLevel16() throws Exception { - ImageView imageView = new ImageView(RuntimeEnvironment.application); - RelativeLayout layout = new RelativeLayout(RuntimeEnvironment.application); + ImageView imageView = new ImageView((Application) ApplicationProvider.getApplicationContext()); + RelativeLayout layout = + new RelativeLayout((Application) ApplicationProvider.getApplicationContext()); layout.addView(imageView, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) imageView.getLayoutParams(); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowRemoteCallbackListTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowRemoteCallbackListTest.java index 8ea9c1e53..d75330c59 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowRemoteCallbackListTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowRemoteCallbackListTest.java @@ -6,11 +6,11 @@ import android.os.Binder; import android.os.IBinder; import android.os.IInterface; import android.os.RemoteCallbackList; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowRemoteCallbackListTest { @Test public void testBasicWiring() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowRenderNodeAnimatorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowRenderNodeAnimatorTest.java index 12cf2cc86..b2db7f070 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowRenderNodeAnimatorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowRenderNodeAnimatorTest.java @@ -9,14 +9,14 @@ import android.app.Activity; import android.os.Build; import android.view.View; import android.view.ViewAnimationUtils; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowRenderNodeAnimatorTest { private Activity activity; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowResolveInfoTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowResolveInfoTest.java index 822b16f81..4bfde61e1 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowResolveInfoTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowResolveInfoTest.java @@ -3,13 +3,13 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.content.pm.ResolveInfo; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowResolveInfoTest { private ResolveInfo mResolveInfo; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowResourcesTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowResourcesTest.java index 09a54df5f..d6095845e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowResourcesTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowResourcesTest.java @@ -4,6 +4,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assume.assumeTrue; import static org.robolectric.shadows.ShadowAssetManager.useLegacy; +import android.app.Application; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -12,6 +13,8 @@ import android.os.Build; import android.util.AttributeSet; import android.util.TypedValue; import android.util.Xml; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.Range; import java.io.InputStream; import org.junit.Before; @@ -19,27 +22,17 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.XmlResourceParserImpl; import org.robolectric.annotation.Config; import org.xmlpull.v1.XmlPullParser; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowResourcesTest { private Resources resources; @Before public void setup() throws Exception { - resources = RuntimeEnvironment.application.getResources(); - } - - @Test - public void getQuantityString() throws Exception { - assertThat(resources.getQuantityString(R.plurals.beer, 0)).isEqualTo("beers"); - assertThat(resources.getQuantityString(R.plurals.beer, 1)).isEqualTo("beer"); - assertThat(resources.getQuantityString(R.plurals.beer, 2)).isEqualTo("beers"); - assertThat(resources.getQuantityString(R.plurals.beer, 3)).isEqualTo("beers"); + resources = ((Application) ApplicationProvider.getApplicationContext()).getResources(); } @Test @@ -180,10 +173,14 @@ public class ShadowResourcesTest { .addAttribute(android.R.attr.viewportHeight, "24.0") .build(); - TypedArray typedArray = RuntimeEnvironment.application.getTheme().obtainStyledAttributes(attributes, new int[] { - android.R.attr.viewportWidth, - android.R.attr.viewportHeight - }, 0, 0); + TypedArray typedArray = + ((Application) ApplicationProvider.getApplicationContext()) + .getTheme() + .obtainStyledAttributes( + attributes, + new int[] {android.R.attr.viewportWidth, android.R.attr.viewportHeight}, + 0, + 0); assertThat(typedArray.getFloat(0, 0)).isEqualTo(12.0f); assertThat(typedArray.getFloat(1, 0)).isEqualTo(24.0f); typedArray.recycle(); @@ -205,10 +202,14 @@ public class ShadowResourcesTest { .addAttribute(android.R.attr.viewportHeight, "@dimen/dimen30px") .build(); - TypedArray typedArray = RuntimeEnvironment.application.getTheme().obtainStyledAttributes(attributes, new int[] { - android.R.attr.viewportWidth, - android.R.attr.viewportHeight - }, 0, 0); + TypedArray typedArray = + ((Application) ApplicationProvider.getApplicationContext()) + .getTheme() + .obtainStyledAttributes( + attributes, + new int[] {android.R.attr.viewportWidth, android.R.attr.viewportHeight}, + 0, + 0); assertThat(typedArray.getDimension(0, 0)).isEqualTo(20f); assertThat(typedArray.getDimension(1, 0)).isEqualTo(30f); typedArray.recycle(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowRestrictionsManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowRestrictionsManagerTest.java index 4596a57c7..4a5a414f5 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowRestrictionsManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowRestrictionsManagerTest.java @@ -4,19 +4,20 @@ import static android.os.Build.VERSION_CODES.LOLLIPOP; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.content.RestrictionEntry; import android.content.RestrictionsManager; import android.os.Bundle; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.Iterables; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public final class ShadowRestrictionsManagerTest { @@ -25,7 +26,7 @@ public final class ShadowRestrictionsManagerTest { @Before public void setUp() { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); restrictionsManager = (RestrictionsManager) context.getSystemService(Context.RESTRICTIONS_SERVICE); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowResultReceiverTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowResultReceiverTest.java index 30a1fc60c..e0d1f2180 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowResultReceiverTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowResultReceiverTest.java @@ -5,11 +5,11 @@ import static org.junit.Assert.assertEquals; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowResultReceiverTest { @Test public void callingSend_shouldCallOverridenOnReceiveResultWithTheSameArguments() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSQLiteConnectionTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSQLiteConnectionTest.java index 55ece15ff..257b6deb8 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSQLiteConnectionTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSQLiteConnectionTest.java @@ -5,11 +5,14 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.robolectric.shadows.ShadowSQLiteConnection.convertSQLWithLocalizedUnicodeCollator; +import android.app.Application; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatatypeMismatchException; import android.database.sqlite.SQLiteStatement; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.almworks.sqlite4java.SQLiteConnection; import java.io.File; import java.util.ArrayList; @@ -20,12 +23,10 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowSQLiteConnectionTest { private SQLiteDatabase database; @@ -33,7 +34,7 @@ public class ShadowSQLiteConnectionTest { private long ptr; private SQLiteConnection conn; private ShadowSQLiteConnection.Connections CONNECTIONS; - + @Before public void setUp() throws Exception { database = createDatabase("database.db"); @@ -55,7 +56,7 @@ public class ShadowSQLiteConnectionTest { assertThat(convertSQLWithLocalizedUnicodeCollator( "select * from `routine` order by name \n\r \f collate\f\n\tunicode" - + "\n, id \n\n\t collate\n\t \n\flocalized")) + + "\n, id \n\n\t collate\n\t \n\flocalized")) .isEqualTo("select * from `routine` order by name COLLATE NOCASE\n" + ", id COLLATE NOCASE"); @@ -96,13 +97,13 @@ public class ShadowSQLiteConnectionTest { assertThat(conn).isNotNull(); assertThat(conn.isOpen()).named("open").isTrue(); } - + @Test public void nativeClose_closesConnection() { ShadowSQLiteConnection.nativeClose(ptr); assertThat(conn.isOpen()).named("open").isFalse(); } - + @Test public void reset_closesConnection() { ShadowSQLiteConnection.reset(); @@ -118,7 +119,7 @@ public class ShadowSQLiteConnectionTest { assertThat(connectionsMap).named("connections after").isEmpty(); } - + @Test public void reset_clearsStatementCache() { final Map<Long, SQLiteStatement> statementsMap = ReflectionHelpers.getField(CONNECTIONS, "statementsMap"); @@ -167,7 +168,8 @@ public class ShadowSQLiteConnectionTest { } private SQLiteDatabase createDatabase(String filename) { - databasePath = RuntimeEnvironment.application.getDatabasePath(filename); + databasePath = + ((Application) ApplicationProvider.getApplicationContext()).getDatabasePath(filename); databasePath.getParentFile().mkdirs(); return SQLiteDatabase.openOrCreateDatabase(databasePath.getPath(), null); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowScaleGestureDetectorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowScaleGestureDetectorTest.java index e407fd6f1..51e11b9d5 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowScaleGestureDetectorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowScaleGestureDetectorTest.java @@ -5,15 +5,16 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.view.MotionEvent; import android.view.ScaleGestureDetector; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowScaleGestureDetectorTest { private ScaleGestureDetector detector; @@ -21,7 +22,8 @@ public class ShadowScaleGestureDetectorTest { @Before public void setUp() throws Exception { - detector = new ScaleGestureDetector(RuntimeEnvironment.application, null); + detector = + new ScaleGestureDetector((Application) ApplicationProvider.getApplicationContext(), null); motionEvent = MotionEvent.obtain(-1, -1, MotionEvent.ACTION_UP, 100, 30, -1); } @@ -47,7 +49,12 @@ public class ShadowScaleGestureDetectorTest { @Test public void test_getListener() throws Exception { TestOnGestureListener listener = new TestOnGestureListener(); - assertSame(listener, shadowOf(new ScaleGestureDetector(RuntimeEnvironment.application, listener)).getListener()); + assertSame( + listener, + shadowOf( + new ScaleGestureDetector( + (Application) ApplicationProvider.getApplicationContext(), listener)) + .getListener()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowScanResultTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowScanResultTest.java index 963abc2da..4670e9736 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowScanResultTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowScanResultTest.java @@ -5,11 +5,11 @@ import static org.junit.Assert.assertNotNull; import static org.robolectric.Shadows.shadowOf; import android.net.wifi.ScanResult; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowScanResultTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowScrollViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowScrollViewTest.java index 984cbf4c3..c5819aa05 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowScrollViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowScrollViewTest.java @@ -2,17 +2,19 @@ package org.robolectric.shadows; import static org.junit.Assert.assertEquals; +import android.app.Application; import android.widget.ScrollView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowScrollViewTest { @Test public void shouldSmoothScrollTo() throws Exception { - ScrollView scrollView = new ScrollView(RuntimeEnvironment.application); + ScrollView scrollView = + new ScrollView((Application) ApplicationProvider.getApplicationContext()); scrollView.smoothScrollTo(7, 6); assertEquals(7, scrollView.getScrollX()); @@ -21,7 +23,8 @@ public class ShadowScrollViewTest { @Test public void shouldSmoothScrollBy() throws Exception { - ScrollView scrollView = new ScrollView(RuntimeEnvironment.application); + ScrollView scrollView = + new ScrollView((Application) ApplicationProvider.getApplicationContext()); scrollView.smoothScrollTo(7, 6); scrollView.smoothScrollBy(10, 20); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowScrollerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowScrollerTest.java index 38680427c..d529ec9da 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowScrollerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowScrollerTest.java @@ -2,21 +2,24 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.view.animation.BounceInterpolator; import android.widget.Scroller; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowScrollerTest { private Scroller scroller; @Before public void setup() throws Exception { - scroller = new Scroller(RuntimeEnvironment.application, new BounceInterpolator()); + scroller = + new Scroller( + (Application) ApplicationProvider.getApplicationContext(), new BounceInterpolator()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSeekBarTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSeekBarTest.java index f54caa3d2..9b2ae36b9 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSeekBarTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSeekBarTest.java @@ -2,17 +2,18 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.widget.SeekBar; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSeekBarTest { private SeekBar seekBar; @@ -22,7 +23,7 @@ public class ShadowSeekBarTest { @Before public void setup() { - seekBar = new SeekBar(RuntimeEnvironment.application); + seekBar = new SeekBar((Application) ApplicationProvider.getApplicationContext()); shadow = Shadows.shadowOf(seekBar); listener = new TestSeekBarChangedListener(); transcript = new ArrayList<>(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSensorManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSensorManagerTest.java index 801bf5a1b..f1b7068b2 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSensorManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSensorManagerTest.java @@ -4,6 +4,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorDirectChannel; @@ -12,16 +13,16 @@ import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Build; import android.os.MemoryFile; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.base.Optional; import org.junit.After; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class ShadowSensorManagerTest { private SensorManager sensorManager; @@ -29,7 +30,10 @@ public class ShadowSensorManagerTest { @Before public void setUp() { - sensorManager = (SensorManager) RuntimeEnvironment.application.getSystemService(Context.SENSOR_SERVICE); + sensorManager = + (SensorManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.SENSOR_SERVICE); shadow = shadowOf(sensorManager); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSensorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSensorTest.java index 5c63c864e..0afe67462 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSensorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSensorTest.java @@ -4,15 +4,13 @@ import static com.google.common.truth.Truth.assertThat; import android.hardware.Sensor; import android.os.Build; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -/** - * Test for {@link ShadowSensor} - */ -@RunWith(RobolectricTestRunner.class) +/** Test for {@link ShadowSensor} */ +@RunWith(AndroidJUnit4.class) public class ShadowSensorTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowServiceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowServiceTest.java index 8f65685b1..1fb085cdc 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowServiceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowServiceTest.java @@ -3,6 +3,7 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.Notification; import android.app.NotificationManager; import android.app.Service; @@ -11,22 +12,25 @@ import android.content.Intent; import android.content.ServiceConnection; import android.media.MediaScannerConnection; import android.os.IBinder; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowServiceTest { private MyService service ; private ShadowService shadow; private Notification.Builder notBuilder; - private final ShadowNotificationManager nm = shadowOf((NotificationManager) RuntimeEnvironment.application - .getSystemService(Context.NOTIFICATION_SERVICE)); + private final ShadowNotificationManager nm = + shadowOf( + (NotificationManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.NOTIFICATION_SERVICE)); @Before public void setup() { @@ -40,7 +44,8 @@ public class ShadowServiceTest { @Test public void shouldUnbindServiceAtShadowApplication() { - ShadowApplication shadowApplication = shadowOf(RuntimeEnvironment.application); + ShadowApplication shadowApplication = + shadowOf((Application) ApplicationProvider.getApplicationContext()); ServiceConnection conn = Shadow.newInstanceOf(MediaScannerConnection.class); service.bindService(new Intent("dummy"), conn, 0); assertThat(shadowApplication.getUnboundServiceConnections()).isEmpty(); @@ -121,6 +126,12 @@ public class ShadowServiceTest { assertThat(shadow.isStoppedBySelf()).isTrue(); } + @Test + public void shouldStopSelfResultWithId() { + service.stopSelfResult(1); + assertThat(shadow.isStoppedBySelf()).isTrue(); + } + public static class MyService extends Service { @Override public void onDestroy() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSettingsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSettingsTest.java index 6b61c7af5..4ae9d3667 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSettingsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSettingsTest.java @@ -3,124 +3,210 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.ContentResolver; import android.provider.Settings; +import android.provider.Settings.Global; +import android.provider.Settings.Secure; import android.text.format.DateFormat; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class ShadowSettingsTest { private ContentResolver contentResolver; @Before - public void setUp() { - contentResolver = RuntimeEnvironment.application.getContentResolver(); + public void setUp() throws Exception { + contentResolver = + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(); } @Test - public void testSystemGetInt() { + public void testSystemGetInt() throws Exception { assertThat(Settings.System.getInt(contentResolver, "property", 0)).isEqualTo(0); assertThat(Settings.System.getInt(contentResolver, "property", 2)).isEqualTo(2); Settings.System.putInt(contentResolver, "property", 1); assertThat(Settings.System.getInt(contentResolver, "property", 0)).isEqualTo(1); - - Settings.System.putString(contentResolver, "property", "11"); - assertThat(Settings.System.getInt(contentResolver, "property", 0)).isEqualTo(11); } @Test - public void testSecureGetInt() { + public void testSecureGetInt() throws Exception { assertThat(Settings.Secure.getInt(contentResolver, "property", 0)).isEqualTo(0); assertThat(Settings.Secure.getInt(contentResolver, "property", 2)).isEqualTo(2); Settings.Secure.putInt(contentResolver, "property", 1); assertThat(Settings.Secure.getInt(contentResolver, "property", 0)).isEqualTo(1); - - Settings.Secure.putString(contentResolver, "property", "11"); - assertThat(Settings.Secure.getInt(contentResolver, "property", 0)).isEqualTo(11); } @Test @Config(minSdk = JELLY_BEAN_MR1) - public void testGlobalGetInt() { + public void testGlobalGetInt() throws Exception { assertThat(Settings.Global.getInt(contentResolver, "property", 0)).isEqualTo(0); assertThat(Settings.Global.getInt(contentResolver, "property", 2)).isEqualTo(2); Settings.Global.putInt(contentResolver, "property", 1); assertThat(Settings.Global.getInt(contentResolver, "property", 0)).isEqualTo(1); - - Settings.Global.putString(contentResolver, "property", "11"); - assertThat(Settings.Global.getInt(contentResolver, "property", 0)).isEqualTo(11); } @Test - public void testSystemGetString() { + public void testSystemGetString() throws Exception { assertThat(Settings.System.getString(contentResolver, "property")).isNull(); Settings.System.putString(contentResolver, "property", "value"); assertThat(Settings.System.getString(contentResolver, "property")).isEqualTo("value"); - - Settings.System.putInt(contentResolver, "property", 123); - assertThat(Settings.System.getString(contentResolver, "property")).isEqualTo("123"); - - Settings.System.putLong(contentResolver, "property", 456L); - assertThat(Settings.System.getString(contentResolver, "property")).isEqualTo("456"); - - Settings.System.putFloat(contentResolver, "property", 7.89f); - assertThat(Settings.System.getString(contentResolver, "property")).isEqualTo("7.89"); } @Test - public void testSystemGetLong() throws Settings.SettingNotFoundException { + public void testSystemGetLong() throws Exception { assertThat(Settings.System.getLong(contentResolver, "property", 10L)).isEqualTo(10L); Settings.System.putLong(contentResolver, "property", 42L); assertThat(Settings.System.getLong(contentResolver, "property")).isEqualTo(42L); assertThat(Settings.System.getLong(contentResolver, "property", 10L)).isEqualTo(42L); - - Settings.System.putString(contentResolver, "property", "11"); - assertThat(Settings.System.getLong(contentResolver, "property", 0)).isEqualTo(11L); } @Test - public void testSystemGetFloat() { + public void testSystemGetFloat() throws Exception { assertThat(Settings.System.getFloat(contentResolver, "property", 23.23f)).isEqualTo(23.23f); Settings.System.putFloat(contentResolver, "property", 42.42f); assertThat(Settings.System.getFloat(contentResolver, "property", 10L)).isEqualTo(42.42f); - - Settings.System.putString(contentResolver, "property", "11.2"); - assertThat(Settings.System.getFloat(contentResolver, "property", 0)).isEqualTo(11.2f); } @Test(expected = Settings.SettingNotFoundException.class) - public void testSystemGetLong_exception() throws Settings.SettingNotFoundException { + public void testSystemGetLong_exception() throws Exception { Settings.System.getLong(contentResolver, "property"); } @Test(expected = Settings.SettingNotFoundException.class) - public void testSystemGetInt_exception() throws Settings.SettingNotFoundException { + public void testSystemGetInt_exception() throws Exception { Settings.System.getInt(contentResolver, "property"); } @Test(expected = Settings.SettingNotFoundException.class) - public void testSystemGetFloat_exception() throws Settings.SettingNotFoundException { + public void testSystemGetFloat_exception() throws Exception { Settings.System.getFloat(contentResolver, "property"); } @Test public void testSet24HourMode_24() { ShadowSettings.set24HourTimeFormat(true); - assertThat(DateFormat.is24HourFormat(RuntimeEnvironment.application)).isTrue(); + assertThat( + DateFormat.is24HourFormat( + ((Application) ApplicationProvider.getApplicationContext()).getBaseContext())) + .isTrue(); } @Test public void testSet24HourMode_12() { ShadowSettings.set24HourTimeFormat(false); - assertThat(DateFormat.is24HourFormat(RuntimeEnvironment.application)).isFalse(); + assertThat( + DateFormat.is24HourFormat( + ((Application) ApplicationProvider.getApplicationContext()).getBaseContext())) + .isFalse(); + } + + @Test + public void testSetAdbEnabled_settingsSecure_true() { + ShadowSettings.setAdbEnabled(true); + + assertThat( + Secure.getInt( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Secure.ADB_ENABLED, + /* def= */ 0)) + .isEqualTo(1); + } + + @Test + public void testSetAdbEnabled_settingsSecure_false() { + ShadowSettings.setAdbEnabled(false); + + assertThat( + Secure.getInt( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Secure.ADB_ENABLED, + /* def= */ 1)) + .isEqualTo(0); + } + + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void testSetAdbEnabled_sinceJBMR1_settingsGlobal_true() { + ShadowSettings.setAdbEnabled(true); + + assertThat( + Global.getInt( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Global.ADB_ENABLED, + /* def= */ 0)) + .isEqualTo(1); + } + + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void testSetAdbEnabled_sinceJBMR1_settingsGlobal_false() { + ShadowSettings.setAdbEnabled(false); + + assertThat( + Global.getInt( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Global.ADB_ENABLED, + /* def= */ 1)) + .isEqualTo(0); + } + + @Test + public void testSetInstallNonMarketApps_settingsSecure_true() { + ShadowSettings.setInstallNonMarketApps(true); + + assertThat( + Secure.getInt( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Secure.INSTALL_NON_MARKET_APPS, + /* def= */ 0)) + .isEqualTo(1); + } + + @Test + public void testSetInstallNonMarketApps_settingsSecure_false() { + ShadowSettings.setInstallNonMarketApps(false); + + assertThat( + Secure.getInt( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Secure.INSTALL_NON_MARKET_APPS, + /* def= */ 1)) + .isEqualTo(0); + } + + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void testSetInstallNonMarketApps_sinceJBMR1_settingsGlobal_true() { + ShadowSettings.setInstallNonMarketApps(true); + + assertThat( + Global.getInt( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Global.INSTALL_NON_MARKET_APPS, + /* def= */ 0)) + .isEqualTo(1); + } + + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void testSetInstallNonMarketApps_sinceJBMR1_settingsGlobal_false() { + ShadowSettings.setInstallNonMarketApps(false); + + assertThat( + Global.getInt( + ((Application) ApplicationProvider.getApplicationContext()).getContentResolver(), + Global.INSTALL_NON_MARKET_APPS, + /* def= */ 1)) + .isEqualTo(0); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowShapeDrawableTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowShapeDrawableTest.java index ca4ce3dc1..ca02d623c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowShapeDrawableTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowShapeDrawableTest.java @@ -5,11 +5,11 @@ import static org.junit.Assert.assertNotNull; import android.graphics.Paint; import android.graphics.drawable.ShapeDrawable; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowShapeDrawableTest { @Test public void getPaint_ShouldReturnTheSamePaint() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSharedMemoryTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSharedMemoryTest.java index 4e6011239..40bc27603 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSharedMemoryTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSharedMemoryTest.java @@ -4,15 +4,13 @@ import static com.google.common.truth.Truth.assertThat; import android.os.Build; import android.os.SharedMemory; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -/** - * Unit tests for {@link ShadowSharedMemory}. - */ -@RunWith(RobolectricTestRunner.class) +/** Unit tests for {@link ShadowSharedMemory}. */ +@RunWith(AndroidJUnit4.class) public class ShadowSharedMemoryTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSharedPreferencesTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSharedPreferencesTest.java index 13c653d60..0fed69109 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSharedPreferencesTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSharedPreferencesTest.java @@ -6,9 +6,12 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verifyZeroInteractions; +import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -16,10 +19,8 @@ import java.util.Set; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSharedPreferencesTest { private final static String FILENAME = "filename"; private SharedPreferences.Editor editor; @@ -31,7 +32,7 @@ public class ShadowSharedPreferencesTest { @Before public void setUp() { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); sharedPreferences = context.getSharedPreferences(FILENAME, Context.MODE_PRIVATE); // Ensure no shared preferences have leaked from previous tests. @@ -208,4 +209,18 @@ public class ShadowSharedPreferencesTest { String restored = anotherSharedPreferences.getString("foo", null); assertThat(restored).isEqualTo("bar"); } + + /** + * Tests a sequence of operations in SharedPrefereces that would previously cause a deadlock. + * + * @throws Exception + */ + @Test + public void commit_multipleTimes() throws Exception { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + sharedPreferences.edit().putBoolean("foo", true).apply(); + sharedPreferences.edit().putBoolean("bar", true).commit(); + assertTrue(sharedPreferences.getBoolean("foo", false)); + assertTrue(sharedPreferences.getBoolean("bar", false)); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowShortcutManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowShortcutManagerTest.java index f7f0f6c1f..fcc36b1b9 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowShortcutManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowShortcutManagerTest.java @@ -4,29 +4,32 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.app.Application; import android.content.Context; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.os.Build; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; /** Unit tests for ShadowShortcutManager. */ @Config(minSdk = Build.VERSION_CODES.N_MR1) -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public final class ShadowShortcutManagerTest { private ShortcutManager shortcutManager; @Before public void setUp() { shortcutManager = - (ShortcutManager) RuntimeEnvironment.application.getSystemService(Context.SHORTCUT_SERVICE); + (ShortcutManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.SHORTCUT_SERVICE); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSimpleCursorAdapterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSimpleCursorAdapterTest.java index fd1a17f55..6b2e4d55e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSimpleCursorAdapterTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSimpleCursorAdapterTest.java @@ -2,20 +2,28 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.widget.SimpleCursorAdapter; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSimpleCursorAdapterTest { @Test public void testChangeCursor() { - SimpleCursorAdapter adapter = new SimpleCursorAdapter(RuntimeEnvironment.application, 1, null, new String[]{"name"}, new int[]{2}, 0); + SimpleCursorAdapter adapter = + new SimpleCursorAdapter( + (Application) ApplicationProvider.getApplicationContext(), + 1, + null, + new String[] {"name"}, + new int[] {2}, + 0); Cursor cursor = setUpDatabase(); @@ -26,7 +34,14 @@ public class ShadowSimpleCursorAdapterTest { @Test public void testSwapCursor() { - SimpleCursorAdapter adapter = new SimpleCursorAdapter(RuntimeEnvironment.application, 1, null, new String[]{"name"}, new int[]{2}, 0); + SimpleCursorAdapter adapter = + new SimpleCursorAdapter( + (Application) ApplicationProvider.getApplicationContext(), + 1, + null, + new String[] {"name"}, + new int[] {2}, + 0); Cursor cursor = setUpDatabase(); @@ -37,7 +52,14 @@ public class ShadowSimpleCursorAdapterTest { @Test public void testSwapCursorToNull() { - SimpleCursorAdapter adapter = new SimpleCursorAdapter(RuntimeEnvironment.application, 1, null, new String[]{"name"}, new int[]{2}, 0); + SimpleCursorAdapter adapter = + new SimpleCursorAdapter( + (Application) ApplicationProvider.getApplicationContext(), + 1, + null, + new String[] {"name"}, + new int[] {2}, + 0); Cursor cursor = setUpDatabase(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSliceManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSliceManagerTest.java new file mode 100644 index 000000000..22ec514de --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSliceManagerTest.java @@ -0,0 +1,71 @@ +package org.robolectric.shadows; + +import static com.google.common.truth.Truth.assertThat; +import static org.robolectric.Shadows.shadowOf; + +import android.app.slice.SliceManager; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build.VERSION_CODES; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +/** Tests for {@link ShadowSliceManager}. */ +@RunWith(AndroidJUnit4.class) +@Config(minSdk = VERSION_CODES.P) +public final class ShadowSliceManagerTest { + + private static final String PACKAGE_NAME_1 = "com.google.testing.slicemanager.foo"; + private static final int PACKAGE_1_UID = 10; + private Uri sliceUri1; + private static final String PACKAGE_NAME_2 = "com.google.testing.slicemanager.bar"; + private static final int PACKAGE_2_UID = 20; + private Uri sliceUri2; + private SliceManager sliceManager; + + @Before + public void setUp() { + PackageManager packageManager = RuntimeEnvironment.application.getPackageManager(); + ShadowApplicationPackageManager shadowPackageManager = + (ShadowApplicationPackageManager) shadowOf(packageManager); + shadowPackageManager.setPackagesForUid(PACKAGE_1_UID, new String[] {PACKAGE_NAME_1}); + shadowPackageManager.setPackagesForUid(PACKAGE_2_UID, new String[] {PACKAGE_NAME_2}); + sliceUri1 = Uri.parse("content://a/b"); + sliceUri2 = Uri.parse("content://c/d"); + sliceManager = ApplicationProvider.getApplicationContext().getSystemService(SliceManager.class); + } + + @Test + public void testGrantSlicePermission_grantsPermissionToPackage() { + sliceManager.grantSlicePermission(PACKAGE_NAME_1, sliceUri1); + assertThat(sliceManager.checkSlicePermission(sliceUri1, /* pid= */ 1, PACKAGE_1_UID)) + .isEqualTo(PackageManager.PERMISSION_GRANTED); + } + + @Test + public void testGrantSlicePermission_doesNotGrantPermissionToOtherPackage() { + sliceManager.grantSlicePermission(PACKAGE_NAME_1, sliceUri1); + assertThat(sliceManager.checkSlicePermission(sliceUri1, /* pid= */ 1, PACKAGE_2_UID)) + .isEqualTo(PackageManager.PERMISSION_DENIED); + } + + @Test + public void testGrantSlicePermission_doesNotGrantPermissionToOtherSliceUri() { + sliceManager.grantSlicePermission(PACKAGE_NAME_1, sliceUri1); + assertThat(sliceManager.checkSlicePermission(sliceUri2, /* pid= */ 1, PACKAGE_1_UID)) + .isEqualTo(PackageManager.PERMISSION_DENIED); + } + + @Test + public void testRevokeSlicePermission_revokesPermissionToPackage() { + sliceManager.grantSlicePermission(PACKAGE_NAME_1, sliceUri1); + sliceManager.revokeSlicePermission(PACKAGE_NAME_1, sliceUri1); + assertThat(sliceManager.checkSlicePermission(sliceUri1, /* pid= */ 1, PACKAGE_1_UID)) + .isEqualTo(PackageManager.PERMISSION_DENIED); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSmsManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSmsManagerTest.java index 93fb2795d..a7ff59f41 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSmsManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSmsManagerTest.java @@ -5,16 +5,17 @@ import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.PendingIntent; import android.telephony.SmsManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.collect.Lists; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = JELLY_BEAN_MR2) public class ShadowSmsManagerTest { private SmsManager smsManager = SmsManager.getDefault(); @@ -78,8 +79,12 @@ public class ShadowSmsManagerTest { public void sendDataMessage_shouldStoreLastParameters() { final short destPort = 24; final byte[] data = new byte[]{0, 1, 2, 3, 4}; - final PendingIntent sentIntent = PendingIntent.getActivity(RuntimeEnvironment.application, 10, null, 0); - final PendingIntent deliveryIntent = PendingIntent.getActivity(RuntimeEnvironment.application, 10, null, 0); + final PendingIntent sentIntent = + PendingIntent.getActivity( + (Application) ApplicationProvider.getApplicationContext(), 10, null, 0); + final PendingIntent deliveryIntent = + PendingIntent.getActivity( + (Application) ApplicationProvider.getApplicationContext(), 10, null, 0); smsManager.sendDataMessage(destAddress, scAddress, destPort, data, sentIntent, deliveryIntent); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSoundPoolTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSoundPoolTest.java index ca2998a6f..bc47871a4 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSoundPoolTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSoundPoolTest.java @@ -4,18 +4,21 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.robolectric.Shadows.shadowOf; import android.media.AudioManager; import android.media.SoundPool; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.Shadows; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowSoundPool.Playback; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSoundPoolTest { @Test @@ -39,10 +42,25 @@ public class ShadowSoundPoolTest { public void playedSoundsFromResourcesAreRecorded() { SoundPool soundPool = createSoundPool(); - int soundId = soundPool.load(RuntimeEnvironment.application, R.raw.sound, 1); + int soundId = soundPool.load(ApplicationProvider.getApplicationContext(), R.raw.sound, 1); soundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1); - assertThat(Shadows.shadowOf(soundPool).wasResourcePlayed(R.raw.sound)).isTrue(); + assertThat(shadowOf(soundPool).wasResourcePlayed(R.raw.sound)).isTrue(); + } + + @Test + public void playedSoundsFromResourcesAreCollected() { + SoundPool soundPool = createSoundPool(); + + int soundId = soundPool.load(ApplicationProvider.getApplicationContext(), R.raw.sound, 1); + soundPool.play(soundId, 1.0f, 0f, 0, 0, 0.5f); + soundPool.play(soundId, 0f, 1.0f, 1, 0, 2.0f); + + assertThat(shadowOf(soundPool).getResourcePlaybacks(R.raw.sound)) + .containsExactly( + new Playback(soundId, 1.0f, 0f, 0, 0, 0.5f), + new Playback(soundId, 0f, 1.0f, 1, 0, 2.0f)) + .inOrder(); } @Test @@ -52,19 +70,92 @@ public class ShadowSoundPoolTest { int soundId = soundPool.load("/mnt/sdcard/sound.wav", 1); soundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1); - assertThat(Shadows.shadowOf(soundPool).wasPathPlayed("/mnt/sdcard/sound.wav")).isTrue(); + assertThat(shadowOf(soundPool).wasPathPlayed("/mnt/sdcard/sound.wav")).isTrue(); + } + + @Test + public void playedSoundsFromPathAreCollected() { + SoundPool soundPool = createSoundPool(); + + int soundId = soundPool.load("/mnt/sdcard/sound.wav", 1); + soundPool.play(soundId, 0f, 1.0f, 1, 0, 2.0f); + soundPool.play(soundId, 1.0f, 0f, 0, 0, 0.5f); + + assertThat(shadowOf(soundPool).getPathPlaybacks("/mnt/sdcard/sound.wav")) + .containsExactly( + new Playback(soundId, 0f, 1.0f, 1, 0, 2.0f), + new Playback(soundId, 1.0f, 0f, 0, 0, 0.5f)) + .inOrder(); + } + + @Test + public void notifyPathLoaded_notifiesListener() { + SoundPool soundPool = createSoundPool(); + SoundPool.OnLoadCompleteListener listener = mock(SoundPool.OnLoadCompleteListener.class); + soundPool.setOnLoadCompleteListener(listener); + + int soundId = soundPool.load("/mnt/sdcard/sound.wav", 1); + shadowOf(soundPool).notifyPathLoaded("/mnt/sdcard/sound.wav", true); + + verify(listener).onLoadComplete(soundPool, soundId, 0); + } + + @Test + public void notifyResourceLoaded_notifiesListener() { + SoundPool soundPool = createSoundPool(); + SoundPool.OnLoadCompleteListener listener = mock(SoundPool.OnLoadCompleteListener.class); + soundPool.setOnLoadCompleteListener(listener); + + int soundId = soundPool.load(ApplicationProvider.getApplicationContext(), R.raw.sound, 1); + shadowOf(soundPool).notifyResourceLoaded(R.raw.sound, true); + + verify(listener).onLoadComplete(soundPool, soundId, 0); + } + + @Test + public void notifyPathLoaded_notifiesFailure() { + SoundPool soundPool = createSoundPool(); + SoundPool.OnLoadCompleteListener listener = mock(SoundPool.OnLoadCompleteListener.class); + soundPool.setOnLoadCompleteListener(listener); + + int soundId = soundPool.load("/mnt/sdcard/sound.wav", 1); + shadowOf(soundPool).notifyPathLoaded("/mnt/sdcard/sound.wav", false); + + verify(listener).onLoadComplete(soundPool, soundId, 1); + } + + @Test + public void notifyResourceLoaded_doNotFailWithoutListener() { + SoundPool soundPool = createSoundPool(); + + soundPool.load("/mnt/sdcard/sound.wav", 1); + shadowOf(soundPool).notifyPathLoaded("/mnt/sdcard/sound.wav", false); + } + + @Test(expected = IllegalArgumentException.class) + public void notifyPathLoaded_failIfLoadWasntCalled() { + SoundPool soundPool = createSoundPool(); + + shadowOf(soundPool).notifyPathLoaded("no.mp3", true); + } + + @Test(expected = IllegalArgumentException.class) + public void notifyResourceLoaded_failIfLoadWasntCalled() { + SoundPool soundPool = createSoundPool(); + + shadowOf(soundPool).notifyResourceLoaded(123, true); } @Test public void playedSoundsAreCleared() { SoundPool soundPool = createSoundPool(); - int soundId = soundPool.load(RuntimeEnvironment.application, R.raw.sound, 1); + int soundId = soundPool.load(ApplicationProvider.getApplicationContext(), R.raw.sound, 1); soundPool.play(soundId, 1.0f, 1.0f, 1, 0, 1); - assertThat(Shadows.shadowOf(soundPool).wasResourcePlayed(R.raw.sound)).isTrue(); - Shadows.shadowOf(soundPool).clearPlayed(); - assertThat(Shadows.shadowOf(soundPool).wasResourcePlayed(R.raw.sound)).isFalse(); + assertThat(shadowOf(soundPool).wasResourcePlayed(R.raw.sound)).isTrue(); + shadowOf(soundPool).clearPlayed(); + assertThat(shadowOf(soundPool).wasResourcePlayed(R.raw.sound)).isFalse(); } private SoundPool createSoundPool() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSpannableStringTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSpannableStringTest.java index e212fa65d..31443c1b2 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSpannableStringTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSpannableStringTest.java @@ -5,12 +5,12 @@ import static com.google.common.truth.Truth.assertThat; import android.text.SpannableString; import android.text.style.URLSpan; import android.text.style.UnderlineSpan; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSpannableStringTest { private static final String TEST_STRING = "Visit us at http://www.foobar.com for more selections"; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSpannedStringTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSpannedStringTest.java index 49f7709ab..37f8fe4d8 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSpannedStringTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSpannedStringTest.java @@ -4,11 +4,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import android.text.SpannedString; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSpannedStringTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSslErrorHandlerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSslErrorHandlerTest.java index 76cca4cea..31be9ab38 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSslErrorHandlerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSslErrorHandlerTest.java @@ -3,14 +3,14 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.webkit.SslErrorHandler; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSslErrorHandlerTest { private SslErrorHandler handler; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowStatFsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowStatFsTest.java index 6763103ba..f58c440cf 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowStatFsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowStatFsTest.java @@ -4,13 +4,13 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; import static com.google.common.truth.Truth.assertThat; import android.os.StatFs; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowStatFsTest { @Test public void shouldRegisterStats() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowStateListDrawableTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowStateListDrawableTest.java index 950256ecd..c7ac37e2a 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowStateListDrawableTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowStateListDrawableTest.java @@ -8,11 +8,11 @@ import android.R; import android.graphics.drawable.Drawable; import android.graphics.drawable.StateListDrawable; import android.util.StateSet; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowStateListDrawableTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowStaticLayoutTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowStaticLayoutTest.java index 8e30ad14c..254db507e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowStaticLayoutTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowStaticLayoutTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowStaticLayoutTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowStatusBarManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowStatusBarManagerTest.java new file mode 100644 index 000000000..1a71c74de --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowStatusBarManagerTest.java @@ -0,0 +1,60 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.M; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.util.ReflectionHelpers; +import org.robolectric.util.ReflectionHelpers.ClassParameter; + +/** Unit tests for {@link ShadowStatusBarManager}. */ +@RunWith(AndroidJUnit4.class) +public final class ShadowStatusBarManagerTest { + + @Test + public void getDisable() throws ClassNotFoundException { + callDisableMethodofStatusBarManager(ShadowStatusBarManager.DEFAULT_DISABLE_MASK); + assertThat( + ((ShadowStatusBarManager) + Shadow.extract( + getApplicationContext().getSystemService(Context.STATUS_BAR_SERVICE))) + .getDisableFlags()) + .isEqualTo(ShadowStatusBarManager.DEFAULT_DISABLE_MASK); + } + + @Test + @Config(minSdk = M) + public void getDisable2() throws ClassNotFoundException { + callDisable2MethodofStatusBarManager(ShadowStatusBarManager.DEFAULT_DISABLE2_MASK); + assertThat( + ((ShadowStatusBarManager) + Shadow.extract( + getApplicationContext().getSystemService(Context.STATUS_BAR_SERVICE))) + .getDisable2Flags()) + .isEqualTo(ShadowStatusBarManager.DEFAULT_DISABLE2_MASK); + } + + private static void callDisableMethodofStatusBarManager(int disableFlags) + throws ClassNotFoundException { + ReflectionHelpers.callInstanceMethod( + Class.forName("android.app.StatusBarManager"), + getApplicationContext().getSystemService(Context.STATUS_BAR_SERVICE), + "disable", + ClassParameter.from(int.class, disableFlags)); + } + + private static void callDisable2MethodofStatusBarManager(int disable2Flags) + throws ClassNotFoundException { + ReflectionHelpers.callInstanceMethod( + Class.forName("android.app.StatusBarManager"), + getApplicationContext().getSystemService(Context.STATUS_BAR_SERVICE), + "disable2", + ClassParameter.from(int.class, disable2Flags)); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowStorageManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowStorageManagerTest.java index b6392afe6..e1c4c7104 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowStorageManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowStorageManagerTest.java @@ -6,16 +6,20 @@ import static org.robolectric.RuntimeEnvironment.application; import static org.robolectric.Shadows.shadowOf; import android.content.Context; +import android.os.Parcel; +import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; +import android.os.storage.StorageVolume; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import java.io.File; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; /** Unit tests for {@link ShadowStorageManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowStorageManagerTest { private StorageManager storageManager; @@ -32,6 +36,24 @@ public class ShadowStorageManagerTest { @Test @Config(minSdk = N) + public void getStorageVolumes() { + File file1 = new File("/storage/sdcard"); + shadowOf(storageManager).addStorageVolume(buildAndGetStorageVolume(file1, "sd card")); + assertThat(shadowOf(storageManager).getStorageVolumes()).isNotNull(); + } + + @Test + @Config(minSdk = N) + public void getStorageVolume() { + File file1 = new File("/storage/internal"); + File file2 = new File("/storage/sdcard"); + shadowOf(storageManager).addStorageVolume(buildAndGetStorageVolume(file1, "internal")); + assertThat(shadowOf(storageManager).getStorageVolume(file1)).isNotNull(); + assertThat(shadowOf(storageManager).getStorageVolume(file2)).isNull(); + } + + @Test + @Config(minSdk = N) public void isFileEncryptedNativeOrEmulated() { shadowOf(storageManager).setFileEncryptedNativeOrEmulated(true); assertThat(StorageManager.isFileEncryptedNativeOrEmulated()).isTrue(); @@ -43,4 +65,13 @@ public class ShadowStorageManagerTest { shadowOf(application.getSystemService(UserManager.class)).setUserUnlocked(true); assertThat(StorageManager.isUserKeyUnlocked(0)).isTrue(); } + + private StorageVolume buildAndGetStorageVolume(File file, String description) { + Parcel parcel = Parcel.obtain(); + parcel.writeInt(0); + UserHandle userHandle = new UserHandle(parcel); + StorageVolumeBuilder storageVolumeBuilder = + new StorageVolumeBuilder("volume", file, description, userHandle, "mounted"); + return storageVolumeBuilder.build(); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowStrictModeTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowStrictModeTest.java index 85b7951e0..8c047e8c5 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowStrictModeTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowStrictModeTest.java @@ -1,11 +1,11 @@ package org.robolectric.shadows; import android.os.StrictMode; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowStrictModeTest { @Test public void setVmPolicyTest() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSubscriptionManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSubscriptionManagerTest.java index df660a0b9..70f503a65 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSubscriptionManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSubscriptionManagerTest.java @@ -6,15 +6,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.RuntimeEnvironment.application; import static org.robolectric.Shadows.shadowOf; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowSubscriptionManager.SubscriptionInfoBuilder; /** Test for {@link ShadowSubscriptionManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = N) public class ShadowSubscriptionManagerTest { @@ -29,6 +31,13 @@ public class ShadowSubscriptionManagerTest { } @Test + public void shouldGiveDefaultSubscriptionId() { + int testId = 42; + ShadowSubscriptionManager.setDefaultSubscriptionId(testId); + assertThat(subscriptionManager.getDefaultSubscriptionId()).isEqualTo(testId); + } + + @Test public void shouldGiveDefaultDataSubscriptionId() { int testId = 42; shadowSubscriptionManager.setDefaultDataSubscriptionId(testId); @@ -48,4 +57,120 @@ public class ShadowSubscriptionManagerTest { shadowSubscriptionManager.setDefaultVoiceSubscriptionId(testId); assertThat(subscriptionManager.getDefaultVoiceSubscriptionId()).isEqualTo(testId); } + + @Test + public void addOnSubscriptionsChangedListener_shouldAddListener() { + DummySubscriptionsChangedListener listener = new DummySubscriptionsChangedListener(); + shadowSubscriptionManager.addOnSubscriptionsChangedListener(listener); + + shadowSubscriptionManager.setActiveSubscriptionInfos( + SubscriptionInfoBuilder.newBuilder().setId(123).buildSubscriptionInfo()); + + assertThat(listener.subscriptionChanged).isTrue(); + } + + @Test + public void removeOnSubscriptionsChangedListener_shouldRemoveListener() { + DummySubscriptionsChangedListener listener = new DummySubscriptionsChangedListener(); + DummySubscriptionsChangedListener listener2 = new DummySubscriptionsChangedListener(); + shadowSubscriptionManager.addOnSubscriptionsChangedListener(listener); + shadowSubscriptionManager.addOnSubscriptionsChangedListener(listener2); + + shadowSubscriptionManager.removeOnSubscriptionsChangedListener(listener); + shadowSubscriptionManager.setActiveSubscriptionInfos( + SubscriptionInfoBuilder.newBuilder().setId(123).buildSubscriptionInfo()); + + assertThat(listener.subscriptionChanged).isFalse(); + assertThat(listener2.subscriptionChanged).isTrue(); + } + + @Test + public void getActiveSubscriptionInfo_shouldReturnInfoWithSubId() { + SubscriptionInfo expectedSubscriptionInfo = + SubscriptionInfoBuilder.newBuilder().setId(123).buildSubscriptionInfo(); + shadowSubscriptionManager.setActiveSubscriptionInfos(expectedSubscriptionInfo); + + assertThat(shadowSubscriptionManager.getActiveSubscriptionInfo(123)) + .isSameAs(expectedSubscriptionInfo); + } + + @Test + public void getActiveSubscriptionInfoForSimSlotIndex_shouldReturnInfoWithSlotIndex() { + SubscriptionInfo expectedSubscriptionInfo = + SubscriptionInfoBuilder.newBuilder().setSimSlotIndex(123).buildSubscriptionInfo(); + shadowSubscriptionManager.setActiveSubscriptionInfos(expectedSubscriptionInfo); + + assertThat(shadowSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(123)) + .isSameAs(expectedSubscriptionInfo); + } + + @Test + public void getActiveSubscriptionInfo_shouldReturnNullForNullList() { + shadowSubscriptionManager.setActiveSubscriptionInfoList(null); + assertThat(shadowSubscriptionManager.getActiveSubscriptionInfo(123)).isNull(); + } + + @Test + public void getActiveSubscriptionInfo_shouldReturnNullForNullVaargsList() { + shadowSubscriptionManager.setActiveSubscriptionInfos((SubscriptionInfo[]) null); + assertThat(shadowSubscriptionManager.getActiveSubscriptionInfo(123)).isNull(); + } + + @Test + public void getActiveSubscriptionInfo_shouldReturnNullForEmptyList() { + shadowSubscriptionManager.setActiveSubscriptionInfos(); + assertThat(shadowSubscriptionManager.getActiveSubscriptionInfo(123)).isNull(); + } + + @Test + public void isNetworkRoaming_shouldReturnTrueIfSet() { + shadowSubscriptionManager.setNetworkRoamingStatus(123, /*isNetworkRoaming=*/ true); + assertThat(shadowSubscriptionManager.isNetworkRoaming(123)).isTrue(); + } + + /** Multi act-asserts are discouraged but here we are testing the set+unset. */ + @Test + public void isNetworkRoaming_shouldReturnFalseIfUnset() { + shadowSubscriptionManager.setNetworkRoamingStatus(123, /*isNetworkRoaming=*/ true); + assertThat(shadowSubscriptionManager.isNetworkRoaming(123)).isTrue(); + + shadowSubscriptionManager.setNetworkRoamingStatus(123, /*isNetworkRoaming=*/ false); + assertThat(shadowSubscriptionManager.isNetworkRoaming(123)).isFalse(); + } + + /** Multi act-asserts are discouraged but here we are testing the set+clear. */ + @Test + public void isNetworkRoaming_shouldReturnFalseOnClear() { + shadowSubscriptionManager.setNetworkRoamingStatus(123, /*isNetworkRoaming=*/ true); + assertThat(shadowSubscriptionManager.isNetworkRoaming(123)).isTrue(); + + shadowSubscriptionManager.clearNetworkRoamingStatus(); + assertThat(shadowSubscriptionManager.isNetworkRoaming(123)).isFalse(); + } + + @Test + public void getActiveSubscriptionInfoCount_shouldReturnZeroIfActiveSubscriptionInfoListNotSet() { + shadowSubscriptionManager.setActiveSubscriptionInfoList(null); + + assertThat(shadowSubscriptionManager.getActiveSubscriptionInfoCount()).isEqualTo(0); + } + + @Test + public void getActiveSubscriptionInfoCount_shouldReturnSizeOfActiveSubscriotionInfosList() { + SubscriptionInfo expectedSubscriptionInfo = + SubscriptionInfoBuilder.newBuilder().setId(123).buildSubscriptionInfo(); + shadowSubscriptionManager.setActiveSubscriptionInfos(expectedSubscriptionInfo); + + assertThat(shadowSubscriptionManager.getActiveSubscriptionInfoCount()).isEqualTo(1); + } + + private static class DummySubscriptionsChangedListener + extends SubscriptionManager.OnSubscriptionsChangedListener { + private boolean subscriptionChanged = false; + + @Override + public void onSubscriptionsChanged() { + subscriptionChanged = true; + } + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSurfaceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSurfaceTest.java index f4bd4224f..5259a0705 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSurfaceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSurfaceTest.java @@ -5,11 +5,11 @@ import static org.robolectric.Shadows.shadowOf; import android.graphics.SurfaceTexture; import android.view.Surface; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSurfaceTest { private final SurfaceTexture texture = new SurfaceTexture(0); private final Surface surface = new Surface(texture); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSurfaceViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSurfaceViewTest.java index 1da99ca3b..5d1538772 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSurfaceViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSurfaceViewTest.java @@ -8,12 +8,12 @@ import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Window; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSurfaceViewTest { private SurfaceHolder.Callback callback1 = new TestCallback(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSyncResultTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSyncResultTest.java index cf16bdf87..a871619dc 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSyncResultTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSyncResultTest.java @@ -5,11 +5,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.content.SyncResult; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSyncResultTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSystemClockTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSystemClockTest.java index 2837517f6..01a9ea9d9 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSystemClockTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSystemClockTest.java @@ -1,5 +1,6 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static android.os.Build.VERSION_CODES.P; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertFalse; @@ -7,15 +8,15 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.os.SystemClock; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.time.DateTimeException; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.internal.bytecode.RobolectricInternals; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSystemClockTest { @Test public void shouldAllowForFakingOfTime() throws Exception { @@ -30,7 +31,7 @@ public class ShadowSystemClockTest { SystemClock.sleep(34); assertThat(SystemClock.uptimeMillis()).isEqualTo(1034); } - + @Test public void testSetCurrentTime() { Robolectric.getForegroundThreadScheduler().advanceTo(1000); @@ -40,7 +41,23 @@ public class ShadowSystemClockTest { assertFalse(SystemClock.setCurrentTimeMillis(1000)); assertThat(ShadowSystemClock.now()).isEqualTo(1034); } - + + @Test + public void testElapsedRealtime() { + Robolectric.getForegroundThreadScheduler().advanceTo(1000); + assertThat(SystemClock.elapsedRealtime()).isEqualTo(1000); + Robolectric.getForegroundThreadScheduler().advanceTo(1034); + assertThat(SystemClock.elapsedRealtime()).isEqualTo(1034); + } + + @Test @Config(minSdk = JELLY_BEAN_MR1) + public void testElapsedRealtimeNanos() { + Robolectric.getForegroundThreadScheduler().advanceTo(1000); + assertThat(SystemClock.elapsedRealtimeNanos()).isEqualTo(1000000000); + Robolectric.getForegroundThreadScheduler().advanceTo(1034); + assertThat(SystemClock.elapsedRealtimeNanos()).isEqualTo(1034000000); + } + @Test public void shouldInterceptSystemTimeCalls() throws Throwable { ShadowSystemClock.setNanoTime(3141592L); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowSystemPropertiesTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowSystemPropertiesTest.java index 1ea40bfbf..98f711d73 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowSystemPropertiesTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowSystemPropertiesTest.java @@ -3,12 +3,12 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.os.SystemProperties; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowSystemPropertiesTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTabActivityTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTabActivityTest.java index fcbd5071d..c7b5eb464 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTabActivityTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTabActivityTest.java @@ -5,13 +5,13 @@ import static com.google.common.truth.Truth.assertThat; import android.app.TabActivity; import android.widget.TabHost; import android.widget.TabWidget; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTabActivityTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTabHostTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTabHostTest.java index 1646944c3..dd83d9cc1 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTabHostTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTabHostTest.java @@ -5,36 +5,37 @@ import static org.junit.Assert.assertNull; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.Application; import android.app.TabActivity; import android.view.View; import android.widget.TabHost; import android.widget.TabWidget; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTabHostTest { @Test public void newTabSpec_shouldMakeATabSpec() throws Exception { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec tabSpec = tabHost.newTabSpec("Foo"); assertThat(tabSpec.getTag()).isEqualTo("Foo"); } @Test public void shouldAddTabsToLayoutWhenAddedToHost() { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); - View fooView = new View(RuntimeEnvironment.application); + View fooView = new View((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec foo = tabHost.newTabSpec("Foo").setIndicator(fooView); - View barView = new View(RuntimeEnvironment.application); + View barView = new View((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec bar = tabHost.newTabSpec("Bar").setIndicator(barView); tabHost.addTab(foo); @@ -46,7 +47,7 @@ public class ShadowTabHostTest { @Test public void shouldReturnTabSpecsByTag() throws Exception { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec foo = tabHost.newTabSpec("Foo"); TabHost.TabSpec bar = tabHost.newTabSpec("Bar"); TabHost.TabSpec baz = tabHost.newTabSpec("Baz"); @@ -62,7 +63,7 @@ public class ShadowTabHostTest { @Test public void shouldFireTheTabChangeListenerWhenCurrentTabIsSet() throws Exception { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec foo = tabHost.newTabSpec("Foo"); TabHost.TabSpec bar = tabHost.newTabSpec("Bar"); @@ -82,7 +83,7 @@ public class ShadowTabHostTest { @Test public void shouldFireTheTabChangeListenerWhenTheCurrentTabIsSetByTag() throws Exception { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec foo = tabHost.newTabSpec("Foo"); TabHost.TabSpec bar = tabHost.newTabSpec("Bar"); @@ -102,14 +103,18 @@ public class ShadowTabHostTest { @Test public void shouldRetrieveTheCurrentViewFromTabContentFactory() { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); - - TabHost.TabSpec foo = tabHost.newTabSpec("Foo").setContent( - tag -> { - TextView tv = new TextView(RuntimeEnvironment.application); - tv.setText("The Text of " + tag); - return tv; - }); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); + + TabHost.TabSpec foo = + tabHost + .newTabSpec("Foo") + .setContent( + tag -> { + TextView tv = + new TextView((Application) ApplicationProvider.getApplicationContext()); + tv.setText("The Text of " + tag); + return tv; + }); tabHost.addTab(foo); tabHost.setCurrentTabByTag("Foo"); @@ -143,7 +148,7 @@ public class ShadowTabHostTest { @Test public void canGetCurrentTabTag() throws Exception { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec foo = tabHost.newTabSpec("Foo"); TabHost.TabSpec bar = tabHost.newTabSpec("Bar"); @@ -160,7 +165,7 @@ public class ShadowTabHostTest { @Test public void canGetCurrentTab() throws Exception { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec foo = tabHost.newTabSpec("Foo"); TabHost.TabSpec bar = tabHost.newTabSpec("Bar"); @@ -184,7 +189,7 @@ public class ShadowTabHostTest { @Test public void setCurrentTabByTagShouldAcceptNullAsParameter() throws Exception { - TabHost tabHost = new TabHost(RuntimeEnvironment.application); + TabHost tabHost = new TabHost((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec foo = tabHost.newTabSpec("Foo"); tabHost.addTab(foo); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTabSpecTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTabSpecTest.java index 7c4e8f34b..735eacaa2 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTabSpecTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTabSpecTest.java @@ -3,6 +3,7 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Intent; import android.graphics.Canvas; import android.graphics.ColorFilter; @@ -10,14 +11,14 @@ import android.graphics.drawable.Drawable; import android.view.View; import android.widget.TabHost; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTabSpecTest { Drawable icon1; @@ -28,8 +29,9 @@ public class ShadowTabSpecTest { @Test public void shouldGetAndSetTheIndicator() throws Exception { - TabHost.TabSpec spec = new TabHost(RuntimeEnvironment.application).newTabSpec("foo"); - View view = new View(RuntimeEnvironment.application); + TabHost.TabSpec spec = + new TabHost((Application) ApplicationProvider.getApplicationContext()).newTabSpec("foo"); + View view = new View((Application) ApplicationProvider.getApplicationContext()); TabHost.TabSpec self = spec.setIndicator(view); assertThat(self).isSameAs(spec); assertThat(shadowOf(spec).getIndicatorAsView()).isSameAs(view); @@ -37,7 +39,8 @@ public class ShadowTabSpecTest { @Test public void shouldGetAndSetTheIntentContent() throws Exception { - TabHost.TabSpec spec = new TabHost(RuntimeEnvironment.application).newTabSpec("foo"); + TabHost.TabSpec spec = + new TabHost((Application) ApplicationProvider.getApplicationContext()).newTabSpec("foo"); Intent intent = new Intent(); TabHost.TabSpec self = spec.setContent(intent); assertThat(self).isSameAs(spec); @@ -46,8 +49,11 @@ public class ShadowTabSpecTest { @Test public void shouldGetAndSetTheIndicatorLabel() throws Exception { - TabHost.TabSpec spec = new TabHost(RuntimeEnvironment.application).newTabSpec("foo") - .setContent(R.layout.main).setIndicator("labelText"); + TabHost.TabSpec spec = + new TabHost((Application) ApplicationProvider.getApplicationContext()) + .newTabSpec("foo") + .setContent(R.layout.main) + .setIndicator("labelText"); assertThat(shadowOf(spec).getIndicatorLabel()).isEqualTo("labelText"); assertThat(shadowOf(spec).getText()).isEqualTo("labelText"); @@ -55,8 +61,11 @@ public class ShadowTabSpecTest { @Test public void shouldGetAndSetTheIndicatorLabelAndIcon() throws Exception { - TabHost.TabSpec spec = new TabHost(RuntimeEnvironment.application).newTabSpec("foo") - .setContent(R.layout.main).setIndicator("labelText", icon1); + TabHost.TabSpec spec = + new TabHost((Application) ApplicationProvider.getApplicationContext()) + .newTabSpec("foo") + .setContent(R.layout.main) + .setIndicator("labelText", icon1); assertThat(shadowOf(spec).getIndicatorLabel()).isEqualTo("labelText"); assertThat(shadowOf(spec).getText()).isEqualTo("labelText"); @@ -65,12 +74,16 @@ public class ShadowTabSpecTest { @Test public void shouldSetTheContentView() throws Exception { - TabHost.TabSpec foo = new TabHost(RuntimeEnvironment.application).newTabSpec("Foo").setContent( - tag -> { - TextView tv = new TextView(RuntimeEnvironment.application); - tv.setText("The Text of " + tag); - return tv; - }); + TabHost.TabSpec foo = + new TabHost((Application) ApplicationProvider.getApplicationContext()) + .newTabSpec("Foo") + .setContent( + tag -> { + TextView tv = + new TextView((Application) ApplicationProvider.getApplicationContext()); + tv.setText("The Text of " + tag); + return tv; + }); ShadowTabHost.ShadowTabSpec shadowFoo = shadowOf(foo); TextView textView = (TextView) shadowFoo.getContentView(); @@ -81,8 +94,10 @@ public class ShadowTabSpecTest { @Test public void shouldSetTheContentViewId() throws Exception { - TabHost.TabSpec foo = new TabHost(RuntimeEnvironment.application).newTabSpec("Foo") - .setContent(R.id.title); + TabHost.TabSpec foo = + new TabHost((Application) ApplicationProvider.getApplicationContext()) + .newTabSpec("Foo") + .setContent(R.id.title); ShadowTabHost.ShadowTabSpec shadowFoo = shadowOf(foo); int viewId = shadowFoo.getContentViewId(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java index cdd426068..c92509b51 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTelecomManagerTest.java @@ -6,20 +6,21 @@ import static android.os.Build.VERSION_CODES.M; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.ComponentName; import android.content.Context; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.List; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowTelecomManagerTest { @@ -27,7 +28,10 @@ public class ShadowTelecomManagerTest { @Before public void setUp() { - telecomService = (TelecomManager) RuntimeEnvironment.application.getSystemService(Context.TELECOM_SERVICE); + telecomService = + (TelecomManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.TELECOM_SERVICE); } @Test @@ -151,6 +155,57 @@ public class ShadowTelecomManagerTest { } @Test + public void testIsRinging_noIncomingOrUnknownCallsAdded_shouldBeFalse() { + assertThat(shadowOf(telecomService).isRinging()).isFalse(); + } + + @Test + public void testIsRinging_incomingCallAdded_shouldBeTrue() { + telecomService.addNewIncomingCall(createHandle("id"), null); + + assertThat(shadowOf(telecomService).isRinging()).isTrue(); + } + + @Test + public void testIsRinging_unknownCallAdded_shouldBeTrue() { + shadowOf(telecomService).addNewUnknownCall(createHandle("id"), null); + + assertThat(shadowOf(telecomService).isRinging()).isTrue(); + } + + @Test + public void testIsRinging_incomingCallAdded_thenRingerSilenced_shouldBeFalse() { + telecomService.addNewIncomingCall(createHandle("id"), null); + telecomService.silenceRinger(); + + assertThat(shadowOf(telecomService).isRinging()).isFalse(); + } + + @Test + public void testIsRinging_unknownCallAdded_thenRingerSilenced_shouldBeFalse() { + shadowOf(telecomService).addNewUnknownCall(createHandle("id"), null); + telecomService.silenceRinger(); + + assertThat(shadowOf(telecomService).isRinging()).isFalse(); + } + + @Test + public void testIsRinging_ringerSilenced_thenIncomingCallAdded_shouldBeTrue() { + telecomService.silenceRinger(); + telecomService.addNewIncomingCall(createHandle("id"), null); + + assertThat(shadowOf(telecomService).isRinging()).isTrue(); + } + + @Test + public void testIsRinging_ringerSilenced_thenUnknownCallAdded_shouldBeTrue() { + telecomService.silenceRinger(); + shadowOf(telecomService).addNewUnknownCall(createHandle("id"), null); + + assertThat(shadowOf(telecomService).isRinging()).isTrue(); + } + + @Test @Config(minSdk = M) public void setDefaultDialerPackage() { shadowOf(telecomService).setDefaultDialer("some.package"); @@ -158,7 +213,8 @@ public class ShadowTelecomManagerTest { } private static PhoneAccountHandle createHandle(String id) { - return createHandle(RuntimeEnvironment.application.getPackageName(), id); + return createHandle( + ((Application) ApplicationProvider.getApplicationContext()).getPackageName(), id); } private static PhoneAccountHandle createHandle(String packageName, String id) { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTelephonyManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTelephonyManagerTest.java index 937f04b28..b1123a8e7 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTelephonyManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTelephonyManagerTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.verify; import static org.robolectric.RuntimeEnvironment.application; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.ComponentName; import android.content.Intent; import android.net.Uri; @@ -34,16 +35,16 @@ import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Collections; import java.util.List; import org.junit.Before; 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) +@RunWith(AndroidJUnit4.class) public class ShadowTelephonyManagerTest { private TelephonyManager telephonyManager; @@ -112,6 +113,19 @@ public class ShadowTelephonyManagerTest { assertEquals("SomeSimOperatorName", telephonyManager.getSimOperatorName()); } + @Test(expected = SecurityException.class) + public void getSimSerialNumber_shouldThrowSecurityExceptionWhenReadPhoneStatePermissionNotGranted() + throws Exception { + shadowTelephonyManager.setReadPhoneStatePermission(false); + telephonyManager.getSimSerialNumber(); + } + + @Test + public void shouldGetSimSerialNumber() { + shadowTelephonyManager.setSimSerialNumber("SomeSerialNumber"); + assertEquals("SomeSerialNumber", telephonyManager.getSimSerialNumber()); + } + @Test public void shouldGiveNetworkType() { shadowTelephonyManager.setNetworkType(TelephonyManager.NETWORK_TYPE_CDMA); @@ -119,6 +133,14 @@ public class ShadowTelephonyManagerTest { } @Test + @Config(minSdk = N) + public void shouldGiveVoiceNetworkType() { + shadowTelephonyManager.setVoiceNetworkType(TelephonyManager.NETWORK_TYPE_CDMA); + assertThat(telephonyManager.getVoiceNetworkType()) + .isEqualTo(TelephonyManager.NETWORK_TYPE_CDMA); + } + + @Test @Config(minSdk = JELLY_BEAN_MR1) public void shouldGiveAllCellInfo() { PhoneStateListener listener = mock(PhoneStateListener.class); @@ -245,7 +267,9 @@ public class ShadowTelephonyManagerTest { public void shouldGiveVoiceVibrationEnabled() { PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle( - new ComponentName(RuntimeEnvironment.application, Object.class), "handle"); + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), Object.class), + "handle"); shadowTelephonyManager.setVoicemailVibrationEnabled(phoneAccountHandle, true); @@ -257,7 +281,9 @@ public class ShadowTelephonyManagerTest { public void shouldGiveVoicemailRingtoneUri() { PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle( - new ComponentName(RuntimeEnvironment.application, Object.class), "handle"); + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), Object.class), + "handle"); Uri ringtoneUri = Uri.fromParts("file", "ringtone.mp3", /* fragment = */ null); shadowTelephonyManager.setVoicemailRingtoneUri(phoneAccountHandle, ringtoneUri); @@ -270,7 +296,9 @@ public class ShadowTelephonyManagerTest { public void shouldSetVoicemailRingtoneUri() { PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle( - new ComponentName(RuntimeEnvironment.application, Object.class), "handle"); + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), Object.class), + "handle"); Uri ringtoneUri = Uri.fromParts("file", "ringtone.mp3", /* fragment = */ null); // Note: Using the real manager to set, instead of the shadow. @@ -284,7 +312,9 @@ public class ShadowTelephonyManagerTest { public void shouldCreateForPhoneAccountHandle() { PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle( - new ComponentName(RuntimeEnvironment.application, Object.class), "handle"); + new ComponentName( + (Application) ApplicationProvider.getApplicationContext(), Object.class), + "handle"); TelephonyManager mockTelephonyManager = mock(TelephonyManager.class); shadowTelephonyManager.setTelephonyManagerForHandle(phoneAccountHandle, mockTelephonyManager); @@ -407,4 +437,12 @@ public class ShadowTelephonyManagerTest { assertThat(shadowTelephonyManager.getSimCountryIso()).isEmpty(); } + + @Test + public void shouldSetSubscriberId() { + String subscriberId = "123451234512345"; + shadowTelephonyManager.setSubscriberId(subscriberId); + + assertThat(shadowTelephonyManager.getSubscriberId()).isEqualTo(subscriberId); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTelephonyTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTelephonyTest.java new file mode 100644 index 000000000..18dc58797 --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTelephonyTest.java @@ -0,0 +1,45 @@ +package org.robolectric.shadows; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Application; +import android.content.Context; +import android.os.Build.VERSION_CODES; +import android.provider.Telephony.Sms; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowTelephony.ShadowSms; + +/** Unit tests for {@link ShadowTelephony}. */ +@RunWith(AndroidJUnit4.class) +@Config(minSdk = VERSION_CODES.KITKAT) +public class ShadowTelephonyTest { + private static final String TEST_PACKAGE_NAME = "test.package.name"; + + private Context context; + + @Before + public void setUp() { + context = (Application) ApplicationProvider.getApplicationContext(); + } + + @Test + public void shadowSms_getDefaultSmsPackage() { + ShadowSms.setDefaultSmsPackage(TEST_PACKAGE_NAME); + + assertThat(Sms.getDefaultSmsPackage(context)).isEqualTo(TEST_PACKAGE_NAME); + } + + @Test + public void shadowSms_getDefaultSmsPackage_returnsNull_whenNoSmsPackageIsSet() { + // Make sure #reset is doing its job + ShadowSms.setDefaultSmsPackage(TEST_PACKAGE_NAME); + ShadowSms.reset(); + + assertThat(Sms.getDefaultSmsPackage(context)).isNull(); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTest.java index 66308c319..8646217af 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTest.java @@ -4,13 +4,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTest { private ClassLoader myClassLoader; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextPaintTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextPaintTest.java index 9fe12e1d2..f60493691 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextPaintTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextPaintTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.text.TextPaint; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTextPaintTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextToSpeechTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextToSpeechTest.java index 7929a229c..042057f11 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextToSpeechTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextToSpeechTest.java @@ -5,13 +5,13 @@ import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import android.speech.tts.TextToSpeech; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTextToSpeechTest { private TextToSpeech textToSpeech; private Activity activity; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextUtilsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextUtilsTest.java index a548f776d..23f6dffad 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextUtilsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextUtilsTest.java @@ -5,12 +5,12 @@ import static org.junit.Assert.assertArrayEquals; import android.text.TextPaint; import android.text.TextUtils; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Arrays; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTextUtilsTest { @Test public void testExpandTemplate() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextViewTest.java index d0ee2d4db..e849b0238 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTextViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTextViewTest.java @@ -15,6 +15,7 @@ import static org.robolectric.Robolectric.buildActivity; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.Application; import android.graphics.Typeface; import android.text.Editable; import android.text.InputFilter; @@ -35,6 +36,8 @@ import android.view.MotionEvent; import android.view.inputmethod.EditorInfo; import android.widget.FrameLayout; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -44,12 +47,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.shadow.api.Shadow; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTextViewTest { private static final String INITIAL_TEXT = "initial text"; @@ -93,8 +94,8 @@ public class ShadowTextViewTest { textView.setText("here's some text http://google.com/\nblah\thttp://another.com/123?456 blah"); assertThat(urlStringsFrom(textView.getUrls())).isEqualTo(asList( - "http://google.com", - "http://another.com/123?456" + "http://google.com", + "http://another.com/123?456" )); } @@ -127,7 +128,9 @@ public class ShadowTextViewTest { @Test public void testGetTextAppearanceId() throws Exception { - textView.setTextAppearance(RuntimeEnvironment.application, android.R.style.TextAppearance_Small); + textView.setTextAppearance( + (Application) ApplicationProvider.getApplicationContext(), + android.R.style.TextAppearance_Small); assertThat(shadowOf(textView).getTextAppearanceId()).isEqualTo(android.R.style.TextAppearance_Small); } @@ -439,7 +442,11 @@ public class ShadowTextViewTest { @Test public void setTextSize_shouldHandleDips() throws Exception { - RuntimeEnvironment.application.getResources().getDisplayMetrics().density = 1.5f; + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDisplayMetrics() + .density = + 1.5f; textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10); assertThat(textView.getTextSize()).isEqualTo(15f); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); @@ -451,7 +458,11 @@ public class ShadowTextViewTest { textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); assertThat(textView.getTextSize()).isEqualTo(10f); - RuntimeEnvironment.application.getResources().getDisplayMetrics().scaledDensity = 1.5f; + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDisplayMetrics() + .scaledDensity = + 1.5f; textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10); assertThat(textView.getTextSize()).isEqualTo(15f); @@ -459,7 +470,11 @@ public class ShadowTextViewTest { @Test public void setTextSize_shouldHandlePixels() throws Exception { - RuntimeEnvironment.application.getResources().getDisplayMetrics().density = 1.5f; + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDisplayMetrics() + .density = + 1.5f; textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 10); assertThat(textView.getTextSize()).isEqualTo(10f); textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 20); @@ -588,7 +603,7 @@ public class ShadowTextViewTest { @Override public boolean onGenericMotionEvent(TextView widget, Spannable text, - MotionEvent event) { + MotionEvent event) { return false; } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java index 7bc8f31b1..b97c61213 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowThemeTest.java @@ -4,6 +4,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Robolectric.buildActivity; import android.app.Activity; +import android.app.Application; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; @@ -14,24 +15,24 @@ import android.util.AttributeSet; import android.util.Xml; import android.view.View; import android.widget.Button; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.xmlpull.v1.XmlPullParser; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowThemeTest { private Resources resources; @Before public void setUp() throws Exception { - resources = RuntimeEnvironment.application.getResources(); + resources = ((Application) ApplicationProvider.getApplicationContext()).getResources(); } @After diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTileServiceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTileServiceTest.java index 860c80e8a..671be4265 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTileServiceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTileServiceTest.java @@ -5,14 +5,14 @@ import static com.google.common.truth.Truth.assertThat; import android.os.Build; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; /** Test for {@link org.robolectric.shadows.ShadowTileService}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(sdk = Build.VERSION_CODES.N) public final class ShadowTileServiceTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTileTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTileTest.java index 19b1bf53f..3c6d7ed56 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTileTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTileTest.java @@ -4,15 +4,15 @@ import static org.robolectric.Shadows.shadowOf; import android.os.Build; import android.service.quicksettings.Tile; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; /** test for {@link org.robolectric.shadows.ShadowTile}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(sdk = Build.VERSION_CODES.N) public final class ShadowTileTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTimePickerDialogTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTimePickerDialogTest.java index 04cc2704b..cdb64c82e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTimePickerDialogTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTimePickerDialogTest.java @@ -3,18 +3,21 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.TimePickerDialog; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTimePickerDialogTest { @Test public void returnsTheIntialHourAndMinutePassedIntoTheTimePickerDialog() throws Exception { - TimePickerDialog timePickerDialog = new TimePickerDialog(RuntimeEnvironment.application, 0, null, 6, 55, false); + TimePickerDialog timePickerDialog = + new TimePickerDialog( + (Application) ApplicationProvider.getApplicationContext(), 0, null, 6, 55, false); ShadowTimePickerDialog shadow = shadowOf(timePickerDialog); assertThat(shadow.getHourOfDay()).isEqualTo(6); assertThat(shadow.getMinute()).isEqualTo(55); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTimeTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTimeTest.java index 9b5466354..faaa7fc1c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTimeTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTimeTest.java @@ -11,15 +11,15 @@ import static org.junit.Assert.assertTrue; import android.os.SystemClock; import android.text.format.Time; import android.util.TimeFormatException; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Arrays; import java.util.TimeZone; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = JELLY_BEAN_MR2) public class ShadowTimeTest { private static final TimeZone DEFAULT_TIMEZONE = TimeZone.getDefault(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTimeZoneFinderTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTimeZoneFinderTest.java index 970fe080b..45a6df31c 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTimeZoneFinderTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTimeZoneFinderTest.java @@ -4,15 +4,15 @@ import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; import android.icu.util.TimeZone; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.stream.Collectors; import libcore.util.TimeZoneFinder; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; /** Unit tests for {@link ShadowTimeZoneFinder}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTimeZoneFinderTest { @Test @@ -20,11 +20,11 @@ public class ShadowTimeZoneFinderTest { public void test() { TimeZoneFinder timeZoneFinder = TimeZoneFinder.getInstance(); assertThat( - timeZoneFinder - .lookupTimeZonesByCountry("us") - .stream() - .map(TimeZone::getID) - .collect(Collectors.toList())) + timeZoneFinder + .lookupTimeZonesByCountry("us") + .stream() + .map(TimeZone::getID) + .collect(Collectors.toList())) .containsAllOf("America/Los_Angeles", "America/New_York", "Pacific/Honolulu"); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowToastTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowToastTest.java index 18799a594..6a1614b08 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowToastTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowToastTest.java @@ -3,35 +3,48 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.view.Gravity; import android.view.View; import android.widget.TextView; import android.widget.Toast; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowToastTest { @Test public void shouldHaveShortDuration() throws Exception { - Toast toast = Toast.makeText(RuntimeEnvironment.application, "short toast", Toast.LENGTH_SHORT); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "short toast", + Toast.LENGTH_SHORT); assertThat(toast).isNotNull(); assertThat(toast.getDuration()).isEqualTo(Toast.LENGTH_SHORT); } @Test public void shouldHaveLongDuration() throws Exception { - Toast toast = Toast.makeText(RuntimeEnvironment.application, "long toast", Toast.LENGTH_LONG); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "long toast", + Toast.LENGTH_LONG); assertThat(toast).isNotNull(); assertThat(toast.getDuration()).isEqualTo(Toast.LENGTH_LONG); } @Test public void shouldMakeTextCorrectly() throws Exception { - Toast toast = Toast.makeText(RuntimeEnvironment.application, "short toast", Toast.LENGTH_SHORT); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "short toast", + Toast.LENGTH_SHORT); assertThat(toast).isNotNull(); assertThat(toast.getDuration()).isEqualTo(Toast.LENGTH_SHORT); toast.show(); @@ -42,7 +55,11 @@ public class ShadowToastTest { @Test public void shouldSetTextCorrectly() throws Exception { - Toast toast = Toast.makeText(RuntimeEnvironment.application, "short toast", Toast.LENGTH_SHORT); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "short toast", + Toast.LENGTH_SHORT); toast.setText("other toast"); toast.show(); assertThat(ShadowToast.getLatestToast()).isSameAs(toast); @@ -52,7 +69,11 @@ public class ShadowToastTest { @Test public void shouldSetTextWithIdCorrectly() throws Exception { - Toast toast = Toast.makeText(RuntimeEnvironment.application, "short toast", Toast.LENGTH_SHORT); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "short toast", + Toast.LENGTH_SHORT); toast.setText(R.string.hello); toast.show(); assertThat(ShadowToast.getLatestToast()).isSameAs(toast); @@ -62,16 +83,20 @@ public class ShadowToastTest { @Test public void shouldSetViewCorrectly() throws Exception { - Toast toast = new Toast(RuntimeEnvironment.application); + Toast toast = new Toast((Application) ApplicationProvider.getApplicationContext()); toast.setDuration(Toast.LENGTH_SHORT); - final View view = new TextView(RuntimeEnvironment.application); + final View view = new TextView((Application) ApplicationProvider.getApplicationContext()); toast.setView(view); assertThat(toast.getView()).isSameAs(view); } @Test public void shouldSetGravityCorrectly() throws Exception { - Toast toast = Toast.makeText(RuntimeEnvironment.application, "short toast", Toast.LENGTH_SHORT); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "short toast", + Toast.LENGTH_SHORT); assertThat(toast).isNotNull(); toast.setGravity(Gravity.CENTER, 0, 0); assertThat(toast.getGravity()).isEqualTo(Gravity.CENTER); @@ -79,7 +104,11 @@ public class ShadowToastTest { @Test public void shouldSetOffsetsCorrectly() throws Exception { - Toast toast = Toast.makeText(RuntimeEnvironment.application, "short toast", Toast.LENGTH_SHORT); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "short toast", + Toast.LENGTH_SHORT); toast.setGravity(0, 12, 34); assertThat(toast.getXOffset()).isEqualTo(12); assertThat(toast.getYOffset()).isEqualTo(34); @@ -88,7 +117,11 @@ public class ShadowToastTest { @Test public void shouldCountToastsCorrectly() throws Exception { assertThat(ShadowToast.shownToastCount()).isEqualTo(0); - Toast toast = Toast.makeText(RuntimeEnvironment.application, "short toast", Toast.LENGTH_SHORT); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "short toast", + Toast.LENGTH_SHORT); assertThat(toast).isNotNull(); toast.show(); toast.show(); @@ -103,7 +136,11 @@ public class ShadowToastTest { @Test public void shouldBeCancelled() throws Exception { - Toast toast = Toast.makeText(RuntimeEnvironment.application, "short toast", Toast.LENGTH_SHORT); + Toast toast = + Toast.makeText( + (Application) ApplicationProvider.getApplicationContext(), + "short toast", + Toast.LENGTH_SHORT); toast.cancel(); ShadowToast shadowToast = shadowOf(toast); assertThat(shadowToast.isCancelled()).isTrue(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTouchDelegateTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTouchDelegateTest.java index 7bb2fd51d..29ee5f05f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTouchDelegateTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTouchDelegateTest.java @@ -2,17 +2,18 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.graphics.Rect; import android.view.TouchDelegate; import android.view.View; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTouchDelegateTest { private ShadowTouchDelegate td; @@ -22,7 +23,7 @@ public class ShadowTouchDelegateTest { @Before public void setUp() throws Exception { rect = new Rect(1, 2, 3, 4); - view = new View(RuntimeEnvironment.application); + view = new View((Application) ApplicationProvider.getApplicationContext()); TouchDelegate realTD = new TouchDelegate(rect, view); td = Shadows.shadowOf(realTD); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTrafficStatsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTrafficStatsTest.java index 7ed2d57a1..54448edfa 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTrafficStatsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTrafficStatsTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static org.junit.Assert.assertEquals; import android.net.TrafficStats; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTrafficStatsTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTypedArrayTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTypedArrayTest.java index edee39d62..853f4811a 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTypedArrayTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTypedArrayTest.java @@ -3,25 +3,26 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertNotNull; +import android.app.Application; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.ColorDrawable; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.res.AttributeResource; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTypedArrayTest { private Context context; @Before public void setUp() throws Exception { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowTypefaceTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowTypefaceTest.java index cc4042792..8346b5e92 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowTypefaceTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowTypefaceTest.java @@ -4,17 +4,18 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.graphics.Typeface; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.File; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.res.FileFsFile; import org.robolectric.util.TestUtil; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowTypefaceTest { private File fontFile; @@ -70,7 +71,8 @@ public class ShadowTypefaceTest { @Test public void createFromAsset_shouldCreateTypeface() { Typeface typeface = - Typeface.createFromAsset(RuntimeEnvironment.application.getAssets(), "myFont.ttf"); + Typeface.createFromAsset( + ((Application) ApplicationProvider.getApplicationContext()).getAssets(), "myFont.ttf"); assertThat(typeface.getStyle()).isEqualTo(Typeface.NORMAL); assertThat(shadowOf(typeface).getFontDescription().getFamilyName()).isEqualTo("myFont.ttf"); @@ -80,7 +82,9 @@ public class ShadowTypefaceTest { @Test public void createFromAsset_throwsExceptionWhenFontNotFound() throws Exception { try { - Typeface.createFromAsset(RuntimeEnvironment.application.getAssets(), "nonexistent.ttf"); + Typeface.createFromAsset( + ((Application) ApplicationProvider.getApplicationContext()).getAssets(), + "nonexistent.ttf"); fail("Expected exception"); } catch (RuntimeException expected) { // Expected diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowUriTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowUriTest.java index 3d074b386..92bc236ba 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowUriTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowUriTest.java @@ -3,11 +3,11 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.net.Uri; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowUriTest { @Test public void shouldParseUris() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowUsageStatsManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowUsageStatsManagerTest.java index fe921fa98..31b9c0909 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowUsageStatsManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowUsageStatsManagerTest.java @@ -8,6 +8,7 @@ import static com.google.common.truth.Truth.assertThat; import static java.util.concurrent.TimeUnit.HOURS; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.app.PendingIntent; import android.app.usage.UsageEvents; import android.app.usage.UsageEvents.Event; @@ -15,6 +16,8 @@ import android.app.usage.UsageStats; import android.app.usage.UsageStatsManager; import android.content.Intent; import android.os.Build; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.ImmutableList; import java.util.Collections; import java.util.List; @@ -23,14 +26,12 @@ import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowUsageStatsManager.AppUsageObserver; import org.robolectric.shadows.ShadowUsageStatsManager.UsageStatsBuilder; /** Test for {@link ShadowUsageStatsManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = LOLLIPOP) public class ShadowUsageStatsManagerTest { @@ -43,7 +44,9 @@ public class ShadowUsageStatsManagerTest { @Before public void setUp() throws Exception { usageStatsManager = - (UsageStatsManager) RuntimeEnvironment.application.getSystemService(USAGE_STATS_SERVICE); + (UsageStatsManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(USAGE_STATS_SERVICE); } @Test @@ -98,6 +101,50 @@ public class ShadowUsageStatsManagerTest { } @Test + public void testQueryEvents_appendEventData_simulateTimeChange_shouldAddOffsetToPreviousData() + throws Exception { + shadowOf(usageStatsManager).addEvent(TEST_PACKAGE_NAME1, 500L, Event.MOVE_TO_FOREGROUND); + shadowOf(usageStatsManager).addEvent(TEST_PACKAGE_NAME1, 1000L, Event.MOVE_TO_BACKGROUND); + shadowOf(usageStatsManager) + .addEvent( + ShadowUsageStatsManager.EventBuilder.buildEvent() + .setTimeStamp(1500L) + .setPackage(TEST_PACKAGE_NAME2) + .setClass(TEST_ACTIVITY_NAME) + .setEventType(Event.MOVE_TO_FOREGROUND) + .build()); + shadowOf(usageStatsManager).addEvent(TEST_PACKAGE_NAME2, 2000L, Event.MOVE_TO_BACKGROUND); + shadowOf(usageStatsManager) + .addEvent( + ShadowUsageStatsManager.EventBuilder.buildEvent() + .setTimeStamp(2500L) + .setPackage(TEST_PACKAGE_NAME1) + .setEventType(Event.MOVE_TO_FOREGROUND) + .setClass(TEST_ACTIVITY_NAME) + .build()); + shadowOf(usageStatsManager).simulateTimeChange(10000L); + + UsageEvents events = usageStatsManager.queryEvents(11000L, 12000L); + Event event = new Event(); + + assertThat(events.hasNextEvent()).isTrue(); + assertThat(events.getNextEvent(event)).isTrue(); + assertThat(event.getPackageName()).isEqualTo(TEST_PACKAGE_NAME1); + assertThat(event.getTimeStamp()).isEqualTo(11000L); + assertThat(event.getEventType()).isEqualTo(Event.MOVE_TO_BACKGROUND); + + assertThat(events.hasNextEvent()).isTrue(); + assertThat(events.getNextEvent(event)).isTrue(); + assertThat(event.getPackageName()).isEqualTo(TEST_PACKAGE_NAME2); + assertThat(event.getTimeStamp()).isEqualTo(11500L); + assertThat(event.getEventType()).isEqualTo(Event.MOVE_TO_FOREGROUND); + assertThat(event.getClassName()).isEqualTo(TEST_ACTIVITY_NAME); + + assertThat(events.hasNextEvent()).isFalse(); + assertThat(events.getNextEvent(event)).isFalse(); + } + + @Test @Config(minSdk = Build.VERSION_CODES.P) public void testGetAppStandbyBucket_withPackageName() throws Exception { assertThat(shadowOf(usageStatsManager).getAppStandbyBuckets()).isEmpty(); @@ -144,11 +191,13 @@ public class ShadowUsageStatsManagerTest { @Config(minSdk = Build.VERSION_CODES.P) public void testRegisterAppUsageObserver_uniqueObserverIds_shouldAddBothObservers() { PendingIntent pendingIntent1 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION1"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION1"), 0); usageStatsManager.registerAppUsageObserver( 12, new String[] {"com.package1", "com.package2"}, 123L, TimeUnit.MINUTES, pendingIntent1); PendingIntent pendingIntent2 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION2"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION2"), 0); usageStatsManager.registerAppUsageObserver( 24, new String[] {"com.package3"}, 456L, TimeUnit.SECONDS, pendingIntent2); @@ -168,11 +217,13 @@ public class ShadowUsageStatsManagerTest { @Config(minSdk = Build.VERSION_CODES.P) public void testRegisterAppUsageObserver_duplicateObserverIds_shouldOverrideExistingObserver() { PendingIntent pendingIntent1 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION1"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION1"), 0); usageStatsManager.registerAppUsageObserver( 12, new String[] {"com.package1", "com.package2"}, 123L, TimeUnit.MINUTES, pendingIntent1); PendingIntent pendingIntent2 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION2"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION2"), 0); usageStatsManager.registerAppUsageObserver( 12, new String[] {"com.package3"}, 456L, TimeUnit.SECONDS, pendingIntent2); @@ -186,11 +237,13 @@ public class ShadowUsageStatsManagerTest { @Config(minSdk = Build.VERSION_CODES.P) public void testUnregisterAppUsageObserver_existingObserverId_shouldRemoveObserver() { PendingIntent pendingIntent1 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION1"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION1"), 0); usageStatsManager.registerAppUsageObserver( 12, new String[] {"com.package1", "com.package2"}, 123L, TimeUnit.MINUTES, pendingIntent1); PendingIntent pendingIntent2 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION2"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION2"), 0); usageStatsManager.registerAppUsageObserver( 24, new String[] {"com.package3"}, 456L, TimeUnit.SECONDS, pendingIntent2); @@ -206,11 +259,13 @@ public class ShadowUsageStatsManagerTest { @Config(minSdk = Build.VERSION_CODES.P) public void testUnregisterAppUsageObserver_nonExistentObserverId_shouldBeNoOp() { PendingIntent pendingIntent1 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION1"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION1"), 0); usageStatsManager.registerAppUsageObserver( 12, new String[] {"com.package1", "com.package2"}, 123L, TimeUnit.MINUTES, pendingIntent1); PendingIntent pendingIntent2 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION2"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION2"), 0); usageStatsManager.registerAppUsageObserver( 24, new String[] {"com.package3"}, 456L, TimeUnit.SECONDS, pendingIntent2); @@ -232,17 +287,20 @@ public class ShadowUsageStatsManagerTest { @Config(minSdk = Build.VERSION_CODES.P) public void testTriggerRegisteredAppUsageObserver_shouldSendIntentAndRemoveObserver() { PendingIntent pendingIntent1 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION1"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION1"), 0); usageStatsManager.registerAppUsageObserver( 12, new String[] {"com.package1", "com.package2"}, 123L, TimeUnit.MINUTES, pendingIntent1); PendingIntent pendingIntent2 = - PendingIntent.getBroadcast(RuntimeEnvironment.application, 0, new Intent("ACTION2"), 0); + PendingIntent.getBroadcast( + (Application) ApplicationProvider.getApplicationContext(), 0, new Intent("ACTION2"), 0); usageStatsManager.registerAppUsageObserver( 24, new String[] {"com.package3"}, 456L, TimeUnit.SECONDS, pendingIntent2); shadowOf(usageStatsManager).triggerRegisteredAppUsageObserver(24, 500000L); - List<Intent> broadcastIntents = shadowOf(RuntimeEnvironment.application).getBroadcastIntents(); + List<Intent> broadcastIntents = + shadowOf((Application) ApplicationProvider.getApplicationContext()).getBroadcastIntents(); assertThat(broadcastIntents).hasSize(1); Intent broadcastIntent = broadcastIntents.get(0); assertThat(broadcastIntent.getAction()).isEqualTo("ACTION2"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowUsbManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowUsbManagerTest.java index 5931ddef4..7a0af700f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowUsbManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowUsbManagerTest.java @@ -7,12 +7,15 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.hardware.usb.UsbPortStatus; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.Arrays; import java.util.stream.Collectors; import org.junit.Before; @@ -20,12 +23,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; /** Unit tests for {@link ShadowUsbManager}. */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowUsbManagerTest { private static final String DEVICE_NAME_1 = "usb1"; private static final String DEVICE_NAME_2 = "usb2"; @@ -39,7 +40,10 @@ public class ShadowUsbManagerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - usbManager = (UsbManager) RuntimeEnvironment.application.getSystemService(Context.USB_SERVICE); + usbManager = + (UsbManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.USB_SERVICE); shadowUsbManager = shadowOf(usbManager); when(usbDevice1.getDeviceName()).thenReturn(DEVICE_NAME_1); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowUserManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowUserManagerTest.java index 2cdca2ff5..a16c5b502 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowUserManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowUserManagerTest.java @@ -1,5 +1,22 @@ package org.robolectric.shadows; +import static android.content.pm.PackageManager.GET_ACTIVITIES; +import static android.content.pm.PackageManager.GET_CONFIGURATIONS; +import static android.content.pm.PackageManager.GET_DISABLED_COMPONENTS; +import static android.content.pm.PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS; +import static android.content.pm.PackageManager.GET_GIDS; +import static android.content.pm.PackageManager.GET_INSTRUMENTATION; +import static android.content.pm.PackageManager.GET_INTENT_FILTERS; +import static android.content.pm.PackageManager.GET_META_DATA; +import static android.content.pm.PackageManager.GET_PERMISSIONS; +import static android.content.pm.PackageManager.GET_PROVIDERS; +import static android.content.pm.PackageManager.GET_RECEIVERS; +import static android.content.pm.PackageManager.GET_SERVICES; +import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES; +import static android.content.pm.PackageManager.GET_SIGNATURES; +import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES; +import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES; +import static android.content.pm.PackageManager.GET_URI_PERMISSION_PATTERNS; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; import static android.os.Build.VERSION_CODES.KITKAT_WATCH; @@ -12,23 +29,23 @@ import static org.junit.Assert.fail; import static org.robolectric.Shadows.shadowOf; import android.Manifest.permission; +import android.app.Application; import android.content.Context; import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Parcel; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowUserManager.UserState; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowUserManagerTest { private UserManager userManager; @@ -36,7 +53,7 @@ public class ShadowUserManagerTest { @Before public void setUp() { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); } @@ -61,7 +78,11 @@ public class ShadowUserManagerTest { restrictions.putCharSequence("test_key", "test_value"); shadowOf(userManager).setApplicationRestrictions(packageName, restrictions); - assertThat(userManager.getApplicationRestrictions(packageName).getCharSequence("test_key")) + assertThat( + userManager + .getApplicationRestrictions(packageName) + .getCharSequence("test_key") + .toString()) .isEqualTo("test_value"); } @@ -136,11 +157,31 @@ public class ShadowUserManagerTest { fail("Expected exception"); } catch (SecurityException expected) {} - PackageInfo packageInfo = RuntimeEnvironment.application.getPackageManager() - .getPackageInfo(RuntimeEnvironment.application.getPackageName(), - PackageManager.GET_PERMISSIONS); - packageInfo.requestedPermissions = new String[] { permission.MANAGE_USERS }; - + PackageInfo packageInfo = + ((Application) ApplicationProvider.getApplicationContext()) + .getPackageManager() + .getPackageInfo( + ((Application) ApplicationProvider.getApplicationContext()).getPackageName(), + GET_ACTIVITIES + | GET_CONFIGURATIONS + | GET_GIDS + | GET_INSTRUMENTATION + | GET_INTENT_FILTERS + | GET_META_DATA + | GET_PERMISSIONS + | GET_PROVIDERS + | GET_RECEIVERS + | GET_SERVICES + | GET_SHARED_LIBRARY_FILES + | GET_SIGNATURES + | GET_SIGNING_CERTIFICATES + | GET_URI_PERMISSION_PATTERNS + | GET_DISABLED_COMPONENTS + | GET_DISABLED_UNTIL_USED_COMPONENTS + | GET_UNINSTALLED_PACKAGES); + packageInfo.requestedPermissions = new String[] {permission.MANAGE_USERS}; + shadowOf(((Application) ApplicationProvider.getApplicationContext()).getPackageManager()) + .addPackage(packageInfo); shadowOf(userManager).setManagedProfile(true); assertThat(userManager.isManagedProfile()).isTrue(); @@ -173,19 +214,6 @@ public class ShadowUserManagerTest { } @Test - @Config(minSdk = N_MR1) - public void isAdminUser() { - // All methods are based on the current user, so no need to pass a UserHandle. - assertThat(userManager.isAdminUser()).isFalse(); - - shadowOf(userManager).setIsAdminUser(true); - assertThat(userManager.isAdminUser()).isTrue(); - - shadowOf(userManager).setIsAdminUser(false); - assertThat(userManager.isAdminUser()).isFalse(); - } - - @Test @Config(minSdk = M) public void isSystemUser() { assertThat(userManager.isSystemUser()).isTrue(); @@ -285,6 +313,65 @@ public class ShadowUserManagerTest { assertThat(userManager.isUserRunningOrStopping(userHandle)).isFalse(); } + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void addSecondaryUser() { + assertThat(userManager.getUserCount()).isEqualTo(1); + shadowOf(userManager).addUser(10, "secondary_user", 0); + assertThat(userManager.getUserCount()).isEqualTo(2); + } + + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void removeSecondaryUser() { + shadowOf(userManager).addUser(10, "secondary_user", 0); + assertThat(shadowOf(userManager).removeUser(10)).isTrue(); + assertThat(userManager.getUserCount()).isEqualTo(1); + } + + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void switchToSecondaryUser() { + shadowOf(userManager).addUser(10, "secondary_user", 0); + shadowOf(userManager).switchUser(10); + assertThat(UserHandle.myUserId()).isEqualTo(10); + } + + @Test + @Config(minSdk = N) + public void canSwitchUser() { + assertThat(shadowOf(userManager).canSwitchUsers()).isFalse(); + shadowOf(userManager).setCanSwitchUser(true); + assertThat(shadowOf(userManager).canSwitchUsers()).isTrue(); + } + + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void getUsers() { + assertThat(userManager.getUsers()).hasSize(1); + shadowOf(userManager).addUser(10, "secondary_user", 0); + assertThat(userManager.getUsers()).hasSize(2); + } + + @Test + @Config(minSdk = JELLY_BEAN_MR1) + public void getUserInfo() { + shadowOf(userManager).addUser(10, "secondary_user", 0); + assertThat(userManager.getUserInfo(10)).isNotNull(); + assertThat(userManager.getUserInfo(10).name).isEqualTo("secondary_user"); + } + + @Test + @Config(minSdk = N) + public void switchToUserNotAddedShouldThrowException() { + try { + shadowOf(userManager).switchUser(10); + fail("Switching to the user that was never added should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + assertThat(e).hasMessageThat().isEqualTo("Must add user before switching to it"); + } + } + // Create user handle from parcel since UserHandle.of() was only added in later APIs. private static UserHandle newUserHandle(int uid) { Parcel userParcel = Parcel.obtain(); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowValueAnimatorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowValueAnimatorTest.java index 5a7ef21b5..84157eeaf 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowValueAnimatorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowValueAnimatorTest.java @@ -3,17 +3,17 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import android.animation.ValueAnimator; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.common.collect.Ordering; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; import org.robolectric.util.TimeUtils; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowValueAnimatorTest { @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowVibratorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowVibratorTest.java index 9e93bab13..caa00b75d 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowVibratorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowVibratorTest.java @@ -4,23 +4,27 @@ import static android.os.Build.VERSION_CODES.O; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.os.Vibrator; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowVibratorTest { private Vibrator vibrator; @Before public void before() { - vibrator = (Vibrator) RuntimeEnvironment.application.getSystemService(Context.VIBRATOR_SERVICE); + vibrator = + (Vibrator) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.VIBRATOR_SERVICE); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowVideoViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowVideoViewTest.java index 2899612eb..b413e51c0 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowVideoViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowVideoViewTest.java @@ -3,22 +3,23 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.media.MediaPlayer; import android.net.Uri; import android.widget.VideoView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowVideoViewTest { private VideoView view; @Before public void setUp() throws Exception { - view = new VideoView(RuntimeEnvironment.application); + view = new VideoView((Application) ApplicationProvider.getApplicationContext()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewAnimatorTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewAnimatorTest.java index a20355df1..0db67f697 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewAnimatorTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewAnimatorTest.java @@ -6,17 +6,17 @@ import static org.junit.Assert.assertSame; import android.app.Application; import android.view.View; import android.widget.ViewAnimator; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowViewAnimatorTest { ViewAnimator viewAnimator; - final Application application = RuntimeEnvironment.application; + final Application application = (Application) ApplicationProvider.getApplicationContext(); @Before public void setUp() { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java index 182095fa1..c7dd68a50 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java @@ -4,18 +4,20 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.view.ViewConfiguration; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowViewConfigurationTest { @Test public void methodsShouldReturnAndroidConstants() { - ViewConfiguration viewConfiguration = ViewConfiguration.get(RuntimeEnvironment.application); + ViewConfiguration viewConfiguration = + ViewConfiguration.get((Application) ApplicationProvider.getApplicationContext()); assertEquals(10, ViewConfiguration.getScrollBarSize()); assertEquals(250, ViewConfiguration.getScrollBarFadeDuration()); @@ -36,7 +38,11 @@ public class ShadowViewConfigurationTest { assertEquals(500, ViewConfiguration.getGlobalActionKeyTimeout()); assertThat(ViewConfiguration.getScrollFriction()).isEqualTo(0.015f); - assertThat(RuntimeEnvironment.application.getResources().getDisplayMetrics().density) + assertThat( + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDisplayMetrics() + .density) .isEqualTo(1f); assertEquals(10, viewConfiguration.getScaledScrollBarSize()); @@ -52,8 +58,13 @@ public class ShadowViewConfigurationTest { @Test public void methodsShouldReturnScaledAndroidConstantsDependingOnPixelDensity() { - RuntimeEnvironment.application.getResources().getDisplayMetrics().density = 1.5f; - ViewConfiguration viewConfiguration = ViewConfiguration.get(RuntimeEnvironment.application); + ((Application) ApplicationProvider.getApplicationContext()) + .getResources() + .getDisplayMetrics() + .density = + 1.5f; + ViewConfiguration viewConfiguration = + ViewConfiguration.get((Application) ApplicationProvider.getApplicationContext()); assertEquals(15, viewConfiguration.getScaledScrollBarSize()); assertEquals(18, viewConfiguration.getScaledFadingEdgeLength()); @@ -68,7 +79,8 @@ public class ShadowViewConfigurationTest { @Test public void testHasPermanentMenuKey() throws Exception { - ViewConfiguration viewConfiguration = ViewConfiguration.get(RuntimeEnvironment.application); + ViewConfiguration viewConfiguration = + ViewConfiguration.get((Application) ApplicationProvider.getApplicationContext()); assertThat(viewConfiguration.hasPermanentMenuKey()).isFalse(); ShadowViewConfiguration shadowViewConfiguration = shadowOf(viewConfiguration); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewFlipperTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewFlipperTest.java index d22e24312..a5ef97d21 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewFlipperTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewFlipperTest.java @@ -2,20 +2,21 @@ package org.robolectric.shadows; import static org.junit.Assert.assertEquals; +import android.app.Application; import android.widget.ViewFlipper; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowViewFlipperTest { protected ViewFlipper flipper; @Before public void setUp() { - flipper = new ViewFlipper(RuntimeEnvironment.application); + flipper = new ViewFlipper((Application) ApplicationProvider.getApplicationContext()); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewGroupTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewGroupTest.java index 225d53861..05c10148e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewGroupTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewGroupTest.java @@ -19,6 +19,8 @@ import android.view.animation.Animation.AnimationListener; import android.view.animation.LayoutAnimationController; import android.widget.FrameLayout; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.junit.After; @@ -26,10 +28,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowViewGroupTest { private String defaultLineSeparator; private ViewGroup root; @@ -42,7 +42,7 @@ public class ShadowViewGroupTest { @Before public void setUp() throws Exception { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); root = new FrameLayout(context); @@ -245,8 +245,8 @@ public class ShadowViewGroupTest { public void addViewWithLayoutParams_shouldStoreLayoutParams() throws Exception { FrameLayout.LayoutParams layoutParams1 = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); FrameLayout.LayoutParams layoutParams2 = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - View child1 = new View(RuntimeEnvironment.application); - View child2 = new View(RuntimeEnvironment.application); + View child1 = new View((Application) ApplicationProvider.getApplicationContext()); + View child2 = new View((Application) ApplicationProvider.getApplicationContext()); root.addView(child1, layoutParams1); root.addView(child2, 1, layoutParams2); assertSame(layoutParams1, child1.getLayoutParams()); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewTest.java index 2d6b256f5..889a4f3af 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewTest.java @@ -16,6 +16,7 @@ import static org.robolectric.Robolectric.setupActivity; import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.app.Application; import android.content.Context; import android.graphics.BitmapFactory; import android.graphics.Point; @@ -41,6 +42,8 @@ import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.widget.FrameLayout; import android.widget.LinearLayout; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -49,8 +52,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.DeviceConfig; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.AccessibilityChecks; @@ -58,7 +59,7 @@ import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.TestRunnable; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowViewTest { private View view; private List<String> transcript; @@ -66,13 +67,13 @@ public class ShadowViewTest { @Before public void setUp() throws Exception { transcript = new ArrayList<>(); - view = new View(RuntimeEnvironment.application); + view = new View((Application) ApplicationProvider.getApplicationContext()); } @Test public void testHasNullLayoutParamsUntilAddedToParent() throws Exception { assertThat(view.getLayoutParams()).isNull(); - new LinearLayout(RuntimeEnvironment.application).addView(view); + new LinearLayout((Application) ApplicationProvider.getApplicationContext()).addView(view); assertThat(view.getLayoutParams()).isNotNull(); } @@ -88,23 +89,26 @@ public class ShadowViewTest { @Test public void measuredDimensions() throws Exception { - View view1 = new View(RuntimeEnvironment.application) { - { - setMeasuredDimension(123, 456); - } - }; + View view1 = + new View((Application) ApplicationProvider.getApplicationContext()) { + { + setMeasuredDimension(123, 456); + } + }; assertThat(view1.getMeasuredWidth()).isEqualTo(123); assertThat(view1.getMeasuredHeight()).isEqualTo(456); } @Test public void layout_shouldCallOnLayoutOnlyIfChanged() throws Exception { - View view1 = new View(RuntimeEnvironment.application) { - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - transcript.add("onLayout " + changed + " " + left + " " + top + " " + right + " " + bottom); - } - }; + View view1 = + new View((Application) ApplicationProvider.getApplicationContext()) { + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + transcript.add( + "onLayout " + changed + " " + left + " " + top + " " + right + " " + bottom); + } + }; view1.layout(0, 0, 0, 0); assertThat(transcript).isEmpty(); view1.layout(1, 2, 3, 4); @@ -141,7 +145,13 @@ public class ShadowViewTest { assertThat(transcript).containsExactly("Gained focus"); transcript.clear(); - shadowOf(view).setMyParent(new LinearLayout(RuntimeEnvironment.application)); // we can never lose focus unless a parent can take it + shadowOf(view) + .setMyParent( + new LinearLayout( + (Application) + ApplicationProvider + .getApplicationContext())); // we can never lose focus unless a parent can + // take it view.clearFocus(); assertFalse(view.isFocused()); @@ -164,10 +174,11 @@ public class ShadowViewTest { assertThat(view.isShown()).isTrue(); shadowOf(view).setMyParent(null); - ViewGroup parent = new LinearLayout(RuntimeEnvironment.application); + ViewGroup parent = new LinearLayout((Application) ApplicationProvider.getApplicationContext()); parent.addView(view); - ViewGroup grandParent = new LinearLayout(RuntimeEnvironment.application); + ViewGroup grandParent = + new LinearLayout((Application) ApplicationProvider.getApplicationContext()); grandParent.addView(parent); grandParent.setVisibility(View.GONE); @@ -177,8 +188,9 @@ public class ShadowViewTest { @Test public void shouldInflateMergeRootedLayoutAndNotCreateReferentialLoops() throws Exception { - LinearLayout root = new LinearLayout(RuntimeEnvironment.application); - LinearLayout.inflate(RuntimeEnvironment.application, R.layout.inner_merge, root); + LinearLayout root = new LinearLayout((Application) ApplicationProvider.getApplicationContext()); + LinearLayout.inflate( + (Application) ApplicationProvider.getApplicationContext(), R.layout.inner_merge, root); for (int i = 0; i < root.getChildCount(); i++) { View child = root.getChildAt(i); assertNotSame(root, child); @@ -207,8 +219,9 @@ public class ShadowViewTest { @Test(expected = RuntimeException.class) public void checkedClick_shouldThrowIfViewIsNotVisible() throws Exception { - ViewGroup grandParent = new LinearLayout(RuntimeEnvironment.application); - ViewGroup parent = new LinearLayout(RuntimeEnvironment.application); + ViewGroup grandParent = + new LinearLayout((Application) ApplicationProvider.getApplicationContext()); + ViewGroup parent = new LinearLayout((Application) ApplicationProvider.getApplicationContext()); grandParent.addView(parent); parent.addView(view); grandParent.setVisibility(View.GONE); @@ -328,9 +341,9 @@ public class ShadowViewTest { @Test public void shouldSupportAllConstructors() throws Exception { - new View(RuntimeEnvironment.application); - new View(RuntimeEnvironment.application, null); - new View(RuntimeEnvironment.application, null, 0); + new View((Application) ApplicationProvider.getApplicationContext()); + new View((Application) ApplicationProvider.getApplicationContext(), null); + new View((Application) ApplicationProvider.getApplicationContext(), null, 0); } @Test @@ -348,7 +361,7 @@ public class ShadowViewTest { .build() ; - view = new View(RuntimeEnvironment.application, attrs); + view = new View((Application) ApplicationProvider.getApplicationContext(), attrs); assertNotNull(shadowOf(view).getOnClickListener()); } @@ -429,7 +442,8 @@ public class ShadowViewTest { @Test public void dispatchTouchEvent_sendsMotionEventToOnTouchEvent() throws Exception { - TouchableView touchableView = new TouchableView(RuntimeEnvironment.application); + TouchableView touchableView = + new TouchableView((Application) ApplicationProvider.getApplicationContext()); MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 12f, 34f, 0); touchableView.dispatchTouchEvent(event); assertThat(touchableView.event).isSameAs(event); @@ -952,7 +966,7 @@ public class ShadowViewTest { private List<String> transcript; public MyView(String name, List<String> transcript) { - super(RuntimeEnvironment.application); + super((Application) ApplicationProvider.getApplicationContext()); this.name = name; this.transcript = transcript; } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowVisualVoicemailSmsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowVisualVoicemailSmsTest.java index 3cb797348..103be5b52 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowVisualVoicemailSmsTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowVisualVoicemailSmsTest.java @@ -2,6 +2,7 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.content.ComponentName; import android.content.Context; import android.os.Build.VERSION_CODES; @@ -9,20 +10,20 @@ import android.os.Bundle; import android.os.Parcel; import android.telecom.PhoneAccountHandle; import android.telephony.VisualVoicemailSms; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; /** Tests for {@link ShadowVisualVoicemailSms} */ -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = VERSION_CODES.O) public class ShadowVisualVoicemailSmsTest { - private final Context appContext = RuntimeEnvironment.application; + private final Context appContext = (Application) ApplicationProvider.getApplicationContext(); private final PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(new ComponentName(appContext, Object.class), "foo"); diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWallpaperManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWallpaperManagerTest.java index 8a5b7610c..3652fa7f5 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowWallpaperManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWallpaperManagerTest.java @@ -2,24 +2,27 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; +import android.app.Application; import android.app.WallpaperManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowWallpaperManagerTest { @Test public void getInstance_shouldCreateInstance() { - WallpaperManager manager = WallpaperManager.getInstance(RuntimeEnvironment.application); + WallpaperManager manager = + WallpaperManager.getInstance((Application) ApplicationProvider.getApplicationContext()); assertThat(manager).isNotNull(); } @Test public void sendWallpaperCommand_shouldNotThrowException() { - WallpaperManager manager = WallpaperManager.getInstance(RuntimeEnvironment.application); + WallpaperManager manager = + WallpaperManager.getInstance((Application) ApplicationProvider.getApplicationContext()); manager.sendWallpaperCommand(null, null, 0, 0, 0, null); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWebStorageTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWebStorageTest.java new file mode 100644 index 000000000..822fe71bf --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWebStorageTest.java @@ -0,0 +1,16 @@ +package org.robolectric.shadows; + +import android.webkit.WebStorage; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for {@link ShadowWebStorage} */ +@RunWith(AndroidJUnit4.class) +public final class ShadowWebStorageTest { + + @Test + public void webStorageDoesNotCrash() throws Exception { + WebStorage.getInstance().deleteAllData(); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWebViewTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWebViewTest.java index ed4d6f92d..b64523383 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowWebViewTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWebViewTest.java @@ -3,6 +3,8 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; +import android.content.pm.PackageInfo; import android.os.Bundle; import android.view.ViewGroup.LayoutParams; import android.webkit.WebBackForwardList; @@ -10,26 +12,23 @@ import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.HashMap; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.Shadows; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowWebViewTest { private WebView webView; - private ShadowWebView shadowWebView; @Before public void setUp() throws Exception { - webView = new WebView(RuntimeEnvironment.application); - shadowWebView = Shadows.shadowOf(webView); + webView = new WebView((Application) ApplicationProvider.getApplicationContext()); } @Test @@ -84,17 +83,17 @@ public class ShadowWebViewTest { public void shouldRecordWebViewClient() { WebViewClient webViewClient = new WebViewClient(); - assertThat(shadowWebView.getWebViewClient()).isNull(); + assertThat(shadowOf(webView).getWebViewClient()).isNull(); webView.setWebViewClient(webViewClient); - assertThat(shadowWebView.getWebViewClient()).isSameAs(webViewClient); + assertThat(shadowOf(webView).getWebViewClient()).isSameAs(webViewClient); } @Test public void shouldRecordWebChromeClient() { WebChromeClient webChromeClient = new WebChromeClient(); - assertThat(shadowWebView.getWebChromeClient()).isNull(); + assertThat(shadowOf(webView).getWebChromeClient()).isNull(); webView.setWebChromeClient(webChromeClient); - assertThat(shadowWebView.getWebChromeClient()).isSameAs(webChromeClient); + assertThat(shadowOf(webView).getWebChromeClient()).isSameAs(webChromeClient); } @Test @@ -102,18 +101,18 @@ public class ShadowWebViewTest { String[] names = {"name1", "name2"}; for (String name : names) { Object obj = new Object(); - assertThat(shadowWebView.getJavascriptInterface(name)).isNull(); + assertThat(shadowOf(webView).getJavascriptInterface(name)).isNull(); webView.addJavascriptInterface(obj, name); - assertThat(shadowWebView.getJavascriptInterface(name)).isSameAs(obj); + assertThat(shadowOf(webView).getJavascriptInterface(name)).isSameAs(obj); } } @Test public void canGoBack() throws Exception { - shadowWebView.clearHistory(); + webView.clearHistory(); assertThat(webView.canGoBack()).isFalse(); - shadowWebView.loadUrl("fake.url", null); - shadowWebView.loadUrl("fake.url", null); + webView.loadUrl("fake.url", null); + webView.loadUrl("fake.url", null); assertThat(webView.canGoBack()).isTrue(); webView.goBack(); assertThat(webView.canGoBack()).isFalse(); @@ -121,77 +120,77 @@ public class ShadowWebViewTest { @Test public void shouldStoreTheNumberOfTimesGoBackWasCalled() throws Exception { - assertThat(shadowWebView.getGoBackInvocations()).isEqualTo(0); + assertThat(shadowOf(webView).getGoBackInvocations()).isEqualTo(0); webView.goBack(); webView.loadUrl("foo.bar", null); // If there is no history (only one page), we shouldn't invoke go back. - assertThat(shadowWebView.getGoBackInvocations()).isEqualTo(0); + assertThat(shadowOf(webView).getGoBackInvocations()).isEqualTo(0); webView.loadUrl("foo.bar", null); webView.loadUrl("foo.bar", null); webView.loadUrl("foo.bar", null); webView.loadUrl("foo.bar", null); webView.loadUrl("foo.bar", null); webView.goBack(); - assertThat(shadowWebView.getGoBackInvocations()).isEqualTo(1); + assertThat(shadowOf(webView).getGoBackInvocations()).isEqualTo(1); webView.goBack(); webView.goBack(); - assertThat(shadowWebView.getGoBackInvocations()).isEqualTo(3); + assertThat(shadowOf(webView).getGoBackInvocations()).isEqualTo(3); webView.goBack(); webView.goBack(); webView.goBack(); // We've gone back one too many times for the history, so we should only have 5 invocations. - assertThat(shadowWebView.getGoBackInvocations()).isEqualTo(5); + assertThat(shadowOf(webView).getGoBackInvocations()).isEqualTo(5); } @Test public void shouldStoreTheNumberOfTimesGoBackWasCalled_SetCanGoBack() { - shadowWebView.setCanGoBack(true); + shadowOf(webView).setCanGoBack(true); webView.goBack(); webView.goBack(); - assertThat(shadowWebView.getGoBackInvocations()).isEqualTo(2); - shadowWebView.setCanGoBack(false); + assertThat(shadowOf(webView).getGoBackInvocations()).isEqualTo(2); + shadowOf(webView).setCanGoBack(false); webView.goBack(); webView.goBack(); - assertThat(shadowWebView.getGoBackInvocations()).isEqualTo(2); + assertThat(shadowOf(webView).getGoBackInvocations()).isEqualTo(2); } @Test public void shouldRecordClearCacheWithoutDiskFiles() { - assertThat(shadowWebView.wasClearCacheCalled()).isFalse(); + assertThat(shadowOf(webView).wasClearCacheCalled()).isFalse(); webView.clearCache(false); - assertThat(shadowWebView.wasClearCacheCalled()).isTrue(); - assertThat(shadowWebView.didClearCacheIncludeDiskFiles()).isFalse(); + assertThat(shadowOf(webView).wasClearCacheCalled()).isTrue(); + assertThat(shadowOf(webView).didClearCacheIncludeDiskFiles()).isFalse(); } @Test public void shouldRecordClearCacheWithDiskFiles() { - assertThat(shadowWebView.wasClearCacheCalled()).isFalse(); + assertThat(shadowOf(webView).wasClearCacheCalled()).isFalse(); webView.clearCache(true); - assertThat(shadowWebView.wasClearCacheCalled()).isTrue(); - assertThat(shadowWebView.didClearCacheIncludeDiskFiles()).isTrue(); + assertThat(shadowOf(webView).wasClearCacheCalled()).isTrue(); + assertThat(shadowOf(webView).didClearCacheIncludeDiskFiles()).isTrue(); } @Test public void shouldRecordClearFormData() { - assertThat(shadowWebView.wasClearFormDataCalled()).isFalse(); + assertThat(shadowOf(webView).wasClearFormDataCalled()).isFalse(); webView.clearFormData(); - assertThat(shadowWebView.wasClearFormDataCalled()).isTrue(); + assertThat(shadowOf(webView).wasClearFormDataCalled()).isTrue(); } @Test public void shouldRecordClearHistory() { - assertThat(shadowWebView.wasClearHistoryCalled()).isFalse(); + assertThat(shadowOf(webView).wasClearHistoryCalled()).isFalse(); webView.clearHistory(); - assertThat(shadowWebView.wasClearHistoryCalled()).isTrue(); + assertThat(shadowOf(webView).wasClearHistoryCalled()).isTrue(); } @Test public void shouldRecordClearView() { - assertThat(shadowWebView.wasClearViewCalled()).isFalse(); + assertThat(shadowOf(webView).wasClearViewCalled()).isFalse(); webView.clearView(); - assertThat(shadowWebView.wasClearViewCalled()).isTrue(); + assertThat(shadowOf(webView).wasClearViewCalled()).isTrue(); } @Test @@ -213,30 +212,30 @@ public class ShadowWebViewTest { @Test @Config(minSdk = 19) public void evaluateJavascript() { - assertThat(shadowWebView.getLastEvaluatedJavascript()).isNull(); + assertThat(shadowOf(webView).getLastEvaluatedJavascript()).isNull(); webView.evaluateJavascript("myScript", null); - assertThat(shadowWebView.getLastEvaluatedJavascript()).isEqualTo("myScript"); + assertThat(shadowOf(webView).getLastEvaluatedJavascript()).isEqualTo("myScript"); } @Test public void shouldRecordDestroy() { - assertThat(shadowWebView.wasDestroyCalled()).isFalse(); + assertThat(shadowOf(webView).wasDestroyCalled()).isFalse(); webView.destroy(); - assertThat(shadowWebView.wasDestroyCalled()).isTrue(); + assertThat(shadowOf(webView).wasDestroyCalled()).isTrue(); } @Test public void shouldRecordOnPause() { - assertThat(shadowWebView.wasOnPauseCalled()).isFalse(); + assertThat(shadowOf(webView).wasOnPauseCalled()).isFalse(); webView.onPause(); - assertThat(shadowWebView.wasOnPauseCalled()).isTrue(); + assertThat(shadowOf(webView).wasOnPauseCalled()).isTrue(); } @Test public void shouldRecordOnResume() { - assertThat(shadowWebView.wasOnResumeCalled()).isFalse(); + assertThat(shadowOf(webView).wasOnResumeCalled()).isFalse(); webView.onResume(); - assertThat(shadowWebView.wasOnResumeCalled()).isTrue(); + assertThat(shadowOf(webView).wasOnResumeCalled()).isTrue(); } @Test @@ -255,7 +254,7 @@ public class ShadowWebViewTest { Bundle outState = new Bundle(); webView.saveState(outState); - WebView newWebView = new WebView(RuntimeEnvironment.application); + WebView newWebView = new WebView((Application) ApplicationProvider.getApplicationContext()); WebBackForwardList historyList = newWebView.restoreState(outState); assertThat(newWebView.canGoBack()).isTrue(); @@ -284,4 +283,52 @@ public class ShadowWebViewTest { assertThat(historyList).isNull(); } + + @Test + public void shouldCopyBackForwardListWhenEmpty() { + WebBackForwardList historyList = webView.copyBackForwardList(); + + assertThat(historyList.getSize()).isEqualTo(0); + assertThat(historyList.getCurrentIndex()).isEqualTo(-1); + assertThat(historyList.getCurrentItem()).isNull(); + } + + @Test + public void shouldCopyBackForwardListWhenPopulated() { + webView.loadUrl("foo1.bar"); + webView.loadUrl("foo2.bar"); + + WebBackForwardList historyList = webView.copyBackForwardList(); + + assertThat(historyList.getSize()).isEqualTo(2); + assertThat(historyList.getCurrentItem().getUrl()).isEqualTo("foo2.bar"); + } + + @Test + public void shouldReturnCopyFromCopyBackForwardList() { + WebBackForwardList historyList = webView.copyBackForwardList(); + + // Adding history after copying should not affect the copy. + webView.loadUrl("foo1.bar"); + webView.loadUrl("foo2.bar"); + + assertThat(historyList.getSize()).isEqualTo(0); + assertThat(historyList.getCurrentIndex()).isEqualTo(-1); + assertThat(historyList.getCurrentItem()).isNull(); + } + + @Test + @Config(minSdk = 26) + public void shouldReturnNullForGetCurrentWebViewPackageIfNotSet() { + assertThat(WebView.getCurrentWebViewPackage()).isNull(); + } + + @Test + @Config(minSdk = 26) + public void shouldReturnStoredPackageInfoForGetCurrentWebViewPackageIfSet() { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "org.robolectric.shadows.shadowebviewtest"; + ShadowWebView.setCurrentWebViewPackage(packageInfo); + assertThat(WebView.getCurrentWebViewPackage()).isEqualTo(packageInfo); + } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiConfigurationTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiConfigurationTest.java index 541daead5..f47f652ea 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiConfigurationTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiConfigurationTest.java @@ -7,12 +7,12 @@ import static org.robolectric.Shadows.shadowOf; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.os.Build; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowWifiConfigurationTest { @Test public void shouldSetTheBitSetsAndWepKeyArrays() throws Exception { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiInfoTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiInfoTest.java index 377f4b1b1..0a5d06a3b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiInfoTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiInfoTest.java @@ -8,14 +8,14 @@ import static org.robolectric.Shadows.shadowOf; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.net.InetAddress; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowWifiInfoTest { private WifiManager wifiManager; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiManagerTest.java index 266afda09..82490674b 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiManagerTest.java @@ -6,6 +6,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.net.ConnectivityManager; import android.net.DhcpInfo; @@ -17,18 +18,20 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.MulticastLock; import android.os.Build; import android.util.Pair; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.util.ArrayList; import java.util.List; 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) +@RunWith(AndroidJUnit4.class) public class ShadowWifiManagerTest { - private final WifiManager wifiManager = (WifiManager) RuntimeEnvironment.application.getSystemService(Context.WIFI_SERVICE); - private final ShadowWifiManager shadowWifiManager = shadowOf(wifiManager); + private final WifiManager wifiManager = + (WifiManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.WIFI_SERVICE); @Test public void shouldReturnWifiInfo() { @@ -38,32 +41,57 @@ public class ShadowWifiManagerTest { @Test public void setWifiInfo_shouldUpdateWifiInfo() { WifiInfo wifiInfo = new WifiInfo(); - shadowWifiManager.setConnectionInfo(wifiInfo); + shadowOf(wifiManager).setConnectionInfo(wifiInfo); assertThat(wifiManager.getConnectionInfo()).isSameAs(wifiInfo); } - @Test(expected = SecurityException.class) - public void setWifiEnabled_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() throws Exception { - shadowWifiManager.setAccessWifiStatePermission(false); - wifiManager.setWifiEnabled(true); + @Test + public void setWifiEnabled_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() + throws Exception { + shadowOf(wifiManager).setAccessWifiStatePermission(false); + try { + wifiManager.setWifiEnabled(true); + fail("SecurityException not thrown"); + } catch (SecurityException e) { + // expected + } } - @Test(expected = SecurityException.class) - public void isWifiEnabled_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() throws Exception { - shadowWifiManager.setAccessWifiStatePermission(false); - wifiManager.isWifiEnabled(); + @Test + public void isWifiEnabled_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() + throws Exception { + shadowOf(wifiManager).setAccessWifiStatePermission(false); + try { + wifiManager.isWifiEnabled(); + fail("SecurityException not thrown"); + } catch (SecurityException e) { + // expected + } } - @Test(expected = SecurityException.class) - public void getWifiState_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() throws Exception { - shadowWifiManager.setAccessWifiStatePermission(false); - wifiManager.getWifiState(); + @Test + public void getWifiState_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() + throws Exception { + shadowOf(wifiManager).setAccessWifiStatePermission(false); + try { + wifiManager.getWifiState(); + fail("SecurityException not thrown"); + } catch (SecurityException e) { + // expected + } } - @Test(expected = SecurityException.class) - public void getConnectionInfo_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() throws Exception { - shadowWifiManager.setAccessWifiStatePermission(false); - wifiManager.getConnectionInfo(); + @Test + public void + getConnectionInfo_shouldThrowSecurityExceptionWhenAccessWifiStatePermissionNotGranted() + throws Exception { + shadowOf(wifiManager).setAccessWifiStatePermission(false); + try { + wifiManager.getConnectionInfo(); + fail("SecurityException not thrown"); + } catch (SecurityException e) { + // expected + } } @Test @@ -80,45 +108,45 @@ public class ShadowWifiManagerTest { // By default startScan() succeeds. assertThat(wifiManager.startScan()).isTrue(); - shadowWifiManager.setStartScanSucceeds(true); + shadowOf(wifiManager).setStartScanSucceeds(true); assertThat(wifiManager.startScan()).isTrue(); - shadowWifiManager.setStartScanSucceeds(false); + shadowOf(wifiManager).setStartScanSucceeds(false); assertThat(wifiManager.startScan()).isFalse(); } @Test @Config(minSdk = JELLY_BEAN_MR2) public void getIsScanAlwaysAvailable() { - shadowWifiManager.setIsScanAlwaysAvailable(true); + shadowOf(wifiManager).setIsScanAlwaysAvailable(true); assertThat(wifiManager.isScanAlwaysAvailable()).isEqualTo(true); - shadowWifiManager.setIsScanAlwaysAvailable(false); + shadowOf(wifiManager).setIsScanAlwaysAvailable(false); assertThat(wifiManager.isScanAlwaysAvailable()).isEqualTo(false); } @Test public void shouldEnableNetworks() throws Exception { wifiManager.enableNetwork(666, true); - Pair<Integer, Boolean> lastEnabled = shadowWifiManager.getLastEnabledNetwork(); + Pair<Integer, Boolean> lastEnabled = shadowOf(wifiManager).getLastEnabledNetwork(); assertThat(lastEnabled).isEqualTo(new Pair<>(666, true)); wifiManager.enableNetwork(777, false); - lastEnabled = shadowWifiManager.getLastEnabledNetwork(); + lastEnabled = shadowOf(wifiManager).getLastEnabledNetwork(); assertThat(lastEnabled).isEqualTo(new Pair<>(777, false)); } @Test public void shouldReturnSetScanResults() throws Exception { List<ScanResult> scanResults = new ArrayList<>(); - shadowWifiManager.setScanResults(scanResults); + shadowOf(wifiManager).setScanResults(scanResults); assertThat(wifiManager.getScanResults()).isSameAs(scanResults); } @Test public void shouldReturnDhcpInfo() { DhcpInfo dhcpInfo = new DhcpInfo(); - shadowWifiManager.setDhcpInfo(dhcpInfo); + shadowOf(wifiManager).setDhcpInfo(dhcpInfo); assertThat(wifiManager.getDhcpInfo()).isSameAs(dhcpInfo); } @@ -203,7 +231,7 @@ public class ShadowWifiManagerTest { @Test public void shouldSaveConfigurations() throws Exception { assertThat(wifiManager.saveConfiguration()).isTrue(); - assertThat(shadowWifiManager.wasConfigurationSaved()).isTrue(); + assertThat(shadowOf(wifiManager).wasConfigurationSaved()).isTrue(); } @Test @@ -213,6 +241,26 @@ public class ShadowWifiManagerTest { } @Test + public void wifiLockAcquireIncreasesActiveLockCount() throws Exception { + WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG"); + assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(0); + lock.acquire(); + assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(1); + lock.release(); + assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(0); + } + + @Test + public void multicastLockAcquireIncreasesActiveLockCount() throws Exception { + MulticastLock lock = wifiManager.createMulticastLock("TAG"); + assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(0); + lock.acquire(); + assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(1); + lock.release(); + assertThat(shadowOf(wifiManager).getActiveLockCount()).isEqualTo(0); + } + + @Test public void shouldAcquireAndReleaseWifilockRefCounted() throws Exception { WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG"); lock.acquire(); @@ -236,17 +284,27 @@ public class ShadowWifiManagerTest { assertThat(lock.isHeld()).isFalse(); } - @Test(expected = RuntimeException.class) + @Test public void shouldThrowRuntimeExceptionIfWifiLockisUnderlocked() throws Exception { WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG"); - lock.release(); + try { + lock.release(); + fail("RuntimeException not thrown"); + } catch (RuntimeException e) { + // expected + } } - @Test(expected = UnsupportedOperationException.class) + @Test public void shouldThrowUnsupportedOperationIfWifiLockisOverlocked() throws Exception { WifiManager.WifiLock lock = wifiManager.createWifiLock("TAG"); - for (int i = 0; i < ShadowWifiManager.ShadowWifiLock.MAX_ACTIVE_LOCKS; i++) { - lock.acquire(); + try { + for (int i = 0; i < ShadowWifiManager.ShadowWifiLock.MAX_ACTIVE_LOCKS; i++) { + lock.acquire(); + } + fail("UnsupportedOperationException not thrown"); + } catch (UnsupportedOperationException e) { + // expected } } @@ -384,7 +442,8 @@ public class ShadowWifiManagerTest { // THEN NetworkInfo networkInfo = ((ConnectivityManager) - RuntimeEnvironment.application.getSystemService(Context.CONNECTIVITY_SERVICE)) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.CONNECTIVITY_SERVICE)) .getActiveNetworkInfo(); assertThat(networkInfo.getType()).isEqualTo(ConnectivityManager.TYPE_WIFI); assertThat(networkInfo.isConnected()).isTrue(); @@ -392,6 +451,16 @@ public class ShadowWifiManagerTest { @Test @Config(minSdk = Build.VERSION_CODES.KITKAT) + public void connect_setsNetworkId_shouldHasNetworkId() throws Exception { + // WHEN + wifiManager.connect(123, null); + + // THEN + assertThat(wifiManager.getConnectionInfo().getNetworkId()).isEqualTo(123); + } + + @Test + @Config(minSdk = Build.VERSION_CODES.KITKAT) public void connect_setsConnectionInfo() throws Exception { // GIVEN WifiConfiguration wifiConfiguration = new WifiConfiguration(); @@ -408,7 +477,7 @@ public class ShadowWifiManagerTest { @Config(minSdk = LOLLIPOP) public void is5GhzBandSupportedAndConfigurable() throws Exception { assertThat(wifiManager.is5GHzBandSupported()).isFalse(); - shadowWifiManager.setIs5GHzBandSupported(true); + shadowOf(wifiManager).setIs5GHzBandSupported(true); assertThat(wifiManager.is5GHzBandSupported()).isTrue(); } } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiP2pManagerTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiP2pManagerTest.java index a62281c7b..985c8dd65 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiP2pManagerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiP2pManagerTest.java @@ -3,18 +3,20 @@ package org.robolectric.shadows; import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.net.wifi.p2p.WifiP2pGroup; import android.net.wifi.p2p.WifiP2pManager; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowWifiP2pManagerTest { private WifiP2pManager manager; @@ -25,9 +27,16 @@ public class ShadowWifiP2pManagerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - manager = (WifiP2pManager) RuntimeEnvironment.application.getSystemService(Context.WIFI_P2P_SERVICE); + manager = + (WifiP2pManager) + ((Application) ApplicationProvider.getApplicationContext()) + .getSystemService(Context.WIFI_P2P_SERVICE); shadowManager = shadowOf(manager); - channel = manager.initialize(RuntimeEnvironment.application, RuntimeEnvironment.application.getMainLooper(), mockListener); + channel = + manager.initialize( + (Application) ApplicationProvider.getApplicationContext(), + ((Application) ApplicationProvider.getApplicationContext()).getMainLooper(), + mockListener); assertThat(channel).isNotNull(); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowManagerGlobalTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowManagerGlobalTest.java index d12e7867d..53a87ede7 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowManagerGlobalTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowManagerGlobalTest.java @@ -4,12 +4,12 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static com.google.common.truth.Truth.assertThat; import android.os.Looper; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) @Config(minSdk = JELLY_BEAN_MR1) public class ShadowWindowManagerGlobalTest { diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowManagerImplTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowManagerImplTest.java new file mode 100644 index 000000000..bf9dcbd91 --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowManagerImplTest.java @@ -0,0 +1,70 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.O; +import static com.google.common.truth.Truth.assertThat; +import static org.robolectric.Shadows.shadowOf; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +/** Unit test for {@link ShadowWindowManagerImpl}. */ +@RunWith(AndroidJUnit4.class) +@Config(minSdk = O) +public class ShadowWindowManagerImplTest { + + private View view; + private LayoutParams layoutParams; + private WindowManager windowManager; + + @Before + public void setUp() { + Context context = ApplicationProvider.getApplicationContext(); + view = new View(context); + windowManager = context.getSystemService(WindowManager.class); + layoutParams = + new LayoutParams( + /*w=*/ ViewGroup.LayoutParams.MATCH_PARENT, + /*h=*/ ViewGroup.LayoutParams.MATCH_PARENT, + LayoutParams.TYPE_APPLICATION_OVERLAY, + LayoutParams.FLAG_LAYOUT_IN_SCREEN, + PixelFormat.TRANSLUCENT); + } + + @Test + public void getViews_isInitiallyEmpty() { + List<View> views = ((ShadowWindowManagerImpl) shadowOf(windowManager)).getViews(); + + assertThat(views).isEmpty(); + } + + @Test + public void getViews_returnsAnAddedView() { + windowManager.addView(view, layoutParams); + + List<View> views = ((ShadowWindowManagerImpl) shadowOf(windowManager)).getViews(); + + assertThat(views).hasSize(1); + assertThat(views.get(0)).isSameAs(view); + } + + @Test + public void getViews_doesNotReturnARemovedView() { + windowManager.addView(view, layoutParams); + windowManager.removeView(view); + + List<View> views = ((ShadowWindowManagerImpl) shadowOf(windowManager)).getViews(); + + assertThat(views).isEmpty(); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowTest.java index e2dfccf99..5b4b055a7 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowWindowTest.java @@ -7,21 +7,22 @@ import static org.robolectric.Shadows.shadowOf; import android.R; import android.app.Activity; +import android.app.Application; import android.os.Bundle; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.LinearLayout; import android.widget.ProgressBar; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ShadowWindowTest { @Test public void getFlag_shouldReturnWindowFlags() throws Exception { @@ -97,13 +98,19 @@ public class ShadowWindowTest { @Test @Config(maxSdk = LOLLIPOP_MR1) public void forPreM_create_shouldCreateImplPhoneWindow() throws Exception { - assertThat(ShadowWindow.create(RuntimeEnvironment.application).getClass().getName()) + assertThat( + ShadowWindow.create((Application) ApplicationProvider.getApplicationContext()) + .getClass() + .getName()) .isEqualTo("com.android.internal.policy.impl.PhoneWindow"); } @Test @Config(minSdk = M) public void forM_create_shouldCreatePhoneWindow() throws Exception { - assertThat(ShadowWindow.create(RuntimeEnvironment.application).getClass().getName()) + assertThat( + ShadowWindow.create((Application) ApplicationProvider.getApplicationContext()) + .getClass() + .getName()) .isEqualTo("com.android.internal.policy.PhoneWindow"); } diff --git a/robolectric/src/test/java/org/robolectric/shadows/VelocityTrackerTest.java b/robolectric/src/test/java/org/robolectric/shadows/VelocityTrackerTest.java index 90c5fcefd..747bb3bda 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/VelocityTrackerTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/VelocityTrackerTest.java @@ -4,13 +4,13 @@ import static com.google.common.truth.Truth.assertThat; import android.view.MotionEvent; import android.view.VelocityTracker; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.Shadows; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class VelocityTrackerTest { VelocityTracker velocityTracker; diff --git a/robolectric/src/test/java/org/robolectric/shadows/ViewInnerTextTest.java b/robolectric/src/test/java/org/robolectric/shadows/ViewInnerTextTest.java index c4d2f35a4..ef67e6e72 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ViewInnerTextTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ViewInnerTextTest.java @@ -3,23 +3,24 @@ package org.robolectric.shadows; import static org.junit.Assert.assertEquals; import static org.robolectric.Shadows.shadowOf; +import android.app.Application; import android.content.Context; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ViewInnerTextTest { private Context context; @Before public void setUp() throws Exception { - context = RuntimeEnvironment.application; + context = (Application) ApplicationProvider.getApplicationContext(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/ViewStubTest.java b/robolectric/src/test/java/org/robolectric/shadows/ViewStubTest.java index f33934031..890673d4f 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ViewStubTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ViewStubTest.java @@ -6,24 +6,25 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import android.app.Application; import android.content.Context; import android.view.View; import android.view.ViewStub; import android.widget.LinearLayout; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class ViewStubTest { private Context ctxt; @Before public void setUp() throws Exception { - ctxt = RuntimeEnvironment.application; + ctxt = (Application) ApplicationProvider.getApplicationContext(); } @Test diff --git a/robolectric/src/test/java/org/robolectric/shadows/XmlPullParserTest.java b/robolectric/src/test/java/org/robolectric/shadows/XmlPullParserTest.java index a8e667bf6..261c181c3 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/XmlPullParserTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/XmlPullParserTest.java @@ -4,8 +4,11 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.res.android.ResourceTypes.ANDROID_NS; import static org.robolectric.res.android.ResourceTypes.AUTO_NS; +import android.app.Application; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -13,12 +16,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.R; import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class XmlPullParserTest { // emulator output: @@ -34,7 +36,8 @@ http://schemas.android.com/apk/res-auto:title(resId=2130771971) type=CDATA: valu @Test public void xmlParser() throws IOException, XmlPullParserException { - Resources resources = RuntimeEnvironment.application.getResources(); + Resources resources = + ((Application) ApplicationProvider.getApplicationContext()).getResources(); XmlResourceParser parser = resources.getXml(R.xml.xml_attrs); assertThat(parser).isNotNull(); diff --git a/robolectric/src/test/java/org/robolectric/util/SQLiteLibraryLoaderTest.java b/robolectric/src/test/java/org/robolectric/util/SQLiteLibraryLoaderTest.java index c9b8ade6f..a46708103 100644 --- a/robolectric/src/test/java/org/robolectric/util/SQLiteLibraryLoaderTest.java +++ b/robolectric/src/test/java/org/robolectric/util/SQLiteLibraryLoaderTest.java @@ -2,15 +2,15 @@ package org.robolectric.util; import static com.google.common.truth.Truth.assertThat; +import androidx.test.ext.junit.runners.AndroidJUnit4; import java.io.IOException; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import org.robolectric.shadows.util.SQLiteLibraryLoader; -@RunWith(RobolectricTestRunner.class) +@RunWith(AndroidJUnit4.class) public class SQLiteLibraryLoaderTest { /** Saved system properties. */ private String savedOs, savedArch; diff --git a/robolectric/src/test/resources/AndroidManifest.xml b/robolectric/src/test/resources/AndroidManifest.xml index 5fb7dda1e..5ba014f13 100644 --- a/robolectric/src/test/resources/AndroidManifest.xml +++ b/robolectric/src/test/resources/AndroidManifest.xml @@ -126,6 +126,8 @@ </intent-filter> </activity> + <activity android:name="org.robolectric.shadows.DisabledActivity" android:enabled="false"/> + <activity-alias android:name="org.robolectric.shadows.TestActivityAlias" android:targetActivity=".shadows.TestActivity"> @@ -140,11 +142,14 @@ <action android:name="org.robolectric.ACTION_DIFFERENT_PACKAGE"/> <data android:mimeType="image/jpeg"/> <category android:name="android.intent.category.LAUNCHER"/> - </intent-filter> <meta-data android:name="metadatasample" android:value="sample"/> + </intent-filter> + <meta-data android:name="metadatasample" android:value="sample"/> </service> <service android:name="com.bar.ServiceWithoutIntentFilter"/> + <service android:name="org.robolectric.shadows.DisabledService" android:enabled="false"/> + <!-- Fully qualified name reference --> <provider android:name="org.robolectric.shadows.testing.TestContentProvider1" diff --git a/robolectric/src/test/resources/TestAndroidManifestWithContentProviders.xml b/robolectric/src/test/resources/TestAndroidManifestWithContentProviders.xml index a6c9eaf58..78c51ebcf 100644 --- a/robolectric/src/test/resources/TestAndroidManifestWithContentProviders.xml +++ b/robolectric/src/test/resources/TestAndroidManifestWithContentProviders.xml @@ -8,7 +8,8 @@ <provider android:name=".tester.PartiallyQualifiedClassName" - android:authorities="org.robolectric.authority2"/> + android:authorities="org.robolectric.authority2" + android:enabled="false"/> <provider android:name="org.robolectric.android.controller.ContentProviderControllerTest$MyContentProvider" diff --git a/robolectric/src/test/resources/TestAndroidManifestWithReceivers.xml b/robolectric/src/test/resources/TestAndroidManifestWithReceivers.xml index a8f8139ff..95120e276 100644 --- a/robolectric/src/test/resources/TestAndroidManifestWithReceivers.xml +++ b/robolectric/src/test/resources/TestAndroidManifestWithReceivers.xml @@ -33,7 +33,7 @@ </intent-filter> </receiver> - <receiver android:name=".test.ConfigTestReceiver"> + <receiver android:name=".test.ConfigTestReceiver" android:enabled="false"> <intent-filter> <action android:name="org.robolectric.ACTION_DOT_SUBPACKAGE"/> </intent-filter> diff --git a/robolectric/src/test/resources/TestAndroidManifestWithServices.xml b/robolectric/src/test/resources/TestAndroidManifestWithServices.xml index bd1c1311f..3322d9d56 100644 --- a/robolectric/src/test/resources/TestAndroidManifestWithServices.xml +++ b/robolectric/src/test/resources/TestAndroidManifestWithServices.xml @@ -10,6 +10,6 @@ </intent-filter> </service> - <service android:name="com.bar.ServiceWithoutIntentFilter"/> + <service android:name="com.bar.ServiceWithoutIntentFilter" android:enabled="false"/> </application> </manifest> diff --git a/robolectric/src/test/resources/res/values/ids.xml b/robolectric/src/test/resources/res/values/ids.xml index 7144911e1..a70cfe362 100644 --- a/robolectric/src/test/resources/res/values/ids.xml +++ b/robolectric/src/test/resources/res/values/ids.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <item name="id_declared_in_item_tag" type="id"/> - <item name="id_with_string_value" type="id">string value</item> + <item name="id_with_string_value" type="id"/> <item name="declared_id" type="id"/> -</resources>
\ No newline at end of file +</resources> diff --git a/robolectric/src/test/resources/res/values/plurals.xml b/robolectric/src/test/resources/res/values/plurals.xml index 95dc456e6..823968a14 100644 --- a/robolectric/src/test/resources/res/values/plurals.xml +++ b/robolectric/src/test/resources/res/values/plurals.xml @@ -5,10 +5,8 @@ In us-en locale, only one and other plurals are used because there are only two possible variants: singular vs plural tense. --> - <item quantity="zero">unused</item> - <item quantity="one">beer</item> - <item quantity="two">unused</item> - <item quantity="other">beers</item> + <item quantity="one">a beer</item> + <item quantity="other">some beers</item> </plurals> <plurals name="minute"> <item quantity="one">@string/minute_singular</item> diff --git a/robolectric/src/test/resources/resources.ap_ b/robolectric/src/test/resources/resources.ap_ Binary files differindex 347ef1573..2f7b7f89f 100644 --- a/robolectric/src/test/resources/resources.ap_ +++ b/robolectric/src/test/resources/resources.ap_ diff --git a/sandbox/build.gradle b/sandbox/build.gradle index 23a27d006..5223a6b08 100644 --- a/sandbox/build.gradle +++ b/sandbox/build.gradle @@ -1,24 +1,19 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) dependencies { - // Compile dependencies - compile project(":annotations") - compile project(":utils") - compile project(":shadowapi") + api project(":annotations") + api project(":utils") + api project(":shadowapi") - compile "org.ow2.asm:asm:6.0" - compile "org.ow2.asm:asm-commons:6.0" - compile "com.google.guava:guava:20.0" - compileOnly "com.google.code.findbugs:jsr305:3.0.1" + api "org.ow2.asm:asm:7.0" + api "org.ow2.asm:asm-commons:7.0" + api "com.google.guava:guava:20.0" + compileOnly "com.google.code.findbugs:jsr305:3.0.2" - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" - testCompile project(":junit") + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" + testImplementation project(":junit") }
\ No newline at end of file diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java index 3fe6d77de..8997be4b2 100644 --- a/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java +++ b/sandbox/src/main/java/org/robolectric/internal/bytecode/ClassInstrumentor.java @@ -2,7 +2,6 @@ package org.robolectric.internal.bytecode; import java.lang.invoke.MethodType; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.objectweb.asm.ClassReader; @@ -191,32 +190,6 @@ public abstract class ClassInstrumentor { } } - /** - * Checks if the given method would override a final method in a superclass. This isn't possible - * at compile time but could have occurred with a synthetic method. - */ - private boolean isOverridingFinalMethod(MutableClass mutableClass, String methodName, - String methodSignature) throws ClassNotFoundException { - ClassNode classNode = mutableClass.classNode; - while (true) { - List<MethodNode> methods = new ArrayList<>(classNode.methods); - - for (MethodNode method : methods) { - if (method.name.equals(methodName) && method.desc.equals(methodSignature)) { - if ((method.access & Opcodes.ACC_FINAL) != 0) { - return true; - } - } - } - - if (classNode.superName == null) { - return false; - } - - classNode = mutableClass.classNodeProvider.getClassNode(classNode.superName); - } - } - private boolean isSyntheticAccessorMethod(MethodNode method) { return (method.access & Opcodes.ACC_SYNTHETIC) != 0; } diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/InvocationProfile.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/InvocationProfile.java index 7ea34a7d6..6766f8674 100644 --- a/sandbox/src/main/java/org/robolectric/internal/bytecode/InvocationProfile.java +++ b/sandbox/src/main/java/org/robolectric/internal/bytecode/InvocationProfile.java @@ -43,7 +43,7 @@ public class InvocationProfile { } boolean isAndroidSupport() { - return clazz.getName().startsWith("android.support"); + return clazz.getName().startsWith("android.support") || clazz.getName().startsWith("androidx."); } boolean strict() { @@ -53,7 +53,9 @@ public class InvocationProfile { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (!(o instanceof InvocationProfile)) { + return false; + } InvocationProfile that = (InvocationProfile) o; diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowMap.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowMap.java index 8d7d9836a..189131abb 100644 --- a/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowMap.java +++ b/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowMap.java @@ -2,13 +2,11 @@ package org.robolectric.internal.bytecode; import com.google.common.collect.ImmutableMap; import java.lang.reflect.InvocationTargetException; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.robolectric.annotation.Config; import org.robolectric.annotation.Implements; import org.robolectric.internal.ShadowProvider; import org.robolectric.shadow.api.ShadowPicker; @@ -35,8 +33,8 @@ public class ShadowMap { final Map<String, String> shadowMap = new HashMap<>(); final Map<String, String> shadowPickerMap = new HashMap<>(); for (ShadowProvider provider : shadowProviders) { - shadowMap.putAll(provider.getShadowMap()); - shadowPickerMap.putAll(provider.getShadowPickerMap()); + shadowMap.putAll(provider.getShadowMap()); + shadowPickerMap.putAll(provider.getShadowPickerMap()); } return new ShadowMap(ImmutableMap.copyOf(shadowMap), Collections.emptyMap(), ImmutableMap.copyOf(shadowPickerMap)); @@ -117,14 +115,6 @@ public class ShadowMap { } } - /** - * @deprecated use {@link #obtainShadowInfo(Class)} instead - */ - @Deprecated - public static ShadowInfo getShadowInfo(Class<?> shadowClass) { - return obtainShadowInfo(shadowClass); - } - public static ShadowInfo obtainShadowInfo(Class<?> clazz) { return obtainShadowInfo(clazz, false); } @@ -224,48 +214,12 @@ public class ShadowMap { return this; } - /** @deprecated Use the Robolectric annotation processor or {@link Config#shadows()} instead. */ - @Deprecated - public Builder addShadowClasses(Collection<Class<?>> shadowClasses) { - for (Class<?> shadowClass : shadowClasses) { - addShadowClass(shadowClass); - } - return this; - } - - /** @deprecated Use the Robolectric annotation processor or {@link Config#shadows()} instead. */ - @Deprecated - public Builder addShadowClass(Class<?> shadowClass) { + Builder addShadowClass(Class<?> shadowClass) { addShadowInfo(obtainShadowInfo(shadowClass)); return this; } - /** @deprecated Use the Robolectric annotation processor or {@link Config#shadows()} instead. */ - @Deprecated - public Builder addShadowClass( - String realClassName, - Class<?> shadowClass, - boolean callThroughByDefault, - boolean looseSignatures) { - addShadowClass(realClassName, shadowClass.getName(), callThroughByDefault, looseSignatures); - return this; - } - - /** @deprecated Use the Robolectric annotation processor or {@link Config#shadows()} instead. */ - @Deprecated - public Builder addShadowClass( - Class<?> realClass, - Class<?> shadowClass, - boolean callThroughByDefault, - boolean looseSignatures) { - addShadowClass( - realClass.getName(), shadowClass.getName(), callThroughByDefault, looseSignatures); - return this; - } - - /** @deprecated Use the Robolectric annotation processor or {@link Config#shadows()} instead. */ - @Deprecated - public Builder addShadowClass( + Builder addShadowClass( String realClassName, String shadowClassName, boolean callThroughByDefault, diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java index 4de178aa9..5c10ef2d3 100644 --- a/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java +++ b/sandbox/src/main/java/org/robolectric/internal/bytecode/ShadowWrangler.java @@ -209,6 +209,7 @@ public class ShadowWrangler implements ClassHandler { return DO_NOTHING; } + shadowMethod.setAccessible(true); MethodHandle mh = LOOKUP.unreflect(shadowMethod); // Robolectric doesn't actually look for static, this for example happens diff --git a/scripts/build-resources.rb b/scripts/build-resources.rb deleted file mode 100755 index 3ef1008f3..000000000 --- a/scripts/build-resources.rb +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env ruby -# -# This script can be used to regenerate sequential resource ids when the -# R.java file is modified in the src/test/resources/res folder. -# -# Note: this script does *NOT* generate resource ids that are consistent -# with the Android aapt tool. This script will likely be removed at some -# near point in the future and replaced by something that invokes aapt -# directly. - -GIT_ROOT = `git rev-parse --show-toplevel`.chomp -START = 0x7f000000 -INCR = 0x10000 - -path_to_r = File.join(GIT_ROOT, "robolectric/src/test/java/org/robolectric/R.java") -if path_to_r =~ /^\/path\/to/ - raise "please change the path to this file!" -else - original_contents = File.read(path_to_r) - num_classes = 0 - x = START - new_contents = original_contents.gsub(/class|0x[0-9a-fA-F]+;/) do |match| - if match == "class" - x = START + INCR * num_classes - num_classes += 1 - "class" - else - val = "0x#{"%x"%x};" - x += 1 - val - end - end - File.open(path_to_r, "w") { |f| f << new_contents } -end diff --git a/scripts/build-resources.sh b/scripts/build-resources.sh index dccc62a95..dad138087 100755 --- a/scripts/build-resources.sh +++ b/scripts/build-resources.sh @@ -6,7 +6,8 @@ scriptsDir=`dirname $0` androidProjDir=`dirname $scriptsDir`/robolectric echo $androidProjDir -aapt=$ANDROID_HOME/build-tools/28.0.1/aapt +aapts=( $ANDROID_HOME/build-tools/28.0.*/aapt ) +aapt=${aapts[-1]} inDir=$androidProjDir/src/test/resources outDir=$androidProjDir/src/test/resources javaSrc=$androidProjDir/src/test/java diff --git a/scripts/install-dependencies.rb b/scripts/install-dependencies.rb index 21d1f2f01..8d64bf736 100755 --- a/scripts/install-dependencies.rb +++ b/scripts/install-dependencies.rb @@ -18,23 +18,23 @@ def concat_maven_file_segments(repo_root_dir, group_id, artifact_id, version, ex raise ArgumentError, "Group ID, Artifact ID, Version, and/or Extension arguments are invalid. Please check your inputs." end # Generate dependency path segments - dep_path_segments = [] + dep_path_segments = [] artifact_file_name = "#{artifact_id}-#{version}.#{extension}" # Start with the root repo dir dep_path_segments << repo_root_dir # Add the split group id segments into the path segments dep_path_segments << group_id.split(".") - + # Then add the artifact id dep_path_segments << artifact_id - + # Then add the version ID dep_path_segments << version - + # Finally, add the version file dep_path_segments << artifact_file_name - + # Concatenate the segments into the target archive dep_path_segments.join("/") end @@ -144,8 +144,10 @@ MULTIDEX_VERSION = "1.0.1" ANDROIDX_TEST_GROUP_ID = "androidx.test" MONITOR_ARTIFACT_ID = "monitor" CORE_ARTIFACT_ID = "core" -ANDROIDX_TEST_VERSION = "1.1.0-alpha4" -ANDROIDX_TEST_CORE_VERSION = "1.0.0-alpha4" +ANDROIDX_TEST_EXT_GROUP_ID = "androidx.test.ext" +EXT_JUNIT_ARTIFACT_ID = "junit" +ANDROIDX_TEST_VERSION = "1.1.0" +ANDROIDX_TEST_CORE_VERSION = "1.0.0" # Play Services constants PLAY_SERVICES_GROUP_ID = "com.google.android.gms" @@ -201,3 +203,4 @@ install_supportlib_from_gmaven('support-media-compat') install_from_gmaven(ANDROIDX_TEST_GROUP_ID, MONITOR_ARTIFACT_ID, ANDROIDX_TEST_VERSION) install_from_gmaven(ANDROIDX_TEST_GROUP_ID, CORE_ARTIFACT_ID, ANDROIDX_TEST_CORE_VERSION) +install_from_gmaven(ANDROIDX_TEST_EXT_GROUP_ID, EXT_JUNIT_ARTIFACT_ID, ANDROIDX_TEST_CORE_VERSION) diff --git a/scripts/update-cpp.sh b/scripts/update-cpp.sh index 122c56058..216815b4a 100755 --- a/scripts/update-cpp.sh +++ b/scripts/update-cpp.sh @@ -4,7 +4,7 @@ set -e #currentVersion=android-8.0.0_r36 #currentVersion=android-8.1.0_r22 -currentVersion=android-9.0.0_r3 +currentVersion=android-9.0.0_r12 baseDir=`dirname $0`/.. frameworksBaseRepoDir="$HOME/Dev/AOSP/frameworks/base" @@ -32,12 +32,18 @@ function showDiffs2() { fi if [ "x$curSha" != "x$thisSha" ]; then - tmpFile="/tmp/diff.tmp" - rm -f "$tmpFile" - echo "Apply changes to: $file" > "$tmpFile" - echo " From $repoFile $version -> $currentVersion" >> "$tmpFile" - (cd "$frameworksBaseRepoDir" && git diff --color=always "${version}..${currentVersion}" "--" "$repoFile" >> "$tmpFile") - less -r "$tmpFile" + (cd "$frameworksBaseRepoDir" && git diff --quiet "${version}..${currentVersion}" "--" "$repoFile") + if [ $? -eq 0 ]; then + echo "No changes in: $file" + echo " From $repoFile $version -> $currentVersion" + else + tmpFile="/tmp/diff.tmp" + rm -f "$tmpFile" + echo "Apply changes to: $file" > "$tmpFile" + echo " From $repoFile $version -> $currentVersion" >> "$tmpFile" + (cd "$frameworksBaseRepoDir" && git diff --color=always "${version}..${currentVersion}" "--" "$repoFile" >> "$tmpFile") + less -r "$tmpFile" + fi fi } diff --git a/shadowapi/build.gradle b/shadowapi/build.gradle index 7d9add699..794c15e65 100644 --- a/shadowapi/build.gradle +++ b/shadowapi/build.gradle @@ -1,17 +1,11 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) dependencies { - // Compile dependencies - compileOnly "com.google.code.findbugs:jsr305:3.0.1" + compileOnly "com.google.code.findbugs:jsr305:3.0.2" - // Testing dependencies - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" }
\ No newline at end of file diff --git a/shadows/androidx/fragment/Android.mk b/shadows/androidx/fragment/Android.mk index 6f07f5b94..abb656795 100644 --- a/shadows/androidx/fragment/Android.mk +++ b/shadows/androidx/fragment/Android.mk @@ -35,7 +35,7 @@ LOCAL_MODULE := Robolectric_shadows_androidx_fragment_tests LOCAL_SRC_FILES := $(call all-java-files-under, src/test/java) -LOCAL_JAVA_RESOURCE_DIRS := src/test/resources +LOCAL_JAVA_RESOURCE_DIRS := src/test/resources/res LOCAL_JAVA_LIBRARIES := \ Robolectric_shadows_androidx_fragment \ diff --git a/shadows/androidx/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java b/shadows/androidx/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java index 89808ea4a..77373ca85 100644 --- a/shadows/androidx/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java +++ b/shadows/androidx/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java @@ -16,10 +16,10 @@ import java.util.List; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.util.TestRunnerWithManifest; +import org.robolectric.RobolectricTestRunner; /** Tests for {@link FragmentController} */ -@RunWith(TestRunnerWithManifest.class) +@RunWith(RobolectricTestRunner.class) public class FragmentControllerTest { @After @@ -232,7 +232,7 @@ public class FragmentControllerTest { @Test public void - setupFragmentWithFragmentAndActivityAndContainViewIdAndBundle_fragmentHasCorrectLifecycle() { + setupFragmentWithFragmentAndActivityAndContainViewIdAndBundle_fragmentHasCorrectLifecycle() { Bundle testBundle = generateTestBundle(); TranscriptFragment fragment = FragmentController.setupFragment( diff --git a/shadows/androidx/fragment/src/test/java/org/robolectric/util/TestRunnerWithManifest.java b/shadows/androidx/fragment/src/test/java/org/robolectric/util/TestRunnerWithManifest.java deleted file mode 100644 index 4a6349734..000000000 --- a/shadows/androidx/fragment/src/test/java/org/robolectric/util/TestRunnerWithManifest.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.robolectric.util; - -import org.junit.runners.model.InitializationError; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.manifest.AndroidManifest; -import org.robolectric.res.Fs; -import org.robolectric.res.FsFile; - -import java.io.File; -import java.net.URI; -import java.net.URL; - -public class TestRunnerWithManifest extends RobolectricTestRunner { - public TestRunnerWithManifest(Class<?> testClass) throws InitializationError { - super(testClass); - } - - private static FsFile resourceFile(String... pathParts) { - return Fs.newFile(resourcesBaseDirFile()).join(pathParts); - } - - private static File resourcesBaseDirFile() { - // Try to locate the manifest file as a classpath resource. - final String resourceName = "/src/test/resources/AndroidManifest.xml"; - final URL resourceUrl = TestRunnerWithManifest.class.getResource(resourceName); - if (resourceUrl != null && "file".equals(resourceUrl.getProtocol())) { - // Construct a path to the manifest file relative to the current working directory. - final URI workingDirectory = URI.create(System.getProperty("user.dir")); - final URI absolutePath = URI.create(resourceUrl.getPath()); - final URI relativePath = workingDirectory.relativize(absolutePath); - return new File(relativePath.toString()).getParentFile(); - } - - // Return a path relative to the current working directory. - return Util.file("src", "test", "resources"); - } - - @Override - protected AndroidManifest getAppManifest(Config config) { - return new AndroidManifest(resourceFile("AndroidManifest.xml"), resourceFile("res"), - resourceFile("assets")); - } -} diff --git a/shadows/framework/build.gradle b/shadows/framework/build.gradle index 65b6a9319..3dc523cab 100644 --- a/shadows/framework/build.gradle +++ b/shadows/framework/build.gradle @@ -1,7 +1,3 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) @@ -41,17 +37,15 @@ jar { } dependencies { - // Project dependencies - compile project(":annotations") - compile project(":resources") - compile project(":utils") - - // Compile dependencies - compileOnly "com.google.code.findbugs:jsr305:3.0.1" - compile "com.almworks.sqlite4java:sqlite4java:0.282" + api project(":annotations") + api project(":resources") + api project(":utils") + + compileOnly "com.google.code.findbugs:jsr305:3.0.2" + api "com.almworks.sqlite4java:sqlite4java:0.282" compileOnly(AndroidSdk.MAX_SDK.coordinates) { force = true } - compile "com.ibm.icu:icu4j:53.1" - compile "com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.1" + api "com.ibm.icu:icu4j:53.1" + api "com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.1" jni "com.github.axet.litedb:libsqlite:0.282-3:natives-mac-x86_64" jni "com.github.axet.litedb:libsqlite:0.282-3:natives-linux-x86" diff --git a/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java b/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java index 019bbf0ab..48a72b3e6 100644 --- a/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java +++ b/shadows/framework/src/main/java/org/robolectric/RuntimeEnvironment.java @@ -17,7 +17,12 @@ import org.robolectric.util.TempDirectory; public class RuntimeEnvironment { public static Context systemContext; - public static Application application; + + /** + * @deprecated Please migrate to {@link + * androidx.test.core.app.ApplicationProvider#getApplicationContext} + */ + @Deprecated public static Application application; private volatile static Thread mainThread = Thread.currentThread(); private static Object activityThread; diff --git a/shadows/framework/src/main/java/org/robolectric/android/ConfigurationV25.java b/shadows/framework/src/main/java/org/robolectric/android/ConfigurationV25.java index ba880a675..d92298a8e 100644 --- a/shadows/framework/src/main/java/org/robolectric/android/ConfigurationV25.java +++ b/shadows/framework/src/main/java/org/robolectric/android/ConfigurationV25.java @@ -15,7 +15,7 @@ import java.util.List; import java.util.Locale; import org.robolectric.RuntimeEnvironment; -// adapted from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/core/java/android/content/res/Configuration.java +// adapted from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/java/android/content/res/Configuration.java public class ConfigurationV25 { private static String localesToResourceQualifier(List<Locale> locs) { diff --git a/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java b/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java index f879ef6a7..8a0af2b11 100644 --- a/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java +++ b/shadows/framework/src/main/java/org/robolectric/android/controller/ActivityController.java @@ -6,7 +6,9 @@ import static org.robolectric.shadow.api.Shadow.extract; import static org.robolectric.util.ReflectionHelpers.ClassParameter.from; import android.app.Activity; +import android.app.ActivityThread; import android.app.Application; +import android.app.Instrumentation; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -55,12 +57,7 @@ public class ActivityController<T extends Activity> extends ComponentController< } public ActivityController<T> create(final Bundle bundle) { - shadowMainLooper.runPaused(new Runnable() { - @Override - public void run() { - ReflectionHelpers.callInstanceMethod(Activity.class, component, "performCreate", from(Bundle.class, bundle)); - } - }); + shadowMainLooper.runPaused(() -> getInstrumentation().callActivityOnCreate(component, bundle)); return this; } @@ -80,7 +77,9 @@ public class ActivityController<T extends Activity> extends ComponentController< } public ActivityController<T> start() { - + // Start and stop are tricky cases. Unlike other lifecycle methods such as + // Instrumentation#callActivityOnPause calls Activity#performPause, Activity#performStop calls + // Instrumentation#callActivityOnStop internally so the dependency direction is the opposite. if (RuntimeEnvironment.getApiLevel() <= O_MR1) { invokeWhilePaused("performStart"); } else { @@ -90,7 +89,8 @@ public class ActivityController<T extends Activity> extends ComponentController< } public ActivityController<T> restoreInstanceState(Bundle bundle) { - invokeWhilePaused("performRestoreInstanceState", from(Bundle.class, bundle)); + shadowMainLooper.runPaused( + () -> getInstrumentation().callActivityOnRestoreInstanceState(component, bundle)); return this; } @@ -144,21 +144,25 @@ public class ActivityController<T extends Activity> extends ComponentController< } public ActivityController<T> userLeaving() { - invokeWhilePaused("performUserLeaving"); + shadowMainLooper.runPaused(() -> getInstrumentation().callActivityOnUserLeaving(component)); return this; } public ActivityController<T> pause() { - invokeWhilePaused("performPause"); + shadowMainLooper.runPaused(() -> getInstrumentation().callActivityOnPause(component)); return this; } public ActivityController<T> saveInstanceState(Bundle outState) { - invokeWhilePaused("performSaveInstanceState", from(Bundle.class, outState)); + shadowMainLooper.runPaused( + () -> getInstrumentation().callActivityOnSaveInstanceState(component, outState)); return this; } public ActivityController<T> stop() { + // Stop and start are tricky cases. Unlike other lifecycle methods such as + // Instrumentation#callActivityOnPause calls Activity#performPause, Activity#performStop calls + // Instrumentation#callActivityOnStop internally so the dependency direction is the opposite. if (RuntimeEnvironment.getApiLevel() <= M) { invokeWhilePaused("performStop"); } else if (RuntimeEnvironment.getApiLevel() <= O_MR1) { @@ -170,7 +174,7 @@ public class ActivityController<T extends Activity> extends ComponentController< } @Override public ActivityController<T> destroy() { - invokeWhilePaused("performDestroy"); + shadowMainLooper.runPaused(() -> getInstrumentation().callActivityOnDestroy(component)); return this; } @@ -364,4 +368,8 @@ public class ActivityController<T extends Activity> extends ComponentController< return this; } + + private static Instrumentation getInstrumentation() { + return ((ActivityThread) RuntimeEnvironment.getActivityThread()).getInstrumentation(); + } } diff --git a/shadows/framework/src/main/java/org/robolectric/fakes/RoboCursor.java b/shadows/framework/src/main/java/org/robolectric/fakes/RoboCursor.java index 765e36bae..c419383c1 100644 --- a/shadows/framework/src/main/java/org/robolectric/fakes/RoboCursor.java +++ b/shadows/framework/src/main/java/org/robolectric/fakes/RoboCursor.java @@ -64,7 +64,12 @@ public class RoboCursor extends BaseCursor { @Override public long getLong(int columnIndex) { - return (Long) results[resultsIndex][columnIndex]; + Object value = results[resultsIndex][columnIndex]; + return value == null + ? 0 + : (value instanceof Number + ? ((Number) value).longValue() + : Long.parseLong(value.toString())); } @Override diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/CachedPathIteratorFactory.java b/shadows/framework/src/main/java/org/robolectric/shadows/CachedPathIteratorFactory.java new file mode 100644 index 000000000..3ad4d8b39 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/CachedPathIteratorFactory.java @@ -0,0 +1,469 @@ +package org.robolectric.shadows; + +import java.awt.geom.CubicCurve2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.QuadCurve2D; +import java.util.ArrayList; + +/** + * Class that returns iterators for a given path. These iterators are lightweight and can be reused + * multiple times to iterate over the path. + * + * <p>copied from + * https://github.com/aosp-mirror/platform_frameworks_base/blob/oreo-release/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/CachedPathIteratorFactory.java + */ +public class CachedPathIteratorFactory { + /* + * A few conventions used in the code: + * Coordinates or coords arrays store segment coordinates. They use the same format as + * PathIterator#currentSegment coordinates array. + * float arrays store always points where the first element is X and the second is Y. + */ + + // This governs how accurate the approximation of the Path is. + private static final float PRECISION = 0.002f; + + private final int mWindingRule; + private final int[] mTypes; + private final float[][] mCoordinates; + private final float[] mSegmentsLength; + private final float mTotalLength; + + public CachedPathIteratorFactory(PathIterator iterator) { + mWindingRule = iterator.getWindingRule(); + + ArrayList<Integer> typesArray = new ArrayList<>(); + ArrayList<float[]> pointsArray = new ArrayList<>(); + float[] points = new float[6]; + while (!iterator.isDone()) { + int type = iterator.currentSegment(points); + int nPoints = getNumberOfPoints(type) * 2; // 2 coordinates per point + + typesArray.add(type); + float[] itemPoints = new float[nPoints]; + System.arraycopy(points, 0, itemPoints, 0, nPoints); + pointsArray.add(itemPoints); + iterator.next(); + } + + mTypes = new int[typesArray.size()]; + mCoordinates = new float[mTypes.length][]; + for (int i = 0; i < typesArray.size(); i++) { + mTypes[i] = typesArray.get(i); + mCoordinates[i] = pointsArray.get(i); + } + + // Do measurement + mSegmentsLength = new float[mTypes.length]; + + // Curves that we can reuse to estimate segments length + CubicCurve2D.Float cubicCurve = new CubicCurve2D.Float(); + QuadCurve2D.Float quadCurve = new QuadCurve2D.Float(); + float lastX = 0; + float lastY = 0; + float totalLength = 0; + for (int i = 0; i < mTypes.length; i++) { + switch (mTypes[i]) { + case PathIterator.SEG_CUBICTO: + cubicCurve.setCurve( + lastX, + lastY, + mCoordinates[i][0], + mCoordinates[i][1], + mCoordinates[i][2], + mCoordinates[i][3], + lastX = mCoordinates[i][4], + lastY = mCoordinates[i][5]); + mSegmentsLength[i] = getFlatPathLength(cubicCurve.getPathIterator(null, PRECISION)); + break; + case PathIterator.SEG_QUADTO: + quadCurve.setCurve( + lastX, + lastY, + mCoordinates[i][0], + mCoordinates[i][1], + lastX = mCoordinates[i][2], + lastY = mCoordinates[i][3]); + mSegmentsLength[i] = getFlatPathLength(quadCurve.getPathIterator(null, PRECISION)); + break; + case PathIterator.SEG_CLOSE: + mSegmentsLength[i] = + (float) + Point2D.distance( + lastX, lastY, lastX = mCoordinates[0][0], lastY = mCoordinates[0][1]); + mCoordinates[i] = new float[2]; + // We convert a SEG_CLOSE segment to a SEG_LINETO so we do not have to worry + // about this special case in the rest of the code. + mTypes[i] = PathIterator.SEG_LINETO; + mCoordinates[i][0] = mCoordinates[0][0]; + mCoordinates[i][1] = mCoordinates[0][1]; + break; + case PathIterator.SEG_MOVETO: + mSegmentsLength[i] = 0; + lastX = mCoordinates[i][0]; + lastY = mCoordinates[i][1]; + break; + case PathIterator.SEG_LINETO: + mSegmentsLength[i] = + (float) Point2D.distance(lastX, lastY, mCoordinates[i][0], mCoordinates[i][1]); + lastX = mCoordinates[i][0]; + lastY = mCoordinates[i][1]; + break; + default: + } + totalLength += mSegmentsLength[i]; + } + + mTotalLength = totalLength; + } + + private static void quadCurveSegment(float[] coords, float t0, float t1) { + // Calculate X and Y at 0.5 (We'll use this to reconstruct the control point later) + float mt = t0 + (t1 - t0) / 2; + float mu = 1 - mt; + float mx = mu * mu * coords[0] + 2 * mu * mt * coords[2] + mt * mt * coords[4]; + float my = mu * mu * coords[1] + 2 * mu * mt * coords[3] + mt * mt * coords[5]; + + float u0 = 1 - t0; + float u1 = 1 - t1; + + // coords at t0 + coords[0] = coords[0] * u0 * u0 + coords[2] * 2 * t0 * u0 + coords[4] * t0 * t0; + coords[1] = coords[1] * u0 * u0 + coords[3] * 2 * t0 * u0 + coords[5] * t0 * t0; + + // coords at t1 + coords[4] = coords[0] * u1 * u1 + coords[2] * 2 * t1 * u1 + coords[4] * t1 * t1; + coords[5] = coords[1] * u1 * u1 + coords[3] * 2 * t1 * u1 + coords[5] * t1 * t1; + + // estimated control point at t'=0.5 + coords[2] = 2 * mx - coords[0] / 2 - coords[4] / 2; + coords[3] = 2 * my - coords[1] / 2 - coords[5] / 2; + } + + private static void cubicCurveSegment(float[] coords, float t0, float t1) { + // http://stackoverflow.com/questions/11703283/cubic-bezier-curve-segment + float u0 = 1 - t0; + float u1 = 1 - t1; + + // Calculate the points at t0 and t1 for the quadratic curves formed by (P0, P1, P2) and + // (P1, P2, P3) + float qxa = coords[0] * u0 * u0 + coords[2] * 2 * t0 * u0 + coords[4] * t0 * t0; + float qxb = coords[0] * u1 * u1 + coords[2] * 2 * t1 * u1 + coords[4] * t1 * t1; + float qxc = coords[2] * u0 * u0 + coords[4] * 2 * t0 * u0 + coords[6] * t0 * t0; + float qxd = coords[2] * u1 * u1 + coords[4] * 2 * t1 * u1 + coords[6] * t1 * t1; + + float qya = coords[1] * u0 * u0 + coords[3] * 2 * t0 * u0 + coords[5] * t0 * t0; + float qyb = coords[1] * u1 * u1 + coords[3] * 2 * t1 * u1 + coords[5] * t1 * t1; + float qyc = coords[3] * u0 * u0 + coords[5] * 2 * t0 * u0 + coords[7] * t0 * t0; + float qyd = coords[3] * u1 * u1 + coords[5] * 2 * t1 * u1 + coords[7] * t1 * t1; + + // Linear interpolation + coords[0] = qxa * u0 + qxc * t0; + coords[1] = qya * u0 + qyc * t0; + + coords[2] = qxa * u1 + qxc * t1; + coords[3] = qya * u1 + qyc * t1; + + coords[4] = qxb * u0 + qxd * t0; + coords[5] = qyb * u0 + qyd * t0; + + coords[6] = qxb * u1 + qxd * t1; + coords[7] = qyb * u1 + qyd * t1; + } + + /** + * Returns the end point of a given segment + * + * @param type the segment type + * @param coords the segment coordinates array + * @param point the return array where the point will be stored + */ + private static void getShapeEndPoint(int type, float[] coords, float[] point) { + // start index of the end point for the segment type + int pointIndex = (getNumberOfPoints(type) - 1) * 2; + point[0] = coords[pointIndex]; + point[1] = coords[pointIndex + 1]; + } + + /** Returns the number of points stored in a coordinates array for the given segment type. */ + private static int getNumberOfPoints(int segmentType) { + switch (segmentType) { + case PathIterator.SEG_QUADTO: + return 2; + case PathIterator.SEG_CUBICTO: + return 3; + case PathIterator.SEG_CLOSE: + return 0; + default: + return 1; + } + } + + /** + * Returns the estimated length of a flat path. If the passed path is not flat (i.e. contains a + * segment that is not {@link PathIterator#SEG_CLOSE}, {@link PathIterator#SEG_MOVETO} or {@link + * PathIterator#SEG_LINETO} this method will fail. + */ + private static float getFlatPathLength(PathIterator iterator) { + float segment[] = new float[6]; + float totalLength = 0; + float[] previousPoint = new float[2]; + boolean isFirstPoint = true; + + while (!iterator.isDone()) { + int type = iterator.currentSegment(segment); + assert type == PathIterator.SEG_LINETO + || type == PathIterator.SEG_CLOSE + || type == PathIterator.SEG_MOVETO; + + // MoveTo shouldn't affect the length + if (!isFirstPoint && type != PathIterator.SEG_MOVETO) { + totalLength += Point2D.distance(previousPoint[0], previousPoint[1], segment[0], segment[1]); + } else { + isFirstPoint = false; + } + previousPoint[0] = segment[0]; + previousPoint[1] = segment[1]; + iterator.next(); + } + + return totalLength; + } + + /** Returns the estimated position along a path of the given length. */ + private void getPointAtLength( + int type, float[] coords, float lastX, float lastY, float t, float[] point) { + if (type == PathIterator.SEG_LINETO) { + point[0] = lastX + (coords[0] - lastX) * t; + point[1] = lastY + (coords[1] - lastY) * t; + // Return here, since we do not need a shape to estimate + return; + } + + float[] curve = new float[8]; + int lastPointIndex = (getNumberOfPoints(type) - 1) * 2; + + System.arraycopy(coords, 0, curve, 2, coords.length); + curve[0] = lastX; + curve[1] = lastY; + if (type == PathIterator.SEG_CUBICTO) { + cubicCurveSegment(curve, 0f, t); + } else { + quadCurveSegment(curve, 0f, t); + } + + point[0] = curve[2 + lastPointIndex]; + point[1] = curve[2 + lastPointIndex + 1]; + } + + public CachedPathIterator iterator() { + return new CachedPathIterator(); + } + + /** Class that allows us to iterate over a path multiple times */ + public class CachedPathIterator implements PathIterator { + private int mNextIndex; + + /** + * Current segment type. + * + * @see PathIterator + */ + private int mCurrentType; + + /** + * Stores the coordinates array of the current segment. The number of points stored depends on + * the segment type. + * + * @see PathIterator + */ + private float[] mCurrentCoords = new float[6]; + + private float mCurrentSegmentLength; + + /** + * Current segment length offset. When asking for the length of the current segment, the length + * will be reduced by this amount. This is useful when we are only using portions of the + * segment. + * + * @see #jumpToSegment(float) + */ + private float mOffsetLength; + + /** Point where the current segment started */ + private float[] mLastPoint = new float[2]; + + private boolean isIteratorDone; + + private CachedPathIterator() { + next(); + } + + public float getCurrentSegmentLength() { + return mCurrentSegmentLength; + } + + @Override + public int getWindingRule() { + return mWindingRule; + } + + @Override + public boolean isDone() { + return isIteratorDone; + } + + @Override + public void next() { + if (mNextIndex >= mTypes.length) { + isIteratorDone = true; + return; + } + + if (mNextIndex >= 1) { + // We've already called next() once so there is a previous segment in this path. + // We want to get the coordinates where the path ends. + getShapeEndPoint(mCurrentType, mCurrentCoords, mLastPoint); + } else { + // This is the first segment, no previous point so initialize to 0, 0 + mLastPoint[0] = mLastPoint[1] = 0f; + } + mCurrentType = mTypes[mNextIndex]; + mCurrentSegmentLength = mSegmentsLength[mNextIndex] - mOffsetLength; + + if (mOffsetLength > 0f && (mCurrentType == SEG_CUBICTO || mCurrentType == SEG_QUADTO)) { + // We need to skip part of the start of the current segment (because + // mOffsetLength > 0) + float[] points = new float[8]; + + if (mNextIndex < 1) { + points[0] = points[1] = 0f; + } else { + getShapeEndPoint(mTypes[mNextIndex - 1], mCoordinates[mNextIndex - 1], points); + } + + System.arraycopy(mCoordinates[mNextIndex], 0, points, 2, mCoordinates[mNextIndex].length); + float t0 = + (mSegmentsLength[mNextIndex] - mCurrentSegmentLength) / mSegmentsLength[mNextIndex]; + if (mCurrentType == SEG_CUBICTO) { + cubicCurveSegment(points, t0, 1f); + } else { + quadCurveSegment(points, t0, 1f); + } + System.arraycopy(points, 2, mCurrentCoords, 0, mCoordinates[mNextIndex].length); + } else { + System.arraycopy( + mCoordinates[mNextIndex], 0, mCurrentCoords, 0, mCoordinates[mNextIndex].length); + } + + mOffsetLength = 0f; + mNextIndex++; + } + + @Override + public int currentSegment(float[] coords) { + System.arraycopy(mCurrentCoords, 0, coords, 0, getNumberOfPoints(mCurrentType) * 2); + return mCurrentType; + } + + @Override + public int currentSegment(double[] coords) { + throw new UnsupportedOperationException(); + } + + /** Returns the point where the current segment ends */ + public void getCurrentSegmentEnd(float[] point) { + point[0] = mLastPoint[0]; + point[1] = mLastPoint[1]; + } + + /** Restarts the iterator and jumps all the segments of this path up to the length value. */ + public void jumpToSegment(float length) { + isIteratorDone = false; + if (length <= 0f) { + mNextIndex = 0; + return; + } + + float accLength = 0; + float lastPoint[] = new float[2]; + for (mNextIndex = 0; mNextIndex < mTypes.length; mNextIndex++) { + float segmentLength = mSegmentsLength[mNextIndex]; + if (accLength + segmentLength >= length && mTypes[mNextIndex] != SEG_MOVETO) { + float[] estimatedPoint = new float[2]; + getPointAtLength( + mTypes[mNextIndex], + mCoordinates[mNextIndex], + lastPoint[0], + lastPoint[1], + (length - accLength) / segmentLength, + estimatedPoint); + + // This segment makes us go further than length so we go back one step, + // set a moveto and offset the length of the next segment by the length + // of this segment that we've already used. + mCurrentType = PathIterator.SEG_MOVETO; + mCurrentCoords[0] = estimatedPoint[0]; + mCurrentCoords[1] = estimatedPoint[1]; + mCurrentSegmentLength = 0; + + // We need to offset next path length to account for the segment we've just + // skipped. + mOffsetLength = length - accLength; + return; + } + accLength += segmentLength; + getShapeEndPoint(mTypes[mNextIndex], mCoordinates[mNextIndex], lastPoint); + } + } + + /** + * Returns the current segment up to certain length. If the current segment is shorter than + * length, then the whole segment is returned. The segment coordinates are copied into the + * coords array. + * + * @return the segment type + */ + public int currentSegment(float[] coords, float length) { + int type = currentSegment(coords); + // If the length is greater than the current segment length, no need to find + // the cut point. Same if this is a SEG_MOVETO. + if (mCurrentSegmentLength <= length || type == SEG_MOVETO) { + return type; + } + + float t = length / getCurrentSegmentLength(); + + // We find at which offset the end point is located within the coords array and set + // a new end point to cut the segment short + switch (type) { + case SEG_CUBICTO: + case SEG_QUADTO: + float[] curve = new float[8]; + curve[0] = mLastPoint[0]; + curve[1] = mLastPoint[1]; + System.arraycopy(coords, 0, curve, 2, coords.length); + if (type == SEG_CUBICTO) { + cubicCurveSegment(curve, 0f, t); + } else { + quadCurveSegment(curve, 0f, t); + } + System.arraycopy(curve, 2, coords, 0, coords.length); + break; + default: + float[] point = new float[2]; + getPointAtLength(type, coords, mLastPoint[0], mLastPoint[1], t, point); + coords[0] = point[0]; + coords[1] = point[1]; + } + + return type; + } + + /** Returns the total length of the path */ + public float getTotalLength() { + return mTotalLength; + } + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java b/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java index e7f4060dd..4bfe1a45f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/Converter.java @@ -270,7 +270,7 @@ public class Converter<T> { try { typedValue.data = findValueFor(data); } catch (Resources.NotFoundException e) { - typedValue.data = Integer.decode(data); + typedValue.data = convertInt(data); } typedValue.assetCookie = 0; typedValue.string = null; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/LegacyManifestParser.java b/shadows/framework/src/main/java/org/robolectric/shadows/LegacyManifestParser.java index 6c071c311..a57d96989 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/LegacyManifestParser.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/LegacyManifestParser.java @@ -183,6 +183,7 @@ public class LegacyManifestParser { activityInfo.targetActivity = data.getTargetActivityName(); activityInfo.exported = data.isExported(); activityInfo.permission = data.getPermission(); + activityInfo.enabled = data.isEnabled(); String themeRef; // Based on ShadowActivity @@ -231,6 +232,7 @@ public class LegacyManifestParser { info.readPermission = data.getReadPermission(); info.writePermission = data.getWritePermission(); info.grantUriPermissions = data.getGrantUriPermissions(); + info.enabled = data.isEnabled(); pkg.providers.add(createProvider(pkg, info)); } @@ -239,7 +241,7 @@ public class LegacyManifestParser { populateComponentInfo(info, pkg, data); info.permission = data.getPermission(); info.exported = data.isExported(); - + info.enabled = data.isEnabled(); Activity receiver = createActivity(pkg, info); for (IntentFilterData intentFilterData : data.getIntentFilters()) { ActivityIntentInfo outInfo = new ActivityIntentInfo(receiver); @@ -254,6 +256,7 @@ public class LegacyManifestParser { populateComponentInfo(info, pkg, data); info.permission = data.getPermission(); info.exported = data.isExported(); + info.enabled = data.isEnabled(); Service service = createService(pkg, info); for (IntentFilterData intentFilterData : data.getIntentFilters()) { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/RoundRectangle.java b/shadows/framework/src/main/java/org/robolectric/shadows/RoundRectangle.java new file mode 100644 index 000000000..f396f43b7 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/RoundRectangle.java @@ -0,0 +1,353 @@ +package org.robolectric.shadows; + +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RectangularShape; +import java.awt.geom.RoundRectangle2D; +import java.util.EnumSet; +import java.util.NoSuchElementException; + +/** + * Defines a rectangle with rounded corners, where the sizes of the corners are potentially + * different. + * + * <p>Copied from + * https://github.com/aosp-mirror/platform_frameworks_base/blob/oreo-release/tools/layoutlib/bridge/src/android/graphics/RoundRectangle.java + */ +public class RoundRectangle extends RectangularShape { + public double x; + public double y; + public double width; + public double height; + public double ulWidth; + public double ulHeight; + public double urWidth; + public double urHeight; + public double lrWidth; + public double lrHeight; + public double llWidth; + public double llHeight; + + private enum Zone { + CLOSE_OUTSIDE, + CLOSE_INSIDE, + MIDDLE, + FAR_INSIDE, + FAR_OUTSIDE + } + + private final EnumSet<Zone> close = EnumSet.of(Zone.CLOSE_OUTSIDE, Zone.CLOSE_INSIDE); + private final EnumSet<Zone> far = EnumSet.of(Zone.FAR_OUTSIDE, Zone.FAR_INSIDE); + + /** + * @param cornerDimensions array of 8 floating-point number corresponding to the width and the + * height of each corner in the following order: upper-left, upper-right, lower-right, + * lower-left. It assumes for the size the same convention as {@link RoundRectangle2D}, that + * is that the width and height of a corner correspond to the total width and height of the + * ellipse that corner is a quarter of. + */ + public RoundRectangle(float x, float y, float width, float height, float[] cornerDimensions) { + assert cornerDimensions.length == 8 + : "The array of corner dimensions must have eight " + "elements"; + + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + float[] dimensions = cornerDimensions.clone(); + // If a value is negative, the corresponding corner is squared + for (int i = 0; i < dimensions.length; i += 2) { + if (dimensions[i] < 0 || dimensions[i + 1] < 0) { + dimensions[i] = 0; + dimensions[i + 1] = 0; + } + } + + double topCornerWidth = (dimensions[0] + dimensions[2]) / 2d; + double bottomCornerWidth = (dimensions[4] + dimensions[6]) / 2d; + double leftCornerHeight = (dimensions[1] + dimensions[7]) / 2d; + double rightCornerHeight = (dimensions[3] + dimensions[5]) / 2d; + + // Rescale the corner dimensions if they are bigger than the rectangle + double scale = Math.min(1.0, width / topCornerWidth); + scale = Math.min(scale, width / bottomCornerWidth); + scale = Math.min(scale, height / leftCornerHeight); + scale = Math.min(scale, height / rightCornerHeight); + + this.ulWidth = dimensions[0] * scale; + this.ulHeight = dimensions[1] * scale; + this.urWidth = dimensions[2] * scale; + this.urHeight = dimensions[3] * scale; + this.lrWidth = dimensions[4] * scale; + this.lrHeight = dimensions[5] * scale; + this.llWidth = dimensions[6] * scale; + this.llHeight = dimensions[7] * scale; + } + + @Override + public double getX() { + return x; + } + + @Override + public double getY() { + return y; + } + + @Override + public double getWidth() { + return width; + } + + @Override + public double getHeight() { + return height; + } + + @Override + public boolean isEmpty() { + return (width <= 0d) || (height <= 0d); + } + + @Override + public void setFrame(double x, double y, double w, double h) { + this.x = x; + this.y = y; + this.width = w; + this.height = h; + } + + @Override + public Rectangle2D getBounds2D() { + return new Rectangle2D.Double(x, y, width, height); + } + + @Override + public boolean contains(double x, double y) { + if (isEmpty()) { + return false; + } + + double x0 = getX(); + double y0 = getY(); + double x1 = x0 + getWidth(); + double y1 = y0 + getHeight(); + // Check for trivial rejection - point is outside bounding rectangle + if (x < x0 || y < y0 || x >= x1 || y >= y1) { + return false; + } + + double insideTopX0 = x0 + ulWidth / 2d; + double insideLeftY0 = y0 + ulHeight / 2d; + if (x < insideTopX0 && y < insideLeftY0) { + // In the upper-left corner + return isInsideCorner(x - insideTopX0, y - insideLeftY0, ulWidth / 2d, ulHeight / 2d); + } + + double insideTopX1 = x1 - urWidth / 2d; + double insideRightY0 = y0 + urHeight / 2d; + if (x > insideTopX1 && y < insideRightY0) { + // In the upper-right corner + return isInsideCorner(x - insideTopX1, y - insideRightY0, urWidth / 2d, urHeight / 2d); + } + + double insideBottomX1 = x1 - lrWidth / 2d; + double insideRightY1 = y1 - lrHeight / 2d; + if (x > insideBottomX1 && y > insideRightY1) { + // In the lower-right corner + return isInsideCorner(x - insideBottomX1, y - insideRightY1, lrWidth / 2d, lrHeight / 2d); + } + + double insideBottomX0 = x0 + llWidth / 2d; + double insideLeftY1 = y1 - llHeight / 2d; + if (x < insideBottomX0 && y > insideLeftY1) { + // In the lower-left corner + return isInsideCorner(x - insideBottomX0, y - insideLeftY1, llWidth / 2d, llHeight / 2d); + } + + // In the central part of the rectangle + return true; + } + + private boolean isInsideCorner(double x, double y, double width, double height) { + double squareDist = height * height * x * x + width * width * y * y; + return squareDist <= width * width * height * height; + } + + private Zone classify( + double coord, double side1, double arcSize1, double side2, double arcSize2) { + if (coord < side1) { + return Zone.CLOSE_OUTSIDE; + } else if (coord < side1 + arcSize1) { + return Zone.CLOSE_INSIDE; + } else if (coord < side2 - arcSize2) { + return Zone.MIDDLE; + } else if (coord < side2) { + return Zone.FAR_INSIDE; + } else { + return Zone.FAR_OUTSIDE; + } + } + + public boolean intersects(double x, double y, double w, double h) { + if (isEmpty() || w <= 0 || h <= 0) { + return false; + } + double x0 = getX(); + double y0 = getY(); + double x1 = x0 + getWidth(); + double y1 = y0 + getHeight(); + // Check for trivial rejection - bounding rectangles do not intersect + if (x + w <= x0 || x >= x1 || y + h <= y0 || y >= y1) { + return false; + } + + double maxLeftCornerWidth = Math.max(ulWidth, llWidth) / 2d; + double maxRightCornerWidth = Math.max(urWidth, lrWidth) / 2d; + double maxUpperCornerHeight = Math.max(ulHeight, urHeight) / 2d; + double maxLowerCornerHeight = Math.max(llHeight, lrHeight) / 2d; + Zone x0class = classify(x, x0, maxLeftCornerWidth, x1, maxRightCornerWidth); + Zone x1class = classify(x + w, x0, maxLeftCornerWidth, x1, maxRightCornerWidth); + Zone y0class = classify(y, y0, maxUpperCornerHeight, y1, maxLowerCornerHeight); + Zone y1class = classify(y + h, y0, maxUpperCornerHeight, y1, maxLowerCornerHeight); + + // Trivially accept if any point is inside inner rectangle + if (x0class == Zone.MIDDLE + || x1class == Zone.MIDDLE + || y0class == Zone.MIDDLE + || y1class == Zone.MIDDLE) { + return true; + } + // Trivially accept if either edge spans inner rectangle + if ((close.contains(x0class) && far.contains(x1class)) + || (close.contains(y0class) && far.contains(y1class))) { + return true; + } + + // Since neither edge spans the center, then one of the corners + // must be in one of the rounded edges. We detect this case if + // a [xy]0class is 3 or a [xy]1class is 1. One of those two cases + // must be true for each direction. + // We now find a "nearest point" to test for being inside a rounded + // corner. + if (x1class == Zone.CLOSE_INSIDE && y1class == Zone.CLOSE_INSIDE) { + // Potentially in upper-left corner + x = x + w - x0 - ulWidth / 2d; + y = y + h - y0 - ulHeight / 2d; + return x > 0 || y > 0 || isInsideCorner(x, y, ulWidth / 2d, ulHeight / 2d); + } + if (x1class == Zone.CLOSE_INSIDE) { + // Potentially in lower-left corner + x = x + w - x0 - llWidth / 2d; + y = y - y1 + llHeight / 2d; + return x > 0 || y < 0 || isInsideCorner(x, y, llWidth / 2d, llHeight / 2d); + } + if (y1class == Zone.CLOSE_INSIDE) { + // Potentially in the upper-right corner + x = x - x1 + urWidth / 2d; + y = y + h - y0 - urHeight / 2d; + return x < 0 || y > 0 || isInsideCorner(x, y, urWidth / 2d, urHeight / 2d); + } + // Potentially in the lower-right corner + x = x - x1 + lrWidth / 2d; + y = y - y1 + lrHeight / 2d; + return x < 0 || y < 0 || isInsideCorner(x, y, lrWidth / 2d, lrHeight / 2d); + } + + @Override + public boolean contains(double x, double y, double w, double h) { + if (isEmpty() || w <= 0 || h <= 0) { + return false; + } + return (contains(x, y) && contains(x + w, y) && contains(x, y + h) && contains(x + w, y + h)); + } + + @Override + public PathIterator getPathIterator(final AffineTransform at) { + return new PathIterator() { + int index; + + // ArcIterator.btan(Math.PI/2) + public static final double CtrlVal = 0.5522847498307933; + private final double ncv = 1.0 - CtrlVal; + + // Coordinates of control points for Bezier curves approximating the straight lines + // and corners of the rounded rectangle. + private final double[][] ctrlpts = { + {0.0, 0.0, 0.0, ulHeight}, + {0.0, 0.0, 1.0, -llHeight}, + {0.0, 0.0, 1.0, -llHeight * ncv, 0.0, ncv * llWidth, 1.0, 0.0, 0.0, llWidth, 1.0, 0.0}, + {1.0, -lrWidth, 1.0, 0.0}, + {1.0, -lrWidth * ncv, 1.0, 0.0, 1.0, 0.0, 1.0, -lrHeight * ncv, 1.0, 0.0, 1.0, -lrHeight}, + {1.0, 0.0, 0.0, urHeight}, + {1.0, 0.0, 0.0, ncv * urHeight, 1.0, -urWidth * ncv, 0.0, 0.0, 1.0, -urWidth, 0.0, 0.0}, + {0.0, ulWidth, 0.0, 0.0}, + {0.0, ncv * ulWidth, 0.0, 0.0, 0.0, 0.0, 0.0, ncv * ulHeight, 0.0, 0.0, 0.0, ulHeight}, + {} + }; + private final int[] types = { + SEG_MOVETO, + SEG_LINETO, + SEG_CUBICTO, + SEG_LINETO, + SEG_CUBICTO, + SEG_LINETO, + SEG_CUBICTO, + SEG_LINETO, + SEG_CUBICTO, + SEG_CLOSE, + }; + + @Override + public int getWindingRule() { + return WIND_NON_ZERO; + } + + @Override + public boolean isDone() { + return index >= ctrlpts.length; + } + + @Override + public void next() { + index++; + } + + @Override + public int currentSegment(float[] coords) { + if (isDone()) { + throw new NoSuchElementException("roundrect iterator out of bounds"); + } + int nc = 0; + double ctrls[] = ctrlpts[index]; + for (int i = 0; i < ctrls.length; i += 4) { + coords[nc++] = (float) (x + ctrls[i] * width + ctrls[i + 1] / 2d); + coords[nc++] = (float) (y + ctrls[i + 2] * height + ctrls[i + 3] / 2d); + } + if (at != null) { + at.transform(coords, 0, coords, 0, nc / 2); + } + return types[index]; + } + + @Override + public int currentSegment(double[] coords) { + if (isDone()) { + throw new NoSuchElementException("roundrect iterator out of bounds"); + } + int nc = 0; + double ctrls[] = ctrlpts[index]; + for (int i = 0; i < ctrls.length; i += 4) { + coords[nc++] = x + ctrls[i] * width + ctrls[i + 1] / 2d; + coords[nc++] = y + ctrls[i + 2] * height + ctrls[i + 3] / 2d; + } + if (at != null) { + at.transform(coords, 0, coords, 0, nc / 2); + } + return types[index]; + } + }; + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsListView.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsListView.java index 5b2d8e1b9..279448e79 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsListView.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsListView.java @@ -12,17 +12,17 @@ public class ShadowAbsListView extends ShadowAdapterView { private int lastSmoothScrollByDuration; @Implementation - public void setOnScrollListener(AbsListView.OnScrollListener l) { + protected void setOnScrollListener(AbsListView.OnScrollListener l) { onScrollListener = l; } @Implementation - public void smoothScrollToPosition(int position) { + protected void smoothScrollToPosition(int position) { smoothScrolledPosition = position; } @Implementation - public void smoothScrollBy(int distance, int duration) { + protected void smoothScrollBy(int distance, int duration) { this.lastSmoothScrollByDistance = distance; this.lastSmoothScrollByDuration = duration; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsSpinner.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsSpinner.java index ef56403ca..a87d0c383 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsSpinner.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAbsSpinner.java @@ -16,13 +16,13 @@ public class ShadowAbsSpinner extends ShadowAdapterView { private boolean animatedTransition; @Implementation - public void setSelection(int position, boolean animate) { + protected void setSelection(int position, boolean animate) { directlyOn(realAbsSpinner, AbsSpinner.class, "setSelection", ClassParameter.from(int.class, position), ClassParameter.from(boolean.class, animate)); animatedTransition = animate; } @Implementation - public void setSelection(int position) { + protected void setSelection(int position) { directlyOn(realAbsSpinner, AbsSpinner.class, "setSelection", ClassParameter.from(int.class, position)); SpinnerAdapter adapter = realAbsSpinner.getAdapter(); if (getItemSelectedListener() != null && adapter != null) { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityManager.java index 7fb6f05ac..db0136329 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityManager.java @@ -71,17 +71,19 @@ public class ShadowAccessibilityManager { } @Implementation - public boolean addAccessibilityStateChangeListener(AccessibilityManager.AccessibilityStateChangeListener listener) { + protected boolean addAccessibilityStateChangeListener( + AccessibilityManager.AccessibilityStateChangeListener listener) { return true; } @Implementation - public boolean removeAccessibilityStateChangeListener(AccessibilityManager.AccessibilityStateChangeListener listener) { + protected boolean removeAccessibilityStateChangeListener( + AccessibilityManager.AccessibilityStateChangeListener listener) { return true; } @Implementation - public List<ServiceInfo> getAccessibilityServiceList () { + protected List<ServiceInfo> getAccessibilityServiceList() { return accessibilityServiceList; } @@ -90,7 +92,8 @@ public class ShadowAccessibilityManager { } @Implementation - public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList (int feedbackTypeFlags) { + protected List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList( + int feedbackTypeFlags) { return enabledAccessibilityServiceList; } @@ -99,7 +102,7 @@ public class ShadowAccessibilityManager { } @Implementation - public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList () { + protected List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() { return installedAccessibilityServiceList; } @@ -108,7 +111,7 @@ public class ShadowAccessibilityManager { } @Implementation - public boolean isEnabled () { + protected boolean isEnabled() { return enabled; } @@ -118,7 +121,7 @@ public class ShadowAccessibilityManager { } @Implementation - public boolean isTouchExplorationEnabled () { + protected boolean isTouchExplorationEnabled() { return touchExplorationEnabled; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityNodeInfo.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityNodeInfo.java index 770481421..24ad675ad 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityNodeInfo.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityNodeInfo.java @@ -184,12 +184,12 @@ public class ShadowAccessibilityNodeInfo { private AccessibilityNodeInfo realAccessibilityNodeInfo; @Implementation - public void __constructor__() { + protected void __constructor__() { ReflectionHelpers.setStaticField(AccessibilityNodeInfo.class, "CREATOR", ShadowAccessibilityNodeInfo.CREATOR); } @Implementation - public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) { + protected static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) { final ShadowAccessibilityNodeInfo shadowInfo = Shadow.extract(info); final AccessibilityNodeInfo obtainedInstance = shadowInfo.getClone(); @@ -204,7 +204,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public static AccessibilityNodeInfo obtain(View view) { + protected static AccessibilityNodeInfo obtain(View view) { // We explicitly avoid allocating the AccessibilityNodeInfo from the actual pool by using the // private constructor. Not doing so affects test suites which use both shadow and // non-shadow objects. @@ -235,12 +235,12 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public static AccessibilityNodeInfo obtain() { + protected static AccessibilityNodeInfo obtain() { return obtain(new View(RuntimeEnvironment.application.getApplicationContext())); } @Implementation - public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) { + protected static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) { AccessibilityNodeInfo node = obtain(root); return node; } @@ -281,7 +281,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public void recycle() { + protected void recycle() { final StrictEqualityNodeWrapper wrapper = new StrictEqualityNodeWrapper(realAccessibilityNodeInfo); if (!obtainedInstances.containsKey(wrapper)) { @@ -318,7 +318,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public int getChildCount() { + protected int getChildCount() { if (children == null) { return 0; } @@ -327,7 +327,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public AccessibilityNodeInfo getChild(int index) { + protected AccessibilityNodeInfo getChild(int index) { if (children == null) { return null; } @@ -341,7 +341,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public AccessibilityNodeInfo getParent() { + protected AccessibilityNodeInfo getParent() { if (parent == null) { return null; } @@ -350,7 +350,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = JELLY_BEAN_MR2) - public boolean refresh() { + protected boolean refresh() { return refreshReturnValue; } @@ -359,32 +359,32 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public boolean isClickable() { + protected boolean isClickable() { return ((propertyFlags & CLICKABLE_MASK) != 0); } @Implementation - public boolean isLongClickable() { + protected boolean isLongClickable() { return ((propertyFlags & LONGCLICKABLE_MASK) != 0); } @Implementation - public boolean isFocusable() { + protected boolean isFocusable() { return ((propertyFlags & FOCUSABLE_MASK) != 0); } @Implementation - public boolean isFocused() { + protected boolean isFocused() { return ((propertyFlags & FOCUSED_MASK) != 0); } @Implementation - public boolean isVisibleToUser() { + protected boolean isVisibleToUser() { return ((propertyFlags & VISIBLE_TO_USER_MASK) != 0); } @Implementation - public boolean isScrollable() { + protected boolean isScrollable() { return ((propertyFlags & SCROLLABLE_MASK) != 0); } @@ -393,7 +393,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = JELLY_BEAN_MR2) - public boolean isEditable() { + protected boolean isEditable() { return ((propertyFlags & EDITABLE_MASK) != 0); } @@ -402,112 +402,112 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public boolean isCheckable() { + protected boolean isCheckable() { return ((propertyFlags & CHECKABLE_MASK) != 0); } @Implementation - public void setCheckable(boolean checkable) { + protected void setCheckable(boolean checkable) { propertyFlags = (propertyFlags & ~CHECKABLE_MASK) | (checkable ? CHECKABLE_MASK : 0); } @Implementation - public void setChecked(boolean checked) { + protected void setChecked(boolean checked) { propertyFlags = (propertyFlags & ~CHECKED_MASK) | (checked ? CHECKED_MASK : 0); } @Implementation - public boolean isChecked() { + protected boolean isChecked() { return ((propertyFlags & CHECKED_MASK) != 0); } @Implementation - public void setEnabled(boolean enabled) { + protected void setEnabled(boolean enabled) { propertyFlags = (propertyFlags & ~ENABLED_MASK) | (enabled ? ENABLED_MASK : 0); } @Implementation - public boolean isEnabled() { + protected boolean isEnabled() { return ((propertyFlags & ENABLED_MASK) != 0); } @Implementation - public void setPassword(boolean password) { + protected void setPassword(boolean password) { propertyFlags = (propertyFlags & ~PASSWORD_MASK) | (password ? PASSWORD_MASK : 0); } @Implementation - public boolean isPassword() { + protected boolean isPassword() { return ((propertyFlags & PASSWORD_MASK) != 0); } @Implementation - public void setSelected(boolean selected) { + protected void setSelected(boolean selected) { propertyFlags = (propertyFlags & ~SELECTED_MASK) | (selected ? SELECTED_MASK : 0); } @Implementation - public boolean isSelected() { + protected boolean isSelected() { return ((propertyFlags & SELECTED_MASK) != 0); } @Implementation - public void setAccessibilityFocused(boolean focused) { + protected void setAccessibilityFocused(boolean focused) { propertyFlags = (propertyFlags & ~A11YFOCUSED_MASK) | (focused ? A11YFOCUSED_MASK : 0); } @Implementation - public boolean isAccessibilityFocused() { + protected boolean isAccessibilityFocused() { return ((propertyFlags & A11YFOCUSED_MASK) != 0); } @Implementation(minSdk = LOLLIPOP) - public void setMultiLine(boolean multiLine) { + protected void setMultiLine(boolean multiLine) { propertyFlags = (propertyFlags & ~MULTILINE_MASK) | (multiLine ? MULTILINE_MASK : 0); } @Implementation(minSdk = LOLLIPOP) - public boolean isMultiLine() { + protected boolean isMultiLine() { return ((propertyFlags & MULTILINE_MASK) != 0); } @Implementation(minSdk = LOLLIPOP) - public void setContentInvalid(boolean contentInvalid) { + protected void setContentInvalid(boolean contentInvalid) { propertyFlags = (propertyFlags & ~CONTENT_INVALID_MASK) | (contentInvalid ? CONTENT_INVALID_MASK : 0); } @Implementation(minSdk = LOLLIPOP) - public boolean isContentInvalid() { + protected boolean isContentInvalid() { return ((propertyFlags & CONTENT_INVALID_MASK) != 0); } @Implementation(minSdk = LOLLIPOP) - public void setDismissable(boolean dismissable) { + protected void setDismissable(boolean dismissable) { propertyFlags = (propertyFlags & ~DISMISSABLE_MASK) | (dismissable ? DISMISSABLE_MASK : 0); } @Implementation(minSdk = LOLLIPOP) - public boolean isDismissable() { + protected boolean isDismissable() { return ((propertyFlags & DISMISSABLE_MASK) != 0); } @Implementation(minSdk = LOLLIPOP) - public void setCanOpenPopup(boolean opensPopup) { + protected void setCanOpenPopup(boolean opensPopup) { propertyFlags = (propertyFlags & ~CAN_OPEN_POPUP_MASK) | (opensPopup ? CAN_OPEN_POPUP_MASK : 0); } @Implementation(minSdk = LOLLIPOP) - public boolean canOpenPopup() { + protected boolean canOpenPopup() { return ((propertyFlags & CAN_OPEN_POPUP_MASK) != 0); } @@ -517,28 +517,28 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public void setClickable(boolean isClickable) { + protected void setClickable(boolean isClickable) { propertyFlags = (propertyFlags & ~CLICKABLE_MASK) | (isClickable ? CLICKABLE_MASK : 0); } @Implementation - public void setLongClickable(boolean isLongClickable) { + protected void setLongClickable(boolean isLongClickable) { propertyFlags = (propertyFlags & ~LONGCLICKABLE_MASK) | (isLongClickable ? LONGCLICKABLE_MASK : 0); } @Implementation - public void setFocusable(boolean isFocusable) { + protected void setFocusable(boolean isFocusable) { propertyFlags = (propertyFlags & ~FOCUSABLE_MASK) | (isFocusable ? FOCUSABLE_MASK : 0); } @Implementation - public void setFocused(boolean isFocused) { + protected void setFocused(boolean isFocused) { propertyFlags = (propertyFlags & ~FOCUSED_MASK) | (isFocused ? FOCUSED_MASK : 0); } @Implementation - public void setScrollable(boolean isScrollable) { + protected void setScrollable(boolean isScrollable) { propertyFlags = (propertyFlags & ~SCROLLABLE_MASK) | (isScrollable ? SCROLLABLE_MASK : 0); } @@ -547,48 +547,48 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = JELLY_BEAN_MR2) - public void setEditable(boolean isEditable) { + protected void setEditable(boolean isEditable) { propertyFlags = (propertyFlags & ~EDITABLE_MASK) | (isEditable ? EDITABLE_MASK : 0); } @Implementation - public void setVisibleToUser(boolean isVisibleToUser) { + protected void setVisibleToUser(boolean isVisibleToUser) { propertyFlags = (propertyFlags & ~VISIBLE_TO_USER_MASK) | (isVisibleToUser ? VISIBLE_TO_USER_MASK : 0); } @Implementation - public void setContentDescription(CharSequence description) { + protected void setContentDescription(CharSequence description) { contentDescription = description; } @Implementation - public CharSequence getContentDescription() { + protected CharSequence getContentDescription() { return contentDescription; } @Implementation - public void setClassName(CharSequence name) { + protected void setClassName(CharSequence name) { className = name; } @Implementation - public CharSequence getClassName() { + protected CharSequence getClassName() { return className; } @Implementation - public void setText(CharSequence t) { + protected void setText(CharSequence t) { text = t; } @Implementation - public CharSequence getText() { + protected CharSequence getText() { return text; } @Implementation(minSdk = JELLY_BEAN_MR2) - public void setTextSelection(int start, int end) { + protected void setTextSelection(int start, int end) { textSelectionStart = start; textSelectionEnd = end; } @@ -599,7 +599,7 @@ public class ShadowAccessibilityNodeInfo { * @return The text selection start if there is selection or UNDEFINED_SELECTION_INDEX. */ @Implementation(minSdk = JELLY_BEAN_MR2) - public int getTextSelectionStart() { + protected int getTextSelectionStart() { return textSelectionStart; } @@ -609,12 +609,12 @@ public class ShadowAccessibilityNodeInfo { * @return The text selection end if there is selection or UNDEFINED_SELECTION_INDEX. */ @Implementation(minSdk = JELLY_BEAN_MR2) - public int getTextSelectionEnd() { + protected int getTextSelectionEnd() { return textSelectionEnd; } @Implementation(minSdk = JELLY_BEAN_MR2) - public AccessibilityNodeInfo getLabelFor() { + protected AccessibilityNodeInfo getLabelFor() { if (labelFor == null) { return null; } @@ -631,7 +631,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = JELLY_BEAN_MR1) - public AccessibilityNodeInfo getLabeledBy() { + protected AccessibilityNodeInfo getLabeledBy() { if (labeledBy == null) { return null; } @@ -648,107 +648,107 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public int getMovementGranularities() { + protected int getMovementGranularities() { return movementGranularities; } @Implementation - public void setMovementGranularities(int movementGranularities) { + protected void setMovementGranularities(int movementGranularities) { this.movementGranularities = movementGranularities; } @Implementation - public CharSequence getPackageName() { + protected CharSequence getPackageName() { return packageName; } @Implementation - public void setPackageName(CharSequence packageName) { + protected void setPackageName(CharSequence packageName) { this.packageName = packageName; } @Implementation(minSdk = JELLY_BEAN_MR2) - public String getViewIdResourceName() { + protected String getViewIdResourceName() { return viewIdResourceName; } @Implementation(minSdk = JELLY_BEAN_MR2) - public void setViewIdResourceName(String viewIdResourceName) { + protected void setViewIdResourceName(String viewIdResourceName) { this.viewIdResourceName = viewIdResourceName; } @Implementation(minSdk = KITKAT) - public CollectionInfo getCollectionInfo() { + protected CollectionInfo getCollectionInfo() { return collectionInfo; } @Implementation(minSdk = KITKAT) - public void setCollectionInfo(CollectionInfo collectionInfo) { + protected void setCollectionInfo(CollectionInfo collectionInfo) { this.collectionInfo = collectionInfo; } @Implementation(minSdk = KITKAT) - public CollectionItemInfo getCollectionItemInfo() { + protected CollectionItemInfo getCollectionItemInfo() { return collectionItemInfo; } @Implementation(minSdk = KITKAT) - public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) { + protected void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) { this.collectionItemInfo = collectionItemInfo; } @Implementation(minSdk = KITKAT) - public int getInputType() { + protected int getInputType() { return inputType; } @Implementation(minSdk = KITKAT) - public void setInputType(int inputType) { + protected void setInputType(int inputType) { this.inputType = inputType; } @Implementation(minSdk = KITKAT) - public int getLiveRegion() { + protected int getLiveRegion() { return liveRegion; } @Implementation(minSdk = KITKAT) - public void setLiveRegion(int liveRegion) { + protected void setLiveRegion(int liveRegion) { this.liveRegion = liveRegion; } @Implementation(minSdk = KITKAT) - public RangeInfo getRangeInfo() { + protected RangeInfo getRangeInfo() { return rangeInfo; } @Implementation(minSdk = KITKAT) - public void setRangeInfo(RangeInfo rangeInfo) { + protected void setRangeInfo(RangeInfo rangeInfo) { this.rangeInfo = rangeInfo; } @Implementation(minSdk = LOLLIPOP) - public int getMaxTextLength() { + protected int getMaxTextLength() { return maxTextLength; } @Implementation(minSdk = LOLLIPOP) - public void setMaxTextLength(int maxTextLength) { + protected void setMaxTextLength(int maxTextLength) { this.maxTextLength = maxTextLength; } @Implementation(minSdk = LOLLIPOP) - public CharSequence getError() { + protected CharSequence getError() { return error; } @Implementation(minSdk = LOLLIPOP) - public void setError(CharSequence error) { + protected void setError(CharSequence error) { this.error = error; } @Implementation(minSdk = LOLLIPOP_MR1) - public AccessibilityNodeInfo getTraversalAfter() { + protected AccessibilityNodeInfo getTraversalAfter() { if (traversalAfter == null) { return null; } @@ -783,7 +783,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = LOLLIPOP_MR1) - public AccessibilityNodeInfo getTraversalBefore() { + protected AccessibilityNodeInfo getTraversalBefore() { if (traversalBefore == null) { return null; } @@ -818,17 +818,17 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public void setSource (View source) { + protected void setSource(View source) { this.view = source; } @Implementation - public void setSource (View root, int virtualDescendantId) { + protected void setSource(View root, int virtualDescendantId) { this.view = root; } @Implementation - public void getBoundsInScreen(Rect outBounds) { + protected void getBoundsInScreen(Rect outBounds) { if (boundsInScreen == null) { boundsInScreen = new Rect(); } @@ -836,7 +836,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public void getBoundsInParent(Rect outBounds) { + protected void getBoundsInParent(Rect outBounds) { if (boundsInParent == null) { boundsInParent = new Rect(); } @@ -844,7 +844,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public void setBoundsInScreen(Rect b) { + protected void setBoundsInScreen(Rect b) { if (boundsInScreen == null) { boundsInScreen = new Rect(b); } else { @@ -853,7 +853,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public void setBoundsInParent(Rect b) { + protected void setBoundsInParent(Rect b) { if (boundsInParent == null) { boundsInParent = new Rect(b); } else { @@ -862,7 +862,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public void addAction(int action) { + protected void addAction(int action) { if (getApiLevel() >= LOLLIPOP) { if ((action & getActionTypeMaskFromFramework()) != 0) { throw new IllegalArgumentException("Action is not a combination of the standard " + @@ -881,7 +881,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = LOLLIPOP) - public void addAction(AccessibilityAction action) { + protected void addAction(AccessibilityAction action) { if (action == null) { return; } @@ -894,13 +894,13 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = LOLLIPOP) - public void removeAction(int action) { + protected void removeAction(int action) { AccessibilityAction convertedAction = getActionFromIdFromFrameWork(action); removeAction(convertedAction); } @Implementation(minSdk = LOLLIPOP) - public boolean removeAction(AccessibilityAction action) { + protected boolean removeAction(AccessibilityAction action) { if (action == null || actionsArray == null) { return false; } @@ -908,20 +908,17 @@ public class ShadowAccessibilityNodeInfo { } /** - * Obtain flags for actions supported. Currently only supports - * {@link AccessibilityNodeInfo#ACTION_CLICK}, - * {@link AccessibilityNodeInfo#ACTION_LONG_CLICK}, - * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD}, - * {@link AccessibilityNodeInfo#ACTION_PASTE}, - * {@link AccessibilityNodeInfo#ACTION_FOCUS}, - * {@link AccessibilityNodeInfo#ACTION_SET_SELECTION}, - * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} - * Returned value is derived from the getters. + * Obtain flags for actions supported. Currently only supports {@link + * AccessibilityNodeInfo#ACTION_CLICK}, {@link AccessibilityNodeInfo#ACTION_LONG_CLICK}, {@link + * AccessibilityNodeInfo#ACTION_SCROLL_FORWARD}, {@link AccessibilityNodeInfo#ACTION_PASTE}, + * {@link AccessibilityNodeInfo#ACTION_FOCUS}, {@link AccessibilityNodeInfo#ACTION_SET_SELECTION}, + * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} Returned value is derived from the + * getters. * * @return Action mask. 0 if no actions supported. */ @Implementation - public int getActions() { + protected int getActions() { if (getApiLevel() >= LOLLIPOP) { int returnValue = 0; if (actionsArray == null) { @@ -955,7 +952,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = LOLLIPOP) - public AccessibilityWindowInfo getWindow() { + protected AccessibilityWindowInfo getWindow() { return accessibilityWindowInfo; } @@ -970,7 +967,7 @@ public class ShadowAccessibilityNodeInfo { } @Implementation(minSdk = LOLLIPOP) - public List<AccessibilityAction> getActionList() { + protected List<AccessibilityAction> getActionList() { if (actionsArray == null) { return Collections.emptyList(); } @@ -979,12 +976,12 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public boolean performAction(int action) { + protected boolean performAction(int action) { return performAction(action, null); } @Implementation - public boolean performAction(int action, Bundle arguments) { + protected boolean performAction(int action, Bundle arguments) { if (performedActionAndArgsList == null) { performedActionAndArgsList = new ArrayList<>(); } @@ -1043,13 +1040,13 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public void addChild(View child) { + protected void addChild(View child) { AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(child); addChild(node); } @Implementation - public void addChild(View root, int virtualDescendantId) { + protected void addChild(View root, int virtualDescendantId) { AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(root, virtualDescendantId); addChild(node); } @@ -1194,7 +1191,7 @@ public class ShadowAccessibilityNodeInfo { private CharSequence label; @Implementation - public void __constructor__(int id, CharSequence label) { + protected void __constructor__(int id, CharSequence label) { if (((id & (int)ReflectionHelpers.getStaticField(AccessibilityNodeInfo.class, "ACTION_TYPE_MASK")) == 0) && Integer.bitCount(id) != 1) { throw new IllegalArgumentException("Invalid standard action id"); } @@ -1203,12 +1200,12 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public int getId() { + protected int getId() { return id; } @Implementation - public CharSequence getLabel() { + protected CharSequence getLabel() { return label; } @@ -1240,12 +1237,12 @@ public class ShadowAccessibilityNodeInfo { } @Implementation - public int describeContents() { + protected int describeContents() { return 0; } @Implementation - public void writeToParcel(Parcel dest, int flags) { + protected void writeToParcel(Parcel dest, int flags) { StrictEqualityNodeWrapper wrapper = new StrictEqualityNodeWrapper(realAccessibilityNodeInfo); int keyOfWrapper = -1; for (int i = 0; i < orderedInstances.size(); i++) { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityRecord.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityRecord.java index 11539a2be..1f7f1059c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityRecord.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityRecord.java @@ -25,7 +25,7 @@ public class ShadowAccessibilityRecord { private int windowId = -1; @Implementation - public void setSource(View root, int virtualDescendantId) { + protected void setSource(View root, int virtualDescendantId) { this.sourceRoot = root; this.virtualDescendantId = virtualDescendantId; Shadow.directlyOn(realRecord, AccessibilityRecord.class, "setSource", @@ -34,7 +34,7 @@ public class ShadowAccessibilityRecord { } @Implementation - public void setSource(View root) { + protected void setSource(View root) { this.sourceRoot = root; this.virtualDescendantId = NO_VIRTUAL_ID; Shadow.directlyOn(realRecord, AccessibilityRecord.class, "setSource", diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityService.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityService.java index 489c2f923..697a1e7e3 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityService.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityService.java @@ -14,8 +14,8 @@ public class ShadowAccessibilityService extends ShadowService { private final List<Integer> globalActionsPerformed = new ArrayList<>(); - @Implementation - public final boolean performGlobalAction(int action) { + @Implementation + protected final boolean performGlobalAction(int action) { globalActionsPerformed.add(action); return true; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityWindowInfo.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityWindowInfo.java index 8de6695e8..ea5584847 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityWindowInfo.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccessibilityWindowInfo.java @@ -52,10 +52,10 @@ public class ShadowAccessibilityWindowInfo { private AccessibilityWindowInfo mRealAccessibilityWindowInfo; @Implementation - public void __constructor__() {} + protected void __constructor__() {} @Implementation - public static AccessibilityWindowInfo obtain() { + protected static AccessibilityWindowInfo obtain() { final AccessibilityWindowInfo obtainedInstance = ReflectionHelpers.callConstructor(AccessibilityWindowInfo.class); StrictEqualityWindowWrapper wrapper = new StrictEqualityWindowWrapper(obtainedInstance); @@ -64,7 +64,7 @@ public class ShadowAccessibilityWindowInfo { } @Implementation - public static AccessibilityWindowInfo obtain(AccessibilityWindowInfo window) { + protected static AccessibilityWindowInfo obtain(AccessibilityWindowInfo window) { final ShadowAccessibilityWindowInfo shadowInfo = Shadow.extract(window); final AccessibilityWindowInfo obtainedInstance = shadowInfo.getClone(); StrictEqualityWindowWrapper wrapper = new StrictEqualityWindowWrapper(obtainedInstance); @@ -160,12 +160,12 @@ public class ShadowAccessibilityWindowInfo { } @Implementation - public int getType() { + protected int getType() { return type; } @Implementation - public int getChildCount() { + protected int getChildCount() { if (children == null) { return 0; } @@ -174,7 +174,7 @@ public class ShadowAccessibilityWindowInfo { } @Implementation - public AccessibilityWindowInfo getChild(int index) { + protected AccessibilityWindowInfo getChild(int index) { if (children == null) { return null; } @@ -183,27 +183,27 @@ public class ShadowAccessibilityWindowInfo { } @Implementation - public AccessibilityWindowInfo getParent() { + protected AccessibilityWindowInfo getParent() { return parent; } @Implementation - public AccessibilityNodeInfo getRoot() { + protected AccessibilityNodeInfo getRoot() { return (rootNode == null) ? null : AccessibilityNodeInfo.obtain(rootNode); } @Implementation - public boolean isActive() { + protected boolean isActive() { return isActive; } @Implementation - public int getId() { + protected int getId() { return id; } @Implementation - public void getBoundsInScreen(Rect outBounds) { + protected void getBoundsInScreen(Rect outBounds) { if (boundsInScreen == null) { outBounds.setEmpty(); } else { @@ -212,7 +212,7 @@ public class ShadowAccessibilityWindowInfo { } @Implementation - public int getLayer() { + protected int getLayer() { return layer; } @@ -223,17 +223,17 @@ public class ShadowAccessibilityWindowInfo { } @Implementation - public boolean isFocused() { + protected boolean isFocused() { return isFocused; } @Implementation - public boolean isAccessibilityFocused() { + protected boolean isAccessibilityFocused() { return isAccessibilityFocused; } @Implementation - public void recycle() { + protected void recycle() { // This shadow does not track recycling of windows. } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccountManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccountManager.java index 421307573..fa8b3b083 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccountManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAccountManager.java @@ -53,26 +53,27 @@ public class ShadowAccountManager { private boolean authenticationErrorOnNextResponse = false; @Implementation - public void __constructor__(Context context, IAccountManager service) { + protected void __constructor__(Context context, IAccountManager service) { mainHandler = new Handler(context.getMainLooper()); } /** - * @deprecated This method will be removed in Robolectric 3.4 Use {@link AccountManager#get(Context)} instead. + * @deprecated This method will be removed in Robolectric 3.4 Use {@link + * AccountManager#get(Context)} instead. */ @Deprecated @Implementation - public static AccountManager get(Context context) { + protected static AccountManager get(Context context) { return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); } @Implementation - public Account[] getAccounts() { + protected Account[] getAccounts() { return accounts.toArray(new Account[accounts.size()]); } @Implementation - public Account[] getAccountsByType(String type) { + protected Account[] getAccountsByType(String type) { if (type == null) { return getAccounts(); } @@ -88,7 +89,7 @@ public class ShadowAccountManager { } @Implementation - public synchronized void setAuthToken(Account account, String tokenType, String authToken) { + protected synchronized void setAuthToken(Account account, String tokenType, String authToken) { if(accounts.contains(account)) { Map<String, String> tokenMap = authTokens.get(account); if(tokenMap == null) { @@ -100,7 +101,7 @@ public class ShadowAccountManager { } @Implementation - public String peekAuthToken(Account account, String tokenType) { + protected String peekAuthToken(Account account, String tokenType) { Map<String, String> tokenMap = authTokens.get(account); if(tokenMap != null) { return tokenMap.get(tokenType); @@ -109,7 +110,7 @@ public class ShadowAccountManager { } @Implementation - public boolean addAccountExplicitly(Account account, String password, Bundle userdata) { + protected boolean addAccountExplicitly(Account account, String password, Bundle userdata) { if (account == null) { throw new IllegalArgumentException("account is null"); } @@ -137,8 +138,8 @@ public class ShadowAccountManager { } @Implementation - public String blockingGetAuthToken(Account account, String authTokenType, - boolean notifyAuthFailure) { + protected String blockingGetAuthToken( + Account account, String authTokenType, boolean notifyAuthFailure) { if (account == null) { throw new IllegalArgumentException("account is null"); } @@ -154,13 +155,12 @@ public class ShadowAccountManager { } /** - * The remove operation is posted to the given {@code handler}, and will be - * executed according to the {@link IdleState} of the corresponding {@link org.robolectric.util.Scheduler}. + * The remove operation is posted to the given {@code handler}, and will be executed according to + * the {@link IdleState} of the corresponding {@link org.robolectric.util.Scheduler}. */ @Implementation - public AccountManagerFuture<Boolean> removeAccount(final Account account, - AccountManagerCallback<Boolean> callback, - Handler handler) { + protected AccountManagerFuture<Boolean> removeAccount( + final Account account, AccountManagerCallback<Boolean> callback, Handler handler) { if (account == null) { throw new IllegalArgumentException("account is null"); } @@ -176,7 +176,7 @@ public class ShadowAccountManager { } @Implementation(minSdk = LOLLIPOP_MR1) - public boolean removeAccountExplicitly(Account account) { + protected boolean removeAccountExplicitly(Account account) { passwords.remove(account); userData.remove(account); if (accounts.remove(account)) { @@ -196,13 +196,13 @@ public class ShadowAccountManager { } @Implementation - public AuthenticatorDescription[] getAuthenticatorTypes() { + protected AuthenticatorDescription[] getAuthenticatorTypes() { return authenticators.values().toArray(new AuthenticatorDescription[authenticators.size()]); } @Implementation - public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener, - Handler handler, boolean updateImmediately) { + protected void addOnAccountsUpdatedListener( + final OnAccountsUpdateListener listener, Handler handler, boolean updateImmediately) { if (listeners.contains(listener)) { return; @@ -216,12 +216,12 @@ public class ShadowAccountManager { } @Implementation - public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) { + protected void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) { listeners.remove(listener); } @Implementation - public String getUserData(Account account, String key) { + protected String getUserData(Account account, String key) { if (account == null) { throw new IllegalArgumentException("account is null"); } @@ -239,7 +239,7 @@ public class ShadowAccountManager { } @Implementation - public void setUserData(Account account, String key, String value) { + protected void setUserData(Account account, String key, String value) { if (account == null) { throw new IllegalArgumentException("account is null"); } @@ -258,7 +258,7 @@ public class ShadowAccountManager { } @Implementation - public void setPassword (Account account, String password) { + protected void setPassword(Account account, String password) { if (account == null) { throw new IllegalArgumentException("account is null"); } @@ -271,7 +271,7 @@ public class ShadowAccountManager { } @Implementation - public String getPassword (Account account) { + protected String getPassword(Account account) { if (account == null) { throw new IllegalArgumentException("account is null"); } @@ -284,7 +284,7 @@ public class ShadowAccountManager { } @Implementation - public void invalidateAuthToken(final String accountType, final String authToken) { + protected void invalidateAuthToken(final String accountType, final String authToken) { Account[] accountsByType = getAccountsByType(accountType); for (Account account : accountsByType) { Map<String, String> tokenMap = authTokens.get(account); @@ -396,7 +396,14 @@ public class ShadowAccountManager { } @Implementation - public AccountManagerFuture<Bundle> addAccount(final String accountType, String authTokenType, String[] requiredFeatures, Bundle addAccountOptions, Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { + protected AccountManagerFuture<Bundle> addAccount( + final String accountType, + String authTokenType, + String[] requiredFeatures, + Bundle addAccountOptions, + Activity activity, + AccountManagerCallback<Bundle> callback, + Handler handler) { addAccountOptionsList.add(addAccountOptions); pendingAddFuture = new RoboAccountManagerFuture(callback, handler, accountType, activity); return pendingAddFuture; @@ -431,37 +438,33 @@ public class ShadowAccountManager { previousNames.put(account, previousName); } - /** - * @see #setPreviousAccountName(Account, String) - */ + /** @see #setPreviousAccountName(Account, String) */ @Implementation(minSdk = LOLLIPOP) - public String getPreviousName(Account account) { + protected String getPreviousName(Account account) { return previousNames.get(account); } @Implementation - public AccountManagerFuture<Bundle> getAuthToken( - final Account account, final String authTokenType, final Bundle options, - final Activity activity, final AccountManagerCallback<Bundle> callback, Handler handler) { + protected AccountManagerFuture<Bundle> getAuthToken( + final Account account, + final String authTokenType, + final Bundle options, + final Activity activity, + final AccountManagerCallback<Bundle> callback, + Handler handler) { return start( new BaseRoboAccountManagerFuture<Bundle>(callback, handler) { @Override public Bundle doWork() throws OperationCanceledException, IOException, AuthenticatorException { - Bundle result = new Bundle(); - - String authToken = blockingGetAuthToken(account, authTokenType, false); - result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); - result.putString(AccountManager.KEY_AUTHTOKEN, authToken); - return result; + return getAuthToken(account, authTokenType); } }); } @Implementation - public AccountManagerFuture<Bundle> getAuthToken( + protected AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final Bundle options, @@ -471,22 +474,42 @@ public class ShadowAccountManager { return start(new BaseRoboAccountManagerFuture<Bundle>(callback, handler) { @Override - public Bundle doWork() throws OperationCanceledException, IOException, AuthenticatorException { - Bundle result = new Bundle(); - - String authToken = blockingGetAuthToken(account, authTokenType, false); - result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); - result.putString(AccountManager.KEY_AUTHTOKEN, authToken); - return result; + public Bundle doWork() + throws OperationCanceledException, IOException, AuthenticatorException { + return getAuthToken(account, authTokenType); } }); } + private Bundle getAuthToken(Account account, String authTokenType) + throws OperationCanceledException, IOException, AuthenticatorException { + Bundle result = new Bundle(); + + String authToken = blockingGetAuthToken(account, authTokenType, false); + result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); + result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); + result.putString(AccountManager.KEY_AUTHTOKEN, authToken); + + if (authToken != null) { + return result; + } + + if (!authenticators.containsKey(account.type)) { + throw new AuthenticatorException("No authenticator specified for " + account.type); + } + + Intent resultIntent = new Intent(); + result.putParcelable(AccountManager.KEY_INTENT, resultIntent); + + return result; + } + @Implementation - public AccountManagerFuture<Boolean> hasFeatures(final Account account, + protected AccountManagerFuture<Boolean> hasFeatures( + final Account account, final String[] features, - AccountManagerCallback<Boolean> callback, Handler handler) { + AccountManagerCallback<Boolean> callback, + Handler handler) { return start(new BaseRoboAccountManagerFuture<Boolean>(callback, handler) { @Override public Boolean doWork() throws OperationCanceledException, IOException, AuthenticatorException { @@ -502,9 +525,11 @@ public class ShadowAccountManager { } @Implementation - public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures( - final String type, final String[] features, - AccountManagerCallback<Account[]> callback, Handler handler) { + protected AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures( + final String type, + final String[] features, + AccountManagerCallback<Account[]> callback, + Handler handler) { return start( new BaseRoboAccountManagerFuture<Account[]>(callback, handler) { @Override @@ -536,7 +561,7 @@ public class ShadowAccountManager { } @Implementation(minSdk = JELLY_BEAN_MR2) - public Account[] getAccountsByTypeForPackage (String type, String packageName) { + protected Account[] getAccountsByTypeForPackage(String type, String packageName) { List<Account> result = new ArrayList<>(); Account[] accountsByType = getAccountsByType(type); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java index bf0c63109..3ca91c8b1 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivity.java @@ -231,12 +231,12 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public ComponentName getCallingActivity() { + protected ComponentName getCallingActivity() { return callingActivity; } @Implementation - public void setDefaultKeyMode(int keyMode) { + protected void setDefaultKeyMode(int keyMode) { mDefaultKeyMode = keyMode; // Some modes use a SpannableStringBuilder to track & dispatch input events @@ -262,23 +262,23 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public final void setResult(int resultCode) { + protected final void setResult(int resultCode) { this.resultCode = resultCode; } @Implementation - public final void setResult(int resultCode, Intent data) { + protected final void setResult(int resultCode, Intent data) { this.resultCode = resultCode; this.resultIntent = data; } @Implementation - public LayoutInflater getLayoutInflater() { + protected LayoutInflater getLayoutInflater() { return LayoutInflater.from(realActivity); } @Implementation - public MenuInflater getMenuInflater() { + protected MenuInflater getMenuInflater() { return new MenuInflater(realActivity); } @@ -290,12 +290,12 @@ public class ShadowActivity extends ShadowContextThemeWrapper { * @throws RuntimeException if the {@code contentView} has not been called first */ @Implementation - public View findViewById(int id) { + protected View findViewById(int id) { return getWindow().findViewById(id); } @Implementation - public final Activity getParent() { + protected final Activity getParent() { return parent; } @@ -310,24 +310,24 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public void onBackPressed() { + protected void onBackPressed() { finish(); } @Implementation - public void finish() { + protected void finish() { // Sets the mFinished field in the real activity so NoDisplay activities can be tested. ReflectionHelpers.setField(Activity.class, realActivity, "mFinished", true); } @Implementation(minSdk = LOLLIPOP) - public void finishAndRemoveTask() { + protected void finishAndRemoveTask() { // Sets the mFinished field in the real activity so NoDisplay activities can be tested. ReflectionHelpers.setField(Activity.class, realActivity, "mFinished", true); } @Implementation(minSdk = JELLY_BEAN) - public void finishAffinity() { + protected void finishAffinity() { // Sets the mFinished field in the real activity so NoDisplay activities can be tested. ReflectionHelpers.setField(Activity.class, realActivity, "mFinished", true); } @@ -347,13 +347,13 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } /** - * Constructs a new Window (a {@link com.android.internal.policy.impl.PhoneWindow}) if no window has previously been - * set. + * Constructs a new Window (a {@link com.android.internal.policy.impl.PhoneWindow}) if no window + * has previously been set. * * @return the window associated with this Activity */ @Implementation - public Window getWindow() { + protected Window getWindow() { Window window = directlyOn(realActivity, Activity.class).getWindow(); if (window == null) { @@ -373,12 +373,12 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public void runOnUiThread(Runnable action) { + protected void runOnUiThread(Runnable action) { ShadowApplication.getInstance().getForegroundThreadScheduler().post(action); } @Implementation - public void setRequestedOrientation(int requestedOrientation) { + protected void setRequestedOrientation(int requestedOrientation) { if (getParent() != null) { getParent().setRequestedOrientation(requestedOrientation); } else { @@ -387,7 +387,7 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public int getRequestedOrientation() { + protected int getRequestedOrientation() { if (getParent() != null) { return getParent().getRequestedOrientation(); } else { @@ -396,7 +396,7 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public int getTaskId() { + protected int getTaskId() { return 0; } @@ -448,7 +448,7 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public Object getLastNonConfigurationInstance() { + protected Object getLastNonConfigurationInstance() { return lastNonConfigurationInstance; } @@ -464,7 +464,7 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public View getCurrentFocus() { + protected View getCurrentFocus() { return currentFocus; } @@ -477,7 +477,7 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public boolean onCreateOptionsMenu(Menu menu) { + protected boolean onCreateOptionsMenu(Menu menu) { optionsMenu = menu; return directlyOn(realActivity, Activity.class).onCreateOptionsMenu(menu); } @@ -498,12 +498,6 @@ public class ShadowActivity extends ShadowContextThemeWrapper { * @return True if the click was handled, false otherwise. */ public boolean clickMenuItem(int menuItemResId) { - if (optionsMenu == null) { - throw new RuntimeException( - "Activity does not have an options menu! Did you forget to call " + - "super.onCreateOptionsMenu(menu) in " + realActivity.getClass().getName() + "?"); - } - final RoboMenuItem item = new RoboMenuItem(menuItemResId); return realActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item); } @@ -541,12 +535,12 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public final void showDialog(int id) { + protected final void showDialog(int id) { showDialog(id, null); } @Implementation - public final void dismissDialog(int id) { + protected final void dismissDialog(int id) { final Dialog dialog = dialogForId.get(id); if (dialog == null) { throw new IllegalArgumentException(); @@ -556,12 +550,12 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public final void removeDialog(int id) { + protected final void removeDialog(int id) { dialogForId.remove(id); } @Implementation - public final boolean showDialog(int id, Bundle bundle) { + protected final boolean showDialog(int id, Bundle bundle) { this.lastShownDialogId = id; Dialog dialog = dialogForId.get(id); @@ -589,7 +583,7 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public final boolean isTaskRoot() { + protected final boolean isTaskRoot() { return mIsTaskRoot; } @@ -606,7 +600,7 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public void overridePendingTransition(int enterAnim, int exitAnim) { + protected void overridePendingTransition(int enterAnim, int exitAnim) { pendingTransitionEnterAnimResId = enterAnim; pendingTransitionExitAnimResId = exitAnim; } @@ -616,7 +610,7 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public void recreate() { + protected void recreate() { Bundle outState = new Bundle(); final ActivityInvoker invoker = new ActivityInvoker(); @@ -635,12 +629,12 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public void startManagingCursor(Cursor c) { + protected void startManagingCursor(Cursor c) { managedCursors.add(c); } @Implementation - public void stopManagingCursor(Cursor c) { + protected void stopManagingCursor(Cursor c) { managedCursors.remove(c); } @@ -649,19 +643,17 @@ public class ShadowActivity extends ShadowContextThemeWrapper { } @Implementation - public final void setVolumeControlStream(int streamType) { + protected final void setVolumeControlStream(int streamType) { this.streamType = streamType; } @Implementation - public final int getVolumeControlStream() { + protected final int getVolumeControlStream() { return streamType; } - @Implementation(minSdk = M) - public final void requestPermissions(String[] permissions, int requestCode) { - } + protected final void requestPermissions(String[] permissions, int requestCode) {} /** * Starts a lock task. diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityGroup.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityGroup.java index 0e47b1331..49ef26d15 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityGroup.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityGroup.java @@ -10,7 +10,7 @@ public class ShadowActivityGroup extends ShadowActivity { private Activity currentActivity; @Implementation - public android.app.Activity getCurrentActivity() { + protected android.app.Activity getCurrentActivity() { return currentActivity; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityManager.java index 75df60bb5..7a0163f81 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityManager.java @@ -42,17 +42,17 @@ public class ShadowActivityManager { } @Implementation - public int getMemoryClass() { + protected int getMemoryClass() { return memoryClass; } @Implementation - public static boolean isUserAMonkey() { + protected static boolean isUserAMonkey() { return false; } @Implementation - public List<ActivityManager.RunningTaskInfo> getRunningTasks(int maxNum) { + protected List<ActivityManager.RunningTaskInfo> getRunningTasks(int maxNum) { return tasks; } @@ -69,12 +69,12 @@ public class ShadowActivityManager { } @Implementation - public List<ActivityManager.RunningServiceInfo> getRunningServices(int maxNum) { + protected List<ActivityManager.RunningServiceInfo> getRunningServices(int maxNum) { return services; } @Implementation - public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() { + protected List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() { // This method is explicitly documented not to return an empty list if (processes.isEmpty()) { return null; @@ -105,12 +105,12 @@ public class ShadowActivityManager { } @Implementation - public void killBackgroundProcesses(String packageName) { + protected void killBackgroundProcesses(String packageName) { backgroundPackage = packageName; } @Implementation - public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) { + protected void getMemoryInfo(ActivityManager.MemoryInfo outInfo) { if (memoryInfo != null) { outInfo.availMem = memoryInfo.availMem; outInfo.lowMemory = memoryInfo.lowMemory; @@ -120,7 +120,7 @@ public class ShadowActivityManager { } @Implementation - public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo() { + protected android.content.pm.ConfigurationInfo getDeviceConfigurationInfo() { return new ConfigurationInfo(); } @@ -181,12 +181,12 @@ public class ShadowActivityManager { } @Implementation(minSdk = O) - public static IActivityManager getService() { + protected static IActivityManager getService() { return ReflectionHelpers.createNullProxy(IActivityManager.class); } @Implementation(minSdk = KITKAT) - public boolean isLowRamDevice() { + protected boolean isLowRamDevice() { if (isLowRamDeviceOverride != null) { return isLowRamDeviceOverride; } @@ -196,9 +196,8 @@ public class ShadowActivityManager { /** * Override the return value of isLowRamDevice(). */ - public ShadowActivityManager setIsLowRamDevice(boolean isLowRamDevice) { + public void setIsLowRamDevice(boolean isLowRamDevice) { isLowRamDeviceOverride = isLowRamDevice; - return this; } @Implementation(minSdk = VERSION_CODES.M) diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java index 6723115f4..65dbc15ff 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java @@ -12,7 +12,7 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -@Implements(value = ActivityThread.class, isInAndroidSdk = false) +@Implements(value = ActivityThread.class, isInAndroidSdk = false, looseSignatures = true) public class ShadowActivityThread { private static ApplicationInfo applicationInfo; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAdapterView.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAdapterView.java index 928e021b4..05a5ea0ff 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAdapterView.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAdapterView.java @@ -23,7 +23,8 @@ public class ShadowAdapterView<T extends Adapter> extends ShadowViewGroup { private AdapterView.OnItemSelectedListener itemSelectedListener; @Implementation - public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener itemSelectedListener) { + protected void setOnItemSelectedListener( + AdapterView.OnItemSelectedListener itemSelectedListener) { this.itemSelectedListener = itemSelectedListener; directlyOn(realAdapterView, AdapterView.class, "setOnItemSelectedListener", ClassParameter.from(AdapterView.OnItemSelectedListener.class, itemSelectedListener)); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlarmManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlarmManager.java index e93fd2f1a..bea306d2e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlarmManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlarmManager.java @@ -39,7 +39,7 @@ public class ShadowAlarmManager { } @Implementation - public void setTimeZone(String timeZone) { + protected void setTimeZone(String timeZone) { // Do the real check first Shadow.directlyOn(realObject, AlarmManager.class).setTimeZone(timeZone); // Then do the right side effect @@ -47,7 +47,7 @@ public class ShadowAlarmManager { } @Implementation - public void set(int type, long triggerAtTime, PendingIntent operation) { + protected void set(int type, long triggerAtTime, PendingIntent operation) { internalSet(type, triggerAtTime, 0L, operation, null); } @@ -58,7 +58,7 @@ public class ShadowAlarmManager { } @Implementation(minSdk = KITKAT) - public void setExact(int type, long triggerAtTime, PendingIntent operation) { + protected void setExact(int type, long triggerAtTime, PendingIntent operation) { internalSet(type, triggerAtTime, 0L, operation, null); } @@ -69,8 +69,8 @@ public class ShadowAlarmManager { } @Implementation(minSdk = KITKAT) - public void setWindow(int type, long windowStartMillis, long windowLengthMillis, - PendingIntent operation) { + protected void setWindow( + int type, long windowStartMillis, long windowLengthMillis, PendingIntent operation) { internalSet(type, windowStartMillis, 0L, operation, null); } @@ -86,33 +86,34 @@ public class ShadowAlarmManager { } @Implementation(minSdk = M) - public void setAndAllowWhileIdle(int type, long triggerAtTime, PendingIntent operation) { + protected void setAndAllowWhileIdle(int type, long triggerAtTime, PendingIntent operation) { internalSet(type, triggerAtTime, 0L, operation, null); } @Implementation(minSdk = M) - public void setExactAndAllowWhileIdle(int type, long triggerAtTime, PendingIntent operation) { + protected void setExactAndAllowWhileIdle(int type, long triggerAtTime, PendingIntent operation) { internalSet(type, triggerAtTime, 0L, operation, null); } @Implementation - public void setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation) { + protected void setRepeating( + int type, long triggerAtTime, long interval, PendingIntent operation) { internalSet(type, triggerAtTime, interval, operation, null); } @Implementation - public void setInexactRepeating(int type, long triggerAtMillis, long intervalMillis, - PendingIntent operation) { + protected void setInexactRepeating( + int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) { internalSet(type, triggerAtMillis, intervalMillis, operation, null); } @Implementation(minSdk = LOLLIPOP) - public void setAlarmClock(AlarmClockInfo info, PendingIntent operation) { + protected void setAlarmClock(AlarmClockInfo info, PendingIntent operation) { internalSet(RTC_WAKEUP, info.getTriggerTime(), 0L, operation, info.getShowIntent()); } @Implementation(minSdk = LOLLIPOP) - public AlarmClockInfo getNextAlarmClock() { + protected AlarmClockInfo getNextAlarmClock() { for (ScheduledAlarm scheduledAlarm : scheduledAlarms) { AlarmClockInfo alarmClockInfo = scheduledAlarm.getAlarmClockInfo(); if (alarmClockInfo != null) { @@ -166,7 +167,7 @@ public class ShadowAlarmManager { } @Implementation - public void cancel(PendingIntent operation) { + protected void cancel(PendingIntent operation) { ShadowPendingIntent shadowPendingIntent = Shadow.extract(operation); final Intent toRemove = shadowPendingIntent.getSavedIntent(); final int requestCode = shadowPendingIntent.getRequestCode(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlertDialog.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlertDialog.java index 1db763025..deace5bfe 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlertDialog.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAlertDialog.java @@ -96,22 +96,29 @@ public class ShadowAlertDialog extends ShadowDialog { } /** - * @return return the view set with {@link AlertDialog.Builder#setView(View)} + * @return the view set with {@link AlertDialog.Builder#setView(View)} */ public View getView() { return getShadowAlertController().getView(); } /** + * @return the icon set with {@link AlertDialog.Builder#setIcon(int)} + */ + public int getIconId() { + return getShadowAlertController().getIconId(); + } + + /** * @return return the view set with {@link AlertDialog.Builder#setCustomTitle(View)} */ public View getCustomTitleView() { return getShadowAlertController().getCustomTitleView(); } - public ShadowAlertController getShadowAlertController() { - AlertController alert = ReflectionHelpers.getField(realAlertDialog, "mAlert"); - return (ShadowAlertController) Shadow.extract(alert); + private ShadowAlertController getShadowAlertController() { + AlertController alertController = ReflectionHelpers.getField(realAlertDialog, "mAlert"); + return (ShadowAlertController) Shadow.extract(alertController); } @Implements(AlertDialog.Builder.class) diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAnimationUtils.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAnimationUtils.java index cc3bbdac8..8666c6b8e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAnimationUtils.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAnimationUtils.java @@ -16,12 +16,12 @@ import org.robolectric.shadow.api.Shadow; public class ShadowAnimationUtils { @Implementation - public static Interpolator loadInterpolator(Context context, int id) { + protected static Interpolator loadInterpolator(Context context, int id) { return new LinearInterpolator(); } @Implementation - public static LayoutAnimationController loadLayoutAnimation(Context context, int id) { + protected static LayoutAnimationController loadLayoutAnimation(Context context, int id) { Animation anim = new TranslateAnimation(0, 0, 30, 0); LayoutAnimationController layoutAnim = new LayoutAnimationController(anim); ShadowLayoutAnimationController shadowLayoutAnimationController = Shadow.extract(layoutAnim); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java index 12d8ad04c..c7177518d 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApkAssets.java @@ -1,7 +1,7 @@ package org.robolectric.shadows; // transliterated from -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/core/jni/android_content_res_ApkAssets.cpp +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android_content_res_ApkAssets.cpp abstract public class ShadowApkAssets { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java index c83d4ba57..959ccd751 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppOpsManager.java @@ -1,33 +1,50 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.KITKAT; +import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; +// BEGIN-INTERNAL +import static android.os.Build.VERSION_CODES.Q; +// END-INTERNAL +import static org.robolectric.shadow.api.Shadow.invokeConstructor; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.AppOpsManager; +import android.app.AppOpsManager.OnOpChangedListener; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; +import android.content.Context; +import android.content.pm.PackageManager.NameNotFoundException; +import android.media.AudioAttributes.AttributeUsage; +import android.os.Binder; import android.os.Build; +import com.android.internal.app.IAppOpsService; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.HiddenApi; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.annotation.RealObject; +import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers.ClassParameter; -/** - * Shadow for the {@link AppOpsManager}. - */ @Implements(value = AppOpsManager.class) public class ShadowAppOpsManager { @@ -38,11 +55,31 @@ public class ShadowAppOpsManager { private static final int PROXY_UID = 0; private static final String PROXY_PACKAGE = ""; + @RealObject private AppOpsManager realObject; + // Recorded operations, keyed by "uid|packageName" private Multimap<String, Integer> mStoredOps = HashMultimap.create(); // "uid|packageName|opCode" => opMode private Map<String, Integer> appModeMap = new HashMap<>(); + // "packageName|opCode" => listener + private BiMap<String, OnOpChangedListener> appOpListeners = HashBiMap.create(); + + // op | (usage << 8) => ModeAndExcpetion + private Map<Integer, ModeAndException> audioRestrictions = new HashMap<>(); + + private Context context; + + @Implementation(minSdk = KITKAT) + protected void __constructor__(Context context, IAppOpsService service) { + this.context = context; + invokeConstructor( + AppOpsManager.class, + realObject, + ClassParameter.from(Context.class, context), + ClassParameter.from(IAppOpsService.class, service)); + } + /** * Change the operating mode for the given op in the given app package. You must pass in both the * uid and name of the application whose mode is being modified; if these do not match, the @@ -50,7 +87,7 @@ public class ShadowAppOpsManager { * * <p>This method is public for testing {@link #checkOpNoThrow}. If {@link #checkOpNoThrow} is * called afterwards with the {@code op}, {@code ui}, and {@code packageName} provided, it will - * return the {@code mode} set here. + * return the {@code mode} set here. * * @param op The operation to modify. One of the OPSTR_* constants. * @param uid The user id of the application whose mode will be changed. @@ -64,14 +101,31 @@ public class ShadowAppOpsManager { setMode(AppOpsManager.strOpToOp(op), uid, packageName, mode); } - /** Int version of {@link #setMode(String, int, String, int)}. Used by system internally. */ + /** + * Int version of {@link #setMode(String, int, String, int)}. + * + * <p>This method is public for testing {@link #checkOpNoThrow}. If {@link #checkOpNoThrow} is * + * called afterwards with the {@code op}, {@code ui}, and {@code packageName} provided, it will * + * return the {@code mode} set here. + */ @Implementation(minSdk = KITKAT) @HiddenApi @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) - protected void setMode(int op, int uid, String packageName, int mode) { - appModeMap.put(getOpMapKey(uid, packageName, op), mode); + public void setMode(int op, int uid, String packageName, int mode) { + Integer oldMode = appModeMap.put(getOpMapKey(uid, packageName, op), mode); + OnOpChangedListener listener = appOpListeners.get(getListenerKey(op, packageName)); + if (listener != null && !Objects.equals(oldMode, mode)) { + String[] sOpToString = ReflectionHelpers.getStaticField(AppOpsManager.class, "sOpToString"); + listener.onOpChanged(sOpToString[op], packageName); + } } + // BEGIN-INTERNAL + @Implementation(minSdk = Q) + public int unsafeCheckOpNoThrow(String op, int uid, String packageName) { + return checkOpNoThrow(AppOpsManager.strOpToOp(op), uid, packageName); + } + // END-INTERNAL @Implementation(minSdk = P) @Deprecated // renamed to unsafeCheckOpNoThrow @@ -82,10 +136,12 @@ public class ShadowAppOpsManager { /** * Like {@link AppOpsManager#checkOp} but instead of throwing a {@link SecurityException} it * returns {@link AppOpsManager#MODE_ERRORED}. + * + * <p>Made public for testing {@link #setMode} as the method is {@coe @hide}. */ @Implementation(minSdk = KITKAT) @HiddenApi - protected int checkOpNoThrow(int op, int uid, String packageName) { + public int checkOpNoThrow(int op, int uid, String packageName) { Integer mode = appModeMap.get(getOpMapKey(uid, packageName, op)); if (mode == null) { return AppOpsManager.MODE_ALLOWED; @@ -101,6 +157,13 @@ public class ShadowAppOpsManager { return AppOpsManager.MODE_ALLOWED; } + @Implementation(minSdk = M) + @HiddenApi + protected int noteProxyOpNoThrow(int op, String proxiedPackageName) { + mStoredOps.put(getInternalKey(Binder.getCallingUid(), proxiedPackageName), op); + return checkOpNoThrow(op, Binder.getCallingUid(), proxiedPackageName); + } + @Implementation(minSdk = KITKAT) @HiddenApi public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) { @@ -121,6 +184,54 @@ public class ShadowAppOpsManager { return ImmutableList.of(new PackageOps(packageName, uid, opEntries)); } + @Implementation(minSdk = KITKAT) + protected void checkPackage(int uid, String packageName) { + try { + // getPackageUid was introduced in API 24, so we call it on the shadow class + ShadowApplicationPackageManager shadowApplicationPackageManager = + Shadow.extract(context.getPackageManager()); + int packageUid = shadowApplicationPackageManager.getPackageUid(packageName, 0); + if (packageUid == uid) { + return; + } + throw new SecurityException("Package " + packageName + " belongs to " + packageUid); + } catch (NameNotFoundException e) { + throw new SecurityException("Package " + packageName + " doesn't belong to " + uid, e); + } + } + + /** + * Sets audio restrictions. + * + * <p>This method is public for testing, as the original method is {@code @hide}. + */ + @Implementation(minSdk = LOLLIPOP) + @HiddenApi + public void setRestriction( + int code, @AttributeUsage int usage, int mode, String[] exceptionPackages) { + audioRestrictions.put( + getAudioRestrictionKey(code, usage), new ModeAndException(mode, exceptionPackages)); + } + + @Nullable + public ModeAndException getRestriction(int code, @AttributeUsage int usage) { + // this gives us room for 256 op_codes. There are 78 as of P. + return audioRestrictions.get(getAudioRestrictionKey(code, usage)); + } + + @Implementation(minSdk = KITKAT) + @HiddenApi + @RequiresPermission(value = android.Manifest.permission.WATCH_APPOPS) + protected void startWatchingMode(int op, String packageName, OnOpChangedListener callback) { + appOpListeners.put(getListenerKey(op, packageName), callback); + } + + @Implementation(minSdk = KITKAT) + @RequiresPermission(value = android.Manifest.permission.WATCH_APPOPS) + protected void stopWatchingMode(OnOpChangedListener callback) { + appOpListeners.inverse().remove(callback); + } + private static OpEntry toOpEntry(Integer op) { if (RuntimeEnvironment.getApiLevel() < Build.VERSION_CODES.M) { return ReflectionHelpers.callConstructor( @@ -143,4 +254,26 @@ public class ShadowAppOpsManager { private static String getOpMapKey(int uid, String packageName, int opInt) { return String.format("%s|%s|%s", uid, packageName, opInt); } + + private static int getAudioRestrictionKey(int code, @AttributeUsage int usage) { + return code | (usage << 8); + } + + private static String getListenerKey(int op, String packageName) { + return String.format("%s|%s", op, packageName); + } + + /** Class holding usage mode and excpetion packages. */ + public static class ModeAndException { + public final int mode; + public final List<String> exceptionPackages; + + public ModeAndException(int mode, String[] exceptionPackages) { + this.mode = mode; + this.exceptionPackages = + exceptionPackages == null + ? Collections.emptyList() + : Collections.unmodifiableList(Arrays.asList(exceptionPackages)); + } + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHost.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHost.java index 45c7ac5b8..2021ca5fa 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHost.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHost.java @@ -19,7 +19,7 @@ public class ShadowAppWidgetHost { private int appWidgetIdToAllocate; @Implementation - public void __constructor__(Context context, int hostId) { + protected void __constructor__(Context context, int hostId) { this.context = context; this.hostId = hostId; } @@ -37,13 +37,13 @@ public class ShadowAppWidgetHost { } @Implementation - public int allocateAppWidgetId() { + protected int allocateAppWidgetId() { return appWidgetIdToAllocate; } @Implementation - public AppWidgetHostView createView(Context context, int appWidgetId, - AppWidgetProviderInfo appWidget) { + protected AppWidgetHostView createView( + Context context, int appWidgetId, AppWidgetProviderInfo appWidget) { AppWidgetHostView hostView = new AppWidgetHostView(context); hostView.setAppWidget(appWidgetId, appWidget); ShadowAppWidgetHostView shadowAppWidgetHostView = Shadow.extract(hostView); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHostView.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHostView.java index 46196d607..90a1d9b45 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHostView.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetHostView.java @@ -14,18 +14,18 @@ public class ShadowAppWidgetHostView extends ShadowViewGroup { private AppWidgetHost host; @Implementation - public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) { + protected void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) { this.appWidgetId = appWidgetId; this.appWidgetInfo = info; } @Implementation - public int getAppWidgetId() { + protected int getAppWidgetId() { return appWidgetId; } @Implementation - public AppWidgetProviderInfo getAppWidgetInfo() { + protected AppWidgetProviderInfo getAppWidgetInfo() { return appWidgetInfo; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetManager.java index f00a9ffa3..09e047c8f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAppWidgetManager.java @@ -60,7 +60,6 @@ public class ShadowAppWidgetManager { // todo: implement } - /** * Finds or creates an {@code AppWidgetManager} for the given {@code context} * @@ -68,12 +67,12 @@ public class ShadowAppWidgetManager { * @return the {@code AppWidgetManager} associated with the given {@code context} */ @Implementation - public static AppWidgetManager getInstance(Context context) { + protected static AppWidgetManager getInstance(Context context) { return instances.getInstance(context); } @Implementation - public void updateAppWidget(int[] appWidgetIds, RemoteViews views) { + protected void updateAppWidget(int[] appWidgetIds, RemoteViews views) { for (int appWidgetId : appWidgetIds) { updateAppWidget(appWidgetId, views); } @@ -83,10 +82,10 @@ public class ShadowAppWidgetManager { * Simulates updating an {@code AppWidget} with a new set of views * * @param appWidgetId id of widget - * @param views views to update + * @param views views to update */ @Implementation - public void updateAppWidget(int appWidgetId, RemoteViews views) { + protected void updateAppWidget(int appWidgetId, RemoteViews views) { WidgetInfo widgetInfo = widgetInfos.get(appWidgetId); int layoutId = views.getLayoutId(); if (widgetInfo.layoutId != layoutId || alwaysRecreateViewsDuringUpdate) { @@ -98,7 +97,7 @@ public class ShadowAppWidgetManager { } @Implementation - public int[] getAppWidgetIds(ComponentName provider) { + protected int[] getAppWidgetIds(ComponentName provider) { List<Integer> idList = new ArrayList<>(); for (int id : widgetInfos.keySet()) { WidgetInfo widgetInfo = widgetInfos.get(id); @@ -114,7 +113,7 @@ public class ShadowAppWidgetManager { } @Implementation - public List<AppWidgetProviderInfo> getInstalledProviders() { + protected List<AppWidgetProviderInfo> getInstalledProviders() { return new ArrayList<>(installedProviders); } @@ -134,7 +133,7 @@ public class ShadowAppWidgetManager { } @Implementation - public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { + protected AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { WidgetInfo widgetInfo = widgetInfos.get(appWidgetId); if (widgetInfo == null) return null; return widgetInfo.info; @@ -152,7 +151,7 @@ public class ShadowAppWidgetManager { } @Implementation - public boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider) { + protected boolean bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider) { if (validWidgetProviderComponentName) { bindAppWidgetId(appWidgetId, provider); return allowedToBindWidgets; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplication.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplication.java index 202709132..f2c10ac21 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplication.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplication.java @@ -54,6 +54,12 @@ public class ShadowApplication extends ShadowContextWrapper { private PopupWindow latestPopupWindow; private ListPopupWindow latestListPopupWindow; + /** + * @deprecated Use + * `shadowOf({@link androidx.test.core.app.ApplicationProvider#getApplicationContext})` + * instead. + */ + @Deprecated public static ShadowApplication getInstance() { return RuntimeEnvironment.application == null ? null @@ -239,19 +245,27 @@ public class ShadowApplication extends ShadowContextWrapper { return appWidgetManager; } + /** + * @deprecated Use {@link ShadowAlertDialog#getLatestAlertDialog()} instead. + */ + @Deprecated public ShadowAlertDialog getLatestAlertDialog() { return latestAlertDialog; } - public void setLatestAlertDialog(ShadowAlertDialog latestAlertDialog) { + protected void setLatestAlertDialog(ShadowAlertDialog latestAlertDialog) { this.latestAlertDialog = latestAlertDialog; } + /** + * @deprecated Use {@link ShadowDialog#getLatestDialog()} instead. + */ + @Deprecated public ShadowDialog getLatestDialog() { return latestDialog; } - public void setLatestDialog(ShadowDialog latestDialog) { + protected void setLatestDialog(ShadowDialog latestDialog) { this.latestDialog = latestDialog; } @@ -305,11 +319,15 @@ public class ShadowApplication extends ShadowContextWrapper { shadowInstrumentation.checkActivities(checkActivities); } + /** + * @deprecated Use {@link ShadowPopupMenu#getLatestPopupMenu()} instead. + */ + @Deprecated public ShadowPopupMenu getLatestPopupMenu() { return latestPopupMenu; } - public void setLatestPopupMenu(ShadowPopupMenu latestPopupMenu) { + protected void setLatestPopupMenu(ShadowPopupMenu latestPopupMenu) { this.latestPopupMenu = latestPopupMenu; } @@ -317,7 +335,7 @@ public class ShadowApplication extends ShadowContextWrapper { return latestPopupWindow; } - public void setLatestPopupWindow(PopupWindow latestPopupWindow) { + protected void setLatestPopupWindow(PopupWindow latestPopupWindow) { this.latestPopupWindow = latestPopupWindow; } @@ -325,7 +343,7 @@ public class ShadowApplication extends ShadowContextWrapper { return latestListPopupWindow; } - public void setLatestListPopupWindow(ListPopupWindow latestListPopupWindow) { + protected void setLatestListPopupWindow(ListPopupWindow latestListPopupWindow) { this.latestListPopupWindow = latestListPopupWindow; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java index e01cac01b..ff86a476b 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java @@ -5,6 +5,7 @@ import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.GET_META_DATA; import static android.content.pm.PackageManager.GET_SIGNATURES; +import static android.content.pm.PackageManager.MATCH_ALL; import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.SIGNATURE_UNKNOWN_PACKAGE; @@ -67,6 +68,8 @@ import android.content.res.Resources; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.os.Handler; import android.os.Looper; import android.os.PersistableBundle; @@ -95,7 +98,6 @@ import org.robolectric.annotation.RealObject; @Implements(value = ApplicationPackageManager.class, isInAndroidSdk = false, looseSignatures = true) public class ShadowApplicationPackageManager extends ShadowPackageManager { - /** Package name of the Android platform. */ private static final String PLATFORM_PACKAGE_NAME = "android"; @@ -105,9 +107,7 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { /** {@link Uri} scheme of installed apps. */ private static final String PACKAGE_SCHEME = "package"; - - @RealObject - private ApplicationPackageManager realObject; + @RealObject private ApplicationPackageManager realObject; private Context context; @@ -159,9 +159,7 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { for (ActivityInfo activity : packageInfo.activities) { if (activityName.equals(activity.name)) { ActivityInfo result = new ActivityInfo(activity); - if ((flags & GET_META_DATA) != 0) { - result.metaData = activity.metaData; - } + applyFlagsToComponentInfo(result, flags); return result; } @@ -216,9 +214,7 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { } } - return results.isEmpty() - ? null - :results.toArray(new String[results.size()]); + return results.isEmpty() ? null : results.toArray(new String[results.size()]); } @Implementation @@ -241,17 +237,8 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { if (packageInfo != null && packageInfo.providers != null) { for (ProviderInfo provider : packageInfo.providers) { if (resolvePackageName(packageName, component).equals(provider.name)) { - ProviderInfo result = new ProviderInfo(); - result.packageName = provider.packageName; - result.name = provider.name; - result.authority = provider.authority; - result.readPermission = provider.readPermission; - result.writePermission = provider.writePermission; - result.pathPermissions = provider.pathPermissions; - - if ((flags & GET_META_DATA) != 0) { - result.metaData = provider.metaData; - } + ProviderInfo result = new ProviderInfo(provider); + applyFlagsToComponentInfo(result, flags); return result; } } @@ -331,28 +318,29 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { @Implementation protected List<ResolveInfo> queryIntentServices(Intent intent, int flags) { - // Check the manually added resolve infos first. + List<ResolveInfo> result = new ArrayList<>(); List<ResolveInfo> resolveInfoList = queryOverriddenIntents(intent, flags); if (!resolveInfoList.isEmpty()) { - return filterResolvedComponent( - resolveInfoList, flags, (resolveInfo) -> resolveInfo.serviceInfo); + result.addAll( + filterResolvedComponent( + resolveInfoList, flags, (resolveInfo) -> resolveInfo.serviceInfo)); } if (isExplicitIntent(intent)) { ResolveInfo resolvedService = resolveServiceForExplicitIntent(intent); if (resolvedService != null) { - resolveInfoList = + result.addAll( filterResolvedComponent( - Arrays.asList(resolvedService), flags, (resolveInfo) -> resolveInfo.serviceInfo); + Arrays.asList(resolvedService), flags, (resolveInfo) -> resolveInfo.serviceInfo)); } } else { - resolveInfoList = + result.addAll( filterResolvedComponent( queryImplicitIntentServices(intent, flags), flags, - (resolveInfo) -> resolveInfo.serviceInfo); + (resolveInfo) -> resolveInfo.serviceInfo)); } - return resolveInfoList; + return result; } private List<ResolveInfo> filterResolvedComponent( @@ -368,8 +356,18 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { for (Iterator<ResolveInfo> iterator = resolveInfoList.iterator(); iterator.hasNext(); ) { ResolveInfo resolveInfo = iterator.next(); - ComponentInfo componentInfo = - (resolveInfo == null) ? null : componentInfoFn.apply(resolveInfo); + ComponentInfo componentInfo = componentInfoFn.apply(resolveInfo); + + boolean hasSomeComponentInfo = + resolveInfo.activityInfo != null + || resolveInfo.serviceInfo != null + || (VERSION.SDK_INT >= VERSION_CODES.KITKAT && resolveInfo.providerInfo != null); + if (componentInfo == null && hasSomeComponentInfo) { + // wrong type of component. For backward compatibility we keep those entries that doesn't + // have any component. + iterator.remove(); + continue; + } if (isFlagSet(flags, PackageManager.MATCH_SYSTEM_ONLY)) { if (componentInfo == null || componentInfo.applicationInfo == null) { @@ -458,9 +456,7 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { return queryIntentActivities(intent, flags); } - /** - * Returns true if intent has specified a specific component. - */ + /** Returns true if intent has specified a specific component. */ private static boolean isExplicitIntent(Intent intent) { return getComponentForIntent(intent) != null; } @@ -509,8 +505,8 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { return null; } - private static <T extends Component> T findMatchingComponent(ComponentName componentName, - List<T> components) { + private static <T extends Component> T findMatchingComponent( + ComponentName componentName, List<T> components) { for (T component : components) { if (componentName.equals(component.getComponentName())) { return component; @@ -653,8 +649,8 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { return PackageManager.PERMISSION_GRANTED; } - if ((permissionsInfo.requestedPermissionsFlags[i] - & REQUESTED_PERMISSION_GRANTED) == REQUESTED_PERMISSION_GRANTED) { + if ((permissionsInfo.requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) + == REQUESTED_PERMISSION_GRANTED) { return PackageManager.PERMISSION_GRANTED; } } @@ -667,18 +663,16 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { * Returns whether a permission should be treated as granted to the package for backward * compatibility reasons. * - * <p> - * Before Robolectric 4.0 the ShadowPackageManager treated every requested permission as + * <p>Before Robolectric 4.0 the ShadowPackageManager treated every requested permission as * automatically granted. 4.0 changes this behavior, and only treats a permission as granted if - * PackageInfo.requestedPermissionFlags[permissionIndex] & REQUESTED_PERMISSION_GRANTED - * == REQUESTED_PERMISSION_GRANTED - * which matches the real PackageManager's behavior. + * PackageInfo.requestedPermissionFlags[permissionIndex] & REQUESTED_PERMISSION_GRANTED == + * REQUESTED_PERMISSION_GRANTED which matches the real PackageManager's behavior. * - * <p>Since many existing tests didn't set the requestedPermissionFlags on their - * {@code PackageInfo} objects, but assumed that all permissions are granted, we auto-grant - * all permissions if the requestedPermissionFlags is not set. - * If the requestedPermissionFlags is set, we assume that the test is configuring the - * permission grant state, and we don't override this setting. + * <p>Since many existing tests didn't set the requestedPermissionFlags on their {@code + * PackageInfo} objects, but assumed that all permissions are granted, we auto-grant all + * permissions if the requestedPermissionFlags is not set. If the requestedPermissionFlags is set, + * we assume that the test is configuring the permission grant state, and we don't override this + * setting. */ private boolean isGrantedForBackwardsCompatibility(String pkgName, PackageInfo permissionsInfo) { // Note: it might be cleaner to auto-grant these permissions when the package is added to the @@ -701,12 +695,8 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { if (packageInfo != null && packageInfo.receivers != null) { for (ActivityInfo receiver : packageInfo.receivers) { if (resolvePackageName(packageName, className).equals(receiver.name)) { - ActivityInfo result = new ActivityInfo(); - result.packageName = receiver.packageName; - result.name = receiver.name; - if ((flags & GET_META_DATA) != 0) { - result.metaData = receiver.metaData; - } + ActivityInfo result = new ActivityInfo(receiver); + applyFlagsToComponentInfo(result, flags); return result; } } @@ -717,28 +707,29 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { @Implementation protected List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) { - // Check the manually added resolve infos first. + List<ResolveInfo> result = new ArrayList<>(); List<ResolveInfo> resolveInfoList = queryOverriddenIntents(intent, flags); if (!resolveInfoList.isEmpty()) { - return filterResolvedComponent( - resolveInfoList, flags, (resolveInfo) -> resolveInfo.activityInfo); + result.addAll( + filterResolvedComponent( + resolveInfoList, flags, (resolveInfo) -> resolveInfo.activityInfo)); } if (isExplicitIntent(intent)) { ResolveInfo resolvedReceiver = resolveReceiverForExplicitIntent(intent); if (resolvedReceiver != null) { - resolveInfoList = + result.addAll( filterResolvedComponent( - Arrays.asList(resolvedReceiver), flags, (resolveInfo) -> resolveInfo.activityInfo); + Arrays.asList(resolvedReceiver), flags, (resolveInfo) -> resolveInfo.activityInfo)); } } else { - resolveInfoList = + result.addAll( filterResolvedComponent( queryImplicitIntentReceivers(intent, flags), flags, - (resolveInfo) -> resolveInfo.activityInfo); + (resolveInfo) -> resolveInfo.activityInfo)); } - return resolveInfoList; + return result; } private static IntentFilter matchIntentFilter( @@ -775,13 +766,11 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { if (packageInfo.services != null) { for (ServiceInfo service : packageInfo.services) { if (serviceName.equals(service.name)) { - ServiceInfo result = new ServiceInfo(); - result.packageName = service.packageName; - result.name = service.name; - result.applicationInfo = service.applicationInfo; - result.permission = service.permission; - if ((flags & GET_META_DATA) != 0) { - result.metaData = service.metaData; + ServiceInfo result = new ServiceInfo(service); + applyFlagsToComponentInfo(result, flags); + result.applicationInfo = new ApplicationInfo(service.applicationInfo); + if (result.processName == null) { + result.processName = result.applicationInfo.processName; } return result; } @@ -792,6 +781,16 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { return null; } + private void applyFlagsToComponentInfo(ComponentInfo result, int flags) + throws NameNotFoundException { + if ((flags & GET_META_DATA) == 0) { + result.metaData = null; + } + if ((flags & MATCH_ALL) != 0) { + return; + } + } + @Implementation protected Resources getResourcesForApplication(@NonNull ApplicationInfo applicationInfo) throws PackageManager.NameNotFoundException { @@ -835,12 +834,16 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { @Implementation(minSdk = M) protected boolean shouldShowRequestPermissionRationale(String permission) { - return permissionRationaleMap.containsKey(permission) ? permissionRationaleMap.get(permission) : false; + return permissionRationaleMap.containsKey(permission) + ? permissionRationaleMap.get(permission) + : false; } @Implementation protected FeatureInfo[] getSystemAvailableFeatures() { - return systemAvailableFeatures.isEmpty() ? null : systemAvailableFeatures.toArray(new FeatureInfo[systemAvailableFeatures.size()]); + return systemAvailableFeatures.isEmpty() + ? null + : systemAvailableFeatures.toArray(new FeatureInfo[systemAvailableFeatures.size()]); } @Implementation @@ -911,37 +914,46 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { @Implementation(maxSdk = JELLY_BEAN) protected void getPackageSizeInfo(Object pkgName, Object observer) { final PackageStats packageStats = packageStatsMap.get((String) pkgName); - new Handler(Looper.getMainLooper()).post(() -> { - try { - ((IPackageStatsObserver) observer).onGetStatsCompleted(packageStats, packageStats != null); - } catch (RemoteException remoteException) { - remoteException.rethrowFromSystemServer(); - } - }); + new Handler(Looper.getMainLooper()) + .post( + () -> { + try { + ((IPackageStatsObserver) observer) + .onGetStatsCompleted(packageStats, packageStats != null); + } catch (RemoteException remoteException) { + remoteException.rethrowFromSystemServer(); + } + }); } @Implementation(minSdk = JELLY_BEAN_MR1, maxSdk = M) protected void getPackageSizeInfo(Object pkgName, Object uid, final Object observer) { final PackageStats packageStats = packageStatsMap.get((String) pkgName); - new Handler(Looper.getMainLooper()).post(() -> { - try { - ((IPackageStatsObserver) observer).onGetStatsCompleted(packageStats, packageStats != null); - } catch (RemoteException remoteException) { - remoteException.rethrowFromSystemServer(); - } - }); + new Handler(Looper.getMainLooper()) + .post( + () -> { + try { + ((IPackageStatsObserver) observer) + .onGetStatsCompleted(packageStats, packageStats != null); + } catch (RemoteException remoteException) { + remoteException.rethrowFromSystemServer(); + } + }); } @Implementation(minSdk = N) protected void getPackageSizeInfoAsUser(Object pkgName, Object uid, final Object observer) { final PackageStats packageStats = packageStatsMap.get((String) pkgName); - new Handler(Looper.getMainLooper()).post(() -> { - try { - ((IPackageStatsObserver) observer).onGetStatsCompleted(packageStats, packageStats != null); - } catch (RemoteException remoteException) { - remoteException.rethrowFromSystemServer(); - } - }); + new Handler(Looper.getMainLooper()) + .post( + () -> { + try { + ((IPackageStatsObserver) observer) + .onGetStatsCompleted(packageStats, packageStats != null); + } catch (RemoteException remoteException) { + remoteException.rethrowFromSystemServer(); + } + }); } @Implementation @@ -1098,9 +1110,7 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { return 0; } - /** - * @see ShadowPackageManager#addPermissionGroupInfo(android.content.pm.PermissionGroupInfo) - */ + /** @see ShadowPackageManager#addPermissionGroupInfo(android.content.pm.PermissionGroupInfo) */ @Implementation protected PermissionGroupInfo getPermissionGroupInfo(String name, int flags) throws NameNotFoundException { @@ -1119,9 +1129,7 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { throw new NameNotFoundException(name); } - /** - * @see ShadowPackageManager#addPermissionGroupInfo(android.content.pm.PermissionGroupInfo) - */ + /** @see ShadowPackageManager#addPermissionGroupInfo(android.content.pm.PermissionGroupInfo) */ @Implementation protected List<PermissionGroupInfo> getAllPermissionGroups(int flags) { ArrayList<PermissionGroupInfo> allPermissionGroups = new ArrayList<PermissionGroupInfo>(); @@ -1137,8 +1145,8 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { for (Package pkg : packages.values()) { for (PermissionGroup permissionGroup : pkg.permissionGroups) { if (!handledPermissionGroups.contains(permissionGroup.info.name)) { - PermissionGroupInfo permissionGroupInfo = PackageParser - .generatePermissionGroupInfo(permissionGroup, flags); + PermissionGroupInfo permissionGroupInfo = + PackageParser.generatePermissionGroupInfo(permissionGroup, flags); allPermissionGroups.add(new PermissionGroupInfo(permissionGroupInfo)); handledPermissionGroups.add(permissionGroup.info.name); } @@ -1154,7 +1162,7 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { PackageInfo info = packageInfos.get(packageName); if (info != null) { try { - PackageInfo packageInfo = getPackageInfo(packageName, -1); + getPackageInfo(packageName, -1); } catch (NameNotFoundException e) { throw new IllegalArgumentException(e); } @@ -1875,4 +1883,9 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager { } return setting.isSuspended(); } + + @Implementation(minSdk = O) + protected boolean isInstantApp(String packageName) { + return false; + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java index ee697f18d..aedfb5054 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscApkAssets9.java @@ -28,7 +28,7 @@ import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers.ClassParameter; // transliterated from -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/core/jni/android_content_res_ApkAssets.cpp +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android_content_res_ApkAssets.cpp @Implements(value = ApkAssets.class, minSdk = Build.VERSION_CODES.P, shadowPicker = Picker.class, isInAndroidSdk = false) @@ -189,12 +189,12 @@ public class ShadowArscApkAssets9 extends ShadowApkAssets { throws IOException { throw new UnsupportedOperationException(); // return getFromCacheOrLoad( - // new Key(fd, friendlyName, system, forceSharedLibrary, false), - // () -> directlyOn(ApkAssets.class, "loadFromPath", - // ClassParameter.from(FileDescriptor.class, fd), - // ClassParameter.from(String.class, friendlyName), - // ClassParameter.from(boolean.class, system), - // ClassParameter.from(boolean.class, forceSharedLibrary))); + // new Key(fd, friendlyName, system, forceSharedLibrary, false), + // () -> directlyOn(ApkAssets.class, "loadFromPath", + // ClassParameter.from(FileDescriptor.class, fd), + // ClassParameter.from(String.class, friendlyName), + // ClassParameter.from(boolean.class, system), + // ClassParameter.from(boolean.class, forceSharedLibrary))); } // static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system, diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java index 85c49aa8e..8c81f564e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager.java @@ -15,7 +15,6 @@ import static org.robolectric.res.android.Errors.BAD_INDEX; import static org.robolectric.res.android.Errors.NO_ERROR; import static org.robolectric.res.android.Util.ALOGV; import static org.robolectric.res.android.Util.isTruthy; -import static org.robolectric.shadow.api.Shadow.directlyOn; import android.content.res.AssetManager; import android.os.Build.VERSION_CODES; @@ -67,7 +66,7 @@ import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowAssetManager.Picker; import org.robolectric.util.ReflectionHelpers; -// native method impls transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/core/jni/android_util_AssetManager.cpp +// native method impls transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android_util_AssetManager.cpp @Implements(value = AssetManager.class, maxSdk = VERSION_CODES.O_MR1, shadowPicker = Picker.class) public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { @@ -89,7 +88,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { } @Implementation - public final String[] list(String path) throws IOException { + protected final String[] list(String path) throws IOException { CppAssetManager am = assetManagerForJavaObject(); String fileName8 = path; @@ -190,7 +189,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { } @Implementation - public String getResourceName(int resid) { + protected String getResourceName(int resid) { CppAssetManager am = assetManagerForJavaObject(); ResourceName name = new ResourceName(); @@ -220,7 +219,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { } @Implementation - public String getResourcePackageName(int resid) { + protected String getResourcePackageName(int resid) { CppAssetManager cppAssetManager = assetManagerForJavaObject(); ResourceName name = new ResourceName(); @@ -232,7 +231,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { } @Implementation - public String getResourceTypeName(int resid) { + protected String getResourceTypeName(int resid) { CppAssetManager cppAssetManager = assetManagerForJavaObject(); ResourceName name = new ResourceName(); @@ -244,7 +243,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { } @Implementation - public String getResourceEntryName(int resid) { + protected String getResourceEntryName(int resid) { CppAssetManager cppAssetManager = assetManagerForJavaObject(); ResourceName name = new ResourceName(); @@ -522,29 +521,29 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { final Ref<Integer> typeSpecFlags = new Ref<>(null); int block = res.getResource(ident, value, false, density, typeSpecFlags, config); if (kThrowOnBadId) { - if (block == BAD_INDEX) { - throw new IllegalStateException("Bad resource!"); - //return 0; - } + if (block == BAD_INDEX) { + throw new IllegalStateException("Bad resource!"); + //return 0; + } } final Ref<Integer> ref = new Ref<>(ident); if (resolve) { - block = res.resolveReference(value, block, ref, typeSpecFlags, config); - if (kThrowOnBadId) { - if (block == BAD_INDEX) { - throw new IllegalStateException("Bad resource!"); - //return 0; - } + block = res.resolveReference(value, block, ref, typeSpecFlags, config); + if (kThrowOnBadId) { + if (block == BAD_INDEX) { + throw new IllegalStateException("Bad resource!"); + //return 0; } + } } if (block >= 0) { - //return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config); + //return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config); return copyValue(outValue, res, value.get(), ref.get(), block, typeSpecFlags.get(), config.get()); } return block; -} + } private static int copyValue(TypedValue outValue, ResTable table, Res_value value, int ref, int block, int typeSpecFlags) { @@ -671,7 +670,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { // /*package*/ static final int STYLE_DENSITY = 5; -/* lowercase hexadecimal notation. */ + /* lowercase hexadecimal notation. */ //# define PRIx8 "x" // # define PRIx16 "x" // # define PRIx32 "x" @@ -904,7 +903,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { //printf("Resolving attribute reference\n"); final Ref<Res_value> resValueRef = new Ref<>(value); int newBlock = res.resolveReference(resValueRef, block, resid, - typeSetFlags, config); + typeSetFlags, config); value = resValueRef.get(); if (kThrowOnBadId) { if (newBlock == BAD_INDEX) { @@ -955,7 +954,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { } @Implementation - public final SparseArray<String> getAssignedPackageIdentifiers() { + protected final SparseArray<String> getAssignedPackageIdentifiers() { CppAssetManager am = assetManagerForJavaObject(); final ResTable res = am.getResources(); @@ -1116,10 +1115,10 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { } } if (valueRef.get().dataType == DataType.STRING.code()) { - final ResStringPool pool = res.getTableStringBlock(block); - str = pool.stringAt(valueRef.get().data); + final ResStringPool pool = res.getTableStringBlock(block); + str = pool.stringAt(valueRef.get().data); - // assume we can skip utf8 vs utf 16 handling + // assume we can skip utf8 vs utf 16 handling // final char* str8 = pool.string8At(value.data, &strLen); // if (str8 != NULL) { @@ -1247,9 +1246,9 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { @HiddenApi @Implementation(maxSdk = VERSION_CODES.KITKAT) protected void init() { - // if (isSystem) { - // verifySystemIdmaps(); - // } + // if (isSystem) { + // verifySystemIdmaps(); + // } init(false); } @@ -1315,7 +1314,7 @@ public class ShadowArscAssetManager extends ShadowAssetManager.ArscBase { return am.getResources().getTableCount(); } - + synchronized private CppAssetManager assetManagerForJavaObject() { if (cppAssetManager == null) { throw new NullPointerException(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager9.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager9.java index 94074e032..edf8811b8 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager9.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowArscAssetManager9.java @@ -1,6 +1,6 @@ package org.robolectric.shadows; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/core/jni/android_util_AssetManager.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android_util_AssetManager.cpp import static android.os.Build.VERSION_CODES.P; import static android.os.Build.VERSION_CODES.Q; @@ -494,7 +494,7 @@ public class ShadowArscAssetManager9 extends ShadowAssetManager.ArscBase { return cppAssetManagerRef; } - // static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) { + // static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) { @Implementation(minSdk = P) protected static void nativeDestroy(long ptr) { if (ptr == systemCppAssetManager2Ref) { @@ -1164,7 +1164,7 @@ public class ShadowArscAssetManager9 extends ShadowAssetManager.ArscBase { } // if (name.type != null) { - result.append(name.type/*, name.type_len*/); + result.append(name.type/*, name.type_len*/); // } else { // result.append( /*util.Utf16ToUtf8(StringPiece16(*/ name.type16 /*, name.type_len))*/); // } @@ -1176,7 +1176,7 @@ public class ShadowArscAssetManager9 extends ShadowAssetManager.ArscBase { } // if (name.entry != null) { - result.append(name.entry/*, name.entry_len*/); + result.append(name.entry/*, name.entry_len*/); // } else { // result.append( /*util.Utf16ToUtf8(StringPiece16(*/ name.entry16 /*, name.entry_len)*/); // } @@ -1211,8 +1211,8 @@ public class ShadowArscAssetManager9 extends ShadowAssetManager.ArscBase { if (name.type != null) { return name.type; - // } else if (name.get().type16 != null) { - // return name.get().type16; // env.NewString(reinterpret_cast<jchar*>(name.type16), name.type_len); + // } else if (name.get().type16 != null) { + // return name.get().type16; // env.NewString(reinterpret_cast<jchar*>(name.type16), name.type_len); } return null; } @@ -1228,8 +1228,8 @@ public class ShadowArscAssetManager9 extends ShadowAssetManager.ArscBase { if (name.entry != null) { return name.entry; - // } else if (name.entry16 != null) { - // return name.entry16; // env.NewString(reinterpret_cast<jchar*>(name.entry16), name.entry_len); + // } else if (name.entry16 != null) { + // return name.entry16; // env.NewString(reinterpret_cast<jchar*>(name.entry16), name.entry_len); } return null; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTask.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTask.java index 3710fe7aa..85700d40f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTask.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTask.java @@ -60,27 +60,28 @@ public class ShadowAsyncTask<Params, Progress, Result> { } @Implementation - public boolean isCancelled() { + protected boolean isCancelled() { return future.isCancelled(); } @Implementation - public boolean cancel(boolean mayInterruptIfRunning) { + protected boolean cancel(boolean mayInterruptIfRunning) { return future.cancel(mayInterruptIfRunning); } @Implementation - public Result get() throws InterruptedException, ExecutionException { + protected Result get() throws InterruptedException, ExecutionException { return future.get(); } @Implementation - public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + protected Result get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { return future.get(timeout, unit); } @Implementation - public AsyncTask<Params, Progress, Result> execute(final Params... params) { + protected AsyncTask<Params, Progress, Result> execute(final Params... params) { status = AsyncTask.Status.RUNNING; getBridge().onPreExecute(); @@ -97,7 +98,8 @@ public class ShadowAsyncTask<Params, Progress, Result> { } @Implementation - public AsyncTask<Params, Progress, Result> executeOnExecutor(Executor executor, Params... params) { + protected AsyncTask<Params, Progress, Result> executeOnExecutor( + Executor executor, Params... params) { status = AsyncTask.Status.RUNNING; getBridge().onPreExecute(); @@ -113,19 +115,19 @@ public class ShadowAsyncTask<Params, Progress, Result> { } @Implementation - public AsyncTask.Status getStatus() { + protected AsyncTask.Status getStatus() { return status; } /** - * Enqueue a call to {@link AsyncTask#onProgressUpdate(Object[])} on UI looper (or run it immediately - * if the looper it is not paused). + * Enqueue a call to {@link AsyncTask#onProgressUpdate(Object[])} on UI looper (or run it + * immediately if the looper it is not paused). * * @param values The progress values to update the UI with. * @see AsyncTask#publishProgress(Object[]) */ @Implementation - public void publishProgress(final Progress... values) { + protected void publishProgress(final Progress... values) { ShadowApplication.getInstance().getForegroundThreadScheduler().post(new Runnable() { @Override public void run() { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTaskLoader.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTaskLoader.java index 7cc673110..f96022642 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTaskLoader.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAsyncTaskLoader.java @@ -15,12 +15,12 @@ public class ShadowAsyncTaskLoader<D> { private BackgroundWorker worker; @Implementation - public void __constructor__(Context context) { + protected void __constructor__(Context context) { worker = new BackgroundWorker(); } @Implementation - public void onForceLoad() { + protected void onForceLoad() { FutureTask<D> future = new FutureTask<D>(worker) { @Override protected void done() { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioEffect.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioEffect.java index c208e400b..a2348a65a 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioEffect.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioEffect.java @@ -17,7 +17,7 @@ public class ShadowAudioEffect { } @Implementation - public static AudioEffect.Descriptor[] queryEffects() { + protected static AudioEffect.Descriptor[] queryEffects() { return DESCRIPTORS.toArray(new AudioEffect.Descriptor[DESCRIPTORS.size()]); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java index b5930bb76..0486d8e1d 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowAudioManager.java @@ -58,19 +58,19 @@ public class ShadowAudioManager { } @Implementation - public int getStreamMaxVolume(int streamType) { + protected int getStreamMaxVolume(int streamType) { AudioStream stream = streamStatus.get(streamType); return (stream != null) ? stream.getMaxVolume() : INVALID_VOLUME; } @Implementation - public int getStreamVolume(int streamType) { + protected int getStreamVolume(int streamType) { AudioStream stream = streamStatus.get(streamType); return (stream != null) ? stream.getCurrentVolume() : INVALID_VOLUME; } @Implementation - public void setStreamVolume(int streamType, int index, int flags) { + protected void setStreamVolume(int streamType, int index, int flags) { AudioStream stream = streamStatus.get(streamType); if (stream != null) { stream.setCurrentVolume(index); @@ -79,7 +79,8 @@ public class ShadowAudioManager { } @Implementation - public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint) { + protected int requestAudioFocus( + android.media.AudioManager.OnAudioFocusChangeListener l, int streamType, int durationHint) { lastAudioFocusRequest = new AudioFocusRequest(l, streamType, durationHint); return nextResponseValue; } @@ -95,7 +96,7 @@ public class ShadowAudioManager { } @Implementation - public int abandonAudioFocus(AudioManager.OnAudioFocusChangeListener l) { + protected int abandonAudioFocus(AudioManager.OnAudioFocusChangeListener l) { lastAbandonedAudioFocusListener = l; return nextResponseValue; } @@ -112,12 +113,12 @@ public class ShadowAudioManager { } @Implementation - public int getRingerMode() { + protected int getRingerMode() { return ringerMode; } @Implementation - public void setRingerMode(int ringerMode) { + protected void setRingerMode(int ringerMode) { if (!AudioManager.isValidRingerMode(ringerMode)) { return; } @@ -132,12 +133,12 @@ public class ShadowAudioManager { } @Implementation - public void setMode(int mode) { + protected void setMode(int mode) { this.mode = mode; } @Implementation - public int getMode() { + protected int getMode() { return this.mode; } @@ -154,57 +155,57 @@ public class ShadowAudioManager { } @Implementation - public void setWiredHeadsetOn(boolean on) { + protected void setWiredHeadsetOn(boolean on) { wiredHeadsetOn = on; } @Implementation - public boolean isWiredHeadsetOn() { + protected boolean isWiredHeadsetOn() { return wiredHeadsetOn; } @Implementation - public void setBluetoothA2dpOn(boolean on) { + protected void setBluetoothA2dpOn(boolean on) { bluetoothA2dpOn = on; } @Implementation - public boolean isBluetoothA2dpOn() { + protected boolean isBluetoothA2dpOn() { return bluetoothA2dpOn; } @Implementation - public void setSpeakerphoneOn(boolean on) { + protected void setSpeakerphoneOn(boolean on) { isSpeakerphoneOn = on; } @Implementation - public boolean isSpeakerphoneOn() { + protected boolean isSpeakerphoneOn() { return isSpeakerphoneOn; } @Implementation - public void setMicrophoneMute(boolean on) { + protected void setMicrophoneMute(boolean on) { isMicrophoneMuted = on; } @Implementation - public boolean isMicrophoneMute() { + protected boolean isMicrophoneMute() { return isMicrophoneMuted; } @Implementation - public boolean isBluetoothScoOn() { + protected boolean isBluetoothScoOn() { return isBluetoothScoOn; } @Implementation - public void setBluetoothScoOn(boolean isBluetoothScoOn) { + protected void setBluetoothScoOn(boolean isBluetoothScoOn) { this.isBluetoothScoOn = isBluetoothScoOn; } @Implementation - public boolean isMusicActive() { + protected boolean isMusicActive() { return isMusicActive; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBaseAdapter.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBaseAdapter.java index fa1c63daa..cab7e4027 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBaseAdapter.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBaseAdapter.java @@ -14,7 +14,7 @@ public class ShadowBaseAdapter { private boolean wasNotifyDataSetChangedCalled; @Implementation - public void notifyDataSetChanged() { + protected void notifyDataSetChanged() { wasNotifyDataSetChangedCalled = true; directlyOn(realBaseAdapter, BaseAdapter.class, "notifyDataSetChanged"); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBatteryManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBatteryManager.java index 9404fdae4..6dad75085 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBatteryManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBatteryManager.java @@ -16,7 +16,7 @@ public class ShadowBatteryManager { private final Map<Integer, Integer> intProperties = new HashMap<>(); @Implementation(minSdk = M) - public boolean isCharging() { + protected boolean isCharging() { return isCharging; } @@ -25,7 +25,7 @@ public class ShadowBatteryManager { } @Implementation(minSdk = LOLLIPOP) - public int getIntProperty(int id) { + protected int getIntProperty(int id) { return intProperties.containsKey(id) ? intProperties.get(id) : Integer.MIN_VALUE; } @@ -34,7 +34,7 @@ public class ShadowBatteryManager { } @Implementation(minSdk = LOLLIPOP) - public long getLongProperty(int id) { + protected long getLongProperty(int id) { return longProperties.containsKey(id) ? longProperties.get(id) : Long.MIN_VALUE; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBinder.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBinder.java index 32c0fa13f..46aed0230 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBinder.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBinder.java @@ -17,7 +17,8 @@ public class ShadowBinder { private static Integer callingPid; @Implementation - public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + protected boolean transact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { if (data != null) { data.setDataPosition(0); } @@ -39,7 +40,7 @@ public class ShadowBinder { } @Implementation - public static final int getCallingPid() { + protected static final int getCallingPid() { if (callingPid != null) { return callingPid; } @@ -47,7 +48,7 @@ public class ShadowBinder { } @Implementation - public static final int getCallingUid() { + protected static final int getCallingUid() { if (callingUid != null) { return callingUid; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmap.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmap.java index 44fc27454..98d40d783 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmap.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmap.java @@ -17,6 +17,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.Buffer; import java.nio.ByteBuffer; +import java.util.Arrays; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.RealObject; @@ -56,6 +57,7 @@ public class ShadowBitmap { private String description = ""; private boolean recycled = false; private boolean hasMipMap; + private boolean isPremultiplied; /** * Returns a textual representation of the appearance of the object. @@ -183,7 +185,7 @@ public class ShadowBitmap { } @Implementation - public boolean compress(Bitmap.CompressFormat format, int quality, OutputStream stream) { + protected boolean compress(Bitmap.CompressFormat format, int quality, OutputStream stream) { try { stream.write((description + " compressed as " + format + " with quality " + quality).getBytes(UTF_8)); } catch (IOException e) { @@ -194,17 +196,23 @@ public class ShadowBitmap { } @Implementation - public static Bitmap createBitmap(int width, int height, Bitmap.Config config) { + protected static Bitmap createBitmap(int width, int height, Bitmap.Config config) { return createBitmap((DisplayMetrics) null, width, height, config); } @Implementation(minSdk = JELLY_BEAN_MR1) - public static Bitmap createBitmap(DisplayMetrics displayMetrics, int width, int height, Bitmap.Config config, boolean hasAlpha) { + protected static Bitmap createBitmap( + DisplayMetrics displayMetrics, + int width, + int height, + Bitmap.Config config, + boolean hasAlpha) { return createBitmap((DisplayMetrics) null, width, height, config); } @Implementation(minSdk = JELLY_BEAN_MR1) - public static Bitmap createBitmap(DisplayMetrics displayMetrics, int width, int height, Bitmap.Config config) { + protected static Bitmap createBitmap( + DisplayMetrics displayMetrics, int width, int height, Bitmap.Config config) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } @@ -224,14 +232,15 @@ public class ShadowBitmap { } @Implementation - public static Bitmap createBitmap(Bitmap src) { + protected static Bitmap createBitmap(Bitmap src) { ShadowBitmap shadowBitmap = Shadow.extract(src); shadowBitmap.appendDescription(" created from Bitmap object"); return src; } @Implementation - public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) { + protected static Bitmap createScaledBitmap( + Bitmap src, int dstWidth, int dstHeight, boolean filter) { if (dstWidth == src.getWidth() && dstHeight == src.getHeight() && !filter) { return src; // Return the original. } @@ -255,7 +264,7 @@ public class ShadowBitmap { } @Implementation - public static Bitmap createBitmap(Bitmap src, int x, int y, int width, int height) { + protected static Bitmap createBitmap(Bitmap src, int x, int y, int width, int height) { if (x == 0 && y == 0 && width == src.getWidth() && height == src.getHeight()) { return src; // Return the original. } @@ -279,13 +288,14 @@ public class ShadowBitmap { } @Implementation - public void setPixels(int[] pixels, int offset, int stride, - int x, int y, int width, int height) { + protected void setPixels( + int[] pixels, int offset, int stride, int x, int y, int width, int height) { this.colors = pixels; } @Implementation - public static Bitmap createBitmap(Bitmap src, int x, int y, int width, int height, Matrix matrix, boolean filter) { + protected static Bitmap createBitmap( + Bitmap src, int x, int y, int width, int height, Matrix matrix, boolean filter) { if (x == 0 && y == 0 && width == src.getWidth() && height == src.getHeight() && (matrix == null || matrix.isIdentity())) { return src; // Return the original. } @@ -335,7 +345,7 @@ public class ShadowBitmap { } @Implementation - public static Bitmap createBitmap(int[] colors, int width, int height, Bitmap.Config config) { + protected static Bitmap createBitmap(int[] colors, int width, int height, Bitmap.Config config) { if (colors.length != width * height) { throw new IllegalArgumentException("array length (" + colors.length + ") did not match width * height (" + (width * height) + ")"); } @@ -351,7 +361,7 @@ public class ShadowBitmap { } @Implementation - public int getPixel(int x, int y) { + protected int getPixel(int x, int y) { internalCheckPixelAccess(x, y); if (colors != null) { // Note that getPixel() returns a non-premultiplied ARGB value; if @@ -365,7 +375,7 @@ public class ShadowBitmap { } @Implementation - public void setPixel(int x, int y, int color) { + protected void setPixel(int x, int y, int color) { if (isRecycled()) { throw new IllegalStateException("Can't call setPixel() on a recycled bitmap"); } else if (!isMutable()) { @@ -379,14 +389,13 @@ public class ShadowBitmap { } /** - * Note that this method will return a RuntimeException unless: - * - {@code pixels} has the same length as the number of pixels of the bitmap. - * - {@code x = 0} - * - {@code y = 0} - * - {@code width} and {@code height} height match the current bitmap's dimensions. + * Note that this method will return a RuntimeException unless: - {@code pixels} has the same + * length as the number of pixels of the bitmap. - {@code x = 0} - {@code y = 0} - {@code width} + * and {@code height} height match the current bitmap's dimensions. */ @Implementation - public void getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height) { + protected void getPixels( + int[] pixels, int offset, int stride, int x, int y, int width, int height) { if (x != 0 || y != 0 || width != getWidth() || @@ -403,27 +412,27 @@ public class ShadowBitmap { } @Implementation - public int getRowBytes() { + protected int getRowBytes() { return getBytesPerPixel(config) * getWidth(); } @Implementation - public int getByteCount() { + protected int getByteCount() { return getRowBytes() * getHeight(); } @Implementation - public void recycle() { + protected void recycle() { recycled = true; } @Implementation - public final boolean isRecycled() { + protected final boolean isRecycled() { return recycled; } @Implementation - public Bitmap copy(Bitmap.Config config, boolean isMutable) { + protected Bitmap copy(Bitmap.Config config, boolean isMutable) { Bitmap newBitmap = ReflectionHelpers.callConstructor(Bitmap.class); ShadowBitmap shadowBitmap = Shadow.extract(newBitmap); shadowBitmap.createdFromBitmap = realBitmap; @@ -433,22 +442,22 @@ public class ShadowBitmap { } @Implementation(minSdk = KITKAT) - public final int getAllocationByteCount() { + protected final int getAllocationByteCount() { return getRowBytes() * getHeight(); } @Implementation - public final Bitmap.Config getConfig() { + protected final Bitmap.Config getConfig() { return config; } @Implementation(minSdk = KITKAT) - public void setConfig(Bitmap.Config config) { + protected void setConfig(Bitmap.Config config) { this.config = config; } @Implementation - public final boolean isMutable() { + protected final boolean isMutable() { return mutable; } @@ -469,72 +478,72 @@ public class ShadowBitmap { } @Implementation - public final boolean hasAlpha() { + protected final boolean hasAlpha() { return hasAlpha; } @Implementation - public void setHasAlpha(boolean hasAlpha) { + protected void setHasAlpha(boolean hasAlpha) { this.hasAlpha = hasAlpha; } @Implementation(minSdk = JELLY_BEAN_MR1) - public final boolean hasMipMap() { + protected final boolean hasMipMap() { return hasMipMap; } @Implementation(minSdk = JELLY_BEAN_MR1) - public final void setHasMipMap(boolean hasMipMap) { + protected final void setHasMipMap(boolean hasMipMap) { this.hasMipMap = hasMipMap; } @Implementation(minSdk = KITKAT) - public void setWidth(int width) { + protected void setWidth(int width) { this.width = width; } @Implementation - public int getWidth() { + protected int getWidth() { return width; } @Implementation(minSdk = KITKAT) - public void setHeight(int height) { + protected void setHeight(int height) { this.height = height; } @Implementation - public int getHeight() { + protected int getHeight() { return height; } @Implementation - public void setDensity(int density) { + protected void setDensity(int density) { this.density = density; } @Implementation - public int getDensity() { + protected int getDensity() { return density; } @Implementation - public int getGenerationId() { + protected int getGenerationId() { return 0; } @Implementation(minSdk = M) - public Bitmap createAshmemBitmap() { + protected Bitmap createAshmemBitmap() { return realBitmap; } @Implementation - public void eraseColor(int c) { - + protected void eraseColor(int color) { + Arrays.fill(colors, color); } @Implementation - public void writeToParcel(Parcel p, int flags) { + protected void writeToParcel(Parcel p, int flags) { p.writeInt(width); p.writeInt(height); p.writeSerializable(config); @@ -542,7 +551,7 @@ public class ShadowBitmap { } @Implementation - public static Bitmap nativeCreateFromParcel(Parcel p) { + protected static Bitmap nativeCreateFromParcel(Parcel p) { int parceledWidth = p.readInt(); int parceledHeight = p.readInt(); Bitmap.Config parceledConfig = (Bitmap.Config) p.readSerializable(); @@ -554,7 +563,7 @@ public class ShadowBitmap { } @Implementation - public void copyPixelsFromBuffer(Buffer dst) { + protected void copyPixelsFromBuffer(Buffer dst) { if (isRecycled()) { throw new IllegalStateException("Can't call copyPixelsFromBuffer() on a recycled bitmap"); } @@ -562,7 +571,7 @@ public class ShadowBitmap { // See the related comment in #copyPixelsToBuffer(Buffer). if (getBytesPerPixel(config) != INTERNAL_BYTES_PER_PIXEL) { throw new RuntimeException("Not implemented: only Bitmaps with " + INTERNAL_BYTES_PER_PIXEL - + " bytes per pixel are supported"); + + " bytes per pixel are supported"); } if (!(dst instanceof ByteBuffer)) { throw new RuntimeException("Not implemented: unsupported Buffer subclass"); @@ -579,14 +588,14 @@ public class ShadowBitmap { } @Implementation - public void copyPixelsToBuffer(Buffer dst) { + protected void copyPixelsToBuffer(Buffer dst) { // Ensure that the Bitmap uses 4 bytes per pixel, since we always use 4 bytes per pixels // internally. Clients of this API probably expect that the buffer size must be >= // getByteCount(), but if we don't enforce this restriction then for RGB_4444 and other // configs that value would be smaller then the buffer size we actually need. if (getBytesPerPixel(config) != INTERNAL_BYTES_PER_PIXEL) { throw new RuntimeException("Not implemented: only Bitmaps with " + INTERNAL_BYTES_PER_PIXEL - + " bytes per pixel are supported"); + + " bytes per pixel are supported"); } if (!(dst instanceof ByteBuffer)) { @@ -614,6 +623,36 @@ public class ShadowBitmap { this.config = config; } + @Implementation(minSdk = KITKAT) + protected void setPremultiplied(boolean isPremultiplied) { + this.isPremultiplied = isPremultiplied; + } + + @Implementation(minSdk = KITKAT) + protected boolean isPremultiplied() { + return isPremultiplied; + } + + @Implementation + protected boolean sameAs(Bitmap other) { + if (other == null) { + return false; + } + ShadowBitmap shadowOtherBitmap = Shadow.extract(other); + if (this.width != shadowOtherBitmap.width || this.height != shadowOtherBitmap.height) { + return false; + } + if (this.config != null + && shadowOtherBitmap.config != null + && this.config != shadowOtherBitmap.config) { + return false; + } + if (!Arrays.equals(colors, shadowOtherBitmap.colors)) { + return false; + } + return true; + } + public Bitmap getRealBitmap() { return realBitmap; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapDrawable.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapDrawable.java index 816c1f63e..14163d676 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapDrawable.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapDrawable.java @@ -30,14 +30,14 @@ public class ShadowBitmapDrawable extends ShadowDrawable { * @param canvas the canvas to draw on */ @Implementation - public void draw(Canvas canvas) { + protected void draw(Canvas canvas) { Paint paint = new Paint(); paint.setColorFilter(colorFilter); canvas.drawBitmap(realBitmapDrawable.getBitmap(), 0, 0, paint); } @Implementation - public Drawable mutate() { + protected Drawable mutate() { Bitmap bitmap = realBitmapDrawable.getBitmap(); BitmapDrawable real = ReflectionHelpers.callConstructor(BitmapDrawable.class, ClassParameter.from(Bitmap.class, bitmap)); ShadowBitmapDrawable shadow = Shadow.extract(real); @@ -47,7 +47,7 @@ public class ShadowBitmapDrawable extends ShadowDrawable { } @Implementation - public void setColorFilter(ColorFilter colorFilter) { + protected void setColorFilter(ColorFilter colorFilter) { this.colorFilter = colorFilter; directlyOn(realBitmapDrawable, BitmapDrawable.class).setColorFilter(colorFilter); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapFactory.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapFactory.java index 4f2346a5b..8a49e3c47 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapFactory.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapFactory.java @@ -37,7 +37,8 @@ public class ShadowBitmapFactory { private static Map<String, Point> widthAndHeightMap = new HashMap<>(); @Implementation - public static Bitmap decodeResourceStream(Resources res, TypedValue value, InputStream is, Rect pad, BitmapFactory.Options opts) { + protected static Bitmap decodeResourceStream( + Resources res, TypedValue value, InputStream is, Rect pad, BitmapFactory.Options opts) { Bitmap bitmap = directlyOn(BitmapFactory.class, "decodeResourceStream", ClassParameter.from(Resources.class, res), ClassParameter.from(TypedValue.class, value), @@ -53,7 +54,7 @@ public class ShadowBitmapFactory { } @Implementation - public static Bitmap decodeResource(Resources res, int id, BitmapFactory.Options options) { + protected static Bitmap decodeResource(Resources res, int id, BitmapFactory.Options options) { if (id == 0) { return null; } @@ -64,17 +65,17 @@ public class ShadowBitmapFactory { } @Implementation - public static Bitmap decodeResource(Resources res, int id) { + protected static Bitmap decodeResource(Resources res, int id) { return decodeResource(res, id, null); } @Implementation - public static Bitmap decodeFile(String pathName) { + protected static Bitmap decodeFile(String pathName) { return decodeFile(pathName, null); } @Implementation - public static Bitmap decodeFile(String pathName, BitmapFactory.Options options) { + protected static Bitmap decodeFile(String pathName, BitmapFactory.Options options) { Bitmap bitmap = create("file:" + pathName, options); ShadowBitmap shadowBitmap = Shadow.extract(bitmap); shadowBitmap.createdFromPath = pathName; @@ -82,7 +83,8 @@ public class ShadowBitmapFactory { } @Implementation - public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, BitmapFactory.Options opts) { + protected static Bitmap decodeFileDescriptor( + FileDescriptor fd, Rect outPadding, BitmapFactory.Options opts) { Bitmap bitmap = create("fd:" + fd, opts); ShadowBitmap shadowBitmap = Shadow.extract(bitmap); shadowBitmap.createdFromFileDescriptor = fd; @@ -90,12 +92,13 @@ public class ShadowBitmapFactory { } @Implementation - public static Bitmap decodeStream(InputStream is) { + protected static Bitmap decodeStream(InputStream is) { return decodeStream(is, null, null); } @Implementation - public static Bitmap decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts) { + protected static Bitmap decodeStream( + InputStream is, Rect outPadding, BitmapFactory.Options opts) { byte[] ninePatchChunk = null; if (is instanceof AssetInputStream) { @@ -130,7 +133,7 @@ public class ShadowBitmapFactory { } @Implementation - public static Bitmap decodeByteArray(byte[] data, int offset, int length) { + protected static Bitmap decodeByteArray(byte[] data, int offset, int length) { Bitmap bitmap = decodeByteArray(data, offset, length, new BitmapFactory.Options()); ShadowBitmap shadowBitmap = Shadow.extract(bitmap); shadowBitmap.createdFromBytes = data; @@ -138,7 +141,8 @@ public class ShadowBitmapFactory { } @Implementation - public static Bitmap decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts) { + protected static Bitmap decodeByteArray( + byte[] data, int offset, int length, BitmapFactory.Options opts) { String desc = new String(data, UTF_8); if (!Charset.forName("US-ASCII").newEncoder().canEncode(desc)) { Checksum checksumEngine = new CRC32(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapRegionDecoder.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapRegionDecoder.java index 29ef61bb2..82f6c79b1 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapRegionDecoder.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBitmapRegionDecoder.java @@ -24,22 +24,26 @@ public class ShadowBitmapRegionDecoder { private int height; @Implementation - public static BitmapRegionDecoder newInstance(byte[] data, int offset, int length, boolean isShareable) throws IOException { + protected static BitmapRegionDecoder newInstance( + byte[] data, int offset, int length, boolean isShareable) throws IOException { return fillWidthAndHeight(newInstance(), new ByteArrayInputStream(data)); } @Implementation - public static BitmapRegionDecoder newInstance(FileDescriptor fd, boolean isShareable) throws IOException { + protected static BitmapRegionDecoder newInstance(FileDescriptor fd, boolean isShareable) + throws IOException { return fillWidthAndHeight(newInstance(), new FileInputStream(fd)); } @Implementation - public static BitmapRegionDecoder newInstance(InputStream is, boolean isShareable) throws IOException { + protected static BitmapRegionDecoder newInstance(InputStream is, boolean isShareable) + throws IOException { return fillWidthAndHeight(newInstance(), is); } @Implementation - public static BitmapRegionDecoder newInstance(String pathName, boolean isShareable) throws IOException { + protected static BitmapRegionDecoder newInstance(String pathName, boolean isShareable) + throws IOException { return fillWidthAndHeight(newInstance(), new FileInputStream(pathName)); } @@ -54,17 +58,17 @@ public class ShadowBitmapRegionDecoder { } @Implementation - public int getWidth() { + protected int getWidth() { return width; } @Implementation - public int getHeight() { + protected int getHeight() { return height; } @Implementation - public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) { + protected Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) { return Bitmap.createBitmap(rect.width(), rect.height(), options.inPreferredConfig != null ? options.inPreferredConfig : Bitmap.Config.ARGB_8888); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java index c2771ce81..e184e4dc9 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothAdapter.java @@ -6,11 +6,14 @@ import static android.os.Build.VERSION_CODES.LOLLIPOP; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter.LeScanCallback; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.os.ParcelUuid; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.UUID; import org.robolectric.annotation.Implementation; @@ -30,14 +33,15 @@ public class ShadowBluetoothAdapter { private String name = "DefaultBluetoothDeviceName"; private int scanMode = BluetoothAdapter.SCAN_MODE_NONE; private boolean isMultipleAdvertisementSupported = true; + private Map<Integer, Integer> profileConnectionStateData = new HashMap<>(); @Implementation - public static BluetoothAdapter getDefaultAdapter() { + protected static BluetoothAdapter getDefaultAdapter() { return (BluetoothAdapter) ShadowApplication.getInstance().getBluetoothAdapter(); } @Implementation - public Set<BluetoothDevice> getBondedDevices() { + protected Set<BluetoothDevice> getBondedDevices() { return Collections.unmodifiableSet(bondedDevices); } @@ -53,31 +57,31 @@ public class ShadowBluetoothAdapter { } @Implementation - public boolean startDiscovery() { + protected boolean startDiscovery() { isDiscovering = true; return true; } @Implementation - public boolean cancelDiscovery() { + protected boolean cancelDiscovery() { isDiscovering = false; return true; } @Implementation(minSdk = JELLY_BEAN_MR2) - public boolean startLeScan(LeScanCallback callback) { + protected boolean startLeScan(LeScanCallback callback) { return startLeScan(null, callback); } @Implementation(minSdk = JELLY_BEAN_MR2) - public boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { + protected boolean startLeScan(UUID[] serviceUuids, LeScanCallback callback) { // Ignoring the serviceUuids param for now. leScanCallbacks.add(callback); return true; } @Implementation(minSdk = JELLY_BEAN_MR2) - public void stopLeScan(LeScanCallback callback) { + protected void stopLeScan(LeScanCallback callback) { leScanCallbacks.remove(callback); } @@ -93,34 +97,34 @@ public class ShadowBluetoothAdapter { } @Implementation - public boolean isDiscovering() { + protected boolean isDiscovering() { return isDiscovering; } @Implementation - public boolean isEnabled() { + protected boolean isEnabled() { return enabled; } @Implementation - public boolean enable() { + protected boolean enable() { enabled = true; return true; } @Implementation - public boolean disable() { + protected boolean disable() { enabled = false; return true; } @Implementation - public String getAddress() { + protected String getAddress() { return this.address; } @Implementation - public int getState() { + protected int getState() { return state; } @@ -158,38 +162,52 @@ public class ShadowBluetoothAdapter { } /** - * Validate a Bluetooth address, such as "00:43:A8:23:10:F0" - * Alphabetic characters must be uppercase to be valid. + * Validate a Bluetooth address, such as "00:43:A8:23:10:F0" Alphabetic characters must be + * uppercase to be valid. * - * @param address - * Bluetooth address as string + * @param address Bluetooth address as string * @return true if the address is valid, false otherwise */ @Implementation - public static boolean checkBluetoothAddress(String address) { + protected static boolean checkBluetoothAddress(String address) { if (address == null || address.length() != ADDRESS_LENGTH) { return false; } for (int i = 0; i < ADDRESS_LENGTH; i++) { char c = address.charAt(i); switch (i % 3) { - case 0: - case 1: - if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { - // hex character, OK - break; - } - return false; - case 2: - if (c == ':') { - break; // OK - } - return false; + case 0: + case 1: + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) { + // hex character, OK + break; + } + return false; + case 2: + if (c == ':') { + break; // OK + } + return false; } } return true; } + /** + * Returns the connection state for the given Bluetooth {@code profile}, defaulting to {@link + * BluetoothProfile.STATE_DISCONNECTED} if the profile's connection state was never set. + * + * <p>Set a Bluetooth profile's connection state via {@link #setProfileConnectionState(int, int)}. + */ + @Implementation + protected int getProfileConnectionState(int profile) { + Integer state = profileConnectionStateData.get(profile); + if (state == null) { + return BluetoothProfile.STATE_DISCONNECTED; + } + return state; + } + public void setAddress(String address) { this.address = address; } @@ -205,4 +223,11 @@ public class ShadowBluetoothAdapter { public void setIsMultipleAdvertisementSupported(boolean supported) { isMultipleAdvertisementSupported = supported; } + + /** + *Sets the connection state {@code state} for the given BLuetoothProfile {@code profile} + */ + public void setProfileConnectionState(int profile, int state) { + profileConnectionStateData.put(profile, state); + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothDevice.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothDevice.java index 0ba4d95d9..d174681d3 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothDevice.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothDevice.java @@ -36,7 +36,7 @@ public class ShadowBluetoothDevice { * from invoking {@link android.bluetooth.BluetoothAdapter#getBluetoothService}. */ @Implementation - public static IBluetooth getService() { + protected static IBluetooth getService() { // Attempt to call the underlying getService method, but ignore any Exceptions. This allows us // to easily create BluetoothDevices for testing purposes without having any actual Bluetooth // capability. @@ -53,7 +53,7 @@ public class ShadowBluetoothDevice { } @Implementation - public String getName() { + protected String getName() { return name; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothGatt.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothGatt.java index 3ca92efda..034e97588 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothGatt.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothGatt.java @@ -14,7 +14,6 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implements; import org.robolectric.shadow.api.Shadow; -/** Shadow for {@link BluetoothGatt}. */ @Implements(value = BluetoothGatt.class, minSdk = JELLY_BEAN_MR2) public class ShadowBluetoothGatt { @@ -31,11 +30,11 @@ public class ShadowBluetoothGatt { Shadow.newInstance( BluetoothGatt.class, new Class<?>[] { - iBluetoothGattClass, - BluetoothDevice.class, - Integer.TYPE, - Boolean.TYPE, - Integer.TYPE + iBluetoothGattClass, + BluetoothDevice.class, + Integer.TYPE, + Boolean.TYPE, + Integer.TYPE }, new Object[] {null, device, 0, false, 0}); } else if (Build.VERSION.SDK_INT >= O) { @@ -43,7 +42,7 @@ public class ShadowBluetoothGatt { Shadow.newInstance( BluetoothGatt.class, new Class<?>[] { - iBluetoothGattClass, BluetoothDevice.class, Integer.TYPE, Integer.TYPE + iBluetoothGattClass, BluetoothDevice.class, Integer.TYPE, Integer.TYPE }, new Object[] {null, device, 0, 0}); } else if (Build.VERSION.SDK_INT >= LOLLIPOP) { @@ -51,7 +50,7 @@ public class ShadowBluetoothGatt { Shadow.newInstance( BluetoothGatt.class, new Class<?>[] { - Context.class, iBluetoothGattClass, BluetoothDevice.class, Integer.TYPE + Context.class, iBluetoothGattClass, BluetoothDevice.class, Integer.TYPE }, new Object[] {RuntimeEnvironment.application, null, device, 0}); } else { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothManager.java index 5b80fae89..afd242f67 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothManager.java @@ -10,8 +10,8 @@ import org.robolectric.annotation.Implements; @Implements(value = BluetoothManager.class, minSdk = JELLY_BEAN_MR2) public class ShadowBluetoothManager { - @Implementation - public BluetoothAdapter getAdapter() { + @Implementation + protected BluetoothAdapter getAdapter() { return BluetoothAdapter.getDefaultAdapter(); } }
\ No newline at end of file diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothServerSocket.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothServerSocket.java index c1b6dbc23..4d1c62e0d 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothServerSocket.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothServerSocket.java @@ -10,7 +10,6 @@ import android.os.ParcelUuid; import org.robolectric.annotation.Implements; import org.robolectric.shadow.api.Shadow; -/** Shadow for {@link BluetoothServerSocket}. */ @Implements(value = BluetoothServerSocket.class) public class ShadowBluetoothServerSocket { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothSocket.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothSocket.java new file mode 100644 index 000000000..2ec95a1c8 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBluetoothSocket.java @@ -0,0 +1,54 @@ +package org.robolectric.shadows; + +import android.bluetooth.BluetoothSocket; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(BluetoothSocket.class) +public class ShadowBluetoothSocket { + private final PipedOutputStream inputStreamFeeder = new PipedOutputStream(); + private final PipedInputStream outputStreamSink = new PipedInputStream(); + private final OutputStream outputStream; + private final InputStream inputStream; + + public ShadowBluetoothSocket() { + try { + outputStream = new PipedOutputStream(outputStreamSink); + inputStream = new PipedInputStream(inputStreamFeeder); + } catch (IOException e) { + // Shouldn't happen. Rethrow as an unchecked exception. + throw new RuntimeException(e); + } + } + + /** + * Returns {@link PipedOutputStream} that controls <b>input</b> stream of the {@link + * BluetoothSocket}. + */ + public PipedOutputStream getInputStreamFeeder() { + return inputStreamFeeder; + } + + /** + * Returns {@link PipedInputStream} that controls <b>output</b> stream of the {@link + * BluetoothSocket}. + */ + public PipedInputStream getOutputStreamSink() { + return outputStreamSink; + } + + @Implementation + protected InputStream getInputStream() { + return inputStream; + } + + @Implementation + protected OutputStream getOutputStream() { + return outputStream; + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastPendingResult.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastPendingResult.java index b4d44860f..2cd2058ee 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastPendingResult.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastPendingResult.java @@ -123,7 +123,7 @@ public final class ShadowBroadcastPendingResult { private final SettableFuture<BroadcastReceiver.PendingResult> finished = SettableFuture.create(); @Implementation - public final void finish() { + protected final void finish() { Preconditions.checkState(finished.set(pendingResult), "Broadcast already finished"); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastReceiver.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastReceiver.java index 80396c1c2..b9659f14e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastReceiver.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBroadcastReceiver.java @@ -15,13 +15,13 @@ public class ShadowBroadcastReceiver { private AtomicBoolean abort; // The abort state of the currently processed broadcast @Implementation - public void abortBroadcast() { + protected void abortBroadcast() { // TODO probably needs a check to prevent calling this method from ordinary Broadcasts abort.set(true); } @Implementation - public void onReceive(Context context, Intent intent) { + protected void onReceive(Context context, Intent intent) { if (abort == null || !abort.get()) { receiver.onReceive(context, intent); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBuild.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBuild.java index 2d440c608..c2d9786e9 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBuild.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowBuild.java @@ -1,8 +1,10 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.L; import static android.os.Build.VERSION_CODES.O; import static org.robolectric.shadow.api.Shadow.directlyOn; +import android.annotation.TargetApi; import android.os.Build; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -105,6 +107,16 @@ public class ShadowBuild { } /** + * Sets the value of the {@link Build#SUPPORTED_64_BIT_ABIS} field. Available in Android L+. + * + * <p>It will be reset for the next test. + */ + @TargetApi(L) + public static void setSupported64BitAbis(String[] supported64BitAbis) { + ReflectionHelpers.setStaticField(Build.class, "SUPPORTED_64_BIT_ABIS", supported64BitAbis); + } + + /** * Override return value from {@link Build#getRadioVersion()} * * @param radioVersion @@ -114,7 +126,7 @@ public class ShadowBuild { } @Implementation - public static String getRadioVersion() { + protected static String getRadioVersion() { if (radioVersionOverride != null) { return radioVersionOverride; } @@ -134,4 +146,11 @@ public class ShadowBuild { // performStaticInitialization(Build.class); } + // BEGIN-INTERNAL + /** + * Temporary constant that maps to Build.VERSION_CODES.Q. + * Useful for projects that still compile against P but want to explicitly run tests on Q. + */ + public static final int Q = Build.VERSION_CODES.Q; + // END-INTERNAL } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCamera.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCamera.java index d682b0f95..667d74fc3 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCamera.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCamera.java @@ -15,6 +15,7 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.RealObject; import org.robolectric.shadow.api.Shadow; +import org.robolectric.util.ReflectionHelpers; @Implements(Camera.class) public class ShadowCamera { @@ -35,18 +36,17 @@ public class ShadowCamera { private static Map<Integer, Camera.CameraInfo> cameras = new HashMap<>(); - @RealObject - private Camera realCamera; + @RealObject private Camera realCamera; @Implementation - public void __constructor__() { + protected void __constructor__() { locked = true; previewing = false; released = false; } @Implementation - public static Camera open() { + protected static Camera open() { lastOpenedCameraId = 0; Camera camera = newInstanceOf(Camera.class); ShadowCamera shadowCamera = Shadow.extract(camera); @@ -55,7 +55,7 @@ public class ShadowCamera { } @Implementation - public static Camera open(int cameraId) { + protected static Camera open(int cameraId) { lastOpenedCameraId = cameraId; Camera camera = newInstanceOf(Camera.class); ShadowCamera shadowCamera = Shadow.extract(camera); @@ -68,17 +68,17 @@ public class ShadowCamera { } @Implementation - public void unlock() { + protected void unlock() { locked = false; } @Implementation - public void reconnect() { + protected void reconnect() { locked = true; } @Implementation - public Camera.Parameters getParameters() { + protected Camera.Parameters getParameters() { if (null == parameters) { parameters = newInstanceOf(Camera.Parameters.class); } @@ -86,42 +86,42 @@ public class ShadowCamera { } @Implementation - public void setParameters(Camera.Parameters params) { + protected void setParameters(Camera.Parameters params) { parameters = params; } @Implementation - public void setPreviewDisplay(SurfaceHolder holder) { + protected void setPreviewDisplay(SurfaceHolder holder) { surfaceHolder = holder; } @Implementation - public void startPreview() { + protected void startPreview() { previewing = true; } @Implementation - public void stopPreview() { + protected void stopPreview() { previewing = false; } @Implementation - public void release() { + protected void release() { released = true; } @Implementation - public void setPreviewCallback(Camera.PreviewCallback cb) { + protected void setPreviewCallback(Camera.PreviewCallback cb) { previewCallback = cb; } @Implementation - public void setOneShotPreviewCallback(Camera.PreviewCallback cb) { + protected void setOneShotPreviewCallback(Camera.PreviewCallback cb) { previewCallback = cb; } @Implementation - public void setPreviewCallbackWithBuffer(Camera.PreviewCallback cb) { + protected void setPreviewCallbackWithBuffer(Camera.PreviewCallback cb) { previewCallback = cb; } @@ -137,7 +137,7 @@ public class ShadowCamera { } @Implementation - public void addCallbackBuffer(byte[] callbackBuffer) { + protected void addCallbackBuffer(byte[] callbackBuffer) { callbackBuffers.add(callbackBuffer); } @@ -146,7 +146,7 @@ public class ShadowCamera { } @Implementation - public void setDisplayOrientation(int degrees) { + protected void setDisplayOrientation(int degrees) { displayOrientation = degrees; if (cameras.containsKey(id)) { cameras.get(id).orientation = degrees; @@ -158,13 +158,13 @@ public class ShadowCamera { } @Implementation - public void autoFocus(Camera.AutoFocusCallback callback) { + protected void autoFocus(Camera.AutoFocusCallback callback) { autoFocusCallback = callback; autoFocusing = true; } @Implementation - public void cancelAutoFocus() { + protected void cancelAutoFocus() { autoFocusCallback = null; autoFocusing = false; } @@ -186,14 +186,14 @@ public class ShadowCamera { } @Implementation - public static void getCameraInfo(int cameraId, Camera.CameraInfo cameraInfo ) { - Camera.CameraInfo foundCam = cameras.get( cameraId ); + protected static void getCameraInfo(int cameraId, Camera.CameraInfo cameraInfo) { + Camera.CameraInfo foundCam = cameras.get(cameraId); cameraInfo.facing = foundCam.facing; cameraInfo.orientation = foundCam.orientation; } @Implementation - public static int getNumberOfCameras() { + protected static int getNumberOfCameras() { return cameras.size(); } @@ -230,9 +230,8 @@ public class ShadowCamera { } /** - * Add a mock {@code Camera.CameraInfo} object to simulate - * the existence of one or more cameras. By default, no - * cameras are defined. + * Add a mock {@code Camera.CameraInfo} object to simulate the existence of one or more cameras. + * By default, no cameras are defined. * * @param id The camera id * @param camInfo The CameraInfo @@ -245,9 +244,7 @@ public class ShadowCamera { cameras.clear(); } - /** - * Shadows the Android {@code Camera.Parameters} class. - */ + /** Shadows the Android {@code Camera.Parameters} class. */ @Implements(Camera.Parameters.class) public static class ShadowParameters { @@ -260,11 +257,28 @@ public class ShadowCamera { private int previewFpsMax = 30; private int previewFps = 30; private int exposureCompensation = 0; + private String flashMode; private String focusMode; + private List<String> supportedFlashModes = new ArrayList<>(); private List<String> supportedFocusModes = new ArrayList<>(); + private static List<Camera.Size> supportedPreviewSizes; + + /** + * Explicitly initialize custom preview sizes array, to switch from default values to + * individually added. + */ + public void initSupportedPreviewSizes() { + supportedPreviewSizes = new ArrayList<>(); + } + + /** Add custom preview sizes to supportedPreviewSizes. */ + public void addSupportedPreviewSize(int width, int height) { + Camera.Size newSize = ReflectionHelpers.newInstance(Camera.class).new Size(width, height); + supportedPreviewSizes.add(newSize); + } @Implementation - public Camera.Size getPictureSize() { + protected Camera.Size getPictureSize() { Camera.Size pictureSize = newInstanceOf(Camera.class).new Size(0, 0); pictureSize.width = pictureWidth; pictureSize.height = pictureHeight; @@ -272,23 +286,23 @@ public class ShadowCamera { } @Implementation - public int getPreviewFormat() { + protected int getPreviewFormat() { return previewFormat; } @Implementation - public void getPreviewFpsRange(int[] range) { + protected void getPreviewFpsRange(int[] range) { range[0] = previewFpsMin; range[1] = previewFpsMax; } @Implementation - public int getPreviewFrameRate() { + protected int getPreviewFrameRate() { return previewFps; } @Implementation - public Camera.Size getPreviewSize() { + protected Camera.Size getPreviewSize() { Camera.Size previewSize = newInstanceOf(Camera.class).new Size(0, 0); previewSize.width = previewWidth; previewSize.height = previewHeight; @@ -296,7 +310,7 @@ public class ShadowCamera { } @Implementation - public List<Camera.Size> getSupportedPictureSizes() { + protected List<Camera.Size> getSupportedPictureSizes() { List<Camera.Size> supportedSizes = new ArrayList<>(); addSize(supportedSizes, 320, 240); addSize(supportedSizes, 640, 480); @@ -305,7 +319,7 @@ public class ShadowCamera { } @Implementation - public List<Integer> getSupportedPictureFormats() { + protected List<Integer> getSupportedPictureFormats() { List<Integer> formats = new ArrayList<>(); formats.add(ImageFormat.NV21); formats.add(ImageFormat.JPEG); @@ -313,7 +327,7 @@ public class ShadowCamera { } @Implementation - public List<Integer> getSupportedPreviewFormats() { + protected List<Integer> getSupportedPreviewFormats() { List<Integer> formats = new ArrayList<>(); formats.add(ImageFormat.NV21); formats.add(ImageFormat.JPEG); @@ -321,7 +335,7 @@ public class ShadowCamera { } @Implementation - public List<int[]> getSupportedPreviewFpsRange() { + protected List<int[]> getSupportedPreviewFpsRange() { List<int[]> supportedRanges = new ArrayList<>(); addRange(supportedRanges, 15000, 15000); addRange(supportedRanges, 10000, 30000); @@ -329,7 +343,7 @@ public class ShadowCamera { } @Implementation - public List<Integer> getSupportedPreviewFrameRates() { + protected List<Integer> getSupportedPreviewFrameRates() { List<Integer> supportedRates = new ArrayList<>(); supportedRates.add(10); supportedRates.add(15); @@ -338,11 +352,13 @@ public class ShadowCamera { } @Implementation - public List<Camera.Size> getSupportedPreviewSizes() { - List<Camera.Size> supportedSizes = new ArrayList<>(); - addSize(supportedSizes, 320, 240); - addSize(supportedSizes, 640, 480); - return supportedSizes; + protected List<Camera.Size> getSupportedPreviewSizes() { + if (supportedPreviewSizes == null) { + initSupportedPreviewSizes(); + addSupportedPreviewSize(320, 240); + addSupportedPreviewSize(640, 480); + } + return supportedPreviewSizes; } public void setSupportedFocusModes(String... focusModes) { @@ -350,83 +366,102 @@ public class ShadowCamera { } @Implementation - public List<String> getSupportedFocusModes() { + protected List<String> getSupportedFocusModes() { return supportedFocusModes; } @Implementation - public String getFocusMode() { + protected String getFocusMode() { return focusMode; } @Implementation - public void setFocusMode(String focusMode) { + protected void setFocusMode(String focusMode) { this.focusMode = focusMode; } @Implementation - public void setPictureSize(int width, int height) { + protected void setPictureSize(int width, int height) { pictureWidth = width; pictureHeight = height; } @Implementation - public void setPreviewFormat(int pixel_format) { + protected void setPreviewFormat(int pixel_format) { previewFormat = pixel_format; } @Implementation - public void setPreviewFpsRange(int min, int max) { + protected void setPreviewFpsRange(int min, int max) { previewFpsMin = min; previewFpsMax = max; } @Implementation - public void setPreviewFrameRate(int fps) { + protected void setPreviewFrameRate(int fps) { previewFps = fps; } @Implementation - public void setPreviewSize(int width, int height) { + protected void setPreviewSize(int width, int height) { previewWidth = width; previewHeight = height; } @Implementation - public void setRecordingHint(boolean recordingHint) { + protected void setRecordingHint(boolean recordingHint) { // Do nothing - this prevents an NPE in the SDK code } @Implementation - public void setRotation(int rotation) { + protected void setRotation(int rotation) { // Do nothing - this prevents an NPE in the SDK code } @Implementation - public int getMinExposureCompensation() { + protected int getMinExposureCompensation() { return -6; } @Implementation - public int getMaxExposureCompensation() { + protected int getMaxExposureCompensation() { return 6; } @Implementation - public float getExposureCompensationStep() { + protected float getExposureCompensationStep() { return 0.5f; } @Implementation - public int getExposureCompensation() { + protected int getExposureCompensation() { return exposureCompensation; } @Implementation - public void setExposureCompensation(int compensation) { + protected void setExposureCompensation(int compensation) { exposureCompensation = compensation; } + public void setSupportedFlashModes(String... flashModes) { + supportedFlashModes = Arrays.asList(flashModes); + } + + @Implementation + protected List<String> getSupportedFlashModes() { + return supportedFlashModes; + } + + @Implementation + protected String getFlashMode() { + return flashMode; + } + + @Implementation + protected void setFlashMode(String flashMode) { + this.flashMode = flashMode; + } + public int getPreviewWidth() { return previewWidth; } @@ -456,7 +491,6 @@ public class ShadowCamera { range[1] = max; ranges.add(range); } - } @Implements(Camera.Size.class) @@ -464,7 +498,7 @@ public class ShadowCamera { @RealObject private Camera.Size realCameraSize; @Implementation - public void __constructor__(Camera camera, int width, int height) { + protected void __constructor__(Camera camera, int width, int height) { realCameraSize.width = width; realCameraSize.height = height; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCameraCharacteristics.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCameraCharacteristics.java new file mode 100644 index 000000000..e023a810f --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCameraCharacteristics.java @@ -0,0 +1,39 @@ +package org.robolectric.shadows; + +import android.annotation.Nullable; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraCharacteristics.Key; +import android.os.Build.VERSION_CODES; +import com.google.common.base.Preconditions; +import java.util.HashMap; +import java.util.Map; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.util.ReflectionHelpers; + +@Implements(value = CameraCharacteristics.class, minSdk = VERSION_CODES.LOLLIPOP) +public class ShadowCameraCharacteristics { + + private final Map<Key<?>, Object> charactersKeyToValue = new HashMap<>(); + + /** Convenience method which returns a new instance of {@link CameraCharacteristics}. */ + public static CameraCharacteristics newCameraCharacteristics() { + return ReflectionHelpers.callConstructor(CameraCharacteristics.class); + } + + @Implementation + @Nullable + protected <T> T get(Key<T> key) { + return (T) charactersKeyToValue.get(key); + } + + /** + * Sets the value for a given key. + * + * @throws IllegalArgumentException if there's an existing value for the key. + */ + public <T> void set(Key<T> key, Object value) { + Preconditions.checkArgument(!charactersKeyToValue.containsKey(key)); + charactersKeyToValue.put(key, value); + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCameraManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCameraManager.java new file mode 100644 index 000000000..faecdfaa6 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCameraManager.java @@ -0,0 +1,52 @@ +package org.robolectric.shadows; + +import android.annotation.NonNull; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraManager; +import android.os.Build.VERSION_CODES; +import com.google.common.base.Preconditions; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(value = CameraManager.class, minSdk = VERSION_CODES.LOLLIPOP) +public class ShadowCameraManager { + + // LinkedHashMap used to ensure getCameraIdList returns ids in the order in which they were added + private final Map<String, CameraCharacteristics> cameraIdToCharacteristics = + new LinkedHashMap<>(); + + @Implementation + @NonNull + protected String[] getCameraIdList() throws CameraAccessException { + Set<String> cameraIds = cameraIdToCharacteristics.keySet(); + return cameraIds.toArray(new String[0]); + } + + @Implementation + @NonNull + protected CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId) { + Preconditions.checkNotNull(cameraId); + CameraCharacteristics characteristics = cameraIdToCharacteristics.get(cameraId); + Preconditions.checkArgument(characteristics != null); + return characteristics; + } + + /** + * Adds the given cameraId and characteristics to this shadow. + * + * <p>The result from {@link #getCameraIdList()} will be in the order in which cameras were added. + * + * @throws IllegalArgumentException if there's already an existing camera with the given id. + */ + public void addCamera(@NonNull String cameraId, @NonNull CameraCharacteristics characteristics) { + Preconditions.checkNotNull(cameraId); + Preconditions.checkNotNull(characteristics); + Preconditions.checkArgument(!cameraIdToCharacteristics.containsKey(cameraId)); + + cameraIdToCharacteristics.put(cameraId, characteristics); + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCanvas.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCanvas.java index 497bf610e..d308315c7 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCanvas.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCanvas.java @@ -54,7 +54,7 @@ public class ShadowCanvas { } @Implementation - public void __constructor__(Bitmap bitmap) { + protected void __constructor__(Bitmap bitmap) { this.targetBitmap = bitmap; } @@ -69,12 +69,12 @@ public class ShadowCanvas { } @Implementation - public void setBitmap(Bitmap bitmap) { + protected void setBitmap(Bitmap bitmap) { targetBitmap = bitmap; } @Implementation - public void drawText(String text, float x, float y, Paint paint) { + protected void drawText(String text, float x, float y, Paint paint) { drawnTextEventHistory.add(new TextHistoryEvent(x, y, paint, text)); } @@ -95,42 +95,42 @@ public class ShadowCanvas { } @Implementation - public void translate(float x, float y) { + protected void translate(float x, float y) { this.translateX = x; this.translateY = y; } @Implementation - public void scale(float sx, float sy) { + protected void scale(float sx, float sy) { this.scaleX = sx; this.scaleY = sy; } @Implementation - public void scale(float sx, float sy, float px, float py) { + protected void scale(float sx, float sy, float px, float py) { this.scaleX = sx; this.scaleY = sy; } @Implementation - public void drawPaint(Paint paint) { + protected void drawPaint(Paint paint) { drawnPaint = paint; } @Implementation - public void drawColor(int color) { + protected void drawColor(int color) { appendDescription("draw color " + color); } @Implementation - public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { + protected void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { describeBitmap(bitmap, paint); int x = (int) (left + translateX); int y = (int) (top + translateY); if (x != 0 || y != 0) { appendDescription(" at (" + x + "," + y + ")"); - } + } if (scaleX != 1 && scaleY != 1) { appendDescription(" scaled by (" + scaleX + "," + scaleY + ")"); @@ -138,7 +138,7 @@ public class ShadowCanvas { } @Implementation - public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { + protected void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) { describeBitmap(bitmap, paint); StringBuilder descriptionBuilder = new StringBuilder(); @@ -154,7 +154,7 @@ public class ShadowCanvas { } @Implementation - public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { + protected void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) { describeBitmap(bitmap, paint); StringBuilder descriptionBuilder = new StringBuilder(); @@ -170,7 +170,7 @@ public class ShadowCanvas { } @Implementation - public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { + protected void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { describeBitmap(bitmap, paint); ShadowMatrix shadowMatrix = Shadow.extract(matrix); @@ -178,7 +178,7 @@ public class ShadowCanvas { } @Implementation - public void drawPath(Path path, Paint paint) { + protected void drawPath(Path path, Paint paint) { pathPaintEvents.add(new PathPaintHistoryEvent(new Path(path), new Paint(paint))); separateLines(); @@ -187,34 +187,39 @@ public class ShadowCanvas { } @Implementation - public void drawCircle(float cx, float cy, float radius, Paint paint) { + protected void drawCircle(float cx, float cy, float radius, Paint paint) { circlePaintEvents.add(new CirclePaintHistoryEvent(cx, cy, radius, paint)); } @Implementation - public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) { + protected void drawArc( + RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) { arcPaintEvents.add(new ArcPaintHistoryEvent(oval, startAngle, sweepAngle, useCenter, paint)); } @Implementation - public void drawRect(float left, float top, float right, float bottom, Paint paint) { + protected void drawRect(float left, float top, float right, float bottom, Paint paint) { rectPaintEvents.add(new RectPaintHistoryEvent(left, top, right, bottom, paint)); } @Implementation - public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) { + protected void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) { linePaintEvents.add(new LinePaintHistoryEvent(startX, startY, stopX, stopY, paint)); } @Implementation - public void drawOval(RectF oval, Paint paint) { + protected void drawOval(RectF oval, Paint paint) { ovalPaintEvents.add(new OvalPaintHistoryEvent(oval, paint)); } @Implementation - public void restore() { + protected int save() { + return 1; } + @Implementation + protected void restore() {} + private void describeBitmap(Bitmap bitmap, Paint paint) { separateLines(); @@ -313,12 +318,12 @@ public class ShadowCanvas { } @Implementation - public int getWidth() { + protected int getWidth() { return width; } @Implementation - public int getHeight() { + protected int getHeight() { return height; } @@ -444,7 +449,7 @@ public class ShadowCanvas { public final Paint paint; public ArcPaintHistoryEvent(RectF oval, float startAngle, float sweepAngle, boolean useCenter, - Paint paint) { + Paint paint) { this.oval = oval; this.startAngle = startAngle; this.sweepAngle = sweepAngle; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCaptioningManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCaptioningManager.java index c41a73c34..04977beb5 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCaptioningManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCaptioningManager.java @@ -1,6 +1,9 @@ package org.robolectric.shadows; +import android.annotation.NonNull; +import android.util.ArraySet; import android.view.accessibility.CaptioningManager; +import android.view.accessibility.CaptioningManager.CaptioningChangeListener; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -10,6 +13,8 @@ public class ShadowCaptioningManager { private float fontScale = 1; private boolean isEnabled = false; + private final ArraySet<CaptioningChangeListener> listeners = new ArraySet<>(); + /** Returns 1.0 as default or the most recent value passed to {@link #setFontScale()} */ @Implementation(minSdk = 19) protected float getFontScale() { @@ -19,6 +24,10 @@ public class ShadowCaptioningManager { /** Sets the value to be returned by {@link CaptioningManager#getFontScale()} */ public void setFontScale(float fontScale) { this.fontScale = fontScale; + + for (CaptioningChangeListener captioningChangeListener : listeners) { + captioningChangeListener.onFontScaleChanged(fontScale); + } } /** Returns false or the most recent value passed to {@link #setEnabled(boolean)} */ @@ -31,4 +40,14 @@ public class ShadowCaptioningManager { public void setEnabled(boolean isEnabled) { this.isEnabled = isEnabled; } + + @Implementation(minSdk = 19) + protected void addCaptioningChangeListener(@NonNull CaptioningChangeListener listener) { + listeners.add(listener); + } + + @Implementation(minSdk = 19) + protected void removeCaptioningChangeListener(@NonNull CaptioningChangeListener listener) { + listeners.remove(listener); + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCarrierConfigManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCarrierConfigManager.java new file mode 100644 index 000000000..62f748544 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCarrierConfigManager.java @@ -0,0 +1,36 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.M; + +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.util.SparseArray; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(value = CarrierConfigManager.class, minSdk = M) +public class ShadowCarrierConfigManager { + + private SparseArray<PersistableBundle> bundles = new SparseArray<>(); + + /** + * Returns {@link android.os.PersistableBundle} previously set by {@link #setConfigForSubId(int)}, + * or default values for an invalid {@code subId}. + */ + @Implementation + protected PersistableBundle getConfigForSubId(int subId) { + PersistableBundle persistableBundle = bundles.get(subId); + if (persistableBundle == null) { + return new PersistableBundle(); + } + return persistableBundle; + } + + /** + * Sets that the {@code config} PersistableBundle for a particular {@code subId}; controls the + * return value of {@link CarrierConfigManager#getConfigForSubId()}. + */ + public void setConfigForSubId(int subId, PersistableBundle config) { + bundles.put(subId, config); + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowChoreographer.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowChoreographer.java index 93f01bc1f..4dde1fd46 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowChoreographer.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowChoreographer.java @@ -70,7 +70,7 @@ public class ShadowChoreographer { } @Implementation - public static Choreographer getInstance() { + protected static Choreographer getInstance() { return instance.get(); } @@ -82,23 +82,24 @@ public class ShadowChoreographer { * AnimationHandler would result in endless looping (the execution of the task results in a new * animation task created and scheduled to the front of the event loop queue). * - * To prevent endless looping, a test may call {@link #setPostCallbackDelay(int)} to specify a + * <p>To prevent endless looping, a test may call {@link #setPostCallbackDelay(int)} to specify a * small delay when animation is scheduled. * * @see #setPostCallbackDelay(int) */ @Implementation - public void postCallback(int callbackType, Runnable action, Object token) { + protected void postCallback(int callbackType, Runnable action, Object token) { postCallbackDelayed(callbackType, action, token, postCallbackDelayMillis); } @Implementation - public void postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis) { + protected void postCallbackDelayed( + int callbackType, Runnable action, Object token, long delayMillis) { handler.postDelayed(action, delayMillis); } @Implementation - public void removeCallbacks(int callbackType, Runnable action, Object token) { + protected void removeCallbacks(int callbackType, Runnable action, Object token) { handler.removeCallbacks(action, token); } @@ -110,18 +111,18 @@ public class ShadowChoreographer { * AnimationHandler would result in endless looping (the execution of the task results in a new * animation task created and scheduled to the front of the event loop queue). * - * To prevent endless looping, a test may call {@link #setPostFrameCallbackDelay(int)} to + * <p>To prevent endless looping, a test may call {@link #setPostFrameCallbackDelay(int)} to * specify a small delay when animation is scheduled. * * @see #setPostCallbackDelay(int) */ @Implementation - public void postFrameCallback(final FrameCallback callback) { + protected void postFrameCallback(final FrameCallback callback) { postFrameCallbackDelayed(callback, postFrameCallbackDelayMillis); } @Implementation - public void postFrameCallbackDelayed(final FrameCallback callback, long delayMillis) { + protected void postFrameCallbackDelayed(final FrameCallback callback, long delayMillis) { handler.postAtTime(new Runnable() { @Override public void run() { callback.doFrame(getFrameTimeNanos()); @@ -130,12 +131,12 @@ public class ShadowChoreographer { } @Implementation - public void removeFrameCallback(FrameCallback callback) { + protected void removeFrameCallback(FrameCallback callback) { handler.removeCallbacksAndMessages(callback); } @Implementation - public long getFrameTimeNanos() { + protected long getFrameTimeNanos() { final long now = nanoTime; nanoTime += ShadowChoreographer.FRAME_INTERVAL; return now; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowClipboardManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowClipboardManager.java index 33f75397e..748d9439c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowClipboardManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowClipboardManager.java @@ -24,7 +24,7 @@ public class ShadowClipboardManager { private ClipData clip; @Implementation - public void setPrimaryClip(ClipData clip) { + protected void setPrimaryClip(ClipData clip) { if (getApiLevel() >= N) { if (clip != null) { clip.prepareToLeaveProcess(true); @@ -43,37 +43,37 @@ public class ShadowClipboardManager { } @Implementation - public ClipData getPrimaryClip() { + protected ClipData getPrimaryClip() { return clip; } @Implementation - public ClipDescription getPrimaryClipDescription() { + protected ClipDescription getPrimaryClipDescription() { return clip == null ? null : clip.getDescription(); } @Implementation - public boolean hasPrimaryClip() { + protected boolean hasPrimaryClip() { return clip != null; } @Implementation - public void addPrimaryClipChangedListener(OnPrimaryClipChangedListener listener) { + protected void addPrimaryClipChangedListener(OnPrimaryClipChangedListener listener) { listeners.add(listener); } @Implementation - public void removePrimaryClipChangedListener(OnPrimaryClipChangedListener listener) { + protected void removePrimaryClipChangedListener(OnPrimaryClipChangedListener listener) { listeners.remove(listener); } @Implementation - public void setText(CharSequence text) { + protected void setText(CharSequence text) { setPrimaryClip(ClipData.newPlainText(null, text)); } @Implementation - public boolean hasText() { + protected boolean hasText() { CharSequence text = directlyOn(realClipboardManager, ClipboardManager.class).getText(); return text != null && text.length() > 0; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColor.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColor.java index eb7d32183..89609cc52 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColor.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColor.java @@ -9,12 +9,12 @@ public class ShadowColor { /** * This is implemented in native code in the Android SDK. * - * Since HSV == HSB then the implementation from {@link java.awt.Color} can be used, - * with a small adjustment to the representation of the hue. + * <p>Since HSV == HSB then the implementation from {@link java.awt.Color} can be used, with a + * small adjustment to the representation of the hue. * - * {@link java.awt.Color} represents hue as 0..1 (where 1 == 100% == 360 degrees), - * while {@link android.graphics.Color} represents hue as 0..360 degrees. The correct hue - * can be calculated by multiplying with 360. + * <p>{@link java.awt.Color} represents hue as 0..1 (where 1 == 100% == 360 degrees), while {@link + * android.graphics.Color} represents hue as 0..360 degrees. The correct hue can be calculated by + * multiplying with 360. * * @param red Red component * @param green Green component @@ -22,13 +22,13 @@ public class ShadowColor { * @param hsv Array to store HSV components */ @Implementation - public static void RGBToHSV(int red, int green, int blue, float hsv[]) { + protected static void RGBToHSV(int red, int green, int blue, float hsv[]) { java.awt.Color.RGBtoHSB(red, green, blue, hsv); hsv[0] = hsv[0] * 360; } @Implementation - public static int HSVToColor(int alpha, float hsv[]) { + protected static int HSVToColor(int alpha, float hsv[]) { int rgb = java.awt.Color.HSBtoRGB(hsv[0] / 360, hsv[1], hsv[2]); return Color.argb(alpha, Color.red(rgb), Color.green(rgb), Color.blue(rgb)); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColorMatrixColorFilter.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColorMatrixColorFilter.java index 147fdc4fa..2016601f3 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColorMatrixColorFilter.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowColorMatrixColorFilter.java @@ -11,12 +11,12 @@ public class ShadowColorMatrixColorFilter { private ColorMatrix matrix; @Implementation - public void __constructor__(ColorMatrix matrix) { + protected void __constructor__(ColorMatrix matrix) { this.matrix = matrix; } @Implementation - public void __constructor__(float[] array) { + protected void __constructor__(float[] array) { this.matrix = new ColorMatrix(array); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCompoundButton.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCompoundButton.java index bc1e58c6a..a8357d8cc 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCompoundButton.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCompoundButton.java @@ -17,13 +17,13 @@ public class ShadowCompoundButton extends ShadowTextView { private Drawable buttonDrawable; @Implementation - public void setButtonDrawable(int buttonDrawableId) { + protected void setButtonDrawable(int buttonDrawableId) { this.buttonDrawableId = buttonDrawableId; directlyOn(realObject, CompoundButton.class, "setButtonDrawable", from(int.class, buttonDrawableId)); } @Implementation - public void setButtonDrawable(Drawable buttonDrawable) { + protected void setButtonDrawable(Drawable buttonDrawable) { this.buttonDrawable = buttonDrawable; directlyOn(realObject, CompoundButton.class, "setButtonDrawable", from(Drawable.class, buttonDrawable)); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowConnectivityManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowConnectivityManager.java index aaed90052..79140ba27 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowConnectivityManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowConnectivityManager.java @@ -1,14 +1,19 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.KITKAT; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.os.Build.VERSION_CODES.M; +import static android.os.Build.VERSION_CODES.N; +import static android.os.Build.VERSION_CODES.O; import static org.robolectric.RuntimeEnvironment.getApiLevel; import android.net.ConnectivityManager; import android.net.ConnectivityManager.OnNetworkActiveListener; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; +import android.os.Handler; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -38,6 +43,8 @@ public class ShadowConnectivityManager { private HashSet<ConnectivityManager.OnNetworkActiveListener> onNetworkActiveListeners = new HashSet<>(); private Map<Network, Boolean> reportedNetworkConnectivity = new HashMap<>(); + private Map<Network, NetworkCapabilities> networkCapabilitiesMap = new HashMap<>(); + private String captivePortalServerUrl = "http://10.0.0.2"; public ShadowConnectivityManager() { NetworkInfo wifi = ShadowNetworkInfo.newInstance(NetworkInfo.DetailedState.DISCONNECTED, @@ -72,7 +79,16 @@ public class ShadowConnectivityManager { } @Implementation(minSdk = LOLLIPOP) - public void registerNetworkCallback(NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback) { + protected void registerNetworkCallback( + NetworkRequest request, ConnectivityManager.NetworkCallback networkCallback) { + registerNetworkCallback(request, networkCallback, null); + } + + @Implementation(minSdk = O) + protected void registerNetworkCallback( + NetworkRequest request, + ConnectivityManager.NetworkCallback networkCallback, + Handler handler) { networkCallbacks.add(networkCallback); } @@ -83,7 +99,7 @@ public class ShadowConnectivityManager { } @Implementation(minSdk = LOLLIPOP) - public void unregisterNetworkCallback (ConnectivityManager.NetworkCallback networkCallback) { + protected void unregisterNetworkCallback(ConnectivityManager.NetworkCallback networkCallback) { if (networkCallback == null) { throw new IllegalArgumentException("Invalid NetworkCallback"); } @@ -93,7 +109,7 @@ public class ShadowConnectivityManager { } @Implementation - public NetworkInfo getActiveNetworkInfo() { + protected NetworkInfo getActiveNetworkInfo() { return activeNetworkInfo; } @@ -102,7 +118,7 @@ public class ShadowConnectivityManager { * @see #setNetworkInfo(int, NetworkInfo) */ @Implementation(minSdk = M) - public Network getActiveNetwork() { + protected Network getActiveNetwork() { if (defaultNetworkActive) { return netIdToNetwork.get(getActiveNetworkInfo().getType()); } @@ -114,7 +130,7 @@ public class ShadowConnectivityManager { * @see #setNetworkInfo(int, NetworkInfo) */ @Implementation - public NetworkInfo[] getAllNetworkInfo() { + protected NetworkInfo[] getAllNetworkInfo() { // todo(xian): is `defaultNetworkActive` really relevant here? if (defaultNetworkActive) { return networkTypeToNetworkInfo @@ -125,46 +141,49 @@ public class ShadowConnectivityManager { } @Implementation - public NetworkInfo getNetworkInfo(int networkType) { + protected NetworkInfo getNetworkInfo(int networkType) { return networkTypeToNetworkInfo.get(networkType); } @Implementation(minSdk = LOLLIPOP) - public NetworkInfo getNetworkInfo(Network network) { + protected NetworkInfo getNetworkInfo(Network network) { + if (network == null) { + return null; + } ShadowNetwork shadowNetwork = Shadow.extract(network); return netIdToNetworkInfo.get(shadowNetwork.getNetId()); } @Implementation(minSdk = LOLLIPOP) - public Network[] getAllNetworks() { + protected Network[] getAllNetworks() { return netIdToNetwork.values().toArray(new Network[netIdToNetwork.size()]); } @Implementation - public boolean getBackgroundDataSetting() { + protected boolean getBackgroundDataSetting() { return backgroundDataSetting; } @Implementation - public void setNetworkPreference(int preference) { + protected void setNetworkPreference(int preference) { networkPreference = preference; } @Implementation - public int getNetworkPreference() { + protected int getNetworkPreference() { return networkPreference; } /** - * Counts {@link ConnectivityManager#TYPE_MOBILE} networks as metered. - * Other types will be considered unmetered. + * Counts {@link ConnectivityManager#TYPE_MOBILE} networks as metered. Other types will be + * considered unmetered. * * @return `true` if the active network is metered, otherwise `false`. * @see #setActiveNetworkInfo(NetworkInfo) * @see #setDefaultNetworkActive(boolean) */ @Implementation - public boolean isActiveNetworkMetered() { + protected boolean isActiveNetworkMetered() { if (defaultNetworkActive && activeNetworkInfo != null) { return activeNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE; } else { @@ -173,13 +192,13 @@ public class ShadowConnectivityManager { } @Implementation(minSdk = M) - public boolean bindProcessToNetwork(Network network) { + protected boolean bindProcessToNetwork(Network network) { processBoundNetwork = network; return true; } @Implementation(minSdk = M) - public Network getBoundNetworkForProcess() { + protected Network getBoundNetworkForProcess() { return processBoundNetwork; } @@ -187,6 +206,23 @@ public class ShadowConnectivityManager { networkTypeToNetworkInfo.put(networkType, networkInfo); } + /** + * Returns the captive portal URL previously set with {@link #setCaptivePortalServerUrl}. + */ + @Implementation(minSdk = N) + protected String getCaptivePortalServerUrl() { + return captivePortalServerUrl; + } + + /** + * Sets the captive portal URL, which will be returned in {@link #getCaptivePortalServerUrl}. + * + * @param captivePortalServerUrl the url of captive portal. + */ + public void setCaptivePortalServerUrl(String captivePortalServerUrl) { + this.captivePortalServerUrl = captivePortalServerUrl; + } + @HiddenApi @Implementation public void setBackgroundDataSetting(boolean b) { backgroundDataSetting = b; @@ -298,4 +334,37 @@ public class ShadowConnectivityManager { protected void reportNetworkConnectivity(Network network, boolean hasConnectivity) { reportedNetworkConnectivity.put(network, new Boolean(hasConnectivity)); } + + /** + * Gets the network capabilities of a given {@link Network}. + * + * @param network The {@link Network} object identifying the network in question. + * @return The {@link android.net.NetworkCapabilities} for the network. + * @see #setNetworkCapabilities(Network, NetworkCapabilities) + */ + @Implementation(minSdk = LOLLIPOP) + protected NetworkCapabilities getNetworkCapabilities(Network network) { + return networkCapabilitiesMap.get(network); + } + + /** + * Sets network capability and affects the result of {@link + * ConnectivityManager#getNetworkCapabilities(Network)} + * + * @param network The {@link Network} object identifying the network in question. + * @param networkCapabilities The {@link android.net.NetworkCapabilities} for the network. + */ + public void setNetworkCapabilities(Network network, NetworkCapabilities networkCapabilities) { + networkCapabilitiesMap.put(network, networkCapabilities); + } + + /** + * Sets the value for enabling/disabling airplane mode + * + * @param enable new status for airplane mode + */ + @Implementation(minSdk = KITKAT) + protected void setAirplaneMode(boolean enable) { + ShadowSettings.setAirplaneMode(enable); + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentObserver.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentObserver.java index 247a74978..c0b989c77 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentObserver.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentObserver.java @@ -13,12 +13,12 @@ public class ShadowContentObserver { private ContentObserver realObserver; @Implementation - public void dispatchChange(boolean selfChange, Uri uri) { + protected void dispatchChange(boolean selfChange, Uri uri) { realObserver.onChange(selfChange, uri); } @Implementation - public void dispatchChange(boolean selfChange) { + protected void dispatchChange(boolean selfChange) { realObserver.onChange(selfChange); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProvider.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProvider.java index 33d8dbb97..fa713eb3f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProvider.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProvider.java @@ -19,7 +19,7 @@ public class ShadowContentProvider { } @Implementation(minSdk = KITKAT) - public String getCallingPackage() { + protected String getCallingPackage() { if (callingPackage != null) { return callingPackage; } else { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProviderClient.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProviderClient.java index 2b7ee24f1..ce4ec846d 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProviderClient.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProviderClient.java @@ -6,9 +6,7 @@ import android.content.ContentProvider; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentProviderResult; -import android.content.ContentResolver; import android.content.ContentValues; -import android.content.IContentProvider; import android.content.OperationApplicationException; import android.content.res.AssetFileDescriptor; import android.database.Cursor; @@ -32,80 +30,86 @@ public class ShadowContentProviderClient { private ContentProvider provider; @Implementation(minSdk = JELLY_BEAN_MR1) - public Bundle call(String method, String arg, Bundle extras) throws RemoteException { + protected Bundle call(String method, String arg, Bundle extras) throws RemoteException { return provider.call(method, arg, extras); } @Implementation - public String getType(Uri uri) throws RemoteException { + protected String getType(Uri uri) throws RemoteException { return provider.getType(uri); } @Implementation - public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { + protected String[] getStreamTypes(Uri uri, String mimeTypeFilter) { return provider.getStreamTypes(uri, mimeTypeFilter); } @Implementation - public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, - String sortOrder) throws RemoteException { + protected Cursor query( + Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder) + throws RemoteException { return provider.query(url, projection, selection, selectionArgs, sortOrder); } @Implementation - public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, - String sortOrder, CancellationSignal cancellationSignal) throws RemoteException { + protected Cursor query( + Uri url, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder, + CancellationSignal cancellationSignal) + throws RemoteException { return provider.query(url, projection, selection, selectionArgs, sortOrder, cancellationSignal); } @Implementation - public Uri insert(Uri url, ContentValues initialValues) throws RemoteException { + protected Uri insert(Uri url, ContentValues initialValues) throws RemoteException { return provider.insert(url, initialValues); } @Implementation - public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException { + protected int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException { return provider.bulkInsert(url, initialValues); } @Implementation - public int delete(Uri url, String selection, String[] selectionArgs) - throws RemoteException { + protected int delete(Uri url, String selection, String[] selectionArgs) throws RemoteException { return provider.delete(url, selection, selectionArgs); } @Implementation - public int update(Uri url, ContentValues values, String selection, String[] selectionArgs) + protected int update(Uri url, ContentValues values, String selection, String[] selectionArgs) throws RemoteException { return provider.update(url, values, selection, selectionArgs); } @Implementation - public ParcelFileDescriptor openFile(Uri url, String mode) + protected ParcelFileDescriptor openFile(Uri url, String mode) throws RemoteException, FileNotFoundException { return provider.openFile(url, mode); } @Implementation - public AssetFileDescriptor openAssetFile(Uri url, String mode) + protected AssetFileDescriptor openAssetFile(Uri url, String mode) throws RemoteException, FileNotFoundException { return provider.openAssetFile(url, mode); } @Implementation - public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri, - String mimeType, Bundle opts) throws RemoteException, FileNotFoundException { + protected final AssetFileDescriptor openTypedAssetFileDescriptor( + Uri uri, String mimeType, Bundle opts) throws RemoteException, FileNotFoundException { return provider.openTypedAssetFile(uri, mimeType, opts); } @Implementation - public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) + protected ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws RemoteException, OperationApplicationException { return provider.applyBatch(operations); } @Implementation - public boolean release() { + protected boolean release() { synchronized (this) { if (released) { throw new IllegalStateException("Already released"); @@ -116,7 +120,7 @@ public class ShadowContentProviderClient { } @Implementation - public ContentProvider getLocalContentProvider() { + protected ContentProvider getLocalContentProvider() { return ContentProvider.coerceToLocalContentProvider(provider.getIContentProvider()); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProviderResult.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProviderResult.java index fa6db38ac..baf44dd13 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProviderResult.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentProviderResult.java @@ -12,7 +12,7 @@ public class ShadowContentProviderResult { @RealObject ContentProviderResult realResult; @Implementation - public void __constructor__(Uri uri) + protected void __constructor__(Uri uri) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field field = realResult.getClass().getField("uri"); @@ -21,7 +21,7 @@ public class ShadowContentProviderResult { } @Implementation - public void __constructor__(int count) + protected void __constructor__(int count) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field field = realResult.getClass().getField("count"); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentResolver.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentResolver.java index e90aae50f..1e6bd0c65 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentResolver.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentResolver.java @@ -51,7 +51,6 @@ import org.robolectric.util.ReflectionHelpers.ClassParameter; @SuppressLint("NewApi") public class ShadowContentResolver { private int nextDatabaseIdForInserts; - private int nextDatabaseIdForUpdates = -1; @RealObject ContentResolver realContentResolver; @@ -145,7 +144,7 @@ public class ShadowContentResolver { } @Implementation - public final InputStream openInputStream(final Uri uri) { + protected final InputStream openInputStream(final Uri uri) { InputStream inputStream = inputStreamMap.get(uri); if (inputStream != null) { return inputStream; @@ -155,7 +154,7 @@ public class ShadowContentResolver { } @Implementation - public final OutputStream openOutputStream(final Uri uri) { + protected final OutputStream openOutputStream(final Uri uri) { OutputStream outputStream = outputStreamMap.get(uri); if (outputStream != null) { return outputStream; @@ -174,18 +173,18 @@ public class ShadowContentResolver { } /** - * If a {@link ContentProvider} is registered for the given {@link Uri}, its - * {@link ContentProvider#insert(Uri, ContentValues)} method will be invoked. + * If a {@link ContentProvider} is registered for the given {@link Uri}, its {@link + * ContentProvider#insert(Uri, ContentValues)} method will be invoked. * - * Tests can verify that this method was called using {@link #getStatements()} or - * {@link #getInsertStatements()}. + * <p>Tests can verify that this method was called using {@link #getStatements()} or {@link + * #getInsertStatements()}. * - * If no appropriate {@link ContentProvider} is found, no action will be taken and - * a {@link Uri} including the incremented value set with - * {@link #setNextDatabaseIdForInserts(int)} will returned. + * <p>If no appropriate {@link ContentProvider} is found, no action will be taken and a {@link + * Uri} including the incremented value set with {@link #setNextDatabaseIdForInserts(int)} will + * returned. */ @Implementation - public final Uri insert(Uri url, ContentValues values) { + protected final Uri insert(Uri url, ContentValues values) { ContentProvider provider = getProvider(url); ContentValues valuesCopy = (values == null) ? null : new ContentValues(values); InsertStatement insertStatement = new InsertStatement(url, provider, valuesCopy); @@ -206,14 +205,11 @@ public class ShadowContentResolver { * Tests can verify that this method was called using {@link #getStatements()} or * {@link #getUpdateStatements()}. * - * If no appropriate {@link ContentProvider} is found, no action will be taken and - * the value set with {@link #setNextDatabaseIdForUpdates(int)} will be incremented and returned. - * - * *Note:* the return value in this case will be changed to {@code 1} in a future release of - * Robolectric. + * @return If no appropriate {@link ContentProvider} is found, no action will be taken and 1 will + * be returned. */ @Implementation - public int update(Uri uri, ContentValues values, String where, String[] selectionArgs) { + protected int update(Uri uri, ContentValues values, String where, String[] selectionArgs) { ContentProvider provider = getProvider(uri); ContentValues valuesCopy = (values == null) ? null : new ContentValues(values); UpdateStatement updateStatement = @@ -224,12 +220,12 @@ public class ShadowContentResolver { if (provider != null) { return provider.update(uri, values, where, selectionArgs); } else { - return nextDatabaseIdForUpdates == -1 ? 1 : ++nextDatabaseIdForUpdates; + return 1; } } @Implementation - public final Cursor query( + protected final Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { ContentProvider provider = getProvider(uri); if (provider != null) { @@ -246,7 +242,7 @@ public class ShadowContentResolver { } @Implementation - public Cursor query( + protected Cursor query( Uri uri, String[] projection, String selection, @@ -269,7 +265,7 @@ public class ShadowContentResolver { } @Implementation - public String getType(Uri uri) { + protected String getType(Uri uri) { ContentProvider provider = getProvider(uri); if (provider != null) { return provider.getType(uri); @@ -279,7 +275,7 @@ public class ShadowContentResolver { } @Implementation - public Bundle call(Uri uri, String method, String arg, Bundle extras) { + protected Bundle call(Uri uri, String method, String arg, Bundle extras) { ContentProvider cp = getProvider(uri); if (cp != null) { return cp.call(method, arg, extras); @@ -289,7 +285,7 @@ public class ShadowContentResolver { } @Implementation - public final ContentProviderClient acquireContentProviderClient(String name) { + protected final ContentProviderClient acquireContentProviderClient(String name) { ContentProvider provider = getProvider(name); if (provider == null) { return null; @@ -298,7 +294,7 @@ public class ShadowContentResolver { } @Implementation - public final ContentProviderClient acquireContentProviderClient(Uri uri) { + protected final ContentProviderClient acquireContentProviderClient(Uri uri) { ContentProvider provider = getProvider(uri); if (provider == null) { return null; @@ -307,7 +303,7 @@ public class ShadowContentResolver { } @Implementation - public final ContentProviderClient acquireUnstableContentProviderClient(String name) { + protected final ContentProviderClient acquireUnstableContentProviderClient(String name) { ContentProvider provider = getProvider(name); if (provider == null) { return null; @@ -316,7 +312,7 @@ public class ShadowContentResolver { } @Implementation - public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) { + protected final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) { ContentProvider provider = getProvider(uri); if (provider == null) { return null; @@ -337,17 +333,17 @@ public class ShadowContentResolver { } @Implementation - public final IContentProvider acquireProvider(String name) { + protected final IContentProvider acquireProvider(String name) { return acquireUnstableProvider(name); } @Implementation - public final IContentProvider acquireProvider(Uri uri) { + protected final IContentProvider acquireProvider(Uri uri) { return acquireUnstableProvider(uri); } @Implementation - public final IContentProvider acquireUnstableProvider(String name) { + protected final IContentProvider acquireUnstableProvider(String name) { ContentProvider cp = getProvider(name); if (cp != null) { return cp.getIContentProvider(); @@ -356,7 +352,7 @@ public class ShadowContentResolver { } @Implementation - public final IContentProvider acquireUnstableProvider(Uri uri) { + protected final IContentProvider acquireUnstableProvider(Uri uri) { ContentProvider cp = getProvider(uri); if (cp != null) { return cp.getIContentProvider(); @@ -365,17 +361,17 @@ public class ShadowContentResolver { } /** - * If a {@link ContentProvider} is registered for the given {@link Uri}, its - * {@link ContentProvider#delete(Uri, String, String[])} method will be invoked. + * If a {@link ContentProvider} is registered for the given {@link Uri}, its {@link + * ContentProvider#delete(Uri, String, String[])} method will be invoked. * - * Tests can verify that this method was called using {@link #getDeleteStatements()} - * or {@link #getDeletedUris()}. + * <p>Tests can verify that this method was called using {@link #getDeleteStatements()} or {@link + * #getDeletedUris()}. * - * If no appropriate {@link ContentProvider} is found, no action will be taken and - * {@code 1} will be returned. + * <p>If no appropriate {@link ContentProvider} is found, no action will be taken and {@code 1} + * will be returned. */ @Implementation - public final int delete(Uri url, String where, String[] selectionArgs) { + protected final int delete(Uri url, String where, String[] selectionArgs) { ContentProvider provider = getProvider(url); DeleteStatement deleteStatement = new DeleteStatement(url, provider, where, selectionArgs); @@ -390,17 +386,17 @@ public class ShadowContentResolver { } /** - * If a {@link ContentProvider} is registered for the given {@link Uri}, its - * {@link ContentProvider#bulkInsert(Uri, ContentValues[])} method will be invoked. + * If a {@link ContentProvider} is registered for the given {@link Uri}, its {@link + * ContentProvider#bulkInsert(Uri, ContentValues[])} method will be invoked. * - * Tests can verify that this method was called using {@link #getStatements()} or - * {@link #getInsertStatements()}. + * <p>Tests can verify that this method was called using {@link #getStatements()} or {@link + * #getInsertStatements()}. * - * If no appropriate {@link ContentProvider} is found, no action will be taken and - * the number of rows in {@code values} will be returned. + * <p>If no appropriate {@link ContentProvider} is found, no action will be taken and the number + * of rows in {@code values} will be returned. */ @Implementation - public final int bulkInsert(Uri url, ContentValues[] values) { + protected final int bulkInsert(Uri url, ContentValues[] values) { ContentProvider provider = getProvider(url); InsertStatement insertStatement = new InsertStatement(url, provider, values); @@ -415,7 +411,7 @@ public class ShadowContentResolver { } @Implementation - public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { + protected void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { notifiedUris.add(new NotifiedUri(uri, observer, syncToNetwork)); for (ContentObserverEntry entry : contentObservers) { @@ -429,12 +425,12 @@ public class ShadowContentResolver { } @Implementation - public void notifyChange(Uri uri, ContentObserver observer) { + protected void notifyChange(Uri uri, ContentObserver observer) { notifyChange(uri, observer, false); } @Implementation - public ContentProviderResult[] applyBatch( + protected ContentProviderResult[] applyBatch( String authority, ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { ContentProvider provider = getProvider(authority); @@ -447,7 +443,7 @@ public class ShadowContentResolver { } @Implementation - public static void requestSync(Account account, String authority, Bundle extras) { + protected static void requestSync(Account account, String authority, Bundle extras) { validateSyncExtrasBundle(extras); Status status = getStatus(account, authority, true); status.syncRequests++; @@ -455,7 +451,7 @@ public class ShadowContentResolver { } @Implementation - public static void cancelSync(Account account, String authority) { + protected static void cancelSync(Account account, String authority) { Status status = getStatus(account, authority); if (status != null) { status.syncRequests = 0; @@ -470,34 +466,34 @@ public class ShadowContentResolver { } @Implementation - public static boolean isSyncActive(Account account, String authority) { + protected static boolean isSyncActive(Account account, String authority) { ShadowContentResolver.Status status = getStatus(account, authority); // TODO: this means a sync is *perpetually* active after one request return status != null && status.syncRequests > 0; } @Implementation - public static void setIsSyncable(Account account, String authority, int syncable) { + protected static void setIsSyncable(Account account, String authority, int syncable) { getStatus(account, authority, true).state = syncable; } @Implementation - public static int getIsSyncable(Account account, String authority) { + protected static int getIsSyncable(Account account, String authority) { return getStatus(account, authority, true).state; } @Implementation - public static boolean getSyncAutomatically(Account account, String authority) { + protected static boolean getSyncAutomatically(Account account, String authority) { return getStatus(account, authority, true).syncAutomatically; } @Implementation - public static void setSyncAutomatically(Account account, String authority, boolean sync) { + protected static void setSyncAutomatically(Account account, String authority, boolean sync) { getStatus(account, authority, true).syncAutomatically = sync; } @Implementation - public static void addPeriodicSync( + protected static void addPeriodicSync( Account account, String authority, Bundle extras, long pollFrequency) { validateSyncExtrasBundle(extras); removePeriodicSync(account, authority, extras); @@ -507,7 +503,7 @@ public class ShadowContentResolver { } @Implementation - public static void removePeriodicSync(Account account, String authority, Bundle extras) { + protected static void removePeriodicSync(Account account, String authority, Bundle extras) { validateSyncExtrasBundle(extras); Status status = getStatus(account, authority); if (status != null) { @@ -521,12 +517,12 @@ public class ShadowContentResolver { } @Implementation - public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) { + protected static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) { return getStatus(account, authority, true).syncs; } @Implementation - public static void validateSyncExtrasBundle(Bundle extras) { + protected static void validateSyncExtrasBundle(Bundle extras) { for (String key : extras.keySet()) { Object value = extras.get(key); if (value == null @@ -545,17 +541,17 @@ public class ShadowContentResolver { } @Implementation - public static void setMasterSyncAutomatically(boolean sync) { + protected static void setMasterSyncAutomatically(boolean sync) { masterSyncAutomatically = sync; } @Implementation - public static boolean getMasterSyncAutomatically() { + protected static boolean getMasterSyncAutomatically() { return masterSyncAutomatically; } @Implementation(minSdk = KITKAT) - public void takePersistableUriPermission(@NonNull Uri uri, int modeFlags) { + protected void takePersistableUriPermission(@NonNull Uri uri, int modeFlags) { Objects.requireNonNull(uri, "uri may not be null"); modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); @@ -583,7 +579,7 @@ public class ShadowContentResolver { } @Implementation(minSdk = KITKAT) - public void releasePersistableUriPermission(@NonNull Uri uri, int modeFlags) { + protected void releasePersistableUriPermission(@NonNull Uri uri, int modeFlags) { Objects.requireNonNull(uri, "uri may not be null"); modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); @@ -617,7 +613,8 @@ public class ShadowContentResolver { } @Implementation(minSdk = KITKAT) - public @NonNull List<UriPermission> getPersistedUriPermissions() { + @NonNull + protected List<UriPermission> getPersistedUriPermissions() { return uriPermissions; } @@ -703,21 +700,6 @@ public class ShadowContentResolver { } /** - * Set the value to be returned by - * {@link ContentResolver#update(Uri, ContentValues, String, String[])} when no appropriate - * {@link ContentProvider} can be found. - * - * @param nextId the number of rows to return - * @deprecated This method will be removed in Robolectric 3.5. Instead, {@code 1} will be - * returned. - */ - @Deprecated - @SuppressWarnings({"unused", "WeakerAccess"}) - public void setNextDatabaseIdForUpdates(int nextId) { - nextDatabaseIdForUpdates = nextId; - } - - /** * Returns the list of {@link InsertStatement}s, {@link UpdateStatement}s, and * {@link DeleteStatement}s invoked on this {@link ContentResolver}. * @@ -789,7 +771,7 @@ public class ShadowContentResolver { } @Implementation - public void registerContentObserver( + protected void registerContentObserver( Uri uri, boolean notifyForDescendents, ContentObserver observer) { if (uri == null || observer == null) { throw new NullPointerException(); @@ -798,13 +780,13 @@ public class ShadowContentResolver { } @Implementation(minSdk = JELLY_BEAN_MR1) - public void registerContentObserver( + protected void registerContentObserver( Uri uri, boolean notifyForDescendents, ContentObserver observer, int userHandle) { registerContentObserver(uri, notifyForDescendents, observer); } @Implementation - public void unregisterContentObserver(ContentObserver observer) { + protected void unregisterContentObserver(ContentObserver observer) { synchronized (contentObservers) { for (ContentObserverEntry entry : contentObservers) { if (entry.observer == observer) { @@ -824,12 +806,6 @@ public class ShadowContentResolver { ShadowContentResolver.syncAdapterTypes = syncAdapterTypes; } - /** @deprecated Do not use this method. */ - @Deprecated - public void clearContentObservers() { - contentObservers.clear(); - } - /** * Returns the content observers registered for updates under the given URI. * diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentUris.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentUris.java index dc04fe2bb..d0308826f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentUris.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContentUris.java @@ -9,12 +9,12 @@ import org.robolectric.annotation.Implements; public class ShadowContentUris { @Implementation - public static Uri withAppendedId(Uri contentUri, long id) { + protected static Uri withAppendedId(Uri contentUri, long id) { return Uri.withAppendedPath(contentUri, String.valueOf(id)); } @Implementation - public static long parseId(Uri contentUri) { + protected static long parseId(Uri contentUri) { if (!contentUri.isHierarchical()) { throw new UnsupportedOperationException(); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContextImpl.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContextImpl.java index d964c6897..5023cbaf0 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContextImpl.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowContextImpl.java @@ -51,7 +51,7 @@ public class ShadowContextImpl { @Implementation @Nullable - public Object getSystemService(String name) { + protected Object getSystemService(String name) { if (removedSystemServices.contains(name)) { return null; } @@ -78,7 +78,7 @@ public class ShadowContextImpl { } @Implementation - public void startIntentSender( + protected void startIntentSender( IntentSender intent, Intent fillInIntent, int flagsMask, @@ -90,22 +90,22 @@ public class ShadowContextImpl { } @Implementation - public ClassLoader getClassLoader() { + protected ClassLoader getClassLoader() { return this.getClass().getClassLoader(); } @Implementation - public int checkCallingPermission(String permission) { + protected int checkCallingPermission(String permission) { return checkPermission(permission, -1, -1); } @Implementation - public int checkCallingOrSelfPermission(String permission) { + protected int checkCallingOrSelfPermission(String permission) { return checkPermission(permission, -1, -1); } @Implementation - public ContentResolver getContentResolver() { + protected ContentResolver getContentResolver() { if (contentResolver == null) { contentResolver = new ContentResolver(realContextImpl) { @@ -137,24 +137,24 @@ public class ShadowContextImpl { } @Implementation - public void sendBroadcast(Intent intent) { + protected void sendBroadcast(Intent intent) { getShadowInstrumentation().sendBroadcastWithPermission(intent, null, realContextImpl); } @Implementation - public void sendBroadcast(Intent intent, String receiverPermission) { + protected void sendBroadcast(Intent intent, String receiverPermission) { getShadowInstrumentation() .sendBroadcastWithPermission(intent, receiverPermission, realContextImpl); } @Implementation - public void sendOrderedBroadcast(Intent intent, String receiverPermission) { + protected void sendOrderedBroadcast(Intent intent, String receiverPermission) { getShadowInstrumentation() .sendOrderedBroadcastWithPermission(intent, receiverPermission, realContextImpl); } @Implementation - public void sendOrderedBroadcast( + protected void sendOrderedBroadcast( Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, @@ -175,22 +175,22 @@ public class ShadowContextImpl { } @Implementation - public void sendStickyBroadcast(Intent intent) { + protected void sendStickyBroadcast(Intent intent) { getShadowInstrumentation().sendStickyBroadcast(intent, realContextImpl); } @Implementation - public int checkPermission(String permission, int pid, int uid) { + protected int checkPermission(String permission, int pid, int uid) { return getShadowInstrumentation().checkPermission(permission, pid, uid); } @Implementation - public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { + protected Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return getShadowInstrumentation().registerReceiver(receiver, filter, realContextImpl); } @Implementation - public Intent registerReceiver( + protected Intent registerReceiver( BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, @@ -200,7 +200,7 @@ public class ShadowContextImpl { } @Implementation(minSdk = JELLY_BEAN_MR1) - public Intent registerReceiverAsUser( + protected Intent registerReceiverAsUser( BroadcastReceiver receiver, UserHandle user, IntentFilter filter, @@ -212,27 +212,27 @@ public class ShadowContextImpl { } @Implementation - public void unregisterReceiver(BroadcastReceiver broadcastReceiver) { + protected void unregisterReceiver(BroadcastReceiver broadcastReceiver) { getShadowInstrumentation().unregisterReceiver(broadcastReceiver); } @Implementation - public ComponentName startService(Intent service) { + protected ComponentName startService(Intent service) { return getShadowInstrumentation().startService(service); } @Implementation(minSdk = O) - public ComponentName startForegroundService(Intent service) { + protected ComponentName startForegroundService(Intent service) { return getShadowInstrumentation().startService(service); } @Implementation - public boolean stopService(Intent name) { + protected boolean stopService(Intent name) { return getShadowInstrumentation().stopService(name); } @Implementation - public boolean bindService(Intent intent, final ServiceConnection serviceConnection, int i) { + protected boolean bindService(Intent intent, final ServiceConnection serviceConnection, int i) { return getShadowInstrumentation().bindService(intent, serviceConnection, i); } @@ -244,27 +244,27 @@ public class ShadowContextImpl { } @Implementation - public void unbindService(final ServiceConnection serviceConnection) { + protected void unbindService(final ServiceConnection serviceConnection) { getShadowInstrumentation().unbindService(serviceConnection); } @Implementation(minSdk = JELLY_BEAN_MR1) - public int getUserId() { + protected int getUserId() { return 0; } @Implementation - public File getExternalCacheDir() { + protected File getExternalCacheDir() { return Environment.getExternalStorageDirectory(); } @Implementation(maxSdk = JELLY_BEAN_MR2) - public File getExternalFilesDir(String type) { + protected File getExternalFilesDir(String type) { return Environment.getExternalStoragePublicDirectory(type); } @Implementation(minSdk = KITKAT) - public File[] getExternalFilesDirs(String type) { + protected File[] getExternalFilesDirs(String type) { return new File[] {Environment.getExternalStoragePublicDirectory(type)}; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieManager.java index b4422fd99..a44ecf519 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieManager.java @@ -17,7 +17,7 @@ public class ShadowCookieManager { } @Implementation - public static CookieManager getInstance() { + protected static CookieManager getInstance() { if (cookieManager == null) { cookieManager = new RoboCookieManager(); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieSyncManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieSyncManager.java index 7d8cae343..7bfe48d2f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieSyncManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCookieSyncManager.java @@ -12,7 +12,7 @@ public class ShadowCookieSyncManager extends ShadowWebSyncManager { private static CookieSyncManager sRef; @Implementation - public static synchronized CookieSyncManager createInstance(Context ctx) { + protected static synchronized CookieSyncManager createInstance(Context ctx) { if (sRef == null) { sRef = Shadow.newInstanceOf(CookieSyncManager.class); } @@ -20,7 +20,7 @@ public class ShadowCookieSyncManager extends ShadowWebSyncManager { } @Implementation - public static CookieSyncManager getInstance() { + protected static CookieSyncManager getInstance() { if (sRef == null) { throw new IllegalStateException("createInstance must be called first"); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCornerPathEffect.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCornerPathEffect.java index d28e1e6e3..3e4bf8ca2 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCornerPathEffect.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCornerPathEffect.java @@ -10,7 +10,7 @@ public class ShadowCornerPathEffect { private float radius; @Implementation - public void __constructor__(float radius) { + protected void __constructor__(float radius) { this.radius = radius; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCountDownTimer.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCountDownTimer.java index c01f1ae01..07d58d7f9 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCountDownTimer.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCountDownTimer.java @@ -14,20 +14,20 @@ public class ShadowCountDownTimer { @RealObject CountDownTimer countDownTimer; @Implementation - public void __constructor__(long millisInFuture, long countDownInterval) { + protected void __constructor__(long millisInFuture, long countDownInterval) { this.countDownInterval = countDownInterval; this.millisInFuture = millisInFuture; this.started = false; } @Implementation - public final synchronized CountDownTimer start() { + protected final synchronized CountDownTimer start() { started = true; return countDownTimer; } @Implementation - public final void cancel() { + protected final void cancel() { started = false; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWindow.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWindow.java index edd311ef3..996019f38 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWindow.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWindow.java @@ -23,27 +23,27 @@ public class ShadowCursorWindow { private static final WindowData WINDOW_DATA = new WindowData(); @Implementation - public static Number nativeCreate(String name, int cursorWindowSize) { + protected static Number nativeCreate(String name, int cursorWindowSize) { return castNativePtr(WINDOW_DATA.create(name, cursorWindowSize)); } @Implementation(maxSdk = KITKAT_WATCH) - public static void nativeDispose(int windowPtr) { + protected static void nativeDispose(int windowPtr) { nativeDispose((long) windowPtr); } @Implementation(minSdk = LOLLIPOP) - public static void nativeDispose(long windowPtr) { + protected static void nativeDispose(long windowPtr) { WINDOW_DATA.close(windowPtr); } @Implementation(maxSdk = KITKAT_WATCH) - public static byte[] nativeGetBlob(int windowPtr, int row, int column) { + protected static byte[] nativeGetBlob(int windowPtr, int row, int column) { return nativeGetBlob((long) windowPtr, row, column); } @Implementation(minSdk = LOLLIPOP) - public static byte[] nativeGetBlob(long windowPtr, int row, int column) { + protected static byte[] nativeGetBlob(long windowPtr, int row, int column) { Value value = WINDOW_DATA.get(windowPtr).value(row, column); switch (value.type) { @@ -61,12 +61,12 @@ public class ShadowCursorWindow { } @Implementation(maxSdk = KITKAT_WATCH) - public static String nativeGetString(int windowPtr, int row, int column) { + protected static String nativeGetString(int windowPtr, int row, int column) { return nativeGetString((long) windowPtr, row, column); } @Implementation(minSdk = LOLLIPOP) - public static String nativeGetString(long windowPtr, int row, int column) { + protected static String nativeGetString(long windowPtr, int row, int column) { Value val = WINDOW_DATA.get(windowPtr).value(row, column); if (val.type == Cursor.FIELD_TYPE_BLOB) { throw new android.database.sqlite.SQLiteException("Getting string when column is blob. Row " + row + ", col " + column); @@ -76,132 +76,132 @@ public class ShadowCursorWindow { } @Implementation(maxSdk = KITKAT_WATCH) - public static long nativeGetLong(int windowPtr, int row, int column) { + protected static long nativeGetLong(int windowPtr, int row, int column) { return nativeGetLong((long) windowPtr, row, column); } @Implementation(minSdk = LOLLIPOP) - public static long nativeGetLong(long windowPtr, int row, int column) { + protected static long nativeGetLong(long windowPtr, int row, int column) { return nativeGetNumber(windowPtr, row, column).longValue(); } @Implementation(maxSdk = KITKAT_WATCH) - public static double nativeGetDouble(int windowPtr, int row, int column) { + protected static double nativeGetDouble(int windowPtr, int row, int column) { return nativeGetDouble((long) windowPtr, row, column); } @Implementation(minSdk = LOLLIPOP) - public static double nativeGetDouble(long windowPtr, int row, int column) { + protected static double nativeGetDouble(long windowPtr, int row, int column) { return nativeGetNumber(windowPtr, row, column).doubleValue(); } @Implementation(maxSdk = KITKAT_WATCH) - public static int nativeGetType(int windowPtr, int row, int column) { + protected static int nativeGetType(int windowPtr, int row, int column) { return nativeGetType((long) windowPtr, row, column); } @Implementation(minSdk = LOLLIPOP) - public static int nativeGetType(long windowPtr, int row, int column) { + protected static int nativeGetType(long windowPtr, int row, int column) { return WINDOW_DATA.get(windowPtr).value(row, column).type; } @Implementation(maxSdk = KITKAT_WATCH) - public static void nativeClear(int windowPtr) { + protected static void nativeClear(int windowPtr) { nativeClear((long) windowPtr); } @Implementation(minSdk = LOLLIPOP) - public static void nativeClear(long windowPtr) { + protected static void nativeClear(long windowPtr) { WINDOW_DATA.clear(windowPtr); } @Implementation(maxSdk = KITKAT_WATCH) - public static int nativeGetNumRows(int windowPtr) { + protected static int nativeGetNumRows(int windowPtr) { return nativeGetNumRows((long) windowPtr); } @Implementation(minSdk = LOLLIPOP) - public static int nativeGetNumRows(long windowPtr) { + protected static int nativeGetNumRows(long windowPtr) { return WINDOW_DATA.get(windowPtr).numRows(); } @Implementation(maxSdk = KITKAT_WATCH) - public static boolean nativePutBlob(int windowPtr, byte[] value, int row, int column) { + protected static boolean nativePutBlob(int windowPtr, byte[] value, int row, int column) { return nativePutBlob((long) windowPtr, value, row, column); } @Implementation(minSdk = LOLLIPOP) - public static boolean nativePutBlob(long windowPtr, byte[] value, int row, int column) { + protected static boolean nativePutBlob(long windowPtr, byte[] value, int row, int column) { return WINDOW_DATA.get(windowPtr).putValue(new Value(value, Cursor.FIELD_TYPE_BLOB), row, column); } @Implementation(maxSdk = KITKAT_WATCH) - public static boolean nativePutString(int windowPtr, String value, int row, int column) { + protected static boolean nativePutString(int windowPtr, String value, int row, int column) { return nativePutString((long) windowPtr, value, row, column); } @Implementation(minSdk = LOLLIPOP) - public static boolean nativePutString(long windowPtr, String value, int row, int column) { + protected static boolean nativePutString(long windowPtr, String value, int row, int column) { return WINDOW_DATA.get(windowPtr).putValue(new Value(value, Cursor.FIELD_TYPE_STRING), row, column); } @Implementation(maxSdk = KITKAT_WATCH) - public static boolean nativePutLong(int windowPtr, long value, int row, int column) { + protected static boolean nativePutLong(int windowPtr, long value, int row, int column) { return nativePutLong((long) windowPtr, value, row, column); } @Implementation(minSdk = LOLLIPOP) - public static boolean nativePutLong(long windowPtr, long value, int row, int column) { + protected static boolean nativePutLong(long windowPtr, long value, int row, int column) { return WINDOW_DATA.get(windowPtr).putValue(new Value(value, Cursor.FIELD_TYPE_INTEGER), row, column); } @Implementation(maxSdk = KITKAT_WATCH) - public static boolean nativePutDouble(int windowPtr, double value, int row, int column) { + protected static boolean nativePutDouble(int windowPtr, double value, int row, int column) { return nativePutDouble((long) windowPtr, value, row, column); } @Implementation(minSdk = LOLLIPOP) - public static boolean nativePutDouble(long windowPtr, double value, int row, int column) { + protected static boolean nativePutDouble(long windowPtr, double value, int row, int column) { return WINDOW_DATA.get(windowPtr).putValue(new Value(value, Cursor.FIELD_TYPE_FLOAT), row, column); } @Implementation(maxSdk = KITKAT_WATCH) - public static boolean nativePutNull(int windowPtr, int row, int column) { + protected static boolean nativePutNull(int windowPtr, int row, int column) { return nativePutNull((long) windowPtr, row, column); } @Implementation(minSdk = LOLLIPOP) - public static boolean nativePutNull(long windowPtr, int row, int column) { + protected static boolean nativePutNull(long windowPtr, int row, int column) { return WINDOW_DATA.get(windowPtr).putValue(new Value(null, Cursor.FIELD_TYPE_NULL), row, column); } @Implementation(maxSdk = KITKAT_WATCH) - public static boolean nativeAllocRow(int windowPtr) { + protected static boolean nativeAllocRow(int windowPtr) { return nativeAllocRow((long) windowPtr); } @Implementation(minSdk = LOLLIPOP) - public static boolean nativeAllocRow(long windowPtr) { + protected static boolean nativeAllocRow(long windowPtr) { return WINDOW_DATA.get(windowPtr).allocRow(); } @Implementation(maxSdk = KITKAT_WATCH) - public static boolean nativeSetNumColumns(int windowPtr, int columnNum) { + protected static boolean nativeSetNumColumns(int windowPtr, int columnNum) { return nativeSetNumColumns((long) windowPtr, columnNum); } @Implementation(minSdk = LOLLIPOP) - public static boolean nativeSetNumColumns(long windowPtr, int columnNum) { + protected static boolean nativeSetNumColumns(long windowPtr, int columnNum) { return WINDOW_DATA.get(windowPtr).setNumColumns(columnNum); } @Implementation(maxSdk = KITKAT_WATCH) - public static String nativeGetName(int windowPtr) { + protected static String nativeGetName(int windowPtr) { return nativeGetName((long) windowPtr); } @Implementation(minSdk = LOLLIPOP) - public static String nativeGetName(long windowPtr) { + protected static String nativeGetName(long windowPtr) { return WINDOW_DATA.get(windowPtr).getName(); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWrapper.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWrapper.java index 163e70320..04623f10c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWrapper.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCursorWrapper.java @@ -19,7 +19,7 @@ public class ShadowCursorWrapper implements Cursor { private Cursor wrappedCursor; @Implementation - public void __constructor__(Cursor c) { + protected void __constructor__(Cursor c) { wrappedCursor = c; } @@ -229,7 +229,7 @@ public class ShadowCursorWrapper implements Cursor { } @Implementation - public Cursor getWrappedCursor() { + protected Cursor getWrappedCursor() { return wrappedCursor; } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateFormat.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateFormat.java index 5aa9fc8b5..c83020fb2 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateFormat.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDateFormat.java @@ -10,17 +10,17 @@ import org.robolectric.annotation.Implements; public class ShadowDateFormat { @Implementation - public static java.text.DateFormat getDateFormat(Context context) { - return new java.text.SimpleDateFormat("MMM-dd-yyyy", Locale.getDefault()); + protected static java.text.DateFormat getDateFormat(Context context) { + return new java.text.SimpleDateFormat("MMM-dd-yyyy", Locale.ROOT); } @Implementation - public static java.text.DateFormat getLongDateFormat(Context context) { - return new java.text.SimpleDateFormat("MMMM dd, yyyy", Locale.getDefault()); + protected static java.text.DateFormat getLongDateFormat(Context context) { + return new java.text.SimpleDateFormat("MMMM dd, yyyy", Locale.ROOT); } @Implementation - public static java.text.DateFormat getTimeFormat(Context context) { - return new java.text.SimpleDateFormat("HH:mm:ss", Locale.getDefault()); + protected static java.text.DateFormat getTimeFormat(Context context) { + return new java.text.SimpleDateFormat("HH:mm:ss", Locale.ROOT); } -}
\ No newline at end of file +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDatePickerDialog.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDatePickerDialog.java index 2841f0557..ffa5793ab 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDatePickerDialog.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDatePickerDialog.java @@ -23,8 +23,13 @@ public class ShadowDatePickerDialog extends ShadowAlertDialog { private DatePickerDialog.OnDateSetListener callBack; @Implementation(maxSdk = M) - public void __constructor__(Context context, int theme, DatePickerDialog.OnDateSetListener callBack, - int year, int monthOfYear, int dayOfMonth) { + protected void __constructor__( + Context context, + int theme, + DatePickerDialog.OnDateSetListener callBack, + int year, + int monthOfYear, + int dayOfMonth) { this.year = year; this.monthOfYear = monthOfYear; this.dayOfMonth = dayOfMonth; @@ -40,8 +45,14 @@ public class ShadowDatePickerDialog extends ShadowAlertDialog { } @Implementation(minSdk = N) - public void __constructor__(Context context, int theme, DatePickerDialog.OnDateSetListener callBack, - Calendar calendar, int year, int monthOfYear, int dayOfMonth) { + protected void __constructor__( + Context context, + int theme, + DatePickerDialog.OnDateSetListener callBack, + Calendar calendar, + int year, + int monthOfYear, + int dayOfMonth) { this.calendar = calendar; this.year = year; this.monthOfYear = monthOfYear; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDebug.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDebug.java index 92dffe2bf..e7d70a80a 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDebug.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDebug.java @@ -22,7 +22,7 @@ public class ShadowDebug { private static String tracingFilename; @Implementation - public static void __staticInitializer__() { + protected static void __staticInitializer__() { // Avoid calling Environment.getLegacyExternalStorageDirectory() } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDevicePolicyManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDevicePolicyManager.java index d7be0c8e1..18b3a57da 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDevicePolicyManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDevicePolicyManager.java @@ -44,7 +44,6 @@ import org.robolectric.annotation.Implements; import org.robolectric.annotation.RealObject; import org.robolectric.shadow.api.Shadow; -/** Shadow for {@link DevicePolicyManager} */ @Implements(DevicePolicyManager.class) @SuppressLint("NewApi") public class ShadowDevicePolicyManager { @@ -58,6 +57,7 @@ public class ShadowDevicePolicyManager { private ComponentName deviceOwner; private ComponentName profileOwner; private List<ComponentName> deviceAdmins = new ArrayList<>(); + private Map<Integer, String> profileOwnerNamesMap = new HashMap<>(); private List<String> permittedAccessibilityServices = new ArrayList<>(); private List<String> permittedInputMethods = new ArrayList<>(); private Map<String, Bundle> applicationRestrictionsMap = new HashMap<>(); @@ -150,39 +150,39 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = JELLY_BEAN_MR2) - public boolean isDeviceOwnerApp(String packageName) { + protected boolean isDeviceOwnerApp(String packageName) { return deviceOwner != null && deviceOwner.getPackageName().equals(packageName); } @Implementation(minSdk = LOLLIPOP) - public boolean isProfileOwnerApp(String packageName) { + protected boolean isProfileOwnerApp(String packageName) { return profileOwner != null && profileOwner.getPackageName().equals(packageName); } @Implementation - public boolean isAdminActive(ComponentName who) { + protected boolean isAdminActive(ComponentName who) { return who != null && deviceAdmins.contains(who); } @Implementation - public List<ComponentName> getActiveAdmins() { + protected List<ComponentName> getActiveAdmins() { return deviceAdmins; } @Implementation(minSdk = LOLLIPOP) - public void addUserRestriction(ComponentName admin, String key) { + protected void addUserRestriction(ComponentName admin, String key) { enforceActiveAdmin(admin); getShadowUserManager().setUserRestriction(Process.myUserHandle(), key, true); } @Implementation(minSdk = LOLLIPOP) - public void clearUserRestriction(ComponentName admin, String key) { + protected void clearUserRestriction(ComponentName admin, String key) { enforceActiveAdmin(admin); getShadowUserManager().setUserRestriction(Process.myUserHandle(), key, false); } @Implementation(minSdk = LOLLIPOP) - public boolean setApplicationHidden(ComponentName admin, String packageName, boolean hidden) { + protected boolean setApplicationHidden(ComponentName admin, String packageName, boolean hidden) { enforceActiveAdmin(admin); if (packagesToFailForSetApplicationHidden.contains(packageName)) { return false; @@ -207,7 +207,7 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = LOLLIPOP) - public boolean isApplicationHidden(ComponentName admin, String packageName) { + protected boolean isApplicationHidden(ComponentName admin, String packageName) { enforceActiveAdmin(admin); return applicationPackageManager.getApplicationHiddenSettingAsUser( packageName, Process.myUserHandle()); @@ -219,10 +219,9 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = LOLLIPOP) - public int enableSystemApp(ComponentName admin, String packageName) { + protected void enableSystemApp(ComponentName admin, String packageName) { enforceActiveAdmin(admin); systemAppsEnabled.add(packageName); - return 1; } /** Returns {@code true} if the given {@code packageName} was a system app and was enabled. */ @@ -231,7 +230,7 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = LOLLIPOP) - public void setUninstallBlocked( + protected void setUninstallBlocked( ComponentName admin, String packageName, boolean uninstallBlocked) { enforceActiveAdmin(admin); if (uninstallBlocked) { @@ -242,7 +241,7 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = LOLLIPOP) - public boolean isUninstallBlocked(ComponentName admin, String packageName) { + protected boolean isUninstallBlocked(ComponentName admin, String packageName) { enforceActiveAdmin(admin); return uninstallBlockedPackages.contains(packageName); } @@ -259,6 +258,15 @@ public class ShadowDevicePolicyManager { return profileOwner; } + /** + * Returns the human-readable name of the profile owner for a user if set using + * {@link #setProfileOwnerName}, otherwise `null`. + */ + @Implementation(minSdk = LOLLIPOP) + protected String getProfileOwnerNameAsUser(int userId) { + return profileOwnerNamesMap.get(userId); + } + private ShadowUserManager getShadowUserManager() { return Shadow.extract(context.getSystemService(Context.USER_SERVICE)); } @@ -283,18 +291,22 @@ public class ShadowDevicePolicyManager { profileOwner = admin; } + public void setProfileOwnerName(int userId, String name) { + profileOwnerNamesMap.put(userId, name); + } + /** Sets the given {@code componentName} as one of the active admins. */ public void setActiveAdmin(ComponentName componentName) { deviceAdmins.add(componentName); } @Implementation - public void removeActiveAdmin(ComponentName admin) { + protected void removeActiveAdmin(ComponentName admin) { deviceAdmins.remove(admin); } @Implementation(minSdk = LOLLIPOP) - public void clearProfileOwner(ComponentName admin) { + protected void clearProfileOwner(ComponentName admin) { profileOwner = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { removeActiveAdmin(admin); @@ -302,7 +314,7 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = LOLLIPOP) - public Bundle getApplicationRestrictions(ComponentName admin, String packageName) { + protected Bundle getApplicationRestrictions(ComponentName admin, String packageName) { enforceDeviceOwnerOrProfileOwner(admin); return getApplicationRestrictions(packageName); } @@ -315,7 +327,7 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = LOLLIPOP) - public void setApplicationRestrictions( + protected void setApplicationRestrictions( ComponentName admin, String packageName, Bundle applicationRestrictions) { enforceDeviceOwnerOrProfileOwner(admin); setApplicationRestrictions(packageName, applicationRestrictions); @@ -355,7 +367,7 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = LOLLIPOP) - public void setAccountManagementDisabled( + protected void setAccountManagementDisabled( ComponentName admin, String accountType, boolean disabled) { enforceDeviceOwnerOrProfileOwner(admin); if (disabled) { @@ -366,7 +378,7 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = LOLLIPOP) - public String[] getAccountTypesWithManagementDisabled() { + protected String[] getAccountTypesWithManagementDisabled() { return accountTypesWithManagementDisabled.toArray(new String[0]); } @@ -377,7 +389,7 @@ public class ShadowDevicePolicyManager { * profile owner and device owner since Android O. */ @Implementation(minSdk = N) - public void setOrganizationName(ComponentName admin, @Nullable CharSequence name) { + protected void setOrganizationName(ComponentName admin, @Nullable CharSequence name) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { enforceDeviceOwnerOrProfileOwner(admin); } else { @@ -430,7 +442,7 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = N) - public void setOrganizationColor(ComponentName admin, int color) { + protected void setOrganizationColor(ComponentName admin, int color) { enforceProfileOwner(admin); organizationColor = color; } @@ -447,7 +459,7 @@ public class ShadowDevicePolicyManager { */ @Implementation(minSdk = N) @Nullable - public CharSequence getOrganizationName(ComponentName admin) { + protected CharSequence getOrganizationName(ComponentName admin) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { enforceDeviceOwnerOrProfileOwner(admin); } else { @@ -458,19 +470,19 @@ public class ShadowDevicePolicyManager { } @Implementation(minSdk = N) - public int getOrganizationColor(ComponentName admin) { + protected int getOrganizationColor(ComponentName admin) { enforceProfileOwner(admin); return organizationColor; } @Implementation(minSdk = LOLLIPOP) - public void setAutoTimeRequired(ComponentName admin, boolean required) { + protected void setAutoTimeRequired(ComponentName admin, boolean required) { enforceDeviceOwnerOrProfileOwner(admin); isAutoTimeRequired = required; } @Implementation(minSdk = LOLLIPOP) - public boolean getAutoTimeRequired() { + protected boolean getAutoTimeRequired() { return isAutoTimeRequired; } @@ -483,7 +495,8 @@ public class ShadowDevicePolicyManager { * set the restriction and return true. */ @Implementation(minSdk = LOLLIPOP) - public boolean setPermittedAccessibilityServices(ComponentName admin, List<String> packageNames) { + protected boolean setPermittedAccessibilityServices( + ComponentName admin, List<String> packageNames) { enforceDeviceOwnerOrProfileOwner(admin); permittedAccessibilityServices = packageNames; return true; @@ -491,7 +504,7 @@ public class ShadowDevicePolicyManager { @Implementation(minSdk = LOLLIPOP) @Nullable - public List<String> getPermittedAccessibilityServices(ComponentName admin) { + protected List<String> getPermittedAccessibilityServices(ComponentName admin) { enforceDeviceOwnerOrProfileOwner(admin); return permittedAccessibilityServices; } @@ -505,7 +518,7 @@ public class ShadowDevicePolicyManager { * restriction and return true. */ @Implementation(minSdk = LOLLIPOP) - public boolean setPermittedInputMethods(ComponentName admin, List<String> packageNames) { + protected boolean setPermittedInputMethods(ComponentName admin, List<String> packageNames) { enforceDeviceOwnerOrProfileOwner(admin); permittedInputMethods = packageNames; return true; @@ -513,7 +526,7 @@ public class ShadowDevicePolicyManager { @Implementation(minSdk = LOLLIPOP) @Nullable - public List<String> getPermittedInputMethods(ComponentName admin) { + protected List<String> getPermittedInputMethods(ComponentName admin) { enforceDeviceOwnerOrProfileOwner(admin); return permittedInputMethods; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDialog.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDialog.java index 5be430b9c..fa43cecbe 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDialog.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDialog.java @@ -58,14 +58,14 @@ public class ShadowDialog { } @Implementation - public void show() { + protected void show() { setLatestDialog(this); shownDialogs.add(realDialog); directlyOn(realDialog, Dialog.class).show(); } @Implementation - public void dismiss() { + protected void dismiss() { directlyOn(realDialog, Dialog.class).dismiss(); hasBeenDismissed = true; } @@ -75,7 +75,7 @@ public class ShadowDialog { } @Implementation - public void setCanceledOnTouchOutside(boolean flag) { + protected void setCanceledOnTouchOutside(boolean flag) { isCancelableOnTouchOutside = flag; directlyOn(realDialog, Dialog.class).setCanceledOnTouchOutside(flag); } @@ -93,7 +93,7 @@ public class ShadowDialog { } @Implementation - public void setOnCancelListener(DialogInterface.OnCancelListener listener) { + protected void setOnCancelListener(DialogInterface.OnCancelListener listener) { this.onCancelListener = listener; directlyOn(realDialog, Dialog.class).setOnCancelListener(listener); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDiscoverySession.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDiscoverySession.java index b91c17b17..0fc9de303 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDiscoverySession.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDiscoverySession.java @@ -6,7 +6,6 @@ import android.net.wifi.aware.DiscoverySession; import org.robolectric.annotation.Implements; import org.robolectric.util.ReflectionHelpers; -/** Shadow for {@link DiscoverySession}. */ @Implements(value = DiscoverySession.class, minSdk = O) public class ShadowDiscoverySession { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplay.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplay.java index 30a9bc87f..089e626d7 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplay.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplay.java @@ -57,14 +57,14 @@ public class ShadowDisplay { private Integer pixelFormat; /** - * If {@link #setScaledDensity(float)} has been called, {@link DisplayMetrics#scaledDensity} - * will be modified to reflect the value specified. Note that this is not a realistic state. + * If {@link #setScaledDensity(float)} has been called, {@link DisplayMetrics#scaledDensity} will + * be modified to reflect the value specified. Note that this is not a realistic state. * * @deprecated This behavior is deprecated and will be removed in Robolectric 3.7. */ @Deprecated @Implementation - public void getMetrics(DisplayMetrics outMetrics) { + protected void getMetrics(DisplayMetrics outMetrics) { if (isJB()) { outMetrics.density = densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; outMetrics.densityDpi = densityDpi; @@ -82,14 +82,14 @@ public class ShadowDisplay { } /** - * If {@link #setScaledDensity(float)} has been called, {@link DisplayMetrics#scaledDensity} - * will be modified to reflect the value specified. Note that this is not a realistic state. + * If {@link #setScaledDensity(float)} has been called, {@link DisplayMetrics#scaledDensity} will + * be modified to reflect the value specified. Note that this is not a realistic state. * * @deprecated This behavior is deprecated and will be removed in Robolectric 3.7. */ @Deprecated @Implementation - public void getRealMetrics(DisplayMetrics outMetrics) { + protected void getRealMetrics(DisplayMetrics outMetrics) { if (isJB()) { getMetrics(outMetrics); outMetrics.widthPixels = realWidth; @@ -109,7 +109,7 @@ public class ShadowDisplay { */ @Deprecated @Implementation - public int getDisplayId() { + protected int getDisplayId() { return displayId == null ? directlyOn(realObject, Display.class).getDisplayId() : displayId; @@ -122,7 +122,7 @@ public class ShadowDisplay { */ @Deprecated @Implementation - public float getRefreshRate() { + protected float getRefreshRate() { return refreshRate == null ? directlyOn(realObject, Display.class).getRefreshRate() : refreshRate; @@ -135,20 +135,20 @@ public class ShadowDisplay { */ @Deprecated @Implementation - public int getPixelFormat() { + protected int getPixelFormat() { return pixelFormat == null ? directlyOn(realObject, Display.class).getPixelFormat() : pixelFormat; } @Implementation(maxSdk = JELLY_BEAN) - public void getSizeInternal(Point outSize, boolean doCompat) { + protected void getSizeInternal(Point outSize, boolean doCompat) { outSize.x = width; outSize.y = height; } @Implementation(maxSdk = JELLY_BEAN) - public void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) { + protected void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) { int minimum = Math.min(width, height); int maximum = Math.max(width, height); outSmallestSize.set(minimum, minimum); @@ -156,7 +156,7 @@ public class ShadowDisplay { } @Implementation(maxSdk = JELLY_BEAN) - public void getRealSize(Point outSize) { + protected void getRealSize(Point outSize) { outSize.set(realWidth, realHeight); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayListCanvas.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayListCanvas.java new file mode 100644 index 000000000..5bec276d1 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDisplayListCanvas.java @@ -0,0 +1,30 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.M; +import static android.os.Build.VERSION_CODES.N; +import static android.os.Build.VERSION_CODES.N_MR1; +import static android.os.Build.VERSION_CODES.O; +import static android.os.Build.VERSION_CODES.P; + +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(className = "android.view.DisplayListCanvas", isInAndroidSdk = false, minSdk = M, maxSdk = P) +public class ShadowDisplayListCanvas extends ShadowCanvas { + + @Implementation(minSdk = O) + protected static long nCreateDisplayListCanvas(long node, int width, int height) { + return 1; + } + + @Config(minSdk = N, maxSdk = N_MR1) + protected static long nCreateDisplayListCanvas(int width, int height) { + return 1; + } + + @Config(maxSdk = M) + protected static long nCreateDisplayListCanvas() { + return 1; + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java index dd086893a..bc272eb1a 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDownloadManager.java @@ -22,14 +22,14 @@ public class ShadowDownloadManager { private Map<Long, DownloadManager.Request> requestMap = new TreeMap<>(); @Implementation - public long enqueue(DownloadManager.Request request) { + protected long enqueue(DownloadManager.Request request) { queueCounter++; requestMap.put(queueCounter, request); return queueCounter; } @Implementation - public int remove(long... ids) { + protected int remove(long... ids) { int removeCount = 0; for (long id : ids) { if (requestMap.remove(id) != null) { @@ -40,7 +40,7 @@ public class ShadowDownloadManager { } @Implementation - public Cursor query(DownloadManager.Query query) { + protected Cursor query(DownloadManager.Query query) { ResultCursor result = new ResultCursor(); ShadowQuery shadow = Shadow.extract(query); long[] ids = shadow.getIds(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDrawable.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDrawable.java index d10f4f413..279f29d7a 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDrawable.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowDrawable.java @@ -41,7 +41,7 @@ public class ShadowDrawable { private boolean wasInvalidated; @Implementation - public static Drawable createFromStream(InputStream is, String srcName) { + protected static Drawable createFromStream(InputStream is, String srcName) { if (corruptStreamSources.contains(srcName)) { return null; } @@ -54,8 +54,8 @@ public class ShadowDrawable { } @Implementation // todo: this sucks, it's all just so we can detect 9-patches - public static Drawable createFromResourceStream(Resources res, TypedValue value, - InputStream is, String srcName, BitmapFactory.Options opts) { + protected static Drawable createFromResourceStream( + Resources res, TypedValue value, InputStream is, String srcName, BitmapFactory.Options opts) { if (is == null) { return null; } @@ -86,7 +86,7 @@ public class ShadowDrawable { } @Implementation - public static Drawable createFromPath(String pathName) { + protected static Drawable createFromPath(String pathName) { BitmapDrawable drawable = new BitmapDrawable(ReflectionHelpers.callConstructor(Bitmap.class)); ShadowBitmapDrawable shadowBitmapDrawable = Shadow.extract(drawable); shadowBitmapDrawable.drawableCreateFromPath = pathName; @@ -106,12 +106,12 @@ public class ShadowDrawable { } @Implementation - public int getIntrinsicWidth() { + protected int getIntrinsicWidth() { return intrinsicWidth; } @Implementation - public int getIntrinsicHeight() { + protected int getIntrinsicHeight() { return intrinsicHeight; } @@ -145,19 +145,19 @@ public class ShadowDrawable { } @Implementation - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { this.alpha = alpha; Shadow.directlyOn(realDrawable, Drawable.class).setAlpha(alpha); } @Implementation - public void invalidateSelf() { + protected void invalidateSelf() { wasInvalidated = true; Shadow.directlyOn(realDrawable, Drawable.class, "invalidateSelf"); } @Implementation(minSdk = KITKAT) - public int getAlpha() { + protected int getAlpha() { return alpha; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEnvironment.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEnvironment.java index ce8801a45..a7f7dd1a8 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEnvironment.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEnvironment.java @@ -34,7 +34,7 @@ public class ShadowEnvironment { static Path EXTERNAL_FILES_DIR; @Implementation - public static String getExternalStorageState() { + protected static String getExternalStorageState() { return externalStorageState; } @@ -57,13 +57,13 @@ public class ShadowEnvironment { } @Implementation - public static File getExternalStorageDirectory() { + protected static File getExternalStorageDirectory() { if (!exists(EXTERNAL_CACHE_DIR)) EXTERNAL_CACHE_DIR = RuntimeEnvironment.getTempDirectory().create("external-cache"); return EXTERNAL_CACHE_DIR.toFile(); } @Implementation - public static File getExternalStoragePublicDirectory(String type) { + protected static File getExternalStoragePublicDirectory(String type) { if (!exists(EXTERNAL_FILES_DIR)) EXTERNAL_FILES_DIR = RuntimeEnvironment.getTempDirectory().create("external-files"); if (type == null) return EXTERNAL_FILES_DIR.toFile(); Path path = EXTERNAL_FILES_DIR.resolve(type); @@ -95,13 +95,13 @@ public class ShadowEnvironment { } @Implementation - public static boolean isExternalStorageRemovable() { + protected static boolean isExternalStorageRemovable() { final Boolean exists = STORAGE_REMOVABLE.get(getExternalStorageDirectory()); return exists != null ? exists : false; } @Implementation(minSdk = KITKAT) - public static String getStorageState(File directory) { + protected static String getStorageState(File directory) { Path directoryPath = directory.toPath(); for (Map.Entry<Path, String> entry : storageState.entrySet()) { if (directoryPath.startsWith(entry.getKey())) { @@ -112,7 +112,7 @@ public class ShadowEnvironment { } @Implementation(minSdk = LOLLIPOP) - public static String getExternalStorageState(File directory) { + protected static String getExternalStorageState(File directory) { Path directoryPath = directory.toPath(); for (Map.Entry<Path, String> entry : storageState.entrySet()) { if (directoryPath.startsWith(entry.getKey())) { @@ -122,21 +122,20 @@ public class ShadowEnvironment { return null; } - @Implementation(minSdk = LOLLIPOP) - public static boolean isExternalStorageRemovable(File path) { + protected static boolean isExternalStorageRemovable(File path) { final Boolean exists = STORAGE_REMOVABLE.get(path); return exists != null ? exists : false; } @Implementation(minSdk = LOLLIPOP) - public static boolean isExternalStorageEmulated(File path) { + protected static boolean isExternalStorageEmulated(File path) { final Boolean emulated = STORAGE_EMULATED.get(path); return emulated != null ? emulated : false; } @Implementation - public static boolean isExternalStorageEmulated() { + protected static boolean isExternalStorageEmulated() { return sIsExternalStorageEmulated; } @@ -212,15 +211,12 @@ public class ShadowEnvironment { storageState.put(directory.toPath(), state); } - /** - * Shadow for {@link android.os.Environment.UserEnvironment} - */ @Implements(className = "android.os.Environment$UserEnvironment", isInAndroidSdk = false, minSdk = JELLY_BEAN_MR1) public static class ShadowUserEnvironment { @Implementation(minSdk = M) - public File[] getExternalDirs() { + protected File[] getExternalDirs() { return externalDirs.toArray(new File[externalDirs.size()]); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEuiccManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEuiccManager.java index db8d3d661..47e787db2 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEuiccManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEuiccManager.java @@ -6,7 +6,6 @@ import android.telephony.euicc.EuiccManager; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -/** Shadow for {@link EuiccManager}. */ @Implements(value = EuiccManager.class, minSdk = P) public class ShadowEuiccManager { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFilter.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFilter.java index daf08fa82..67fcbd7e4 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFilter.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFilter.java @@ -12,7 +12,7 @@ public class ShadowFilter { @RealObject private Filter realObject; @Implementation - public void filter(CharSequence constraint, Filter.FilterListener listener) { + protected void filter(CharSequence constraint, Filter.FilterListener listener) { try { Class<?> forName = Class.forName("android.widget.Filter$FilterResults"); Object filtering; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFloatMath.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFloatMath.java index bcec84242..1f3fa9b1f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFloatMath.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFloatMath.java @@ -24,27 +24,27 @@ import org.robolectric.annotation.Implements; @Implements(FloatMath.class) public class ShadowFloatMath { @Implementation - public static float floor(float value) { + protected static float floor(float value) { return (float) Math.floor(value); } @Implementation - public static float ceil(float value) { + protected static float ceil(float value) { return (float) Math.ceil(value); } @Implementation - public static float sin(float angle) { + protected static float sin(float angle) { return (float) Math.sin(angle); } @Implementation - public static float cos(float angle) { + protected static float cos(float angle) { return (float) Math.cos(angle); } @Implementation - public static float sqrt(float value) { + protected static float sqrt(float value) { return (float) Math.sqrt(value); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFontFamily.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFontFamily.java new file mode 100644 index 000000000..297417827 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowFontFamily.java @@ -0,0 +1,20 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.O; + +import android.graphics.FontFamily; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(value = FontFamily.class, minSdk = LOLLIPOP, isInAndroidSdk = false) +public class ShadowFontFamily { + + @Implementation(minSdk = O) + protected static long nInitBuilder(String lang, int variant) { + return 1; + } + + @Implementation(minSdk = O) + protected void abortCreation() {} +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGLES20.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGLES20.java index 4c5901f7f..b49291567 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGLES20.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGLES20.java @@ -1,4 +1,4 @@ -package com.google.android.libraries.youtube.edit.shadows; +package org.robolectric.shadows; import android.opengl.GLES20; import org.robolectric.annotation.Implementation; @@ -9,11 +9,19 @@ import org.robolectric.annotation.Implements; */ @Implements(GLES20.class) public class ShadowGLES20 { + private static int framebufferCount = 0; private static int textureCount = 0; private static int shaderCount = 0; private static int programCount = 0; @Implementation + protected static void glGenFramebuffers(int n, int[] framebuffers, int offset) { + for (int i = 0; i < n; i++) { + framebuffers[offset + i] = ++framebufferCount; + } + } + + @Implementation protected static void glGenTextures(int n, int[] textures, int offset) { for (int i = 0; i < n; i++) { textures[offset + i] = ++textureCount; @@ -32,4 +40,24 @@ public class ShadowGLES20 { protected static int glCreateProgram() { return ++programCount; } + + @Implementation + protected static void glGetShaderiv(int shader, int pname, int[] params, int offset) { + switch (pname) { + case GLES20.GL_COMPILE_STATUS: + params[0] = GLES20.GL_TRUE; + break; + default: // no-op + } + } + + @Implementation + protected static void glGetProgramiv(int program, int pname, int[] params, int offset) { + switch (pname) { + case GLES20.GL_LINK_STATUS: + params[0] = GLES20.GL_TRUE; + break; + default: // no-op + } + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGeocoder.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGeocoder.java index 9c61dd2e5..cb39f7f7e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGeocoder.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGeocoder.java @@ -16,11 +16,9 @@ public final class ShadowGeocoder { private static boolean isPresent = true; private List<Address> fromLocation = new ArrayList<>(); - /** - * @return `true` by default, or the value specified via {@link #setIsPresent(boolean)} - */ + /** @return `true` by default, or the value specified via {@link #setIsPresent(boolean)} */ @Implementation - public static boolean isPresent() { + protected static boolean isPresent() { return isPresent; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGradientDrawable.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGradientDrawable.java index 11be668b6..f6a0100eb 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGradientDrawable.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowGradientDrawable.java @@ -16,12 +16,18 @@ public class ShadowGradientDrawable extends ShadowDrawable { private int color; @Implementation - public void setColor(int color) { + protected void setColor(int color) { this.color = color; directlyOn(realGradientDrawable, GradientDrawable.class).setColor(color); } - public int getColor() { + /** + * Returns the color of this drawable as set by the last call to {@link #setColor(int color)}. + * + * <p>Note that this only works if the color is explicitly set with {@link #setColor(int color)}. + * If the color of this drawable is set by another method, the result will be {@code 0}. + */ + public int getLastSetColor() { return color; } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHardwareRenderer.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHardwareRenderer.java new file mode 100644 index 000000000..458f0fb82 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHardwareRenderer.java @@ -0,0 +1,20 @@ +// BEGIN-INTERNAL +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.Q; + +import android.graphics.HardwareRenderer; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(value = HardwareRenderer.class, isInAndroidSdk = false, minSdk = Q) +public class ShadowHardwareRenderer { + + private static long nextCreateProxy = 0; + + @Implementation + protected static long nCreateProxy(boolean translucent, long rootRenderNode) { + return ++nextCreateProxy; + } +} +// END-INTERNAL
\ No newline at end of file diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHttpResponseCache.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHttpResponseCache.java index 7697b704a..0fb712d4b 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHttpResponseCache.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowHttpResponseCache.java @@ -4,6 +4,7 @@ import static org.robolectric.shadow.api.Shadow.newInstanceOf; import android.net.http.HttpResponseCache; import java.io.File; +import java.net.CacheRequest; import java.net.CacheResponse; import java.net.URI; import java.net.URLConnection; @@ -28,7 +29,7 @@ public class ShadowHttpResponseCache { private int networkCount = 0; @Implementation - public static HttpResponseCache install(File directory, long maxSize) { + protected static HttpResponseCache install(File directory, long maxSize) { HttpResponseCache cache = newInstanceOf(HttpResponseCache.class); ShadowHttpResponseCache shadowCache = Shadow.extract(cache); shadowCache.originalObject = cache; @@ -41,58 +42,59 @@ public class ShadowHttpResponseCache { } @Implementation - public static HttpResponseCache getInstalled() { + protected static HttpResponseCache getInstalled() { synchronized (LOCK) { return (installed != null) ? installed.originalObject : null; } } @Implementation - public long maxSize() { + protected long maxSize() { return maxSize; } @Implementation - public long size() { + protected long size() { return 0; } @Implementation - public void close() { + protected void close() { synchronized (LOCK) { installed = null; } } @Implementation - public void delete() { + protected void delete() { close(); } @Implementation - public int getHitCount() { + protected int getHitCount() { return hitCount; } @Implementation - public int getNetworkCount() { + protected int getNetworkCount() { return networkCount; } @Implementation - public int getRequestCount() { + protected int getRequestCount() { return requestCount; } @Implementation - public CacheResponse get(URI uri, String requestMethod, Map<String, List<String>> requestHeaders) { + protected CacheResponse get( + URI uri, String requestMethod, Map<String, List<String>> requestHeaders) { requestCount += 1; networkCount += 1; // Always pretend we had a cache miss and had to fall back to the network. return null; } @Implementation - public CacheResponse put(URI uri, URLConnection urlConnection) { + protected CacheRequest put(URI uri, URLConnection urlConnection) { // Do not cache any data. All requests will be a miss. return null; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java index c321d4104..f7edf2406 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowImageDecoder.java @@ -26,7 +26,7 @@ import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers.ClassParameter; -// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r8/core/jni/android/graphics/ImageDecoder.cpp +// transliterated from https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android/graphics/ImageDecoder.cpp @SuppressWarnings({"NewApi", "UnusedDeclaration"}) // ImageDecoder is in fact in SDK, but make it false for now so projects which compile against < P // still work diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputDevice.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputDevice.java index caa021a76..c9552c0d6 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputDevice.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputDevice.java @@ -17,7 +17,7 @@ public class ShadowInputDevice { } @Implementation - public String getName() { + protected String getName() { return deviceName; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEvent.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEvent.java index 457be7053..86aa12b7b 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEvent.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEvent.java @@ -10,7 +10,7 @@ public class ShadowInputEvent { protected InputDevice device; @Implementation - public InputDevice getDevice() { + protected InputDevice getDevice() { return device; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEventReceiver.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEventReceiver.java index 227aa481b..1a15841d2 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEventReceiver.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputEventReceiver.java @@ -7,6 +7,7 @@ import org.robolectric.annotation.Implements; @Implements(value = InputEventReceiver.class, isInAndroidSdk = false) public class ShadowInputEventReceiver { @Implementation + @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") public void consumeBatchedInputEvents(long frameTimeNanos) { // The real implementation of this calls a JNI method, and logs a statement if the native // object isn't present. Since the native object will never be present in Robolectric tests, it diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java index a4e100460..4c8ebf509 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInputManager.java @@ -9,9 +9,6 @@ import org.robolectric.annotation.Implements; import org.robolectric.annotation.Resetter; import org.robolectric.util.ReflectionHelpers; -/* - * Shadow for InputManager. - */ @Implements(value = InputManager.class) public class ShadowInputManager { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java index d6acd01c4..d117de48c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowInstrumentation.java @@ -79,12 +79,12 @@ public class ShadowInstrumentation { private boolean checkActivities; @Implementation(minSdk = P) - public Activity startActivitySync(Intent intent, Bundle options) { + protected Activity startActivitySync(Intent intent, Bundle options) { throw new UnsupportedOperationException("Implement me!!"); } @Implementation - public ActivityResult execStartActivity( + protected ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, @@ -97,7 +97,7 @@ public class ShadowInstrumentation { } @Implementation(maxSdk = LOLLIPOP_MR1) - public ActivityResult execStartActivity( + protected ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, @@ -124,7 +124,7 @@ public class ShadowInstrumentation { } @Implementation - public void execStartActivities( + protected void execStartActivities( Context who, IBinder contextThread, IBinder token, @@ -137,13 +137,13 @@ public class ShadowInstrumentation { } @Implementation(minSdk = LOLLIPOP) - public void execStartActivityFromAppTask( + protected void execStartActivityFromAppTask( Context who, IBinder contextThread, Object appTask, Intent intent, Bundle options) { throw new UnsupportedOperationException("Implement me!!"); } @Implementation(minSdk = M) - public ActivityResult execStartActivity( + protected ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, @@ -156,7 +156,7 @@ public class ShadowInstrumentation { } @Implementation(minSdk = JELLY_BEAN_MR1) - public ActivityResult execStartActivity( + protected ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, @@ -169,7 +169,7 @@ public class ShadowInstrumentation { } @Implementation(minSdk = M) - public ActivityResult execStartActivityAsCaller( + protected ActivityResult execStartActivityAsCaller( Context who, IBinder contextThread, IBinder token, diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIntentService.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIntentService.java index 34c885222..06669266e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIntentService.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIntentService.java @@ -20,7 +20,7 @@ public class ShadowIntentService extends ShadowService { } @Implementation - public void setIntentRedelivery(boolean enabled) { + protected void setIntentRedelivery(boolean enabled) { mRedelivery = enabled; directlyOn(realIntentService, IntentService.class, "setIntentRedelivery", ClassParameter.from(boolean.class, enabled)); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIoUtils.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIoUtils.java index 77cde7ab6..62360eeb1 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIoUtils.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowIoUtils.java @@ -2,12 +2,12 @@ package org.robolectric.shadows; import static java.nio.charset.StandardCharsets.UTF_8; +import android.os.Build; import java.io.FileDescriptor; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import libcore.io.IoUtils; -import libcore.util.NonNull; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -19,9 +19,10 @@ public class ShadowIoUtils { return new String(Files.readAllBytes(Paths.get(absolutePath)), UTF_8); } - //BEGIN-INTERNAL - @Implementation(minSdk = android.os.Build.VERSION_CODES.Q) - public static void setFdOwner(@NonNull FileDescriptor fd, @NonNull Object owner) { + // BEGIN-INTERNAL + @Implementation(minSdk = Build.VERSION_CODES.Q) + protected static void setFdOwner(FileDescriptor fd, Object owner) { + // ignore, fails in JVM environment } - //END-INTERNAL + // END-INTERNAL } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobScheduler.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobScheduler.java index ab0908961..5725b7f65 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobScheduler.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobScheduler.java @@ -14,6 +14,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import org.robolectric.annotation.HiddenApi; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -21,22 +22,23 @@ import org.robolectric.annotation.Implements; public abstract class ShadowJobScheduler { @Implementation - public abstract int schedule(JobInfo job); + protected abstract int schedule(JobInfo job); @Implementation - public abstract void cancel(int jobId); + protected abstract void cancel(int jobId); @Implementation - public abstract void cancelAll(); + protected abstract void cancelAll(); @Implementation - public abstract List<JobInfo> getAllPendingJobs(); + protected abstract List<JobInfo> getAllPendingJobs(); @Implementation(minSdk = N) + @HiddenApi public abstract JobInfo getPendingJob(int jobId); @Implementation(minSdk = O) - public abstract int enqueue(JobInfo job, JobWorkItem work); + protected abstract int enqueue(JobInfo job, JobWorkItem work); public abstract void failOnJob(int jobId); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobService.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobService.java index fee5f86ff..42baa4c1f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobService.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJobService.java @@ -7,10 +7,6 @@ import android.app.job.JobService; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -/** - * Shadow for classes that extend jobservice. The shadowOf method can be used to obtain an instances - * shadow to view state using utility methods. - */ @Implements(value = JobService.class, minSdk = LOLLIPOP) public class ShadowJobService extends ShadowService { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJsResult.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJsResult.java index aa6429318..cf125510a 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJsResult.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowJsResult.java @@ -10,7 +10,7 @@ public class ShadowJsResult { private boolean wasCancelled; @Implementation - public void cancel() { + protected void cancel() { wasCancelled = true; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java index b8235c645..b10e462f8 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowKeyCharacterMap.java @@ -92,12 +92,12 @@ public class ShadowKeyCharacterMap { } @Implementation - public static KeyCharacterMap load(int deviceId) { + protected static KeyCharacterMap load(int deviceId) { return ReflectionHelpers.callConstructor(KeyCharacterMap.class); } @Implementation - public KeyEvent[] getEvents(char[] charArray) { + protected KeyEvent[] getEvents(char[] charArray) { int eventsPerChar = 2; KeyEvent[] events = new KeyEvent[charArray.length * eventsPerChar]; @@ -110,12 +110,12 @@ public class ShadowKeyCharacterMap { } @Implementation - public int getKeyboardType() { + protected int getKeyboardType() { return KeyCharacterMap.FULL; } @Implementation - public int get(int keyCode, int metaState) { + protected int get(int keyCode, int metaState) { return Character.toLowerCase(KEY_CODE_TO_CHAR.get(keyCode)); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java index 57b3f978b..d709e452d 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyApkAssets.java @@ -7,7 +7,7 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; // transliterated from -// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r3/core/jni/android_content_res_ApkAssets.cpp +// https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/android_content_res_ApkAssets.cpp @Implements(value = android.content.res.ApkAssets.class, minSdk = Build.VERSION_CODES.P, isInAndroidSdk = false) public class ShadowLegacyApkAssets extends ShadowApkAssets { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java index 35a9b675e..a914dc830 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLegacyAssetManager.java @@ -82,7 +82,6 @@ import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowAssetManager.Picker; import org.robolectric.util.Logger; import org.robolectric.util.ReflectionHelpers; -import org.robolectric.util.ReflectionHelpers.ClassParameter; @SuppressLint("NewApi") @Implements(value = AssetManager.class, /* this one works for P too... maxSdk = VERSION_CODES.O_MR1,*/ @@ -237,22 +236,22 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { protected void __constructor__() { resourceTable = RuntimeEnvironment.getAppResourceTable(); - + if (RuntimeEnvironment.getApiLevel() >= P) { invokeConstructor(AssetManager.class, realObject); } - + } @Implementation protected void __constructor__(boolean isSystem) { resourceTable = isSystem ? RuntimeEnvironment.getSystemResourceTable() : RuntimeEnvironment.getAppResourceTable(); - + if (RuntimeEnvironment.getApiLevel() >= P) { invokeConstructor(AssetManager.class, realObject, from(boolean.class, isSystem)); } - + } @Implementation(minSdk = P) @@ -372,17 +371,17 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { } @Implementation - public final InputStream open(String fileName) throws IOException { + protected final InputStream open(String fileName) throws IOException { return findAssetFile(fileName).getInputStream(); } @Implementation - public final InputStream open(String fileName, int accessMode) throws IOException { + protected final InputStream open(String fileName, int accessMode) throws IOException { return findAssetFile(fileName).getInputStream(); } @Implementation - public final AssetFileDescriptor openFd(String fileName) throws IOException { + protected final AssetFileDescriptor openFd(String fileName) throws IOException { File file = new File(findAssetFile(fileName).getPath()); if (file.getPath().startsWith("jar")) { file = getFileFromZip(file); @@ -442,7 +441,7 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { } @Implementation - public final String[] list(String path) throws IOException { + protected final String[] list(String path) throws IOException { List<String> assetFiles = new ArrayList<>(); for (FsFile assetsDir : getAllAssetDirs()) { @@ -532,7 +531,8 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { } @Implementation - public final XmlResourceParser openXmlResourceParser(int cookie, String fileName) throws IOException { + protected final XmlResourceParser openXmlResourceParser(int cookie, String fileName) + throws IOException { XmlBlock xmlBlock = XmlBlock.create(Fs.fileFromPath(fileName), resourceTable.getPackageName()); if (xmlBlock == null) { throw new Resources.NotFoundException(fileName); @@ -653,7 +653,7 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { } @Implementation - public String[] getLocales() { + protected String[] getLocales() { return new String[0]; // todo } @@ -862,7 +862,7 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { } } - @HiddenApi @Implementation(minSdk = LOLLIPOP) + @HiddenApi @Implementation(minSdk = LOLLIPOP, maxSdk = O_MR1) protected static void dumpTheme(long theme, int priority, String tag, String prefix) { throw new UnsupportedOperationException("not yet implemented"); } @@ -932,15 +932,15 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { // BEGIN-INTERNAL @HiddenApi @Implementation(minSdk = Q) protected static void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr, - long srcAssetManagerPtr, long srcThemePtr) { + long srcAssetManagerPtr, long srcThemePtr) { copyTheme(dstThemePtr, srcThemePtr); } // END-INTERNAL @HiddenApi @Implementation(maxSdk = KITKAT_WATCH) - protected static void applyStyle(int themeToken, int defStyleAttr, int defStyleRes, + protected static boolean applyStyle(int themeToken, int defStyleAttr, int defStyleRes, int xmlParserToken, int[] attrs, int[] outValues, int[] outIndices) { - applyStyle((long)themeToken, defStyleAttr, defStyleRes, (long)xmlParserToken, attrs, + return applyStyle((long)themeToken, defStyleAttr, defStyleRes, (long)xmlParserToken, attrs, outValues, outIndices); } @@ -961,12 +961,13 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { } @HiddenApi @Implementation(minSdk = LOLLIPOP, maxSdk = N_MR1) - protected static void applyStyle(long themeToken, int defStyleAttr, int defStyleRes, + protected static boolean applyStyle(long themeToken, int defStyleAttr, int defStyleRes, long xmlParserToken, int[] attrs, int[] outValues, int[] outIndices) { // no-op + return false; } - @HiddenApi @Implementation(minSdk = LOLLIPOP) + @HiddenApi @Implementation(minSdk = LOLLIPOP, maxSdk = O_MR1) protected static boolean resolveAttrs(long themeToken, int defStyleAttr, int defStyleRes, int[] inValues, int[] attrs, int[] outValues, int[] outIndices) { @@ -1288,22 +1289,22 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { } @Implementation - public String getResourceName(int resid) { + protected String getResourceName(int resid) { return getResName(resid).getFullyQualifiedName(); } @Implementation - public String getResourcePackageName(int resid) { + protected String getResourcePackageName(int resid) { return getResName(resid).packageName; } @Implementation - public String getResourceTypeName(int resid) { + protected String getResourceTypeName(int resid) { return getResName(resid).type; } @Implementation - public String getResourceEntryName(int resid) { + protected String getResourceEntryName(int resid) { return getResName(resid).name; } @@ -1323,7 +1324,7 @@ public class ShadowLegacyAssetManager extends ShadowAssetManager { } @Implementation(minSdk = LOLLIPOP, maxSdk = O_MR1) - public final SparseArray<String> getAssignedPackageIdentifiers() { + protected final SparseArray<String> getAssignedPackageIdentifiers() { return new SparseArray<>(); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinearGradient.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinearGradient.java index a7597d2ee..27fab96c2 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinearGradient.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinearGradient.java @@ -17,7 +17,7 @@ public class ShadowLinearGradient { private Shader.TileMode tile; @Implementation - public void __constructor__( + protected void __constructor__( float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile) { this.x0 = x0; this.y0 = y0; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinkMovementMethod.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinkMovementMethod.java index 0286c0919..4df7e345c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinkMovementMethod.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinkMovementMethod.java @@ -9,7 +9,7 @@ import org.robolectric.annotation.Implements; @Implements(LinkMovementMethod.class) public class ShadowLinkMovementMethod { @Implementation - public static MovementMethod getInstance() { + protected static MovementMethod getInstance() { return new LinkMovementMethod(); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinux.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinux.java index b7d8b3b90..0e480ceec 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinux.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLinux.java @@ -18,7 +18,7 @@ import org.robolectric.annotation.Implements; @Implements(value = Linux.class, minSdk = Build.VERSION_CODES.O, isInAndroidSdk = false) public class ShadowLinux { @Implementation - public static void mkdir(String path, int mode) throws ErrnoException { + public void mkdir(String path, int mode) throws ErrnoException { new File(path).mkdirs(); } @@ -51,7 +51,7 @@ public class ShadowLinux { } @Implementation - protected static FileDescriptor open(String path, int flags, int mode) throws ErrnoException { + protected FileDescriptor open(String path, int flags, int mode) throws ErrnoException { try { RandomAccessFile randomAccessFile = new RandomAccessFile(path, modeToString(mode)); return randomAccessFile.getFD(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowListPopupWindow.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowListPopupWindow.java index 3d4ad7979..ce198a5ad 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowListPopupWindow.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowListPopupWindow.java @@ -11,12 +11,12 @@ import org.robolectric.shadow.api.Shadow; @Implements(ListPopupWindow.class) public class ShadowListPopupWindow { - + @RealObject private ListPopupWindow realListPopupWindow; @Implementation - public void show() { + protected void show() { ShadowApplication shadowApplication = Shadow.extract(RuntimeEnvironment.application); shadowApplication.setLatestListPopupWindow(realListPopupWindow); directlyOn(realListPopupWindow, ListPopupWindow.class).show(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLocationManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLocationManager.java index fc62e4069..027695fe5 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLocationManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLocationManager.java @@ -55,7 +55,7 @@ public class ShadowLocationManager { long lastSeenTime; ListenerRegistration(String provider, long minTime, float minDistance, Location locationAtCreation, - LocationListener listener) { + LocationListener listener) { this.provider = provider; this.minTime = minTime; this.minDistance = minDistance; @@ -70,7 +70,7 @@ public class ShadowLocationManager { new HashMap<>(); @Implementation - public boolean isProviderEnabled(String provider) { + protected boolean isProviderEnabled(String provider) { LocationProviderEntry map = providersEnabled.get(provider); if (map != null) { Boolean isEnabled = map.getKey(); @@ -80,7 +80,7 @@ public class ShadowLocationManager { } @Implementation - public List<String> getAllProviders() { + protected List<String> getAllProviders() { Set<String> allKnownProviders = new LinkedHashSet<>(providersEnabled.keySet()); allKnownProviders.add(LocationManager.GPS_PROVIDER); allKnownProviders.add(LocationManager.NETWORK_PROVIDER); @@ -138,7 +138,7 @@ public class ShadowLocationManager { } @Implementation - public List<String> getProviders(boolean enabledOnly) { + protected List<String> getProviders(boolean enabledOnly) { ArrayList<String> enabledProviders = new ArrayList<>(); for (String provider : getAllProviders()) { if (!enabledOnly || providersEnabled.get(provider) != null) { @@ -149,12 +149,12 @@ public class ShadowLocationManager { } @Implementation - public Location getLastKnownLocation(String provider) { + protected Location getLastKnownLocation(String provider) { return lastKnownLocations.get(provider); } @Implementation - public boolean addGpsStatusListener(Listener listener) { + protected boolean addGpsStatusListener(Listener listener) { if (!gpsStatusListeners.contains(listener)) { gpsStatusListeners.add(listener); } @@ -162,12 +162,12 @@ public class ShadowLocationManager { } @Implementation - public void removeGpsStatusListener(Listener listener) { + protected void removeGpsStatusListener(Listener listener) { gpsStatusListeners.remove(listener); } @Implementation - public String getBestProvider(Criteria criteria, boolean enabled) { + protected String getBestProvider(Criteria criteria, boolean enabled) { lastBestProviderCriteria = criteria; lastBestProviderEnabled = enabled; @@ -231,20 +231,21 @@ public class ShadowLocationManager { // @SystemApi @Implementation(minSdk = P) - public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) { + protected void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) { getContext().checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS); locationEnabledForUser.put(userHandle, enabled); } // @SystemApi @Implementation(minSdk = P) - public boolean isLocationEnabledForUser(UserHandle userHandle) { + protected boolean isLocationEnabledForUser(UserHandle userHandle) { Boolean result = locationEnabledForUser.get(userHandle); return result == null ? false : result; } @Implementation - public void requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener) { + protected void requestLocationUpdates( + String provider, long minTime, float minDistance, LocationListener listener) { addLocationListener(provider, listener, minTime, minDistance); } @@ -271,13 +272,14 @@ public class ShadowLocationManager { } @Implementation - public void requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener, - Looper looper) { + protected void requestLocationUpdates( + String provider, long minTime, float minDistance, LocationListener listener, Looper looper) { addLocationListener(provider, listener, minTime, minDistance); } @Implementation - public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, PendingIntent pendingIntent) { + protected void requestLocationUpdates( + long minTime, float minDistance, Criteria criteria, PendingIntent pendingIntent) { if (pendingIntent == null) { throw new IllegalStateException("Intent must not be null"); } @@ -288,8 +290,8 @@ public class ShadowLocationManager { } @Implementation - public void requestLocationUpdates(String provider, long minTime, float minDistance, - PendingIntent pendingIntent) { + protected void requestLocationUpdates( + String provider, long minTime, float minDistance, PendingIntent pendingIntent) { if (pendingIntent == null) { throw new IllegalStateException("Intent must not be null"); } @@ -301,7 +303,7 @@ public class ShadowLocationManager { } @Implementation - public void removeUpdates(LocationListener listener) { + protected void removeUpdates(LocationListener listener) { removedLocationListeners.add(listener); } @@ -318,7 +320,7 @@ public class ShadowLocationManager { } @Implementation - public void removeUpdates(PendingIntent pendingIntent) { + protected void removeUpdates(PendingIntent pendingIntent) { while (requestLocationUdpateCriteriaPendingIntents.remove(pendingIntent) != null); while (requestLocationUdpateProviderPendingIntents.remove(pendingIntent) != null); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLog.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLog.java index be30606c2..9f49e49c5 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLog.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLog.java @@ -33,72 +33,72 @@ public class ShadowLog { private static boolean wtfIsFatal = false; @Implementation - public static void e(String tag, String msg) { - e(tag, msg, null); + protected static int e(String tag, String msg) { + return e(tag, msg, null); } @Implementation - public static void e(String tag, String msg, Throwable throwable) { - addLog(Log.ERROR, tag, msg, throwable); + protected static int e(String tag, String msg, Throwable throwable) { + return addLog(Log.ERROR, tag, msg, throwable); } @Implementation - public static void d(String tag, String msg) { - d(tag, msg, null); + protected static int d(String tag, String msg) { + return d(tag, msg, null); } @Implementation - public static void d(String tag, String msg, Throwable throwable) { - addLog(Log.DEBUG, tag, msg, throwable); + protected static int d(String tag, String msg, Throwable throwable) { + return addLog(Log.DEBUG, tag, msg, throwable); } @Implementation - public static void i(String tag, String msg) { - i(tag, msg, null); + protected static int i(String tag, String msg) { + return i(tag, msg, null); } @Implementation - public static void i(String tag, String msg, Throwable throwable) { - addLog(Log.INFO, tag, msg, throwable); + protected static int i(String tag, String msg, Throwable throwable) { + return addLog(Log.INFO, tag, msg, throwable); } @Implementation - public static void v(String tag, String msg) { - v(tag, msg, null); + protected static int v(String tag, String msg) { + return v(tag, msg, null); } @Implementation - public static void v(String tag, String msg, Throwable throwable) { - addLog(Log.VERBOSE, tag, msg, throwable); + protected static int v(String tag, String msg, Throwable throwable) { + return addLog(Log.VERBOSE, tag, msg, throwable); } @Implementation - public static void w(String tag, String msg) { - w(tag, msg, null); + protected static int w(String tag, String msg) { + return w(tag, msg, null); } @Implementation - public static void w(String tag, Throwable throwable) { - w(tag, null, throwable); + protected static int w(String tag, Throwable throwable) { + return w(tag, null, throwable); } - @Implementation - public static void w(String tag, String msg, Throwable throwable) { - addLog(Log.WARN, tag, msg, throwable); + protected static int w(String tag, String msg, Throwable throwable) { + return addLog(Log.WARN, tag, msg, throwable); } @Implementation - public static void wtf(String tag, String msg) { - wtf(tag, msg, null); + protected static int wtf(String tag, String msg) { + return wtf(tag, msg, null); } @Implementation - public static void wtf(String tag, String msg, Throwable throwable) { + protected static int wtf(String tag, String msg, Throwable throwable) { addLog(Log.ASSERT, tag, msg, throwable); if (wtfIsFatal) { throw new TerribleFailure(msg, throwable); } + return 0; } /** Sets whether calling {@link Log#wtf} will throw {@link TerribleFailure}. */ @@ -107,7 +107,7 @@ public class ShadowLog { } @Implementation - public static boolean isLoggable(String tag, int level) { + protected static boolean isLoggable(String tag, int level) { synchronized (tagToLevel) { if (tagToLevel.containsKey(tag)) { return level >= tagToLevel.get(tag); @@ -133,7 +133,7 @@ public class ShadowLog { tagToLevel.put(tag, level); } - private static void addLog(int level, String tag, String msg, Throwable throwable) { + private static int addLog(int level, String tag, String msg, Throwable throwable) { if (stream != null) { logToStream(stream, level, tag, msg, throwable); } @@ -152,6 +152,8 @@ public class ShadowLog { itemList.add(item); logs.add(item); + + return 0; } private static void logToStream(PrintStream ps, int level, String tag, String msg, Throwable throwable) { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLooper.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLooper.java index b8724ff5d..5e91f50a6 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLooper.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowLooper.java @@ -30,6 +30,7 @@ import org.robolectric.util.Scheduler; @Implements(Looper.class) @SuppressWarnings("SynchronizeOnNonFinalField") public class ShadowLooper { + // Replaced SoftThreadLocal with a WeakHashMap, because ThreadLocal make it impossible to access their contents from other // threads, but we need to be able to access the loopers for all threads so that we can shut them down when resetThreadLoopers() // is called. This also allows us to implement the useful getLooperForThread() method. @@ -73,7 +74,7 @@ public class ShadowLooper { } @Implementation - public void __constructor__(boolean quitAllowed) { + protected void __constructor__(boolean quitAllowed) { invokeConstructor(Looper.class, realObject, from(boolean.class, quitAllowed)); if (isMainThread()) { mainLooper = realObject; @@ -84,17 +85,17 @@ public class ShadowLooper { } @Implementation - public static Looper getMainLooper() { + protected static Looper getMainLooper() { return mainLooper; } @Implementation - public static Looper myLooper() { + protected static Looper myLooper() { return getLooperForThread(Thread.currentThread()); } @Implementation - public static void loop() { + protected static void loop() { shadowOf(Looper.myLooper()).doLoop(); } @@ -112,13 +113,13 @@ public class ShadowLooper { } @Implementation - public void quit() { + protected void quit() { if (realObject == Looper.getMainLooper()) throw new RuntimeException("Main thread not allowed to quit"); quitUnchecked(); } @Implementation(minSdk = JELLY_BEAN_MR2) - public void quitSafely() { + protected void quitSafely() { quit(); } @@ -137,6 +138,8 @@ public class ShadowLooper { } } + /** @deprecated Use `shadowOf({@link Looper#getMainLooper()})` instead. */ + @Deprecated public static ShadowLooper getShadowMainLooper() { return shadowOf(Looper.getMainLooper()); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMatrix.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMatrix.java index 80267f471..2b1b5b1d6 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMatrix.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMatrix.java @@ -4,8 +4,10 @@ import static android.os.Build.VERSION_CODES.KITKAT; import static android.os.Build.VERSION_CODES.LOLLIPOP; import android.graphics.Matrix; +import android.graphics.Matrix.ScaleToFit; import android.graphics.PointF; import android.graphics.RectF; +import java.awt.geom.AffineTransform; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; @@ -35,10 +37,10 @@ public class ShadowMatrix { private final Deque<String> postOps = new ArrayDeque<>(); private final Map<String, String> setOps = new LinkedHashMap<>(); - private SimpleMatrix mMatrix = SimpleMatrix.IDENTITY; + private SimpleMatrix simpleMatrix = SimpleMatrix.newIdentityMatrix(); @Implementation - public void __constructor__(Matrix src) { + protected void __constructor__(Matrix src) { set(src); } @@ -69,229 +71,247 @@ public class ShadowMatrix { } @Implementation - public boolean isIdentity() { - return mMatrix.equals(SimpleMatrix.IDENTITY); + protected boolean isIdentity() { + return simpleMatrix.equals(SimpleMatrix.IDENTITY); } @Implementation(minSdk = LOLLIPOP) - public boolean isAffine() { - return mMatrix.isAffine(); + protected boolean isAffine() { + return simpleMatrix.isAffine(); } @Implementation - public boolean rectStaysRect() { - return mMatrix.rectStaysRect(); + protected boolean rectStaysRect() { + return simpleMatrix.rectStaysRect(); } @Implementation - public void getValues(float[] values) { - mMatrix.getValues(values); + protected void getValues(float[] values) { + simpleMatrix.getValues(values); } @Implementation - public void setValues(float[] values) { - mMatrix = new SimpleMatrix(values); + protected void setValues(float[] values) { + simpleMatrix = new SimpleMatrix(values); } @Implementation - public void set(Matrix src) { + protected void set(Matrix src) { reset(); if (src != null) { ShadowMatrix shadowMatrix = Shadow.extract(src); preOps.addAll(shadowMatrix.preOps); postOps.addAll(shadowMatrix.postOps); setOps.putAll(shadowMatrix.setOps); - mMatrix = new SimpleMatrix(getSimpleMatrix(src)); + simpleMatrix = new SimpleMatrix(getSimpleMatrix(src)); } } @Implementation - public void reset() { + protected void reset() { preOps.clear(); postOps.clear(); setOps.clear(); - mMatrix = SimpleMatrix.IDENTITY; + simpleMatrix = SimpleMatrix.newIdentityMatrix(); } @Implementation - public void setTranslate(float dx, float dy) { + protected void setTranslate(float dx, float dy) { setOps.put(TRANSLATE, dx + " " + dy); - mMatrix = SimpleMatrix.translate(dx, dy); + simpleMatrix = SimpleMatrix.translate(dx, dy); } @Implementation - public void setScale(float sx, float sy, float px, float py) { + protected void setScale(float sx, float sy, float px, float py) { setOps.put(SCALE, sx + " " + sy + " " + px + " " + py); - mMatrix = SimpleMatrix.scale(sx, sy, px, py); + simpleMatrix = SimpleMatrix.scale(sx, sy, px, py); } @Implementation - public void setScale(float sx, float sy) { + protected void setScale(float sx, float sy) { setOps.put(SCALE, sx + " " + sy); - mMatrix = SimpleMatrix.scale(sx, sy); + simpleMatrix = SimpleMatrix.scale(sx, sy); } @Implementation - public void setRotate(float degrees, float px, float py) { + protected void setRotate(float degrees, float px, float py) { setOps.put(ROTATE, degrees + " " + px + " " + py); - mMatrix = SimpleMatrix.rotate(degrees, px, py); + simpleMatrix = SimpleMatrix.rotate(degrees, px, py); } @Implementation - public void setRotate(float degrees) { + protected void setRotate(float degrees) { setOps.put(ROTATE, Float.toString(degrees)); - mMatrix = SimpleMatrix.rotate(degrees); + simpleMatrix = SimpleMatrix.rotate(degrees); } @Implementation - public void setSinCos(float sinValue, float cosValue, float px, float py) { + protected void setSinCos(float sinValue, float cosValue, float px, float py) { setOps.put(SINCOS, sinValue + " " + cosValue + " " + px + " " + py); - mMatrix = SimpleMatrix.sinCos(sinValue, cosValue, px, py); + simpleMatrix = SimpleMatrix.sinCos(sinValue, cosValue, px, py); } @Implementation - public void setSinCos(float sinValue, float cosValue) { + protected void setSinCos(float sinValue, float cosValue) { setOps.put(SINCOS, sinValue + " " + cosValue); - mMatrix = SimpleMatrix.sinCos(sinValue, cosValue); + simpleMatrix = SimpleMatrix.sinCos(sinValue, cosValue); } @Implementation - public void setSkew(float kx, float ky, float px, float py) { + protected void setSkew(float kx, float ky, float px, float py) { setOps.put(SKEW, kx + " " + ky + " " + px + " " + py); - mMatrix = SimpleMatrix.skew(kx, ky, px, py); + simpleMatrix = SimpleMatrix.skew(kx, ky, px, py); } @Implementation - public void setSkew(float kx, float ky) { + protected void setSkew(float kx, float ky) { setOps.put(SKEW, kx + " " + ky); - mMatrix = SimpleMatrix.skew(kx, ky); + simpleMatrix = SimpleMatrix.skew(kx, ky); } @Implementation - public boolean setConcat(Matrix a, Matrix b) { - mMatrix = getSimpleMatrix(a).multiply(getSimpleMatrix(b)); + protected boolean setConcat(Matrix a, Matrix b) { + simpleMatrix = getSimpleMatrix(a).multiply(getSimpleMatrix(b)); return true; } @Implementation - public boolean preTranslate(float dx, float dy) { + protected boolean preTranslate(float dx, float dy) { preOps.addFirst(TRANSLATE + " " + dx + " " + dy); return preConcat(SimpleMatrix.translate(dx, dy)); } @Implementation - public boolean preScale(float sx, float sy, float px, float py) { + protected boolean preScale(float sx, float sy, float px, float py) { preOps.addFirst(SCALE + " " + sx + " " + sy + " " + px + " " + py); return preConcat(SimpleMatrix.scale(sx, sy, px, py)); } @Implementation - public boolean preScale(float sx, float sy) { + protected boolean preScale(float sx, float sy) { preOps.addFirst(SCALE + " " + sx + " " + sy); return preConcat(SimpleMatrix.scale(sx, sy)); } @Implementation - public boolean preRotate(float degrees, float px, float py) { + protected boolean preRotate(float degrees, float px, float py) { preOps.addFirst(ROTATE + " " + degrees + " " + px + " " + py); return preConcat(SimpleMatrix.rotate(degrees, px, py)); } @Implementation - public boolean preRotate(float degrees) { + protected boolean preRotate(float degrees) { preOps.addFirst(ROTATE + " " + Float.toString(degrees)); return preConcat(SimpleMatrix.rotate(degrees)); } @Implementation - public boolean preSkew(float kx, float ky, float px, float py) { + protected boolean preSkew(float kx, float ky, float px, float py) { preOps.addFirst(SKEW + " " + kx + " " + ky + " " + px + " " + py); return preConcat(SimpleMatrix.skew(kx, ky, px, py)); } @Implementation - public boolean preSkew(float kx, float ky) { + protected boolean preSkew(float kx, float ky) { preOps.addFirst(SKEW + " " + kx + " " + ky); return preConcat(SimpleMatrix.skew(kx, ky)); } @Implementation - public boolean preConcat(Matrix other) { + protected boolean preConcat(Matrix other) { preOps.addFirst(MATRIX + " " + other); return preConcat(getSimpleMatrix(other)); } @Implementation - public boolean postTranslate(float dx, float dy) { + protected boolean postTranslate(float dx, float dy) { postOps.addLast(TRANSLATE + " " + dx + " " + dy); return postConcat(SimpleMatrix.translate(dx, dy)); } @Implementation - public boolean postScale(float sx, float sy, float px, float py) { + protected boolean postScale(float sx, float sy, float px, float py) { postOps.addLast(SCALE + " " + sx + " " + sy + " " + px + " " + py); return postConcat(SimpleMatrix.scale(sx, sy, px, py)); } @Implementation - public boolean postScale(float sx, float sy) { + protected boolean postScale(float sx, float sy) { postOps.addLast(SCALE + " " + sx + " " + sy); return postConcat(SimpleMatrix.scale(sx, sy)); } @Implementation - public boolean postRotate(float degrees, float px, float py) { + protected boolean postRotate(float degrees, float px, float py) { postOps.addLast(ROTATE + " " + degrees + " " + px + " " + py); return postConcat(SimpleMatrix.rotate(degrees, px, py)); } @Implementation - public boolean postRotate(float degrees) { + protected boolean postRotate(float degrees) { postOps.addLast(ROTATE + " " + Float.toString(degrees)); return postConcat(SimpleMatrix.rotate(degrees)); } @Implementation - public boolean postSkew(float kx, float ky, float px, float py) { + protected boolean postSkew(float kx, float ky, float px, float py) { postOps.addLast(SKEW + " " + kx + " " + ky + " " + px + " " + py); return postConcat(SimpleMatrix.skew(kx, ky, px, py)); } @Implementation - public boolean postSkew(float kx, float ky) { + protected boolean postSkew(float kx, float ky) { postOps.addLast(SKEW + " " + kx + " " + ky); return postConcat(SimpleMatrix.skew(kx, ky)); } @Implementation - public boolean postConcat(Matrix other) { + protected boolean postConcat(Matrix other) { postOps.addLast(MATRIX + " " + other); return postConcat(getSimpleMatrix(other)); } @Implementation - public boolean invert(Matrix inverse) { - final SimpleMatrix inverseMatrix = mMatrix.invert(); + protected boolean invert(Matrix inverse) { + final SimpleMatrix inverseMatrix = simpleMatrix.invert(); if (inverseMatrix != null) { if (inverse != null) { final ShadowMatrix shadowInverse = Shadow.extract(inverse); - shadowInverse.mMatrix = inverseMatrix; + shadowInverse.simpleMatrix = inverseMatrix; } return true; } return false; } + boolean hasPerspective() { + return (simpleMatrix.mValues[6] != 0 || simpleMatrix.mValues[7] != 0 || simpleMatrix.mValues[8] != 1); + } + + protected AffineTransform getAffineTransform() { + // the AffineTransform constructor takes the value in a different order + // for a matrix [ 0 1 2 ] + // [ 3 4 5 ] + // the order is 0, 3, 1, 4, 2, 5... + return new AffineTransform( + simpleMatrix.mValues[0], + simpleMatrix.mValues[3], + simpleMatrix.mValues[1], + simpleMatrix.mValues[4], + simpleMatrix.mValues[2], + simpleMatrix.mValues[5]); + } + public PointF mapPoint(float x, float y) { - return mMatrix.transform(new PointF(x, y)); + return simpleMatrix.transform(new PointF(x, y)); } public PointF mapPoint(PointF point) { - return mMatrix.transform(point); + return simpleMatrix.transform(point); } @Implementation - public boolean mapRect(RectF destination, RectF source) { + protected boolean mapRect(RectF destination, RectF source) { final PointF leftTop = mapPoint(source.left, source.top); final PointF rightBottom = mapPoint(source.right, source.bottom); destination.set( @@ -313,11 +333,11 @@ public class ShadowMatrix { @Implementation protected void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int vectorCount) { - final float transX = mMatrix.mValues[Matrix.MTRANS_X]; - final float transY = mMatrix.mValues[Matrix.MTRANS_Y]; + final float transX = simpleMatrix.mValues[Matrix.MTRANS_X]; + final float transY = simpleMatrix.mValues[Matrix.MTRANS_Y]; - mMatrix.mValues[Matrix.MTRANS_X] = 0; - mMatrix.mValues[Matrix.MTRANS_Y] = 0; + simpleMatrix.mValues[Matrix.MTRANS_X] = 0; + simpleMatrix.mValues[Matrix.MTRANS_Y] = 0; for (int i = 0; i < vectorCount; i++) { final PointF mapped = mapPoint(src[srcIndex + i * 2], src[srcIndex + i * 2 + 1]); @@ -325,25 +345,43 @@ public class ShadowMatrix { dst[dstIndex + i * 2 + 1] = mapped.y; } - mMatrix.mValues[Matrix.MTRANS_X] = transX; - mMatrix.mValues[Matrix.MTRANS_Y] = transY; + simpleMatrix.mValues[Matrix.MTRANS_X] = transX; + simpleMatrix.mValues[Matrix.MTRANS_Y] = transY; + } + + @Implementation + protected float mapRadius(float radius) { + float[] src = new float[] {radius, 0.f, 0.f, radius}; + mapVectors(src, 0, src, 0, 2); + + float l1 = (float) Math.hypot(src[0], src[1]); + float l2 = (float) Math.hypot(src[2], src[3]); + return (float) Math.sqrt(l1 * l2); + } + + @Implementation + protected boolean setRectToRect(RectF src, RectF dst, Matrix.ScaleToFit stf) { + if (src.isEmpty()) { + reset(); + return false; + } + return simpleMatrix.setRectToRect(src, dst, stf); } @Implementation @Override public boolean equals(Object obj) { - final float[] values; if (obj instanceof Matrix) { - return getSimpleMatrix(((Matrix) obj)).equals(mMatrix); + return getSimpleMatrix(((Matrix) obj)).equals(simpleMatrix); } else { - return obj instanceof ShadowMatrix && obj.equals(mMatrix); + return obj instanceof ShadowMatrix && obj.equals(simpleMatrix); } } @Implementation(minSdk = KITKAT) @Override public int hashCode() { - return Objects.hashCode(mMatrix); + return Objects.hashCode(simpleMatrix); } public String getDescription() { @@ -352,16 +390,16 @@ public class ShadowMatrix { private static SimpleMatrix getSimpleMatrix(Matrix matrix) { final ShadowMatrix otherMatrix = Shadow.extract(matrix); - return otherMatrix.mMatrix; + return otherMatrix.simpleMatrix; } private boolean postConcat(SimpleMatrix matrix) { - mMatrix = matrix.multiply(mMatrix); + simpleMatrix = matrix.multiply(simpleMatrix); return true; } private boolean preConcat(SimpleMatrix matrix) { - mMatrix = mMatrix.multiply(matrix); + simpleMatrix = simpleMatrix.multiply(matrix); return true; } @@ -369,11 +407,16 @@ public class ShadowMatrix { * A simple implementation of an immutable matrix. */ private static class SimpleMatrix { - private static final SimpleMatrix IDENTITY = new SimpleMatrix(new float[] { - 1.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, - }); + private static final SimpleMatrix IDENTITY = newIdentityMatrix(); + + private static SimpleMatrix newIdentityMatrix() { + return new SimpleMatrix( + new float[] { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + }); + } private final float[] mValues; @@ -517,6 +560,62 @@ public class ShadowMatrix { point.x * mValues[3] + point.y * mValues[4] + mValues[5]); } + // See: https://android.googlesource.com/platform/frameworks/base/+/6fca81de9b2079ec88e785f58bf49bf1f0c105e2/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java + protected boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) { + if (dst.isEmpty()) { + mValues[0] = + mValues[1] = + mValues[2] = mValues[3] = mValues[4] = mValues[5] = mValues[6] = mValues[7] = 0; + mValues[8] = 1; + } else { + float tx = dst.width() / src.width(); + float sx = dst.width() / src.width(); + float ty = dst.height() / src.height(); + float sy = dst.height() / src.height(); + boolean xLarger = false; + + if (stf != ScaleToFit.FILL) { + if (sx > sy) { + xLarger = true; + sx = sy; + } else { + sy = sx; + } + } + + tx = dst.left - src.left * sx; + ty = dst.top - src.top * sy; + if (stf == ScaleToFit.CENTER || stf == ScaleToFit.END) { + float diff; + + if (xLarger) { + diff = dst.width() - src.width() * sy; + } else { + diff = dst.height() - src.height() * sy; + } + + if (stf == ScaleToFit.CENTER) { + diff = diff / 2; + } + + if (xLarger) { + tx += diff; + } else { + ty += diff; + } + } + + mValues[0] = sx; + mValues[4] = sy; + mValues[2] = tx; + mValues[5] = ty; + mValues[1] = mValues[3] = mValues[6] = mValues[7] = 0; + } + // shared cleanup + mValues[8] = 1; + return true; + } + @Override public boolean equals(Object o) { return this == o || (o instanceof SimpleMatrix && equals((SimpleMatrix) o)); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaMetadataRetriever.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaMetadataRetriever.java index 1f044c25a..0d17e8812 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaMetadataRetriever.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaMetadataRetriever.java @@ -31,27 +31,27 @@ public class ShadowMediaMetadataRetriever { } @Implementation - public void setDataSource(String path) { + protected void setDataSource(String path) { setDataSource(toDataSource(path)); } @Implementation - public void setDataSource(Context context, Uri uri) { + protected void setDataSource(Context context, Uri uri) { setDataSource(toDataSource(context, uri)); } @Implementation - public void setDataSource(String uri, Map<String, String> headers) { + protected void setDataSource(String uri, Map<String, String> headers) { setDataSource(toDataSource(uri, headers)); } @Implementation - public void setDataSource(FileDescriptor fd, long offset, long length) { + protected void setDataSource(FileDescriptor fd, long offset, long length) { setDataSource(toDataSource(fd, offset, length)); } @Implementation - public String extractMetadata(int keyCode) { + protected String extractMetadata(int keyCode) { if (metadata.containsKey(dataSource)) { return metadata.get(dataSource).get(keyCode); } @@ -59,7 +59,7 @@ public class ShadowMediaMetadataRetriever { } @Implementation - public Bitmap getFrameAtTime(long timeUs, int option) { + protected Bitmap getFrameAtTime(long timeUs, int option) { return (frames.containsKey(dataSource) ? frames.get(dataSource).get(timeUs) : null); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaPlayer.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaPlayer.java index 1614031fb..6e6c93896 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaPlayer.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaPlayer.java @@ -42,11 +42,11 @@ import org.robolectric.shadows.util.DataSource; * testing that your code properly handles asynchronous errors and events. This * near impossible task is made quite straightforward using this implementation * of {@link MediaPlayer} with Robolectric. - * + * * This shadow implementation provides much of the functionality needed to * emulate {@link MediaPlayer} initialization and playback behavior without having * to play actual media files. A summary of the features included are: - * + * * * Construction-time callback hook {@link CreateListener} so that * newly-created {@link MediaPlayer} instances can have their shadows configured * before they are used. @@ -78,31 +78,31 @@ import org.robolectric.shadows.util.DataSource; * {@link #addMediaInfo(DataSource, MediaInfo)} respectively) <i>before</i> * calling {@link #setDataSource}, otherwise you'll get an * {@link IllegalArgumentException}. - * + * * The current features of {@code ShadowMediaPlayer} were focused on development * for testing playback of audio tracks. Thus support for emulating timed text and * video events is incomplete. None of these features would be particularly onerous * to add/fix - contributions welcome, of course! - * + * * @author Fr Jeremy Krieg, Holy Monastery of St Nectarios, Adelaide, Australia */ @Implements(MediaPlayer.class) public class ShadowMediaPlayer extends ShadowPlayerBase { @Implementation - public static void __staticInitializer__() { + protected static void __staticInitializer__() { // don't bind the JNI library } /** * Listener that is called when a new MediaPlayer is constructed. - * + * * @see #setCreateListener(CreateListener) */ protected static CreateListener createListener; private static final Map<DataSource, Exception> exceptions = new HashMap<>(); private static final Map<DataSource, MediaInfo> mediaInfo = new HashMap<>(); - + @RealObject private MediaPlayer player; @@ -117,7 +117,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Possible behavior modes for the media player when a method is invoked in an * invalid state. - * + * * @see #setInvalidStateBehavior */ public enum InvalidStateBehavior { @@ -154,7 +154,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { public interface MediaEvent { public void run(MediaPlayer mp, ShadowMediaPlayer smp); } - + /** * Class specifying information for an emulated media object. Used by * ShadowMediaPlayer when setDataSource() is called to populate the shadow @@ -174,12 +174,12 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { public MediaInfo() { this(1000, 0); } - + /** * Creates a new {@code MediaInfo} object with the given duration and * preparation delay. A completion callback event is scheduled at * {@code duration} ms from the end. - * + * * @param duration * the duration (in ms) of this emulated media. A callback event * will be scheduled at this offset to stop playback simulation and @@ -199,7 +199,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Retrieves the current preparation delay for this media. - * + * * @return The current preparation delay (in ms). */ public int getPreparationDelay() { @@ -208,7 +208,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Sets the current preparation delay for this media. - * + * * @param preparationDelay * the new preparation delay (in ms). */ @@ -220,7 +220,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Schedules a generic event to run at the specified playback offset. Events * are run on the thread on which the {@link android.media.MediaPlayer * MediaPlayer} was created. - * + * * @param offset * the offset from the start of playback at which this event will * run. @@ -242,7 +242,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Schedules an error event to run at the specified playback offset. A * reference to the actual MediaEvent that is scheduled is returned, which can * be used in a subsequent call to {@link #removeEventAtOffset}. - * + * * @param offset * the offset from the start of playback at which this error will * trigger. @@ -266,7 +266,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Schedules an info event to run at the specified playback offset. A * reference to the actual MediaEvent that is scheduled is returned, which can * be used in a subsequent call to {@link #removeEventAtOffset}. - * + * * @param offset * the offset from the start of playback at which this event will * trigger. @@ -297,7 +297,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * playback offset. A reference to the actual MediaEvent that is scheduled is * returned, which can be used in a subsequent call to * {@link #removeEventAtOffset}. - * + * * This event will issue an {@link MediaPlayer.OnInfoListener#onInfo * onInfo()} callback with {@link MediaPlayer#MEDIA_INFO_BUFFERING_START} to * signal the start of buffering and then call {@link #doStop()} to @@ -305,7 +305,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * after {@code length} ms which fires a * {@link MediaPlayer#MEDIA_INFO_BUFFERING_END} info event and invokes * {@link #doStart()} to resume playback. - * + * * @param offset * the offset from the start of playback at which this underrun * will trigger. @@ -336,7 +336,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Removes the specified event from the playback schedule at the given * playback offset. - * + * * @param offset * the offset at which the event was scheduled. * @param event @@ -356,7 +356,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Removes the specified event from the playback schedule at all playback * offsets where it has been scheduled. - * + * * @param event * the event to remove. * @see ShadowMediaPlayer.MediaInfo#removeEventAtOffset(int,ShadowMediaPlayer.MediaEvent) @@ -378,16 +378,16 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { Message msg = handler.obtainMessage(MEDIA_EVENT, e); handler.sendMessage(msg); } - + public void postEventDelayed(MediaEvent e, long delay) { Message msg = handler.obtainMessage(MEDIA_EVENT, e); handler.sendMessageDelayed(msg, delay); } - + /** * Callback interface for clients that wish to be informed when a new * {@link MediaPlayer} instance is constructed. - * + * * @see #setCreateListener */ public static interface CreateListener { @@ -395,7 +395,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Method that is invoked when a new {@link MediaPlayer} is created. This * method is invoked at the end of the constructor, after all of the default * setup has been completed. - * + * * @param player * reference to the newly-created media player object. * @param shadow @@ -504,7 +504,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { } @Implementation - public static MediaPlayer create(Context context, int resId) { + protected static MediaPlayer create(Context context, int resId) { MediaPlayer mp = new MediaPlayer(); ShadowMediaPlayer shadow = Shadow.extract(mp); shadow.sourceResId = resId; @@ -520,7 +520,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { } @Implementation - public static MediaPlayer create(Context context, Uri uri) { + protected static MediaPlayer create(Context context, Uri uri) { MediaPlayer mp = new MediaPlayer(); try { mp.setDataSource(context, uri); @@ -533,7 +533,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { } @Implementation - public void __constructor__() { + protected void __constructor__() { // Contract of audioSessionId is that if it is 0 (which represents // the master mix) then that's an error. By default it generates // an ID that is unique system-wide. We could simulate guaranteed @@ -583,7 +583,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Usually this method would not be called directly, but indirectly through one of the * other {@link #setDataSource(String)} implementations, which use {@link DataSource#toDataSource(String)} * methods to convert their discrete parameters into a single {@link DataSource} instance. - * + * * @param dataSource the data source that is being set. * @throws IOException if the specified data source has been configured to throw an IO exception. * @see #addException(DataSource, IOException) @@ -605,14 +605,14 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { doSetDataSource(dataSource); state = INITIALIZED; } - + /** * Sets the data source without doing any other emulation. Sets the * internal data source only. * Calling directly can be useful for setting up a {@link ShadowMediaPlayer} * instance during specific testing so that you don't have to clutter your * tests catching exceptions you know won't be thrown. - * + * * @param dataSource the data source that is being set. * @see #setDataSource(DataSource) */ @@ -623,51 +623,52 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { } this.dataSource = dataSource; } - + @Implementation - public void setDataSource(String path) throws IOException { + protected void setDataSource(String path) throws IOException { setDataSource(toDataSource(path)); } @Implementation - public void setDataSource(Context context, Uri uri, Map<String, String> headers) throws IOException { + protected void setDataSource(Context context, Uri uri, Map<String, String> headers) + throws IOException { setDataSource(toDataSource(context, uri, headers)); sourceUri = uri; } @Implementation - public void setDataSource(String uri, Map<String, String> headers) throws IOException { + protected void setDataSource(String uri, Map<String, String> headers) throws IOException { setDataSource(toDataSource(uri, headers)); } @Implementation - public void setDataSource(FileDescriptor fd, long offset, long length) throws IOException { + protected void setDataSource(FileDescriptor fd, long offset, long length) throws IOException { setDataSource(toDataSource(fd, offset, length)); } public static MediaInfo getMediaInfo(DataSource dataSource) { return mediaInfo.get(dataSource); } - + public static void addMediaInfo(DataSource dataSource, MediaInfo info) { mediaInfo.put(dataSource, info); } - + public static void addException(DataSource dataSource, RuntimeException e) { exceptions.put(dataSource, e); } - + public static void addException(DataSource dataSource, IOException e) { exceptions.put(dataSource, e); } - + /** * Checks states for methods that only log when there is an error. Such * methods throw an {@link IllegalArgumentException} when invoked in the END * state, but log an error in other disallowed states. This method will either * emulate this behavior or else will generate an assertion if invoked from a * disallowed state if {@link #setAssertOnError assertOnError} is set. - * + * * @param method * the name of the method being tested. * @param allowedStates @@ -678,19 +679,19 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { */ private void checkStateLog(String method, EnumSet<State> allowedStates) { switch (invalidStateBehavior) { - case SILENT: - break; - case EMULATE: - if (state == END) { - String msg = "Can't call " + method + " from state " + state; - throw new IllegalStateException(msg); - } - break; - case ASSERT: - if (!allowedStates.contains(state) || state == END) { - String msg = "Can't call " + method + " from state " + state; - throw new AssertionError(msg); - } + case SILENT: + break; + case EMULATE: + if (state == END) { + String msg = "Can't call " + method + " from state " + state; + throw new IllegalStateException(msg); + } + break; + case ASSERT: + if (!allowedStates.contains(state) || state == END) { + String msg = "Can't call " + method + " from state " + state; + throw new AssertionError(msg); + } } } @@ -700,13 +701,13 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * onError()} when invoked in an illegal state. Such methods always throw * {@link IllegalStateException} rather than invoke {@code onError()} if * they are invoked from the END state. - * + * * This method will either emulate this behavior by posting an * {@code onError()} callback to the current thread's message queue (or * throw an {@link IllegalStateException} if invoked from the END state), or * else it will generate an assertion if {@link #setAssertOnError * assertOnError} is set. - * + * * @param method * the name of the method being tested. * @param allowedStates @@ -719,19 +720,19 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { private boolean checkStateError(String method, EnumSet<State> allowedStates) { if (!allowedStates.contains(state)) { switch (invalidStateBehavior) { - case SILENT: - break; - case EMULATE: - if (state == END) { + case SILENT: + break; + case EMULATE: + if (state == END) { + String msg = "Can't call " + method + " from state " + state; + throw new IllegalStateException(msg); + } + state = ERROR; + postEvent(invalidStateErrorCallback); + return false; + case ASSERT: String msg = "Can't call " + method + " from state " + state; - throw new IllegalStateException(msg); - } - state = ERROR; - postEvent(invalidStateErrorCallback); - return false; - case ASSERT: - String msg = "Can't call " + method + " from state " + state; - throw new AssertionError(msg); + throw new AssertionError(msg); } } return true; @@ -743,7 +744,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * {@link IllegalArgumentException} if it determines that the method has been * invoked from a disallowed state, or else it will generate an assertion if * {@link #setAssertOnError assertOnError} is set. - * + * * @param method * the name of the method being tested. * @param allowedStates @@ -756,44 +757,43 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { if (!allowedStates.contains(state)) { String msg = "Can't call " + method + " from state " + state; switch (invalidStateBehavior) { - case SILENT: - break; - case EMULATE: - throw new IllegalStateException(msg); - case ASSERT: - throw new AssertionError(msg); + case SILENT: + break; + case EMULATE: + throw new IllegalStateException(msg); + case ASSERT: + throw new AssertionError(msg); } } } @Implementation - public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) { + protected void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) { completionListener = listener; } @Implementation - public void setOnSeekCompleteListener( - MediaPlayer.OnSeekCompleteListener listener) { + protected void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener) { seekCompleteListener = listener; } @Implementation - public void setOnPreparedListener(MediaPlayer.OnPreparedListener listener) { + protected void setOnPreparedListener(MediaPlayer.OnPreparedListener listener) { preparedListener = listener; } @Implementation - public void setOnInfoListener(MediaPlayer.OnInfoListener listener) { + protected void setOnInfoListener(MediaPlayer.OnInfoListener listener) { infoListener = listener; } @Implementation - public void setOnErrorListener(MediaPlayer.OnErrorListener listener) { + protected void setOnErrorListener(MediaPlayer.OnErrorListener listener) { errorListener = listener; } @Implementation - public boolean isLooping() { + protected boolean isLooping() { checkStateException("isLooping()", nonEndStates); return looping; } @@ -804,20 +804,20 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { .complementOf(EnumSet.of(ERROR, END)); @Implementation - public void setLooping(boolean looping) { + protected void setLooping(boolean looping) { checkStateError("setLooping()", nonErrorStates); this.looping = looping; } @Implementation - public void setVolume(float left, float right) { + protected void setVolume(float left, float right) { checkStateError("setVolume()", nonErrorStates); leftVolume = left; rightVolume = right; } @Implementation - public boolean isPlaying() { + protected boolean isPlaying() { checkStateError("isPlaying()", nonErrorStates); return state == STARTED; } @@ -826,19 +826,17 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { STOPPED); /** - * Simulates {@link MediaPlayer#prepareAsync()}. Sleeps for - * {@link MediaInfo#getPreparationDelay() preparationDelay} ms by calling - * {@link SystemClock#sleep(long)} before calling - * {@link #invokePreparedListener()}. - * - * If {@code preparationDelay} is not positive and non-zero, there is no - * sleep. - * + * Simulates {@link MediaPlayer#prepareAsync()}. Sleeps for {@link MediaInfo#getPreparationDelay() + * preparationDelay} ms by calling {@link SystemClock#sleep(long)} before calling {@link + * #invokePreparedListener()}. + * + * <p>If {@code preparationDelay} is not positive and non-zero, there is no sleep. + * * @see MediaInfo#setPreparationDelay(int) * @see #invokePreparedListener() */ @Implementation - public void prepare() { + protected void prepare() { checkStateException("prepare()", preparableStates); MediaInfo info = getMediaInfo(); if (info.preparationDelay > 0) { @@ -848,17 +846,16 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { } /** - * Simulates {@link MediaPlayer#prepareAsync()}. Sets state to PREPARING and - * posts a callback to {@link #invokePreparedListener()} if the current - * preparation delay for the current media (see {@link #getMediaInfo()}) is >= - * 0, otherwise the test suite is responsible for calling - * {@link #invokePreparedListener()} directly if required. - * + * Simulates {@link MediaPlayer#prepareAsync()}. Sets state to PREPARING and posts a callback to + * {@link #invokePreparedListener()} if the current preparation delay for the current media (see + * {@link #getMediaInfo()}) is >= 0, otherwise the test suite is responsible for calling {@link + * #invokePreparedListener()} directly if required. + * * @see MediaInfo#setPreparationDelay(int) * @see #invokePreparedListener() */ @Implementation - public void prepareAsync() { + protected void prepareAsync() { checkStateException("prepareAsync()", preparableStates); state = PREPARING; MediaInfo info = getMediaInfo(); @@ -873,14 +870,14 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Simulates private native method {@link MediaPlayer#_start()}. Sets state to STARTED and calls * {@link #doStart()} to start scheduling playback callback events. - * - * If the current state is PLAYBACK_COMPLETED, the current position is reset - * to zero before starting playback. - * + * + * <p>If the current state is PLAYBACK_COMPLETED, the current position is reset to zero before + * starting playback. + * * @see #doStart() */ @Implementation - public void start() { + protected void start() { if (checkStateError("start()", startableStates)) { if (state == PLAYBACK_COMPLETED) { startOffset = 0; @@ -911,14 +908,14 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Tests to see if the player is really playing. - * + * * The player is defined as "really playing" if simulated playback events * (including playback completion) are being scheduled and invoked and * {@link #getCurrentPosition currentPosition} is being updated as time * passes. Note that while the player will normally be really playing if in * the STARTED state, this is not always the case - for example, if a pending * seek is in progress, or perhaps a buffer underrun is being simulated. - * + * * @return {@code true} if the player is really playing or * {@code false} if the player is internally paused. * @see #doStart @@ -932,7 +929,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Starts simulated playback. Until this method is called, the player is not * "really playing" (see {@link #isReallyPlaying} for a definition of * "really playing"). - * + * * This method is used internally by the various shadow method implementations * of the MediaPlayer public API, but may also be called directly by the test * suite if you wish to simulate an internal pause. For example, to simulate @@ -942,7 +939,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * end and restart normal playback (which is what * {@link ShadowMediaPlayer.MediaInfo#scheduleBufferUnderrunAtOffset(int, int) scheduleBufferUnderrunAtOffset()} * does). - * + * * @see #isReallyPlaying() * @see #doStop() */ @@ -955,11 +952,11 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Pauses simulated playback. After this method is called, the player is no * longer "really playing" (see {@link #isReallyPlaying} for a definition of * "really playing"). - * + * * This method is used internally by the various shadow method implementations * of the MediaPlayer public API, but may also be called directly by the test * suite if you wish to simulate an internal pause. - * + * * @see #isReallyPlaying() * @see #doStart() */ @@ -976,13 +973,13 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { PAUSED, PLAYBACK_COMPLETED); /** - * Simulates {@link MediaPlayer#_pause()}. Invokes {@link #doStop()} to suspend - * playback event callbacks and sets the state to PAUSED. - * + * Simulates {@link MediaPlayer#_pause()}. Invokes {@link #doStop()} to suspend playback event + * callbacks and sets the state to PAUSED. + * * @see #doStop() */ @Implementation - public void _pause() { + protected void _pause() { if (checkStateError("pause()", pausableStates)) { doStop(); state = PAUSED; @@ -992,11 +989,11 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { static final EnumSet<State> allStates = EnumSet.allOf(State.class); /** - * Simulates call to {@link MediaPlayer#_release()}. Calls {@link #doStop()} to - * suspend playback event callbacks and sets the state to END. + * Simulates call to {@link MediaPlayer#_release()}. Calls {@link #doStop()} to suspend playback + * event callbacks and sets the state to END. */ @Implementation - public void _release() { + protected void _release() { checkStateException("release()", allStates); doStop(); state = END; @@ -1004,11 +1001,11 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { } /** - * Simulates call to {@link MediaPlayer#_reset()}. Calls {@link #doStop()} to - * suspend playback event callbacks and sets the state to IDLE. + * Simulates call to {@link MediaPlayer#_reset()}. Calls {@link #doStop()} to suspend playback + * event callbacks and sets the state to IDLE. */ @Implementation - public void _reset() { + protected void _reset() { checkStateException("reset()", nonEndStates); doStop(); state = IDLE; @@ -1020,11 +1017,11 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { STARTED, PAUSED, STOPPED, PLAYBACK_COMPLETED); /** - * Simulates call to {@link MediaPlayer#release()}. Calls {@link #doStop()} to - * suspend playback event callbacks and sets the state to STOPPED. + * Simulates call to {@link MediaPlayer#release()}. Calls {@link #doStop()} to suspend playback + * event callbacks and sets the state to STOPPED. */ @Implementation - public void _stop() { + protected void _stop() { if (checkStateError("stop()", stoppableStates)) { doStop(); state = STOPPED; @@ -1036,52 +1033,52 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { PLAYBACK_COMPLETED); @Implementation - public void attachAuxEffect(int effectId) { + protected void attachAuxEffect(int effectId) { checkStateError("attachAuxEffect()", attachableStates); auxEffect = effectId; } @Implementation - public int getAudioSessionId() { + protected int getAudioSessionId() { checkStateException("getAudioSessionId()", allStates); return audioSessionId; } /** - * Simulates call to {@link MediaPlayer#getCurrentPosition()}. Simply does the - * state validity checks and then invokes {@link #getCurrentPositionRaw()} to - * calculate the simulated playback position. - * + * Simulates call to {@link MediaPlayer#getCurrentPosition()}. Simply does the state validity + * checks and then invokes {@link #getCurrentPositionRaw()} to calculate the simulated playback + * position. + * * @return The current offset (in ms) of the simulated playback. * @see #getCurrentPositionRaw() */ @Implementation - public int getCurrentPosition() { + protected int getCurrentPosition() { checkStateError("getCurrentPosition()", attachableStates); return getCurrentPositionRaw(); } /** - * Simulates call to {@link MediaPlayer#getDuration()}. Retrieves the duration - * as defined by the current {@link MediaInfo} instance. - * + * Simulates call to {@link MediaPlayer#getDuration()}. Retrieves the duration as defined by the + * current {@link MediaInfo} instance. + * * @return The duration (in ms) of the current simulated playback. * @see #addMediaInfo(DataSource, MediaInfo) */ @Implementation - public int getDuration() { + protected int getDuration() { checkStateError("getDuration()", stoppableStates); return getMediaInfo().duration; } @Implementation - public int getVideoHeight() { + protected int getVideoHeight() { checkStateLog("getVideoHeight()", attachableStates); return videoHeight; } @Implementation - public int getVideoWidth() { + protected int getVideoWidth() { checkStateLog("getVideoWidth()", attachableStates); return videoWidth; } @@ -1090,16 +1087,14 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { STARTED, PAUSED, PLAYBACK_COMPLETED); /** - * Simulates seeking to specified position. The seek will complete after - * {@link #seekDelay} ms (defaults to 0), or else if seekDelay is negative - * then the controlling test is expected to simulate seek completion by - * manually invoking {@link #invokeSeekCompleteListener}. - * - * @param seekTo - * the offset (in ms) from the start of the track to seek to. + * Simulates seeking to specified position. The seek will complete after {@link #seekDelay} ms + * (defaults to 0), or else if seekDelay is negative then the controlling test is expected to + * simulate seek completion by manually invoking {@link #invokeSeekCompleteListener}. + * + * @param seekTo the offset (in ms) from the start of the track to seek to. */ @Implementation - public void seekTo(int seekTo) { + protected void seekTo(int seekTo) { seekTo(seekTo, MediaPlayer.SEEK_PREVIOUS_SYNC); } @@ -1125,7 +1120,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { static private final EnumSet<State> idleState = EnumSet.of(IDLE); @Implementation - public void setAudioSessionId(int sessionId) { + protected void setAudioSessionId(int sessionId) { checkStateError("setAudioSessionId()", idleState); audioSessionId = sessionId; } @@ -1134,7 +1129,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { INITIALIZED, STOPPED); @Implementation - public void setAudioStreamType(int audioStreamType) { + protected void setAudioStreamType(int audioStreamType) { checkStateError("setAudioStreamType()", nonPlayingStates); this.audioStreamType = audioStreamType; } @@ -1151,7 +1146,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * is invoked soon after, without a break in the code. Using this callback * means you don't have to change this common pattern just so that you can * customize the shadow for testing. - * + * * @param createListener * the listener to be invoked */ @@ -1168,7 +1163,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * offset (no matter how long playback may be paused for, or where you seek * to, etc), see {@link MediaInfo#scheduleEventAtOffset(int, ShadowMediaPlayer.MediaEvent)} and * its various helpers. - * + * * @return Handler object that can be used to schedule asynchronous events on * this media player. */ @@ -1181,7 +1176,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * method is invoked in an invalid state. See * {@link #setInvalidStateBehavior(InvalidStateBehavior)} for a discussion of * the available modes and their associated behaviors. - * + * * @return The current invalid state behavior mode. * @see #setInvalidStateBehavior */ @@ -1220,7 +1215,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * * Additionally, all three methods behave synchronously (throwing * {@link IllegalStateException} when invoked from the END state. - * + * * To complicate matters slightly, the official documentation sometimes * contradicts observed behavior. For example, the documentation says it is * illegal to call {@link #setDataSource} from the ERROR state - however, in @@ -1252,7 +1247,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Retrieves the currently selected {@link MediaInfo}. This instance is used * to define current duration, preparation delay, exceptions for * {@code setDataSource()}, playback events, etc. - * + * * @return The currently selected {@link MediaInfo}. * @see #addMediaInfo * @see #doSetDataSource(DataSource) @@ -1264,7 +1259,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Sets the current position, bypassing the normal state checking. Use with * care. - * + * * @param position * the new playback position. */ @@ -1275,7 +1270,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Retrieves the current position without doing the state checking that the * emulated version of {@link #getCurrentPosition()} does. - * + * * @return The current playback position within the current clip. */ public int getCurrentPositionRaw() { @@ -1289,7 +1284,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Retrieves the current duration without doing the state checking that the * emulated version does. - * + * * @return The duration of the current clip loaded by the player. */ public int getDurationRaw() { @@ -1299,7 +1294,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Retrieves the current state of the {@link MediaPlayer}. Uses the states as * defined in the {@link MediaPlayer} documentation. - * + * * @return The current state of the {@link MediaPlayer}, as defined in the * MediaPlayer documentation. * @see #setState @@ -1312,11 +1307,11 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Forces the @link MediaPlayer} into the specified state. Uses the states as * defined in the {@link MediaPlayer} documentation. - * + * * Note that by invoking this method directly you can get the player into an * inconsistent state that a real player could not be put in (eg, in the END * state but with playback events still happening). Use with care. - * + * * @param state * the new state of the {@link MediaPlayer}, as defined in the * MediaPlayer documentation. @@ -1335,7 +1330,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * it should be annotated with {@link Implementation}, because * there is a private method in the later API versions with * the same name, however this would fail on earlier versions. - * + * * @return audioStreamType */ public int getTheAudioStreamType() { @@ -1354,7 +1349,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Default is 0. If set to -1, then seekTo() will not call the * OnSeekCompleteListener automatically; you will need to call * invokeSeekCompleteListener() manually. - * + * * @param seekDelay * length of time to delay (ms) */ @@ -1364,7 +1359,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Useful for assertions. - * + * * @return The current {@code auxEffect} setting. */ public int getAuxEffect() { @@ -1373,7 +1368,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Retrieves the pending seek setting. - * + * * @return The position to which the shadow player is seeking for the seek in * progress (ie, after the call to {@link #seekTo} but before a call * to {@link #invokeSeekCompleteListener()}). Returns {@code -1} @@ -1386,9 +1381,9 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Retrieves the data source (if any) that was passed in to * {@link #setDataSource(DataSource)}. - * + * * Useful for assertions. - * + * * @return The source passed in to {@code setDataSource}. */ public DataSource getDataSource() { @@ -1399,7 +1394,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Retrieves the source path (if any) that was passed in to * {@link MediaPlayer#setDataSource(Context, Uri, Map)} or * {@link MediaPlayer#setDataSource(Context, Uri)}. - * + * * @return The source Uri passed in to {@code setDataSource}. */ public Uri getSourceUri() { @@ -1409,7 +1404,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Retrieves the resource ID used in the call to {@link #create(Context, int)} * (if any). - * + * * @return The resource ID passed in to {@code create()}, or * {@code -1} if a different method of setting the source was * used. @@ -1441,7 +1436,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { * Tests to see if the player is in the PREPARED state. * This is mainly used for backward compatibility. * {@link #getState} may be more useful for new testing applications. - * + * * @return {@code true} if the MediaPlayer is in the PREPARED state, * false otherwise. */ @@ -1507,7 +1502,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Allows test cases to directly simulate invocation of the OnInfo event. - * + * * @param what * parameter to pass in to {@code what} in * {@link MediaPlayer.OnInfoListener#onInfo(MediaPlayer, int, int)}. @@ -1523,7 +1518,7 @@ public class ShadowMediaPlayer extends ShadowPlayerBase { /** * Allows test cases to directly simulate invocation of the OnError event. - * + * * @param what * parameter to pass in to {@code what} in * {@link MediaPlayer.OnErrorListener#onError(MediaPlayer, int, int)}. diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaRecorder.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaRecorder.java index 7dc410dc9..c70ca98d5 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaRecorder.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaRecorder.java @@ -10,7 +10,7 @@ import org.robolectric.annotation.Implements; public class ShadowMediaRecorder { @SuppressWarnings("UnusedDeclaration") @Implementation - public static void __staticInitializer__() { + protected static void __staticInitializer__() { // don't bind the JNI library } @@ -48,132 +48,132 @@ public class ShadowMediaRecorder { private MediaRecorder.OnInfoListener infoListener; @Implementation - public void __constructor__() { + protected void __constructor__() { state = STATE_INITIAL; } @Implementation - public void setAudioChannels(int numChannels) { + protected void setAudioChannels(int numChannels) { audioChannels = numChannels; } @Implementation - public void setAudioEncoder(int audio_encoder) { + protected void setAudioEncoder(int audio_encoder) { audioEncoder = audio_encoder; state = STATE_DATA_SOURCE_CONFIGURED; } @Implementation - public void setAudioEncodingBitRate(int bitRate) { + protected void setAudioEncodingBitRate(int bitRate) { audioBitRate = bitRate; } @Implementation - public void setAudioSamplingRate(int samplingRate) { + protected void setAudioSamplingRate(int samplingRate) { audioSamplingRate = samplingRate; } @Implementation - public void setAudioSource(int audio_source) { + protected void setAudioSource(int audio_source) { audioSource = audio_source; state = STATE_INITIALIZED; } @Implementation - public void setCamera(Camera c) { + protected void setCamera(Camera c) { camera = c; } @Implementation - public void setMaxDuration(int max_duration_ms) { + protected void setMaxDuration(int max_duration_ms) { maxDuration = max_duration_ms; } @Implementation - public void setMaxFileSize(long max_filesize_bytes) { + protected void setMaxFileSize(long max_filesize_bytes) { maxFileSize = max_filesize_bytes; } @Implementation - public void setOnErrorListener(MediaRecorder.OnErrorListener l) { + protected void setOnErrorListener(MediaRecorder.OnErrorListener l) { errorListener = l; } @Implementation - public void setOnInfoListener(MediaRecorder.OnInfoListener listener) { + protected void setOnInfoListener(MediaRecorder.OnInfoListener listener) { infoListener = listener; } @Implementation - public void setOutputFile(String path) { + protected void setOutputFile(String path) { outputPath = path; state = STATE_DATA_SOURCE_CONFIGURED; } @Implementation - public void setOutputFormat(int output_format) { + protected void setOutputFormat(int output_format) { outputFormat = output_format; state = STATE_DATA_SOURCE_CONFIGURED; } @Implementation - public void setPreviewDisplay(Surface sv) { + protected void setPreviewDisplay(Surface sv) { previewDisplay = sv; state = STATE_DATA_SOURCE_CONFIGURED; } @Implementation - public void setVideoEncoder(int video_encoder) { + protected void setVideoEncoder(int video_encoder) { videoEncoder = video_encoder; state = STATE_DATA_SOURCE_CONFIGURED; } @Implementation - public void setVideoEncodingBitRate(int bitRate) { + protected void setVideoEncodingBitRate(int bitRate) { videoBitRate = bitRate; } @Implementation - public void setVideoFrameRate(int rate) { + protected void setVideoFrameRate(int rate) { videoFrameRate = rate; state = STATE_DATA_SOURCE_CONFIGURED; } @Implementation - public void setVideoSize(int width, int height) { + protected void setVideoSize(int width, int height) { videoWidth = width; videoHeight = height; state = STATE_DATA_SOURCE_CONFIGURED; } @Implementation - public void setVideoSource(int video_source) { + protected void setVideoSource(int video_source) { videoSource = video_source; state = STATE_INITIALIZED; } @Implementation - public void prepare() { + protected void prepare() { state = STATE_PREPARED; } @Implementation - public void start() { + protected void start() { state = STATE_RECORDING; } @Implementation - public void stop() { + protected void stop() { state = STATE_INITIAL; } @Implementation - public void reset() { + protected void reset() { state = STATE_INITIAL; } @Implementation - public void release() { + protected void release() { state = STATE_RELEASED; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaStore.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaStore.java index cc1521ade..d9609b36e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaStore.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMediaStore.java @@ -18,7 +18,7 @@ public class ShadowMediaStore { public static class ShadowMedia { @Implementation - public static Bitmap getBitmap(ContentResolver cr, Uri url) { + protected static Bitmap getBitmap(ContentResolver cr, Uri url) { return ShadowBitmapFactory.create(url.toString()); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMemoryMappedFile.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMemoryMappedFile.java index f9095b435..5af527198 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMemoryMappedFile.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMemoryMappedFile.java @@ -81,6 +81,7 @@ public class ShadowMemoryMappedFile { } @Implementation + @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") public int size() { return bytes.length; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessage.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessage.java index cb36cb219..8d6846728 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessage.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessage.java @@ -56,12 +56,11 @@ public class ShadowMessage { } /** - * Hook to unscheduled the callback when the message is recycled. - * Invokes {@link #unschedule()} and then calls through to - * {@link Message#recycle()} on the real object. + * Hook to unscheduled the callback when the message is recycled. Invokes {@link #unschedule()} + * and then calls through to {@link Message#recycle()} on the real object. */ @Implementation(maxSdk = KITKAT_WATCH) - public void recycle() { + protected void recycle() { unschedule(); directlyOn(realMessage, Message.class, "recycle"); } @@ -85,18 +84,18 @@ public class ShadowMessage { } /** - * Convenience method to provide access to the private {@code Message.isInUse()} - * method. Note that the definition of "in use" changed with API 21: + * Convenience method to provide access to the private {@code Message.isInUse()} method. Note that + * the definition of "in use" changed with API 21: * - * In API 19, a message was only considered "in use" during its dispatch. In API 21, the - * message is considered "in use" from the time it is enqueued until the time that - * it is freshly obtained via a call to {@link Message#obtain()}. This means that - * in API 21 messages that are in the recycled pool will still be marked as "in use". + * <p>In API 19, a message was only considered "in use" during its dispatch. In API 21, the + * message is considered "in use" from the time it is enqueued until the time that it is freshly + * obtained via a call to {@link Message#obtain()}. This means that in API 21 messages that are in + * the recycled pool will still be marked as "in use". * * @return {@code true} if the message is currently "in use", {@code false} otherwise. */ @Implementation - public boolean isInUse() { + protected boolean isInUse() { return directlyOn(realMessage, Message.class, "isInUse"); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessageQueue.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessageQueue.java index 57b311277..5ad4e32be 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessageQueue.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessageQueue.java @@ -44,6 +44,7 @@ public class ShadowMessageQueue { // rather than automatic. @HiddenApi @Implementation + @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") public static Number nativeInit() { return 1; } @@ -55,8 +56,7 @@ public class ShadowMessageQueue { } @Implementation(minSdk = LOLLIPOP) - public static void nativeDestroy(long ptr) { - } + protected static void nativeDestroy(long ptr) {} @HiddenApi @Implementation(minSdk = KITKAT, maxSdk = KITKAT_WATCH) @@ -65,7 +65,7 @@ public class ShadowMessageQueue { } @Implementation(minSdk = LOLLIPOP, maxSdk = LOLLIPOP_MR1) - public static boolean nativeIsIdling(long ptr) { + protected static boolean nativeIsIdling(long ptr) { return false; } @@ -93,7 +93,7 @@ public class ShadowMessageQueue { @Implementation @SuppressWarnings("SynchronizeOnNonFinalField") - public boolean enqueueMessage(final Message msg, long when) { + protected boolean enqueueMessage(final Message msg, long when) { final boolean retval = directlyOn(realQueue, MessageQueue.class, "enqueueMessage", from(Message.class, msg), from(long.class, when)); if (retval) { final Runnable callback = new Runnable() { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessenger.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessenger.java index fb89fab54..0594f0786 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessenger.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMessenger.java @@ -29,28 +29,28 @@ public class ShadowMessenger { private Handler handler; @Implementation - public void __constructor__(Handler handler) { + protected void __constructor__(Handler handler) { this.handler = handler; Object target = ReflectionHelpers.callInstanceMethod(handler, "getIMessenger"); ReflectionHelpers.setField(messenger, "mTarget", target); } @Implementation - public void __constructor__(IBinder target) { + protected void __constructor__(IBinder target) { if (target != null && target instanceof FakeBinder) { handler = ((FakeBinder) target).handler; } } @Implementation - public void send(Message message) throws RemoteException { + protected void send(Message message) throws RemoteException { lastMessageSent = message; message.setTarget(handler); message.sendToTarget(); } @Implementation - public IBinder getBinder() { + protected IBinder getBinder() { return new FakeBinder(handler); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMimeTypeMap.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMimeTypeMap.java index c8a4a3234..d1e9f3d6c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMimeTypeMap.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMimeTypeMap.java @@ -16,7 +16,7 @@ public class ShadowMimeTypeMap { private static final Object singletonLock = new Object(); @Implementation - public static MimeTypeMap getSingleton() { + protected static MimeTypeMap getSingleton() { if (singleton == null) { synchronized (singletonLock) { if (singleton == null) { @@ -37,7 +37,7 @@ public class ShadowMimeTypeMap { } @Implementation - public String getMimeTypeFromExtension(String extension) { + protected String getMimeTypeFromExtension(String extension) { if (extensionToMimeTypeMap.containsKey(extension)) return extensionToMimeTypeMap.get(extension); @@ -45,7 +45,7 @@ public class ShadowMimeTypeMap { } @Implementation - public String getExtensionFromMimeType(String mimeType) { + protected String getExtensionFromMimeType(String mimeType) { if (mimeTypeToExtensionMap.containsKey(mimeType)) return mimeTypeToExtensionMap.get(mimeType); @@ -63,12 +63,12 @@ public class ShadowMimeTypeMap { } @Implementation - public boolean hasExtension(String extension) { + protected boolean hasExtension(String extension) { return extensionToMimeTypeMap.containsKey(extension); } @Implementation - public boolean hasMimeType(String mimeType) { + protected boolean hasMimeType(String mimeType) { return mimeTypeToExtensionMap.containsKey(mimeType); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMotionEvent.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMotionEvent.java index 9a63f1cc8..c422b70e4 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMotionEvent.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowMotionEvent.java @@ -646,12 +646,14 @@ public class ShadowMotionEvent { @Implementation(maxSdk = KITKAT_WATCH) @HiddenApi - protected static void nativeSetSource(int nativePtr, int source) { + protected static int nativeSetSource(int nativePtr, int source) { nativeSetSource((long) nativePtr, source); + return 0; } @Implementation(minSdk = LOLLIPOP) @HiddenApi + @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") protected static void nativeSetSource(long nativePtr, int source) { NativeInput.MotionEvent event = getNativeMotionEvent(nativePtr); event.setSource(source); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetwork.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetwork.java index 71899b271..8981bca19 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetwork.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetwork.java @@ -27,7 +27,7 @@ public class ShadowNetwork { } @Implementation - public void __constructor__(int netId) { + protected void __constructor__(int netId) { this.netId = netId; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetworkInfo.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetworkInfo.java index 29c542164..19d26f252 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetworkInfo.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNetworkInfo.java @@ -12,9 +12,9 @@ public class ShadowNetworkInfo { private int connectionType; private int connectionSubType; private NetworkInfo.DetailedState detailedState; - + @Implementation - public static void __staticInitializer__() {} + protected static void __staticInitializer__() {} /** * @deprecated use {@link #newInstance(NetworkInfo.DetailedState, int, int, boolean, @@ -53,37 +53,37 @@ public class ShadowNetworkInfo { } @Implementation - public boolean isConnected() { + protected boolean isConnected() { return state == NetworkInfo.State.CONNECTED; } @Implementation - public boolean isConnectedOrConnecting() { + protected boolean isConnectedOrConnecting() { return isConnected() || state == NetworkInfo.State.CONNECTING; } @Implementation - public NetworkInfo.State getState() { + protected NetworkInfo.State getState() { return state; } @Implementation - public NetworkInfo.DetailedState getDetailedState() { + protected NetworkInfo.DetailedState getDetailedState() { return detailedState; } @Implementation - public int getType(){ + protected int getType() { return connectionType; } @Implementation - public int getSubtype() { + protected int getSubtype() { return connectionSubType; } @Implementation - public boolean isAvailable() { + protected boolean isAvailable() { return isAvailable; } @@ -124,7 +124,7 @@ public class ShadowNetworkInfo { * * @param connectionType the value that {@link #getType()} will return. */ - public void setConnectionType(int connectionType){ + public void setConnectionType(int connectionType) { this.connectionType = connectionType; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNfcAdapter.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNfcAdapter.java index 1ddd8073c..b39cac8bc 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNfcAdapter.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNfcAdapter.java @@ -28,7 +28,7 @@ public class ShadowNfcAdapter { private NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback; @Implementation - public static NfcAdapter getNfcAdapter(Context context) { + protected static NfcAdapter getNfcAdapter(Context context) { if (!hardwareExists) { return null; } @@ -36,7 +36,8 @@ public class ShadowNfcAdapter { } @Implementation - public void enableForegroundDispatch(Activity activity, PendingIntent intent, IntentFilter[] filters, String[][] techLists) { + protected void enableForegroundDispatch( + Activity activity, PendingIntent intent, IntentFilter[] filters, String[][] techLists) { this.enabledActivity = activity; this.intent = intent; this.filters = filters; @@ -44,7 +45,7 @@ public class ShadowNfcAdapter { } @Implementation - public void disableForegroundDispatch(Activity activity) { + protected void disableForegroundDispatch(Activity activity) { disabledActivity = activity; } @@ -68,7 +69,8 @@ public class ShadowNfcAdapter { } @Implementation - public void setNdefPushMessageCallback(NfcAdapter.CreateNdefMessageCallback callback, Activity activity, Activity... activities) { + protected void setNdefPushMessageCallback( + NfcAdapter.CreateNdefMessageCallback callback, Activity activity, Activity... activities) { this.ndefPushMessageCallback = callback; } @@ -79,7 +81,7 @@ public class ShadowNfcAdapter { * #getOnNdefPushCompleteCallback}. */ @Implementation - public void setOnNdefPushCompleteCallback( + protected void setOnNdefPushCompleteCallback( NfcAdapter.OnNdefPushCompleteCallback callback, Activity activity, Activity... activities) { if (activity == null) { throw new NullPointerException("activity cannot be null"); @@ -93,7 +95,7 @@ public class ShadowNfcAdapter { } @Implementation - public boolean isEnabled() { + protected boolean isEnabled() { return enabled; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNinePatch.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNinePatch.java index 52257031e..917586094 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNinePatch.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNinePatch.java @@ -7,7 +7,7 @@ import org.robolectric.annotation.Implements; @Implements(NinePatch.class) public class ShadowNinePatch { @Implementation - public static boolean isNinePatchChunk(byte[] chunk) { + protected static boolean isNinePatchChunk(byte[] chunk) { return chunk != null; } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNotificationManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNotificationManager.java index ee8c708a2..7be1c644e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNotificationManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNotificationManager.java @@ -38,22 +38,22 @@ public class ShadowNotificationManager { private Policy notificationPolicy; @Implementation - public void notify(int id, Notification notification) { + protected void notify(int id, Notification notification) { notify(null, id, notification); } @Implementation - public void notify(String tag, int id, Notification notification) { + protected void notify(String tag, int id, Notification notification) { notifications.put(new Key(tag, id), notification); } @Implementation - public void cancel(int id) { + protected void cancel(int id) { cancel(null, id); } @Implementation - public void cancel(String tag, int id) { + protected void cancel(String tag, int id) { Key key = new Key(tag, id); if (notifications.containsKey(key)) { notifications.remove(key); @@ -61,12 +61,12 @@ public class ShadowNotificationManager { } @Implementation - public void cancelAll() { + protected void cancelAll() { notifications.clear(); } @Implementation(minSdk = Build.VERSION_CODES.N) - public boolean areNotificationsEnabled() { + protected boolean areNotificationsEnabled() { return mAreNotificationsEnabled; } @@ -96,23 +96,23 @@ public class ShadowNotificationManager { } @Implementation(minSdk = Build.VERSION_CODES.O) - public Object /*NotificationChannel*/ getNotificationChannel(String channelId) { + protected Object /*NotificationChannel*/ getNotificationChannel(String channelId) { return notificationChannels.get(channelId); } @Implementation(minSdk = Build.VERSION_CODES.O) - public void createNotificationChannelGroup(Object /*NotificationChannelGroup*/ group) { + protected void createNotificationChannelGroup(Object /*NotificationChannelGroup*/ group) { String id = ReflectionHelpers.callInstanceMethod(group, "getId"); notificationChannelGroups.put(id, group); } @Implementation(minSdk = Build.VERSION_CODES.O) - public List<Object /*NotificationChannelGroup*/> getNotificationChannelGroups() { + protected List<Object /*NotificationChannelGroup*/> getNotificationChannelGroups() { return ImmutableList.copyOf(notificationChannelGroups.values()); } @Implementation(minSdk = Build.VERSION_CODES.O) - public void createNotificationChannel(Object /*NotificationChannel*/ channel) { + protected void createNotificationChannel(Object /*NotificationChannel*/ channel) { String id = ReflectionHelpers.callInstanceMethod(channel, "getId"); // Per documentation, recreating a deleted channel should have the same settings as the old // deleted channel. See @@ -126,7 +126,7 @@ public class ShadowNotificationManager { } @Implementation(minSdk = Build.VERSION_CODES.O) - public void createNotificationChannels(List<Object /*NotificationChannel*/> channelList) { + protected void createNotificationChannels(List<Object /*NotificationChannel*/> channelList) { for (Object channel : channelList) { createNotificationChannel(channel); } @@ -138,7 +138,7 @@ public class ShadowNotificationManager { } @Implementation(minSdk = Build.VERSION_CODES.O) - public void deleteNotificationChannel(String channelId) { + protected void deleteNotificationChannel(String channelId) { if (getNotificationChannel(channelId) != null) { Object /*NotificationChannel*/ channel = notificationChannels.remove(channelId); deletedNotificationChannels.put(channelId, channel); @@ -151,7 +151,7 @@ public class ShadowNotificationManager { * notification channel groups nor to notification channels. */ @Implementation(minSdk = Build.VERSION_CODES.O) - public void deleteNotificationChannelGroup(String channelGroupId) { + protected void deleteNotificationChannelGroup(String channelGroupId) { if (getNotificationChannelGroup(channelGroupId) != null) { // Deleting a channel group also deleted all associated channels. See // https://developer.android.com/reference/android/app/NotificationManager.html#deleteNotificationChannelGroup%28java.lang.String%29 @@ -182,7 +182,7 @@ public class ShadowNotificationManager { * @see NotificationManager#getCurrentInterruptionFilter() */ @Implementation(minSdk = M) - public final void setInterruptionFilter(int interruptionFilter) { + protected final void setInterruptionFilter(int interruptionFilter) { currentInteruptionFilter = interruptionFilter; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNsdManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNsdManager.java index 18c2f8ccc..fb6823194 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNsdManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNsdManager.java @@ -4,7 +4,6 @@ import android.net.nsd.NsdManager; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -/** Shadow for {@link android.net.nsd.NsdManager} */ @Implements(NsdManager.class) public class ShadowNsdManager { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNumberPicker.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNumberPicker.java index 22cd77904..031308537 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNumberPicker.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNumberPicker.java @@ -18,57 +18,57 @@ public class ShadowNumberPicker extends ShadowLinearLayout { private NumberPicker.OnValueChangeListener onValueChangeListener; @Implementation - public void setValue(int value) { + protected void setValue(int value) { this.value = value; } @Implementation - public int getValue() { + protected int getValue() { return value; } @Implementation - public void setDisplayedValues(String[] displayedValues) { + protected void setDisplayedValues(String[] displayedValues) { this.displayedValues = displayedValues; } @Implementation - public String[] getDisplayedValues() { + protected String[] getDisplayedValues() { return displayedValues; } @Implementation - public void setMinValue(int minValue) { + protected void setMinValue(int minValue) { this.minValue = minValue; } @Implementation - public void setMaxValue(int maxValue) { + protected void setMaxValue(int maxValue) { this.maxValue = maxValue; } @Implementation - public int getMinValue() { + protected int getMinValue() { return this.minValue; } @Implementation - public int getMaxValue() { + protected int getMaxValue() { return this.maxValue; } @Implementation - public void setWrapSelectorWheel(boolean wrapSelectorWheel) { + protected void setWrapSelectorWheel(boolean wrapSelectorWheel) { this.wrapSelectorWheel = wrapSelectorWheel; } @Implementation - public boolean getWrapSelectorWheel() { + protected boolean getWrapSelectorWheel() { return wrapSelectorWheel; } @Implementation - public void setOnValueChangedListener(NumberPicker.OnValueChangeListener listener) { + protected void setOnValueChangedListener(NumberPicker.OnValueChangeListener listener) { directlyOn(realNumberPicker, NumberPicker.class).setOnValueChangedListener(listener); this.onValueChangeListener = listener; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOpenGLMatrix.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOpenGLMatrix.java index 6bec3f8ff..2f91ba9c2 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOpenGLMatrix.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOpenGLMatrix.java @@ -8,30 +8,26 @@ import org.robolectric.annotation.Implements; public class ShadowOpenGLMatrix { /** - * Multiplies two 4x4 matrices together and stores the result in a third 4x4 - * matrix. In matrix notation: result = lhs x rhs. Due to the way - * matrix multiplication works, the result matrix will have the same - * effect as first multiplying by the rhs matrix, then multiplying by - * the lhs matrix. This is the opposite of what you might expect. + * Multiplies two 4x4 matrices together and stores the result in a third 4x4 matrix. In matrix + * notation: result = lhs x rhs. Due to the way matrix multiplication works, the result matrix + * will have the same effect as first multiplying by the rhs matrix, then multiplying by the lhs + * matrix. This is the opposite of what you might expect. * - * The same float array may be passed for result, lhs, and/or rhs. However, - * the result element values are undefined if the result elements overlap - * either the lhs or rhs elements. + * <p>The same float array may be passed for result, lhs, and/or rhs. However, the result element + * values are undefined if the result elements overlap either the lhs or rhs elements. * - * @param result The float array that holds the result. - * @param resultOffset The offset into the result array where the result is - * stored. - * @param lhs The float array that holds the left-hand-side matrix. - * @param lhsOffset The offset into the lhs array where the lhs is stored - * @param rhs The float array that holds the right-hand-side matrix. - * @param rhsOffset The offset into the rhs array where the rhs is stored. - * @throws IllegalArgumentException if result, lhs, or rhs are null, or if - * resultOffset + 16 > result.length or lhsOffset + 16 > lhs.length or - * rhsOffset + 16 > rhs.length. + * @param result The float array that holds the result. + * @param resultOffset The offset into the result array where the result is stored. + * @param lhs The float array that holds the left-hand-side matrix. + * @param lhsOffset The offset into the lhs array where the lhs is stored + * @param rhs The float array that holds the right-hand-side matrix. + * @param rhsOffset The offset into the rhs array where the rhs is stored. + * @throws IllegalArgumentException if result, lhs, or rhs are null, or if resultOffset + 16 > + * result.length or lhsOffset + 16 > lhs.length or rhsOffset + 16 > rhs.length. */ @Implementation - public static void multiplyMM(float[] result, int resultOffset, - float[] lhs, int lhsOffset, float[] rhs, int rhsOffset) { + protected static void multiplyMM( + float[] result, int resultOffset, float[] lhs, int lhsOffset, float[] rhs, int rhsOffset) { if (result == null) { throw new IllegalArgumentException("result == null"); } @@ -71,30 +67,31 @@ public class ShadowOpenGLMatrix { } /** - * Multiplies a 4 element vector by a 4x4 matrix and stores the result in a - * 4-element column vector. In matrix notation: result = lhs x rhs + * Multiplies a 4 element vector by a 4x4 matrix and stores the result in a 4-element column + * vector. In matrix notation: result = lhs x rhs * - * The same float array may be passed for resultVec, lhsMat, and/or rhsVec. - * However, the resultVec element values are undefined if the resultVec - * elements overlap either the lhsMat or rhsVec elements. + * <p>The same float array may be passed for resultVec, lhsMat, and/or rhsVec. However, the + * resultVec element values are undefined if the resultVec elements overlap either the lhsMat or + * rhsVec elements. * - * @param resultVec The float array that holds the result vector. - * @param resultVecOffset The offset into the result array where the result - * vector is stored. - * @param lhsMat The float array that holds the left-hand-side matrix. - * @param lhsMatOffset The offset into the lhs array where the lhs is stored - * @param rhsVec The float array that holds the right-hand-side vector. - * @param rhsVecOffset The offset into the rhs vector where the rhs vector - * is stored. - * @throws IllegalArgumentException if resultVec, lhsMat, - * or rhsVec are null, or if resultVecOffset + 4 > resultVec.length - * or lhsMatOffset + 16 > lhsMat.length or - * rhsVecOffset + 4 > rhsVec.length. + * @param resultVec The float array that holds the result vector. + * @param resultVecOffset The offset into the result array where the result vector is stored. + * @param lhsMat The float array that holds the left-hand-side matrix. + * @param lhsMatOffset The offset into the lhs array where the lhs is stored + * @param rhsVec The float array that holds the right-hand-side vector. + * @param rhsVecOffset The offset into the rhs vector where the rhs vector is stored. + * @throws IllegalArgumentException if resultVec, lhsMat, or rhsVec are null, or if + * resultVecOffset + 4 > resultVec.length or lhsMatOffset + 16 > lhsMat.length or rhsVecOffset + * + 4 > rhsVec.length. */ @Implementation - public static void multiplyMV(float[] resultVec, - int resultVecOffset, float[] lhsMat, int lhsMatOffset, - float[] rhsVec, int rhsVecOffset) { + protected static void multiplyMV( + float[] resultVec, + int resultVecOffset, + float[] lhsMat, + int lhsMatOffset, + float[] rhsVec, + int rhsVecOffset) { if (resultVec == null) { throw new IllegalArgumentException("resultVec == null"); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOutline.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOutline.java index 25ede37c6..d09466817 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOutline.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOutline.java @@ -11,6 +11,5 @@ import org.robolectric.annotation.Implements; public class ShadowOutline { @Implementation - public void setConvexPath(Path convexPath) { - } + protected void setConvexPath(Path convexPath) {} }
\ No newline at end of file diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOverScroller.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOverScroller.java index 9a72a4d09..00d01c1b8 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOverScroller.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowOverScroller.java @@ -18,44 +18,44 @@ public class ShadowOverScroller { private boolean started; @Implementation - public int getStartX() { + protected int getStartX() { return startX; } @Implementation - public int getStartY() { + protected int getStartY() { return startY; } @Implementation - public int getCurrX() { + protected int getCurrX() { long dt = deltaTime(); return dt >= duration ? finalX : startX + (int) ((deltaX() * dt) / duration); } @Implementation - public int getCurrY() { + protected int getCurrY() { long dt = deltaTime(); return dt >= duration ? finalY : startY + (int) ((deltaY() * dt) / duration); } @Implementation - public int getFinalX() { + protected int getFinalX() { return finalX; } @Implementation - public int getFinalY() { + protected int getFinalY() { return finalY; } @Implementation - public int getDuration() { + protected int getDuration() { return (int) duration; } @Implementation - public void startScroll(int startX, int startY, int dx, int dy, int duration) { + protected void startScroll(int startX, int startY, int dx, int dy, int duration) { this.startX = startX; this.startY = startY; finalX = startX + dx; @@ -73,12 +73,12 @@ public class ShadowOverScroller { } @Implementation - public void abortAnimation() { + protected void abortAnimation() { duration = deltaTime() - 1; } @Implementation - public void forceFinished(boolean finished) { + protected void forceFinished(boolean finished) { if (!finished) { throw new RuntimeException("Not implemented."); } @@ -89,7 +89,7 @@ public class ShadowOverScroller { } @Implementation - public boolean computeScrollOffset() { + protected boolean computeScrollOffset() { if (!started) { return false; } @@ -98,17 +98,17 @@ public class ShadowOverScroller { } @Implementation - public boolean isFinished() { + protected boolean isFinished() { return deltaTime() > duration; } @Implementation - public int timePassed() { + protected int timePassed() { return (int) deltaTime(); } @Implementation - public boolean isScrollingInDirection(float xvel, float yvel) { + protected boolean isScrollingInDirection(float xvel, float yvel) { final int dx = finalX - startX; final int dy = finalY - startY; return !isFinished() diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageInstaller.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageInstaller.java index 217af64a4..ef6be55ad 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageInstaller.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageInstaller.java @@ -38,12 +38,13 @@ public class ShadowPackageInstaller { } @Implementation - public List<PackageInstaller.SessionInfo> getAllSessions() { + protected List<PackageInstaller.SessionInfo> getAllSessions() { return ImmutableList.copyOf(sessionInfos.values()); } @Implementation - public void registerSessionCallback(@NonNull PackageInstaller.SessionCallback callback, @NonNull Handler handler) { + protected void registerSessionCallback( + @NonNull PackageInstaller.SessionCallback callback, @NonNull Handler handler) { CallbackInfo callbackInfo = new CallbackInfo(); callbackInfo.callback = callback; callbackInfo.handler = handler; @@ -52,12 +53,12 @@ public class ShadowPackageInstaller { @Implementation @Nullable - public PackageInstaller.SessionInfo getSessionInfo(int sessionId) { + protected PackageInstaller.SessionInfo getSessionInfo(int sessionId) { return sessionInfos.get(sessionId); } @Implementation - public int createSession(@NonNull PackageInstaller.SessionParams params) throws IOException { + protected int createSession(@NonNull PackageInstaller.SessionParams params) throws IOException { final PackageInstaller.SessionInfo sessionInfo = new PackageInstaller.SessionInfo(); sessionInfo.sessionId = nextSessionId++; sessionInfo.active = true; @@ -77,7 +78,7 @@ public class ShadowPackageInstaller { } @Implementation - public void abandonSession(int sessionId) { + protected void abandonSession(int sessionId) { sessionInfos.remove(sessionId); sessions.remove(sessionId); @@ -93,7 +94,7 @@ public class ShadowPackageInstaller { @Implementation @NonNull - public PackageInstaller.Session openSession(int sessionId) throws IOException { + protected PackageInstaller.Session openSession(int sessionId) throws IOException { if (!sessionInfos.containsKey(sessionId)) { throw new SecurityException("Invalid session Id: " + sessionId); } @@ -161,10 +162,12 @@ public class ShadowPackageInstaller { private ShadowPackageInstaller shadowPackageInstaller; @Implementation(maxSdk = KITKAT_WATCH) - public void __constructor__() {} + protected void __constructor__() {} @Implementation - public @NonNull OutputStream openWrite(@NonNull String name, long offsetBytes, long lengthBytes) throws IOException { + @NonNull + protected OutputStream openWrite(@NonNull String name, long offsetBytes, long lengthBytes) + throws IOException { outputStream = new OutputStream() { @Override public void write(int aByte) throws IOException { @@ -181,12 +184,10 @@ public class ShadowPackageInstaller { } @Implementation - public void fsync(@NonNull OutputStream out) throws IOException { - - } + protected void fsync(@NonNull OutputStream out) throws IOException {} @Implementation - public void commit(@NonNull IntentSender statusReceiver) { + protected void commit(@NonNull IntentSender statusReceiver) { this.statusReceiver = statusReceiver; if (outputStreamOpen) { throw new SecurityException("OutputStream still open"); @@ -196,12 +197,10 @@ public class ShadowPackageInstaller { } @Implementation - public void close() { - - } + protected void close() {} @Implementation - public void abandon() { + protected void abandon() { shadowPackageInstaller.abandonSession(sessionId); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageManager.java index 7b8c458bd..b436df89c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageManager.java @@ -198,12 +198,10 @@ public class ShadowPackageManager { static final Map<String, PackageSetting> packageSettings = new HashMap<>(); - // From com.android.server.pm.PackageManagerService.compareSignatures(). static int compareSignature(Signature[] signatures1, Signature[] signatures2) { if (signatures1 == null) { - return (signatures2 == null) ? SIGNATURE_NEITHER_SIGNED - : SIGNATURE_FIRST_NOT_SIGNED; + return (signatures2 == null) ? SIGNATURE_NEITHER_SIGNED : SIGNATURE_FIRST_NOT_SIGNED; } if (signatures2 == null) { return SIGNATURE_SECOND_NOT_SIGNED; @@ -248,16 +246,36 @@ public class ShadowPackageManager { applicationInfo.publicSourceDir = applicationInfo.sourceDir; if (RuntimeEnvironment.getApiLevel() >= N) { - applicationInfo.credentialProtectedDataDir = tempDirectory.createIfNotExists("userDataDir").toAbsolutePath().toString(); - applicationInfo.deviceProtectedDataDir = tempDirectory.createIfNotExists("deviceDataDir").toAbsolutePath().toString(); + applicationInfo.credentialProtectedDataDir = + tempDirectory.createIfNotExists("userDataDir").toAbsolutePath().toString(); + applicationInfo.deviceProtectedDataDir = + tempDirectory.createIfNotExists("deviceDataDir").toAbsolutePath().toString(); + } + } + + /** + * Sets extra resolve infos for an intent. + * + * <p>Those entries are added to whatever might be in the manifest already. + */ + public void setResolveInfosForIntent(Intent intent, List<ResolveInfo> info) { + resolveInfoForIntent.remove(intent); + for (ResolveInfo resolveInfo : info) { + addResolveInfoForIntent(intent, resolveInfo); } } + /** + * @deprecated please use {@link #setResolveInfosForIntent} or {@link + * #addResolveInfoForIntent(Intent, ResolveInfo)} instead. + */ + @Deprecated public void addResolveInfoForIntent(Intent intent, List<ResolveInfo> info) { - resolveInfoForIntent.put(intent, info); + setResolveInfosForIntent(intent, info); } public void addResolveInfoForIntent(Intent intent, ResolveInfo info) { + Preconditions.checkNotNull(info); List<ResolveInfo> infoList = resolveInfoForIntent.get(intent); if (infoList == null) { infoList = new ArrayList<>(); @@ -313,7 +331,8 @@ public class ShadowPackageManager { } /** - * Return the flags set in call to {@link android.app.ApplicationPackageManager#setComponentEnabledSetting(ComponentName, int, int)}. + * Return the flags set in call to {@link + * android.app.ApplicationPackageManager#setComponentEnabledSetting(ComponentName, int, int)}. * * @param componentName The component name. * @return The flags. @@ -340,9 +359,8 @@ public class ShadowPackageManager { /** * Registers ("installs") a package with the PackageManager. * - * <p> - * In order to create PackageInfo objects in a valid state please use - * {@link androidx.test.core.content.pm.PackageInfoBuilder}. + * <p>In order to create PackageInfo objects in a valid state please use {@link + * androidx.test.core.content.pm.PackageInfoBuilder}. */ public void addPackage(PackageInfo packageInfo) { PackageStats packageStats = new PackageStats(packageInfo.packageName); @@ -357,7 +375,8 @@ public class ShadowPackageManager { packageSettings.put(packageInfo.packageName, new PackageSetting()); - applicationEnabledSettingMap.put(packageInfo.packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); + applicationEnabledSettingMap.put( + packageInfo.packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); if (packageInfo.applicationInfo != null) { namesForUid.put(packageInfo.applicationInfo.uid, packageInfo.packageName); } @@ -383,9 +402,11 @@ public class ShadowPackageManager { /** * Allows overriding or adding permission-group elements. These would be otherwise specified by - * either (the system)[https://developer.android.com/guide/topics/permissions/requesting.html#perm-groups] - * or by (the app itself)[https://developer.android.com/guide/topics/manifest/permission-group-element.html], - * as part of its manifest + * either (the + * system)[https://developer.android.com/guide/topics/permissions/requesting.html#perm-groups] or + * by (the app + * itself)[https://developer.android.com/guide/topics/manifest/permission-group-element.html], as + * part of its manifest * * <p>{@link android.content.pm.PackageParser.PermissionGroup}s added through this method have * precedence over those specified with the same name by one of the aforementioned methods. @@ -402,7 +423,6 @@ public class ShadowPackageManager { packageInfos.remove(packageName); packageSettings.remove(packageName); - } public void setSystemFeature(String name, boolean supported) { @@ -527,7 +547,8 @@ public class ShadowPackageManager { protected void freeStorage(long freeStorageSize, IntentSender pi) {} /** - * Runs the callbacks pending from calls to {@link PackageManager#deletePackage(String, IPackageDeleteObserver, int)} + * Runs the callbacks pending from calls to {@link PackageManager#deletePackage(String, + * IPackageDeleteObserver, int)} */ public void doPendingUninstallCallbacks() { boolean hasDeletePackagesPermission = false; @@ -565,8 +586,9 @@ public class ShadowPackageManager { } /** - * Returns package names successfully deleted with {@link PackageManager#deletePackage(String, IPackageDeleteObserver, int)} - * Note that like real {@link PackageManager} the calling context must have {@link android.Manifest.permission#DELETE_PACKAGES} permission set. + * Returns package names successfully deleted with {@link PackageManager#deletePackage(String, + * IPackageDeleteObserver, int)} Note that like real {@link PackageManager} the calling context + * must have {@link android.Manifest.permission#DELETE_PACKAGES} permission set. */ public Set<String> getDeletedPackages() { return deletedPackages; @@ -583,6 +605,7 @@ public class ShadowPackageManager { /** * Internal use only. + * * @param appPackage */ public void addPackageInternal(Package appPackage) { @@ -659,8 +682,10 @@ public class ShadowPackageManager { } packageInfo.applicationInfo.uid = Process.myUid(); - packageInfo.applicationInfo.dataDir = RuntimeEnvironment.getTempDirectory() - .createIfNotExists(packageInfo.packageName + "-dataDir").toString(); + packageInfo.applicationInfo.dataDir = + RuntimeEnvironment.getTempDirectory() + .createIfNotExists(packageInfo.packageName + "-dataDir") + .toString(); addPackage(packageInfo); } @@ -974,8 +999,6 @@ public class ShadowPackageManager { hiddenPackages.clear(); sequenceNumberChangedPackagesMap.clear(); - packageSettings.clear(); - } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageParser.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageParser.java index e71ab5a20..6777956fd 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageParser.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPackageParser.java @@ -14,9 +14,6 @@ import org.robolectric.res.FsFile; import org.robolectric.shadows.ShadowLog.LogItem; import org.robolectric.util.ReflectionHelpers; -/** - * Shadow for {@link PackageParser} - */ @Implements(value = PackageParser.class, isInAndroidSdk = false) public class ShadowPackageParser { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java index afdbff373..479d02aeb 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPaint.java @@ -40,7 +40,7 @@ public class ShadowPaint { private Paint.Align textAlign = Paint.Align.LEFT; @Implementation - public void __constructor__(Paint otherPaint) { + protected void __constructor__(Paint otherPaint) { ShadowPaint otherShadowPaint = Shadow.extract(otherPaint); this.color = otherShadowPaint.color; this.style = otherShadowPaint.style; @@ -63,94 +63,93 @@ public class ShadowPaint { } @Implementation(minSdk = N) - public static long nInit() { + protected static long nInit() { return 1; } @Implementation - public int getFlags() { + protected int getFlags() { return flags; } @Implementation - public void setFlags(int flags) { + protected void setFlags(int flags) { this.flags = flags; } @Implementation - public Shader setShader(Shader shader) { + protected Shader setShader(Shader shader) { this.shader = shader; return shader; } @Implementation - public int getAlpha() { + protected int getAlpha() { return alpha; } @Implementation - public void setAlpha(int alpha) { + protected void setAlpha(int alpha) { this.alpha = alpha; } - @Implementation - public Shader getShader() { + protected Shader getShader() { return shader; } @Implementation - public void setColor(int color) { + protected void setColor(int color) { this.color = color; } @Implementation - public int getColor() { + protected int getColor() { return color; } @Implementation - public void setStyle(Paint.Style style) { + protected void setStyle(Paint.Style style) { this.style = style; } @Implementation - public Paint.Style getStyle() { + protected Paint.Style getStyle() { return style; } @Implementation - public void setStrokeCap(Paint.Cap cap) { + protected void setStrokeCap(Paint.Cap cap) { this.cap = cap; } @Implementation - public Paint.Cap getStrokeCap() { + protected Paint.Cap getStrokeCap() { return cap; } @Implementation - public void setStrokeJoin(Paint.Join join) { + protected void setStrokeJoin(Paint.Join join) { this.join = join; } @Implementation - public Paint.Join getStrokeJoin() { + protected Paint.Join getStrokeJoin() { return join; } @Implementation - public void setStrokeWidth(float width) { + protected void setStrokeWidth(float width) { this.width = width; } @Implementation - public float getStrokeWidth() { + protected float getStrokeWidth() { return width; } @Implementation - public void setShadowLayer(float radius, float dx, float dy, int color) { + protected void setShadowLayer(float radius, float dx, float dy, int color) { shadowRadius = radius; shadowDx = dx; shadowDy = dy; @@ -158,33 +157,33 @@ public class ShadowPaint { } @Implementation - public Typeface getTypeface() { + protected Typeface getTypeface() { return typeface; } @Implementation - public Typeface setTypeface(Typeface typeface) { + protected Typeface setTypeface(Typeface typeface) { this.typeface = typeface; return typeface; } @Implementation - public float getTextSize() { + protected float getTextSize() { return textSize; } @Implementation - public void setTextSize(float textSize) { + protected void setTextSize(float textSize) { this.textSize = textSize; } @Implementation - public void setTextAlign(Paint.Align align) { + protected void setTextAlign(Paint.Align align) { textAlign = align; } @Implementation - public Paint.Align getTextAlign() { + protected Paint.Align getTextAlign() { return textAlign; } @@ -229,64 +228,64 @@ public class ShadowPaint { } @Implementation - public ColorFilter getColorFilter() { + protected ColorFilter getColorFilter() { return filter; } @Implementation - public ColorFilter setColorFilter(ColorFilter filter) { + protected ColorFilter setColorFilter(ColorFilter filter) { this.filter = filter; return filter; } @Implementation - public void setAntiAlias(boolean antiAlias) { + protected void setAntiAlias(boolean antiAlias) { this.flags = (flags & ~Paint.ANTI_ALIAS_FLAG) | (antiAlias ? Paint.ANTI_ALIAS_FLAG : 0); } @Implementation - public void setDither(boolean dither) { + protected void setDither(boolean dither) { this.dither = dither; } @Implementation - public final boolean isDither() { + protected final boolean isDither() { return dither; } @Implementation - public final boolean isAntiAlias() { + protected final boolean isAntiAlias() { return (flags & Paint.ANTI_ALIAS_FLAG) == Paint.ANTI_ALIAS_FLAG; } @Implementation - public PathEffect getPathEffect() { + protected PathEffect getPathEffect() { return pathEffect; } @Implementation - public PathEffect setPathEffect(PathEffect effect) { + protected PathEffect setPathEffect(PathEffect effect) { this.pathEffect = effect; return effect; } @Implementation - public float measureText(String text) { + protected float measureText(String text) { return text.length(); } @Implementation - public float measureText(CharSequence text, int start, int end) { + protected float measureText(CharSequence text, int start, int end) { return end - start; } @Implementation - public float measureText(String text, int start, int end) { + protected float measureText(String text, int start, int end) { return end - start; } @Implementation - public float measureText(char[] text, int index, int count) { + protected float measureText(char[] text, int index, int count) { return count; } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcel.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcel.java index 31f75773c..dcb9719b3 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcel.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcel.java @@ -189,6 +189,7 @@ public class ShadowParcel { } @Implementation(minSdk = LOLLIPOP) + @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") protected static void nativeSetDataSize(long nativePtr, int size) { NATIVE_PTR_TO_PARCEL.get(nativePtr).setDataSize(size); } @@ -423,6 +424,7 @@ public class ShadowParcel { } @Implementation(minSdk = LOLLIPOP) + @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") protected static void nativeFreeBuffer(long nativePtr) { NATIVE_PTR_TO_PARCEL.get(nativePtr).clear(); } @@ -456,6 +458,7 @@ public class ShadowParcel { } @Implementation(minSdk = LOLLIPOP) + @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") protected static void nativeUnmarshall(long nativePtr, byte[] data, int offset, int length) { NATIVE_PTR_TO_PARCEL.put(nativePtr, ByteBuffer.fromByteArray(data, offset, length)); } @@ -467,6 +470,7 @@ public class ShadowParcel { } @Implementation(minSdk = LOLLIPOP) + @SuppressWarnings("robolectric.ShadowReturnTypeMismatch") protected static void nativeAppendFrom( long thisNativePtr, long otherNativePtr, int offset, int length) { ByteBuffer thisByteBuffer = NATIVE_PTR_TO_PARCEL.get(thisNativePtr); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcelFileDescriptor.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcelFileDescriptor.java index ed5016673..524649458 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcelFileDescriptor.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowParcelFileDescriptor.java @@ -16,6 +16,7 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.RealObject; import org.robolectric.shadow.api.Shadow; +import org.robolectric.util.ReflectionHelpers; @Implements(ParcelFileDescriptor.class) @SuppressLint("NewApi") @@ -31,8 +32,8 @@ public class ShadowParcelFileDescriptor { @Implementation protected void __constructor__(ParcelFileDescriptor wrapped) { - invokeConstructor(ParcelFileDescriptor.class, realObject, - from(ParcelFileDescriptor.class, wrapped)); + invokeConstructor( + ParcelFileDescriptor.class, realObject, from(ParcelFileDescriptor.class, wrapped)); if (wrapped != null) { ShadowParcelFileDescriptor shadowParcelFileDescriptor = Shadow.extract(wrapped); this.file = shadowParcelFileDescriptor.file; @@ -59,9 +60,11 @@ public class ShadowParcelFileDescriptor { return "rw"; } switch (mode & ParcelFileDescriptor.MODE_READ_WRITE) { - case ParcelFileDescriptor.MODE_READ_ONLY: return "r"; - case ParcelFileDescriptor.MODE_WRITE_ONLY: return "rw"; - case ParcelFileDescriptor.MODE_READ_WRITE: return "rw"; + case ParcelFileDescriptor.MODE_READ_ONLY: + return "r"; + case ParcelFileDescriptor.MODE_WRITE_ONLY: + case ParcelFileDescriptor.MODE_READ_WRITE: + return "rw"; } // TODO: this probably should be an error that we reach here, but default to 'rw' for now @@ -70,14 +73,16 @@ public class ShadowParcelFileDescriptor { @Implementation protected static ParcelFileDescriptor[] createPipe() throws IOException { - File file = new File(RuntimeEnvironment.getTempDirectory().create(PIPE_TMP_DIR).toFile(), PIPE_FILE_NAME); + File file = + new File( + RuntimeEnvironment.getTempDirectory().create(PIPE_TMP_DIR).toFile(), PIPE_FILE_NAME); if (!file.createNewFile()) { throw new IOException("Cannot create pipe file: " + file.getAbsolutePath()); } ParcelFileDescriptor readSide = open(file, ParcelFileDescriptor.MODE_READ_ONLY); ParcelFileDescriptor writeSide = open(file, ParcelFileDescriptor.MODE_READ_WRITE); file.deleteOnExit(); - return new ParcelFileDescriptor[]{readSide, writeSide}; + return new ParcelFileDescriptor[] {readSide, writeSide}; } @Implementation @@ -98,14 +103,13 @@ public class ShadowParcelFileDescriptor { } } - /** - * Overrides framework to avoid call to {@link FileDescriptor#getInt() which does not exist on JVM. - * - * @return a fixed int (`0`) - */ @Implementation protected int getFd() { - return 0; + try { + return ReflectionHelpers.getField(file.getFD(), "fd"); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Implementation diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPath.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPath.java index a709d8aab..e7253a28b 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPath.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPath.java @@ -1,15 +1,32 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.JELLY_BEAN; +import static android.os.Build.VERSION_CODES.KITKAT; import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static org.robolectric.shadow.api.Shadow.extract; import static org.robolectric.shadows.ShadowPath.Point.Type.LINE_TO; import static org.robolectric.shadows.ShadowPath.Point.Type.MOVE_TO; +import android.graphics.Matrix; import android.graphics.Path; +import android.graphics.Path.Direction; +import android.graphics.RectF; +import android.util.Log; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; import java.util.ArrayList; import java.util.List; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -import org.robolectric.shadow.api.Shadow; +import org.robolectric.annotation.RealObject; /** * The shadow only supports straight-line paths. @@ -17,51 +34,121 @@ import org.robolectric.shadow.api.Shadow; @SuppressWarnings({"UnusedDeclaration"}) @Implements(Path.class) public class ShadowPath { + private static final String TAG = ShadowPath.class.getSimpleName(); + private static final float EPSILON = 1e-4f; + + @RealObject private Path realObject; + private List<Point> points = new ArrayList<>(); private Point wasMovedTo; - private String quadDescription = ""; + + private float mLastX = 0; + private float mLastY = 0; + private Path2D mPath = new Path2D.Double(); + private boolean mCachedIsEmpty = true; + private Path.FillType mFillType = Path.FillType.WINDING; + protected boolean isSimplePath; @Implementation - public void __constructor__(Path path) { - ShadowPath shadowPath = Shadow.extract(path); + protected void __constructor__(Path path) { + ShadowPath shadowPath = extract(path); points = new ArrayList<>(shadowPath.getPoints()); - wasMovedTo = shadowPath.wasMovedTo; - quadDescription = shadowPath.quadDescription; + } + + Path2D getJavaShape() { + return mPath; } @Implementation - public void moveTo(float x, float y) { + protected void moveTo(float x, float y) { + mPath.moveTo(mLastX = x, mLastY = y); + + // Legacy recording behavior Point p = new Point(x, y, MOVE_TO); points.add(p); - wasMovedTo = p; } @Implementation - public void lineTo(float x, float y) { + protected void lineTo(float x, float y) { + if (!hasPoints()) { + mPath.moveTo(mLastX = 0, mLastY = 0); + } + mPath.lineTo(mLastX = x, mLastY = y); + + // Legacy recording behavior Point point = new Point(x, y, LINE_TO); points.add(point); } @Implementation - public void quadTo(float x1, float y1, float x2, float y2) { - quadDescription = "Add a quadratic bezier from last point, approaching (" + x1 + "," + y1 + "), ending at (" + x2 + "," + y2 + ")"; + protected void quadTo(float x1, float y1, float x2, float y2) { + isSimplePath = false; + if (!hasPoints()) { + moveTo(0, 0); + } + mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2); + } + + @Implementation + protected void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) { + if (!hasPoints()) { + mPath.moveTo(0, 0); + } + mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3); + } + + private boolean hasPoints() { + return !mPath.getPathIterator(null).isDone(); } @Implementation - public void reset() { + protected void reset() { + mPath.reset(); + mLastX = 0; + mLastY = 0; + + // Legacy recording behavior points.clear(); - wasMovedTo = null; - quadDescription = ""; } - // TODO: This should only be used to enable interpolator resource parsing @Implementation(minSdk = LOLLIPOP) - public float[] approximate(float acceptableError) { - return new float[]{0, 0, 0, 1, 1, 1}; - } + protected float[] approximate(float acceptableError) { + PathIterator iterator = mPath.getPathIterator(null, acceptableError); + + float segment[] = new float[6]; + float totalLength = 0; + ArrayList<Point2D.Float> points = new ArrayList<Point2D.Float>(); + Point2D.Float previousPoint = null; + while (!iterator.isDone()) { + int type = iterator.currentSegment(segment); + Point2D.Float currentPoint = new Point2D.Float(segment[0], segment[1]); + // MoveTo shouldn't affect the length + if (previousPoint != null && type != PathIterator.SEG_MOVETO) { + totalLength += currentPoint.distance(previousPoint); + } + previousPoint = currentPoint; + points.add(currentPoint); + iterator.next(); + } + + int nPoints = points.size(); + float[] result = new float[nPoints * 3]; + previousPoint = null; + // Distance that we've covered so far. Used to calculate the fraction of the path that + // we've covered up to this point. + float walkedDistance = .0f; + for (int i = 0; i < nPoints; i++) { + Point2D.Float point = points.get(i); + float distance = previousPoint != null ? (float) previousPoint.distance(point) : .0f; + walkedDistance += distance; + result[i * 3] = walkedDistance / totalLength; + result[i * 3 + 1] = point.x; + result[i * 3 + 2] = point.y; + + previousPoint = point; + } - public String getQuadDescription() { - return quadDescription; + return result; } /** @@ -71,13 +158,6 @@ public class ShadowPath { return points; } - /** - * @return whether the {@link #moveTo(float, float)} method was called - */ - public Point getWasMovedTo() { - return wasMovedTo; - } - public static class Point { private final float x; private final float y; @@ -133,4 +213,400 @@ public class ShadowPath { return type; } } + + @Implementation + protected void rewind() { + // call out to reset since there's nothing to optimize in + // terms of data structs. + reset(); + } + + @Implementation + protected void set(Path src) { + mPath.reset(); + + ShadowPath shadowSrc = extract(src); + setFillType(shadowSrc.mFillType); + mPath.append(shadowSrc.mPath, false /*connect*/); + } + + @Implementation(minSdk = KITKAT) + protected boolean op(Path path1, Path path2, Path.Op op) { + Log.w(TAG, "android.graphics.Path#op() not supported yet."); + return false; + } + + @Implementation(minSdk = LOLLIPOP) + protected boolean isConvex() { + Log.w(TAG, "android.graphics.Path#isConvex() not supported yet."); + return true; + } + + @Implementation + protected Path.FillType getFillType() { + return mFillType; + } + + @Implementation + protected void setFillType(Path.FillType fillType) { + mFillType = fillType; + mPath.setWindingRule(getWindingRule(fillType)); + } + + /** + * Returns the Java2D winding rules matching a given Android {@link FillType}. + * + * @param type the android fill type + * @return the matching java2d winding rule. + */ + private static int getWindingRule(Path.FillType type) { + switch (type) { + case WINDING: + case INVERSE_WINDING: + return GeneralPath.WIND_NON_ZERO; + case EVEN_ODD: + case INVERSE_EVEN_ODD: + return GeneralPath.WIND_EVEN_ODD; + + default: + assert false; + return GeneralPath.WIND_NON_ZERO; + } + } + + @Implementation + protected boolean isInverseFillType() { + throw new UnsupportedOperationException("isInverseFillType"); + } + + @Implementation + protected void toggleInverseFillType() { + throw new UnsupportedOperationException("toggleInverseFillType"); + } + + @Implementation + protected boolean isEmpty() { + if (!mCachedIsEmpty) { + return false; + } + + float[] coords = new float[6]; + mCachedIsEmpty = Boolean.TRUE; + for (PathIterator it = mPath.getPathIterator(null); !it.isDone(); it.next()) { + int type = it.currentSegment(coords); + // if (type != PathIterator.SEG_MOVETO) { + // Once we know that the path is not empty, we do not need to check again unless + // Path#reset is called. + mCachedIsEmpty = false; + return false; + // } + } + + return true; + } + + @Implementation + protected boolean isRect(RectF rect) { + // create an Area that can test if the path is a rect + Area area = new Area(mPath); + if (area.isRectangular()) { + if (rect != null) { + fillBounds(rect); + } + + return true; + } + + return false; + } + + @Implementation + protected void computeBounds(RectF bounds, boolean exact) { + fillBounds(bounds); + } + + @Implementation + protected void incReserve(int extraPtCount) { + throw new UnsupportedOperationException("incReserve"); + } + + @Implementation + protected void rMoveTo(float dx, float dy) { + dx += mLastX; + dy += mLastY; + mPath.moveTo(mLastX = dx, mLastY = dy); + } + + @Implementation + protected void rLineTo(float dx, float dy) { + if (!hasPoints()) { + mPath.moveTo(mLastX = 0, mLastY = 0); + } + + if (Math.abs(dx) < EPSILON && Math.abs(dy) < EPSILON) { + // The delta is so small that this shouldn't generate a line + return; + } + + dx += mLastX; + dy += mLastY; + mPath.lineTo(mLastX = dx, mLastY = dy); + } + + @Implementation + protected void rQuadTo(float dx1, float dy1, float dx2, float dy2) { + if (!hasPoints()) { + mPath.moveTo(mLastX = 0, mLastY = 0); + } + dx1 += mLastX; + dy1 += mLastY; + dx2 += mLastX; + dy2 += mLastY; + mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2); + } + + @Implementation + protected void rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3) { + if (!hasPoints()) { + mPath.moveTo(mLastX = 0, mLastY = 0); + } + x1 += mLastX; + y1 += mLastY; + x2 += mLastX; + y2 += mLastY; + x3 += mLastX; + y3 += mLastY; + mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3); + } + + @Implementation + protected void arcTo(RectF oval, float startAngle, float sweepAngle) { + arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false); + } + + @Implementation + protected void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) { + arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo); + } + + @Implementation(minSdk = LOLLIPOP) + protected void arcTo( + float left, + float top, + float right, + float bottom, + float startAngle, + float sweepAngle, + boolean forceMoveTo) { + isSimplePath = false; + Arc2D arc = + new Arc2D.Float( + left, top, right - left, bottom - top, -startAngle, -sweepAngle, Arc2D.OPEN); + mPath.append(arc, true /*connect*/); + + resetLastPointFromPath(); + } + + @Implementation + protected void close() { + if (!hasPoints()) { + mPath.moveTo(mLastX = 0, mLastY = 0); + } + mPath.closePath(); + } + + @Implementation + protected void addRect(RectF rect, Direction dir) { + addRect(rect.left, rect.top, rect.right, rect.bottom, dir); + } + + @Implementation + protected void addRect(float left, float top, float right, float bottom, Path.Direction dir) { + moveTo(left, top); + + switch (dir) { + case CW: + lineTo(right, top); + lineTo(right, bottom); + lineTo(left, bottom); + break; + case CCW: + lineTo(left, bottom); + lineTo(right, bottom); + lineTo(right, top); + break; + } + + close(); + + resetLastPointFromPath(); + } + + @Implementation(minSdk = LOLLIPOP) + protected void addOval(float left, float top, float right, float bottom, Path.Direction dir) { + mPath.append(new Ellipse2D.Float(left, top, right - left, bottom - top), false); + } + + @Implementation + protected void addCircle(float x, float y, float radius, Path.Direction dir) { + mPath.append(new Ellipse2D.Float(x - radius, y - radius, radius * 2, radius * 2), false); + } + + @Implementation(minSdk = LOLLIPOP) + protected void addArc( + float left, float top, float right, float bottom, float startAngle, float sweepAngle) { + mPath.append( + new Arc2D.Float( + left, top, right - left, bottom - top, -startAngle, -sweepAngle, Arc2D.OPEN), + false); + } + + @Implementation(minSdk = JELLY_BEAN) + protected void addRoundRect(RectF rect, float rx, float ry, Direction dir) { + addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir); + } + + @Implementation(minSdk = JELLY_BEAN) + protected void addRoundRect(RectF rect, float[] radii, Direction dir) { + if (rect == null) { + throw new NullPointerException("need rect parameter"); + } + addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir); + } + + @Implementation(minSdk = LOLLIPOP) + protected void addRoundRect( + float left, float top, float right, float bottom, float rx, float ry, Path.Direction dir) { + mPath.append( + new RoundRectangle2D.Float(left, top, right - left, bottom - top, rx * 2, ry * 2), false); + } + + @Implementation(minSdk = LOLLIPOP) + protected void addRoundRect( + float left, float top, float right, float bottom, float[] radii, Path.Direction dir) { + if (radii.length < 8) { + throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values"); + } + isSimplePath = false; + + float[] cornerDimensions = new float[radii.length]; + for (int i = 0; i < radii.length; i++) { + cornerDimensions[i] = 2 * radii[i]; + } + mPath.append( + new RoundRectangle(left, top, right - left, bottom - top, cornerDimensions), false); + } + + @Implementation + protected void addPath(Path src, float dx, float dy) { + isSimplePath = false; + ShadowPath.addPath(realObject, src, AffineTransform.getTranslateInstance(dx, dy)); + } + + @Implementation + protected void addPath(Path src) { + isSimplePath = false; + ShadowPath.addPath(realObject, src, null); + } + + @Implementation + protected void addPath(Path src, Matrix matrix) { + if (matrix == null) { + return; + } + ShadowPath shadowSrc = extract(src); + if (!shadowSrc.isSimplePath) isSimplePath = false; + + ShadowMatrix shadowMatrix = extract(matrix); + ShadowPath.addPath(realObject, src, shadowMatrix.getAffineTransform()); + } + + private static void addPath(Path destPath, Path srcPath, AffineTransform transform) { + if (destPath == null) { + return; + } + + if (srcPath == null) { + return; + } + + ShadowPath shadowDestPath = extract(destPath); + ShadowPath shadowSrcPath = extract(srcPath); + if (transform != null) { + shadowDestPath.mPath.append(shadowSrcPath.mPath.getPathIterator(transform), false); + } else { + shadowDestPath.mPath.append(shadowSrcPath.mPath, false); + } + } + + @Implementation + protected void offset(float dx, float dy, Path dst) { + if (dst != null) { + dst.set(realObject); + } else { + dst = realObject; + } + dst.offset(dx, dy); + } + + @Implementation + protected void offset(float dx, float dy) { + GeneralPath newPath = new GeneralPath(); + + PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy)); + + newPath.append(iterator, false /*connect*/); + mPath = newPath; + } + + @Implementation + protected void setLastPoint(float dx, float dy) { + mLastX = dx; + mLastY = dy; + } + + @Implementation + protected void transform(Matrix matrix, Path dst) { + ShadowMatrix shadowMatrix = extract(matrix); + + if (shadowMatrix.hasPerspective()) { + Log.w(TAG, "android.graphics.Path#transform() only supports affine transformations."); + } + + GeneralPath newPath = new GeneralPath(); + + PathIterator iterator = mPath.getPathIterator(shadowMatrix.getAffineTransform()); + newPath.append(iterator, false /*connect*/); + + if (dst != null) { + ShadowPath shadowPath = extract(dst); + shadowPath.mPath = newPath; + } else { + mPath = newPath; + } + } + + @Implementation + protected void transform(Matrix matrix) { + transform(matrix, null); + } + + /** + * Fills the given {@link RectF} with the path bounds. + * + * @param bounds the RectF to be filled. + */ + public void fillBounds(RectF bounds) { + Rectangle2D rect = mPath.getBounds2D(); + bounds.left = (float) rect.getMinX(); + bounds.right = (float) rect.getMaxX(); + bounds.top = (float) rect.getMinY(); + bounds.bottom = (float) rect.getMaxY(); + } + + private void resetLastPointFromPath() { + Point2D last = mPath.getCurrentPoint(); + mLastX = (float) last.getX(); + mLastY = (float) last.getY(); + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathMeasure.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathMeasure.java new file mode 100644 index 000000000..4e5deb62f --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathMeasure.java @@ -0,0 +1,58 @@ +package org.robolectric.shadows; + +import android.graphics.Path; +import android.graphics.PathMeasure; +import java.math.BigDecimal; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.shadow.api.Shadow; + +@Implements(PathMeasure.class) +public class ShadowPathMeasure { + + private CachedPathIteratorFactory mOriginalPathIterator; + + @Implementation + protected void __constructor__(Path path, boolean forceClosed) { + if (path != null) { + ShadowPath shadowPath = (ShadowPath) Shadow.extract(path); + mOriginalPathIterator = + new CachedPathIteratorFactory(shadowPath.getJavaShape().getPathIterator(null)); + } + } + + /** + * Return the total length of the current contour, or 0 if no path is associated with this measure + * object. + */ + @Implementation + protected float getLength() { + if (mOriginalPathIterator == null) { + return 0; + } + + return mOriginalPathIterator.iterator().getTotalLength(); + } + + /** Note: This is not mathematically correct. */ + @Implementation + protected boolean getPosTan(float distance, float pos[], float tan[]) { + if (pos != null && pos.length < 2 || tan != null && tan.length < 2) { + throw new ArrayIndexOutOfBoundsException(); + } + + // This is not mathematically correct, but the simulation keeps the support library happy. + if (getLength() > 0) { + pos[0] = round(distance / getLength(), 4); + pos[1] = round(distance / getLength(), 4); + } + + return true; + } + + private static float round(float d, int decimalPlace) { + BigDecimal bd = new BigDecimal(d); + bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); + return bd.floatValue(); + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathParser.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathParser.java index a127f383c..1ababc0e4 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathParser.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPathParser.java @@ -2,21 +2,59 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.N; +import android.graphics.Path; +import android.util.Log; import android.util.PathParser; +import android.util.PathParser.PathData; +import java.util.ArrayList; +import java.util.Arrays; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @Implements(value = PathParser.class, minSdk = N, isInAndroidSdk = false) public class ShadowPathParser { + static final String LOGTAG = ShadowPathParser.class.getSimpleName(); + @Implementation - public static long nCreatePathDataFromString(String pathString, int stringLength) { - return 1; + protected static Path createPathFromPathData(String pathData) { + Path path = new Path(); + PathDataNode[] nodes = createNodesFromPathData(pathData); + if (nodes != null) { + PathDataNode.nodesToPath(nodes, path); + return path; + } + return null; + } + + public static PathDataNode[] createNodesFromPathData(String pathData) { + if (pathData == null) { + return null; + } + int start = 0; + int end = 1; + + ArrayList<PathDataNode> list = new ArrayList<PathDataNode>(); + while (end < pathData.length()) { + end = nextStart(pathData, end); + String s = pathData.substring(start, end).trim(); + if (s.length() > 0) { + float[] val = getFloats(s); + addNode(list, s.charAt(0), val); + } + + start = end; + end++; + } + if ((end - start) == 1 && start < pathData.length()) { + addNode(list, pathData.charAt(start), new float[0]); + } + return list.toArray(new PathDataNode[list.size()]); } @Implementation - public static boolean nInterpolatePathData(long outDataPtr, long fromDataPtr, - long toDataPtr, float fraction) { + protected static boolean interpolatePathData( + PathData outData, PathData fromData, PathData toData, float fraction) { return true; } @@ -24,4 +62,567 @@ public class ShadowPathParser { public static boolean nCanMorph(long fromDataPtr, long toDataPtr) { return true; } -}
\ No newline at end of file + + private static int nextStart(String s, int end) { + char c; + + while (end < s.length()) { + c = s.charAt(end); + if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) { + return end; + } + end++; + } + return end; + } + + private static void addNode(ArrayList<PathDataNode> list, char cmd, float[] val) { + list.add(new PathDataNode(cmd, val)); + } + + private static class ExtractFloatResult { + // We need to return the position of the next separator and whether the + // next float starts with a '-'. + int mEndPosition; + boolean mEndWithNegSign; + } + + private static float[] getFloats(String s) { + if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { + return new float[0]; + } + try { + float[] results = new float[s.length()]; + int count = 0; + int startPosition = 1; + int endPosition = 0; + + ExtractFloatResult result = new ExtractFloatResult(); + int totalLength = s.length(); + + // The startPosition should always be the first character of the + // current number, and endPosition is the character after the current + // number. + while (startPosition < totalLength) { + extract(s, startPosition, result); + endPosition = result.mEndPosition; + + if (startPosition < endPosition) { + results[count++] = Float.parseFloat(s.substring(startPosition, endPosition)); + } + + if (result.mEndWithNegSign) { + // Keep the '-' sign with next number. + startPosition = endPosition; + } else { + startPosition = endPosition + 1; + } + } + return Arrays.copyOf(results, count); + } catch (NumberFormatException e) { + Log.e(LOGTAG, "error in parsing \"" + s + "\""); + throw e; + } + } + + private static void extract(String s, int start, ExtractFloatResult result) { + // Now looking for ' ', ',' or '-' from the start. + int currentIndex = start; + boolean foundSeparator = false; + result.mEndWithNegSign = false; + for (; currentIndex < s.length(); currentIndex++) { + char currentChar = s.charAt(currentIndex); + switch (currentChar) { + case ' ': + case ',': + foundSeparator = true; + break; + case '-': + if (currentIndex != start) { + foundSeparator = true; + result.mEndWithNegSign = true; + } + break; + } + if (foundSeparator) { + break; + } + } + // When there is nothing found, then we put the end position to the end + // of the string. + result.mEndPosition = currentIndex; + } + + public static class PathDataNode { + private char mType; + private float[] mParams; + + private PathDataNode(char type, float[] params) { + mType = type; + mParams = params; + } + + private PathDataNode(PathDataNode n) { + mType = n.mType; + mParams = Arrays.copyOf(n.mParams, n.mParams.length); + } + + /** + * Convert an array of PathDataNode to Path. + * + * @param node The source array of PathDataNode. + * @param path The target Path object. + */ + public static void nodesToPath(PathDataNode[] node, Path path) { + float[] current = new float[4]; + char previousCommand = 'm'; + for (int i = 0; i < node.length; i++) { + addCommand(path, current, previousCommand, node[i].mType, node[i].mParams); + previousCommand = node[i].mType; + } + } + + /** + * The current PathDataNode will be interpolated between the <code>nodeFrom</code> and <code> + * nodeTo</code> according to the <code>fraction</code>. + * + * @param nodeFrom The start value as a PathDataNode. + * @param nodeTo The end value as a PathDataNode + * @param fraction The fraction to interpolate. + */ + public void interpolatePathDataNode( + PathDataNode nodeFrom, PathDataNode nodeTo, float fraction) { + for (int i = 0; i < nodeFrom.mParams.length; i++) { + mParams[i] = nodeFrom.mParams[i] * (1 - fraction) + nodeTo.mParams[i] * fraction; + } + } + + private static void addCommand( + Path path, float[] current, char previousCmd, char cmd, float[] val) { + + int incr = 2; + float currentX = current[0]; + float currentY = current[1]; + float ctrlPointX = current[2]; + float ctrlPointY = current[3]; + float reflectiveCtrlPointX; + float reflectiveCtrlPointY; + + switch (cmd) { + case 'z': + case 'Z': + path.close(); + return; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + incr = 2; + break; + case 'h': + case 'H': + case 'v': + case 'V': + incr = 1; + break; + case 'c': + case 'C': + incr = 6; + break; + case 's': + case 'S': + case 'q': + case 'Q': + incr = 4; + break; + case 'a': + case 'A': + incr = 7; + break; + } + for (int k = 0; k < val.length; k += incr) { + switch (cmd) { + case 'm': // moveto - Start a new sub-path (relative) + path.rMoveTo(val[k + 0], val[k + 1]); + currentX += val[k + 0]; + currentY += val[k + 1]; + break; + case 'M': // moveto - Start a new sub-path + path.moveTo(val[k + 0], val[k + 1]); + currentX = val[k + 0]; + currentY = val[k + 1]; + break; + case 'l': // lineto - Draw a line from the current point (relative) + path.rLineTo(val[k + 0], val[k + 1]); + currentX += val[k + 0]; + currentY += val[k + 1]; + break; + case 'L': // lineto - Draw a line from the current point + path.lineTo(val[k + 0], val[k + 1]); + currentX = val[k + 0]; + currentY = val[k + 1]; + break; + case 'z': // closepath - Close the current subpath + case 'Z': // closepath - Close the current subpath + path.close(); + break; + case 'h': // horizontal lineto - Draws a horizontal line (relative) + path.rLineTo(val[k + 0], 0); + currentX += val[k + 0]; + break; + case 'H': // horizontal lineto - Draws a horizontal line + path.lineTo(val[k + 0], currentY); + currentX = val[k + 0]; + break; + case 'v': // vertical lineto - Draws a vertical line from the current point (r) + path.rLineTo(0, val[k + 0]); + currentY += val[k + 0]; + break; + case 'V': // vertical lineto - Draws a vertical line from the current point + path.lineTo(currentX, val[k + 0]); + currentY = val[k + 0]; + break; + case 'c': // curveto - Draws a cubic Bézier curve (relative) + path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], val[k + 4], val[k + 5]); + + ctrlPointX = currentX + val[k + 2]; + ctrlPointY = currentY + val[k + 3]; + currentX += val[k + 4]; + currentY += val[k + 5]; + + break; + case 'C': // curveto - Draws a cubic Bézier curve + path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3], val[k + 4], val[k + 5]); + currentX = val[k + 4]; + currentY = val[k + 5]; + ctrlPointX = val[k + 2]; + ctrlPointY = val[k + 3]; + break; + case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp) + reflectiveCtrlPointX = 0; + reflectiveCtrlPointY = 0; + if (previousCmd == 'c' + || previousCmd == 's' + || previousCmd == 'C' + || previousCmd == 'S') { + reflectiveCtrlPointX = currentX - ctrlPointX; + reflectiveCtrlPointY = currentY - ctrlPointY; + } + path.rCubicTo( + reflectiveCtrlPointX, + reflectiveCtrlPointY, + val[k + 0], + val[k + 1], + val[k + 2], + val[k + 3]); + + ctrlPointX = currentX + val[k + 0]; + ctrlPointY = currentY + val[k + 1]; + currentX += val[k + 2]; + currentY += val[k + 3]; + break; + case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp) + reflectiveCtrlPointX = currentX; + reflectiveCtrlPointY = currentY; + if (previousCmd == 'c' + || previousCmd == 's' + || previousCmd == 'C' + || previousCmd == 'S') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX; + reflectiveCtrlPointY = 2 * currentY - ctrlPointY; + } + path.cubicTo( + reflectiveCtrlPointX, + reflectiveCtrlPointY, + val[k + 0], + val[k + 1], + val[k + 2], + val[k + 3]); + ctrlPointX = val[k + 0]; + ctrlPointY = val[k + 1]; + currentX = val[k + 2]; + currentY = val[k + 3]; + break; + case 'q': // Draws a quadratic Bézier (relative) + path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); + ctrlPointX = currentX + val[k + 0]; + ctrlPointY = currentY + val[k + 1]; + currentX += val[k + 2]; + currentY += val[k + 3]; + break; + case 'Q': // Draws a quadratic Bézier + path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]); + ctrlPointX = val[k + 0]; + ctrlPointY = val[k + 1]; + currentX = val[k + 2]; + currentY = val[k + 3]; + break; + case 't': // Draws a quadratic Bézier curve(reflective control point)(relative) + reflectiveCtrlPointX = 0; + reflectiveCtrlPointY = 0; + if (previousCmd == 'q' + || previousCmd == 't' + || previousCmd == 'Q' + || previousCmd == 'T') { + reflectiveCtrlPointX = currentX - ctrlPointX; + reflectiveCtrlPointY = currentY - ctrlPointY; + } + path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, val[k + 0], val[k + 1]); + ctrlPointX = currentX + reflectiveCtrlPointX; + ctrlPointY = currentY + reflectiveCtrlPointY; + currentX += val[k + 0]; + currentY += val[k + 1]; + break; + case 'T': // Draws a quadratic Bézier curve (reflective control point) + reflectiveCtrlPointX = currentX; + reflectiveCtrlPointY = currentY; + if (previousCmd == 'q' + || previousCmd == 't' + || previousCmd == 'Q' + || previousCmd == 'T') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX; + reflectiveCtrlPointY = 2 * currentY - ctrlPointY; + } + path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, val[k + 0], val[k + 1]); + ctrlPointX = reflectiveCtrlPointX; + ctrlPointY = reflectiveCtrlPointY; + currentX = val[k + 0]; + currentY = val[k + 1]; + break; + case 'a': // Draws an elliptical arc + // (rx ry x-axis-rotation large-arc-flag sweep-flag x y) + drawArc( + path, + currentX, + currentY, + val[k + 5] + currentX, + val[k + 6] + currentY, + val[k + 0], + val[k + 1], + val[k + 2], + val[k + 3] != 0, + val[k + 4] != 0); + currentX += val[k + 5]; + currentY += val[k + 6]; + ctrlPointX = currentX; + ctrlPointY = currentY; + break; + case 'A': // Draws an elliptical arc + drawArc( + path, + currentX, + currentY, + val[k + 5], + val[k + 6], + val[k + 0], + val[k + 1], + val[k + 2], + val[k + 3] != 0, + val[k + 4] != 0); + currentX = val[k + 5]; + currentY = val[k + 6]; + ctrlPointX = currentX; + ctrlPointY = currentY; + break; + } + previousCmd = cmd; + } + current[0] = currentX; + current[1] = currentY; + current[2] = ctrlPointX; + current[3] = ctrlPointY; + } + + private static void drawArc( + Path p, + float x0, + float y0, + float x1, + float y1, + float a, + float b, + float theta, + boolean isMoreThanHalf, + boolean isPositiveArc) { + + /* Convert rotation angle from degrees to radians */ + double thetaD = Math.toRadians(theta); + /* Pre-compute rotation matrix entries */ + double cosTheta = Math.cos(thetaD); + double sinTheta = Math.sin(thetaD); + /* Transform (x0, y0) and (x1, y1) into unit space */ + /* using (inverse) rotation, followed by (inverse) scale */ + double x0p = (x0 * cosTheta + y0 * sinTheta) / a; + double y0p = (-x0 * sinTheta + y0 * cosTheta) / b; + double x1p = (x1 * cosTheta + y1 * sinTheta) / a; + double y1p = (-x1 * sinTheta + y1 * cosTheta) / b; + + /* Compute differences and averages */ + double dx = x0p - x1p; + double dy = y0p - y1p; + double xm = (x0p + x1p) / 2; + double ym = (y0p + y1p) / 2; + /* Solve for intersecting unit circles */ + double dsq = dx * dx + dy * dy; + if (dsq == 0.0) { + Log.w(LOGTAG, " Points are coincident"); + return; /* Points are coincident */ + } + double disc = 1.0 / dsq - 1.0 / 4.0; + if (disc < 0.0) { + Log.w(LOGTAG, "Points are too far apart " + dsq); + float adjust = (float) (Math.sqrt(dsq) / 1.99999); + drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta, isMoreThanHalf, isPositiveArc); + return; /* Points are too far apart */ + } + double s = Math.sqrt(disc); + double sdx = s * dx; + double sdy = s * dy; + double cx; + double cy; + if (isMoreThanHalf == isPositiveArc) { + cx = xm - sdy; + cy = ym + sdx; + } else { + cx = xm + sdy; + cy = ym - sdx; + } + + double eta0 = Math.atan2((y0p - cy), (x0p - cx)); + + double eta1 = Math.atan2((y1p - cy), (x1p - cx)); + + double sweep = (eta1 - eta0); + if (isPositiveArc != (sweep >= 0)) { + if (sweep > 0) { + sweep -= 2 * Math.PI; + } else { + sweep += 2 * Math.PI; + } + } + + cx *= a; + cy *= b; + double tcx = cx; + cx = cx * cosTheta - cy * sinTheta; + cy = tcx * sinTheta + cy * cosTheta; + + arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep); + } + + /** + * Converts an arc to cubic Bezier segments and records them in p. + * + * @param p The target for the cubic Bezier segments + * @param cx The x coordinate center of the ellipse + * @param cy The y coordinate center of the ellipse + * @param a The radius of the ellipse in the horizontal direction + * @param b The radius of the ellipse in the vertical direction + * @param e1x E(eta1) x coordinate of the starting point of the arc + * @param e1y E(eta2) y coordinate of the starting point of the arc + * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane + * @param start The start angle of the arc on the ellipse + * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse + */ + private static void arcToBezier( + Path p, + double cx, + double cy, + double a, + double b, + double e1x, + double e1y, + double theta, + double start, + double sweep) { + // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html + // and http://www.spaceroots.org/documents/ellipse/node22.html + + // Maximum of 45 degrees per cubic Bezier segment + int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI)); + + double eta1 = start; + double cosTheta = Math.cos(theta); + double sinTheta = Math.sin(theta); + double cosEta1 = Math.cos(eta1); + double sinEta1 = Math.sin(eta1); + double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1); + double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1); + + double anglePerSegment = sweep / numSegments; + for (int i = 0; i < numSegments; i++) { + double eta2 = eta1 + anglePerSegment; + double sinEta2 = Math.sin(eta2); + double cosEta2 = Math.cos(eta2); + double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2); + double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2); + double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2; + double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2; + double tanDiff2 = Math.tan((eta2 - eta1) / 2); + double alpha = Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3; + double q1x = e1x + alpha * ep1x; + double q1y = e1y + alpha * ep1y; + double q2x = e2x - alpha * ep2x; + double q2y = e2y - alpha * ep2y; + + p.cubicTo((float) q1x, (float) q1y, (float) q2x, (float) q2y, (float) e2x, (float) e2y); + eta1 = eta2; + e1x = e2x; + e1y = e2y; + ep1x = ep2x; + ep1y = ep2y; + } + } + } + + @Implements(value = PathParser.PathData.class, minSdk = N, isInAndroidSdk = false) + public static class ShadowPathData { + long mNativePathData = 0; + + @Implementation + public void __constructor__() { + // mNativePathData = nCreateEmptyPathData(); + } + + @Implementation + public void __constructor__(PathParser.PathData data) { + // mNativePathData = nCreatePathData(data.mNativePathData); + } + + @Implementation + public void __constructor__(String pathString) { + // mNativePathData = nCreatePathDataFromString(pathString, pathString.length()); + // if (mNativePathData == 0) { + // throw new IllegalArgumentException("Invalid pathData: " + pathString); + // } + } + + @Implementation + public long getNativePtr() { + return mNativePathData; + } + + /** + * Update the path data to match the source. Before calling this, make sure canMorph(target, + * source) is true. + * + * @param source The source path represented in PathData + */ + @Implementation + public void setPathData(PathParser.PathData source) { + // nSetPathData(mNativePathData, source.mNativePathData); + } + + @Override + @Implementation + protected void finalize() throws Throwable { + if (mNativePathData != 0) { + // nFinalize(mNativePathData); + mNativePathData = 0; + } + super.finalize(); + } + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPeerHandle.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPeerHandle.java index 105ffd624..c94d5dfdb 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPeerHandle.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPeerHandle.java @@ -6,7 +6,6 @@ import android.net.wifi.aware.PeerHandle; import org.robolectric.annotation.Implements; import org.robolectric.util.ReflectionHelpers; -/** Shadow for {@link PeerHandle}. */ @Implements(value = PeerHandle.class, minSdk = O) public class ShadowPeerHandle { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPendingIntent.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPendingIntent.java index 3f18118c4..d508cb6bd 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPendingIntent.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPendingIntent.java @@ -60,37 +60,37 @@ public class ShadowPendingIntent { private boolean canceled; @Implementation - public static PendingIntent getActivity( + protected static PendingIntent getActivity( Context context, int requestCode, @NonNull Intent intent, int flags) { return create(context, new Intent[] {intent}, Type.ACTIVITY, requestCode, flags); } @Implementation - public static PendingIntent getActivity( + protected static PendingIntent getActivity( Context context, int requestCode, @NonNull Intent intent, int flags, Bundle options) { return create(context, new Intent[] {intent}, Type.ACTIVITY, requestCode, flags); } @Implementation - public static PendingIntent getActivities( + protected static PendingIntent getActivities( Context context, int requestCode, @NonNull Intent[] intents, int flags) { return create(context, intents, Type.ACTIVITY, requestCode, flags); } @Implementation - public static PendingIntent getActivities( + protected static PendingIntent getActivities( Context context, int requestCode, @NonNull Intent[] intents, int flags, Bundle options) { return create(context, intents, Type.ACTIVITY, requestCode, flags); } @Implementation - public static PendingIntent getBroadcast( + protected static PendingIntent getBroadcast( Context context, int requestCode, @NonNull Intent intent, int flags) { return create(context, new Intent[] {intent}, Type.BROADCAST, requestCode, flags); } @Implementation - public static PendingIntent getService( + protected static PendingIntent getService( Context context, int requestCode, @NonNull Intent intent, int flags) { return create(context, new Intent[] {intent}, Type.SERVICE, requestCode, flags); } @@ -103,7 +103,7 @@ public class ShadowPendingIntent { @Implementation @SuppressWarnings("ReferenceEquality") - public void cancel() { + protected void cancel() { for (Iterator<PendingIntent> i = createdIntents.iterator(); i.hasNext(); ) { PendingIntent pendingIntent = i.next(); if (pendingIntent == realPendingIntent) { @@ -115,7 +115,7 @@ public class ShadowPendingIntent { } @Implementation - public void send() throws CanceledException { + protected void send() throws CanceledException { send(savedContext, 0, null); } @@ -125,9 +125,8 @@ public class ShadowPendingIntent { send(savedContext, code, null, onFinished, handler); } - @Implementation - public void send(Context context, int code, Intent intent) throws CanceledException { + protected void send(Context context, int code, Intent intent) throws CanceledException { send(context, code, intent, null, null); } @@ -196,7 +195,7 @@ public class ShadowPendingIntent { } @Implementation - public IntentSender getIntentSender() { + protected IntentSender getIntentSender() { return new RoboIntentSender(realPendingIntent); } @@ -284,12 +283,12 @@ public class ShadowPendingIntent { } @Implementation - public String getTargetPackage() { + protected String getTargetPackage() { return getCreatorPackage(); } @Implementation(minSdk = JELLY_BEAN_MR1) - public String getCreatorPackage() { + protected String getCreatorPackage() { return (creatorPackage == null) ? RuntimeEnvironment.application.getPackageName() : creatorPackage; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPicture.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPicture.java index 82deb6ac0..d12fe9b59 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPicture.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPicture.java @@ -16,32 +16,32 @@ public class ShadowPicture { private int height; @Implementation - public void __constructor__() {} + protected void __constructor__() {} @Implementation(minSdk = LOLLIPOP) - public void __constructor__(long nativePicture) {} + protected void __constructor__(long nativePicture) {} @Implementation(maxSdk = KITKAT_WATCH) - public void __constructor__(int nativePicture, boolean fromStream) {} + protected void __constructor__(int nativePicture, boolean fromStream) {} @Implementation - public void __constructor__(Picture src) { + protected void __constructor__(Picture src) { width = src.getWidth(); height = src.getHeight(); } @Implementation - public int getWidth() { + protected int getWidth() { return width; } @Implementation - public int getHeight() { + protected int getHeight() { return height; } @Implementation - public Canvas beginRecording(int width, int height) { + protected Canvas beginRecording(int width, int height) { this.width = width; this.height = height; return new Canvas(Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupMenu.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupMenu.java index d7c5bec6b..4c5727168 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupMenu.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupMenu.java @@ -19,20 +19,20 @@ public class ShadowPopupMenu { private PopupMenu.OnMenuItemClickListener onMenuItemClickListener; @Implementation - public void show() { + protected void show() { this.isShowing = true; setLatestPopupMenu(this); directlyOn(realPopupMenu, PopupMenu.class).show(); } @Implementation - public void dismiss() { + protected void dismiss() { this.isShowing = false; directlyOn(realPopupMenu, PopupMenu.class).dismiss(); } @Implementation - public void setOnMenuItemClickListener(PopupMenu.OnMenuItemClickListener listener) { + protected void setOnMenuItemClickListener(PopupMenu.OnMenuItemClickListener listener) { this.onMenuItemClickListener = listener; directlyOn(realPopupMenu, PopupMenu.class).setOnMenuItemClickListener(listener); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupWindow.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupWindow.java index 427aa441f..d9210ab80 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupWindow.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPopupWindow.java @@ -16,7 +16,7 @@ public class ShadowPopupWindow { private PopupWindow realPopupWindow; @Implementation - public void invokePopup(WindowManager.LayoutParams p) { + protected void invokePopup(WindowManager.LayoutParams p) { ShadowApplication.getInstance().setLatestPopupWindow(realPopupWindow); directlyOn(realPopupWindow, PopupWindow.class, diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPorterDuffColorFilter.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPorterDuffColorFilter.java index 2827072be..b22daa229 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPorterDuffColorFilter.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPorterDuffColorFilter.java @@ -7,25 +7,39 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.annotation.RealObject; +import org.robolectric.shadow.api.Shadow; +import org.robolectric.util.ReflectionHelpers.ClassParameter; + @Implements(PorterDuffColorFilter.class) public class ShadowPorterDuffColorFilter { private int color; private PorterDuff.Mode mode; + @RealObject private PorterDuffColorFilter realPorterDuffColorFilter; + @Implementation - public void __constructor__(int color, PorterDuff.Mode mode) { + protected void __constructor__(int color, PorterDuff.Mode mode) { + // We need these copies because before Lollipop, PorterDuffColorFilter had no fields, it would + // just delegate to a native instance. If we remove them, the shadow cannot access the fields + // on KitKat and earlier. this.color = color; this.mode = mode; + Shadow.invokeConstructor( + PorterDuffColorFilter.class, + realPorterDuffColorFilter, + ClassParameter.from(int.class, color), + ClassParameter.from(PorterDuff.Mode.class, mode)); } @Implementation(minSdk = LOLLIPOP, maxSdk = P) - public void setColor(int color) { + protected void setColor(int color) { this.color = color; } @Implementation(minSdk = LOLLIPOP, maxSdk = P) - public void setMode(PorterDuff.Mode mode) { + protected void setMode(PorterDuff.Mode mode) { this.mode = mode; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java index b54a5b211..010088497 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowPowerManager.java @@ -32,14 +32,14 @@ public class ShadowPowerManager { private Map<String, Boolean> ignoringBatteryOptimizations = new HashMap<>(); @Implementation - public PowerManager.WakeLock newWakeLock(int flags, String tag) { + protected PowerManager.WakeLock newWakeLock(int flags, String tag) { PowerManager.WakeLock wl = Shadow.newInstanceOf(PowerManager.WakeLock.class); getInstance().addWakeLock(wl); return wl; } @Implementation - public boolean isScreenOn() { + protected boolean isScreenOn() { return isScreenOn; } @@ -48,7 +48,7 @@ public class ShadowPowerManager { } @Implementation(minSdk = LOLLIPOP) - public boolean isInteractive() { + protected boolean isInteractive() { return isInteractive; } @@ -57,12 +57,13 @@ public class ShadowPowerManager { } @Implementation(minSdk = LOLLIPOP) - public boolean isPowerSaveMode() { + protected boolean isPowerSaveMode() { return isPowerSaveMode; } - @HiddenApi @Implementation(minSdk = KITKAT_WATCH) - protected void setPowerSaveMode(boolean powerSaveMode) { + @HiddenApi + @Implementation(minSdk = KITKAT_WATCH) + protected boolean setPowerSaveMode(boolean powerSaveMode) { final Context context = RuntimeEnvironment.application; final int perm = context.getPackageManager() .checkPermission(permission.DEVICE_POWER, context.getPackageName()); @@ -71,6 +72,7 @@ public class ShadowPowerManager { "You need DEVICE_POWER permission to: set the device power-save mode"); } isPowerSaveMode = powerSaveMode; + return true; } /** @@ -84,7 +86,7 @@ public class ShadowPowerManager { private Map<Integer, Boolean> supportedWakeLockLevels = new HashMap<>(); @Implementation(minSdk = LOLLIPOP) - public boolean isWakeLockLevelSupported(int level) { + protected boolean isWakeLockLevelSupported(int level) { return supportedWakeLockLevels.containsKey(level) ? supportedWakeLockLevels.get(level) : false; } @@ -125,7 +127,7 @@ public class ShadowPowerManager { } @Implementation(minSdk = M) - public boolean isIgnoringBatteryOptimizations(String packageName) { + protected boolean isIgnoringBatteryOptimizations(String packageName) { Boolean result = ignoringBatteryOptimizations.get(packageName); return result == null ? false : result; } @@ -157,12 +159,12 @@ public class ShadowPowerManager { private WorkSource workSource = null; @Implementation - public void acquire() { + protected void acquire() { acquire(0); } @Implementation - public synchronized void acquire(long timeout) { + protected synchronized void acquire(long timeout) { if (refCounted) { refCount++; } else { @@ -171,7 +173,7 @@ public class ShadowPowerManager { } @Implementation - public synchronized void release() { + protected synchronized void release() { if (refCounted) { if (--refCount < 0) throw new RuntimeException("WakeLock under-locked"); } else { @@ -180,7 +182,7 @@ public class ShadowPowerManager { } @Implementation - public synchronized boolean isHeld() { + protected synchronized boolean isHeld() { return refCounted ? refCount > 0 : locked; } @@ -194,12 +196,12 @@ public class ShadowPowerManager { } @Implementation - public void setReferenceCounted(boolean value) { + protected void setReferenceCounted(boolean value) { refCounted = value; } @Implementation - public synchronized void setWorkSource(WorkSource ws) { + protected synchronized void setWorkSource(WorkSource ws) { workSource = ws; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProcess.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProcess.java index 840697ab9..536fce060 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProcess.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProcess.java @@ -119,7 +119,7 @@ public class ShadowProcess { // android.os.Process.myUid(), which persists between tests. } - private static int getRandomApplicationUid() { + static int getRandomApplicationUid() { // UIDs are randomly initialized to prevent tests from depending on any given value. Tests // should access the current process UID via android.os.Process::myUid(). return ThreadLocalRandom.current() diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProgressDialog.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProgressDialog.java index 6bac60d9c..280eeefa7 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProgressDialog.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowProgressDialog.java @@ -30,7 +30,7 @@ public class ShadowProgressDialog extends ShadowAlertDialog { } @Implementation - public void setProgressStyle(int style) { + protected void setProgressStyle(int style) { mProgressStyle = style; directlyOn(realProgressDialog, ProgressDialog.class).setProgressStyle(style); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRecordingCanvas.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRecordingCanvas.java new file mode 100644 index 000000000..e22e1a02a --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRecordingCanvas.java @@ -0,0 +1,29 @@ +// BEGIN-INTERNAL +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.Q; + +import android.graphics.RecordingCanvas; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(value = RecordingCanvas.class, isInAndroidSdk = false, minSdk = Q) +public class ShadowRecordingCanvas extends ShadowCanvas { + + @Implementation + protected static long nCreateDisplayListCanvas(long node, int width, int height) { + return 1; + } + + @Config + protected static long nCreateDisplayListCanvas(int width, int height) { + return 1; + } + + @Config + protected static long nCreateDisplayListCanvas() { + return 1; + } +} +// END-INTERNAL
\ No newline at end of file diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRegion.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRegion.java index 75217ba95..067f8ad2e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRegion.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRegion.java @@ -1,16 +1,17 @@ package org.robolectric.shadows; import android.graphics.Region; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.HiddenApi; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @Implements(Region.class) public class ShadowRegion { - public static int nextId = 1; + public static long nextId = 1; @HiddenApi @Implementation - public static int nativeConstructor() { - return nextId++; + public static Number nativeConstructor() { + return RuntimeEnvironment.castNativePtr(nextId++); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRemoteCallbackList.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRemoteCallbackList.java index 07b1d972b..4bf84b373 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRemoteCallbackList.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRemoteCallbackList.java @@ -33,12 +33,12 @@ public class ShadowRemoteCallbackList<E extends IInterface> { } @Implementation - public boolean register(E callback) { + protected boolean register(E callback) { return register(callback, null); } @Implementation - public boolean register(E callback, Object cookie) { + protected boolean register(E callback, Object cookie) { synchronized (callbacks) { if (killed) { return false; @@ -56,7 +56,7 @@ public class ShadowRemoteCallbackList<E extends IInterface> { } @Implementation - public boolean unregister(E callback) { + protected boolean unregister(E callback) { synchronized (callbacks) { Callback cb = callbacks.remove(callback.asBinder()); if (cb != null) { @@ -68,7 +68,7 @@ public class ShadowRemoteCallbackList<E extends IInterface> { } @Implementation - public void kill() { + protected void kill() { synchronized (callbacks) { for (Callback cb : callbacks.values()) { cb.callback.asBinder().unlinkToDeath(cb, 0); @@ -79,15 +79,15 @@ public class ShadowRemoteCallbackList<E extends IInterface> { } @Implementation - public void onCallbackDied(E callback) {} + protected void onCallbackDied(E callback) {} @Implementation - public void onCallbackDied(E callback, Object cookie) { + protected void onCallbackDied(E callback, Object cookie) { onCallbackDied(callback); } @Implementation - public int beginBroadcast() { + protected int beginBroadcast() { synchronized (callbacks) { if (broadcastCount > 0) { throw new IllegalStateException("beginBroadcast() called while already in a broadcast"); @@ -109,17 +109,17 @@ public class ShadowRemoteCallbackList<E extends IInterface> { } @Implementation - public E getBroadcastItem(int index) { + protected E getBroadcastItem(int index) { return ((Callback) activeBroadcast[index]).callback; } @Implementation - public Object getBroadcastCookie(int index) { + protected Object getBroadcastCookie(int index) { return ((Callback) activeBroadcast[index]).cookie; } @Implementation - public void finishBroadcast() { + protected void finishBroadcast() { if (broadcastCount < 0) { throw new IllegalStateException("finishBroadcast() called outside of a broadcast"); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRenderNode.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRenderNode.java index ae565614f..83b7ac6c4 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRenderNode.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowRenderNode.java @@ -1,12 +1,13 @@ +// BEGIN-INTERNAL package org.robolectric.shadows; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.Q; import android.graphics.RenderNode; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -@Implements(value = RenderNode.class, isInAndroidSdk = false, minSdk = LOLLIPOP) +@Implements(value = RenderNode.class, isInAndroidSdk = false, minSdk = Q) public class ShadowRenderNode { private float alpha = 1f; private float cameraDistance; @@ -196,4 +197,10 @@ public class ShadowRenderNode { public float getPivotY() { return pivotY; } -}
\ No newline at end of file + + @Implementation + protected boolean isValid() { + return true; + } +} +// END-INTERNAL
\ No newline at end of file diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResolveInfo.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResolveInfo.java index 03fb25897..d80fe2338 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResolveInfo.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResolveInfo.java @@ -46,7 +46,7 @@ public class ShadowResolveInfo { } @Implementation - public String loadLabel(PackageManager mgr) { + protected CharSequence loadLabel(PackageManager mgr) { return label; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResultReceiver.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResultReceiver.java index b31fe20c2..6ee4aa0c3 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResultReceiver.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowResultReceiver.java @@ -13,7 +13,7 @@ public class ShadowResultReceiver { @RealObject private ResultReceiver realResultReceiver; @Implementation - public void send(int resultCode, android.os.Bundle resultData) { + protected void send(int resultCode, android.os.Bundle resultData) { ReflectionHelpers.callInstanceMethod(realResultReceiver, "onReceiveResult", ClassParameter.from(Integer.TYPE, resultCode), ClassParameter.from(Bundle.class, resultData)); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteOpenHelper.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteOpenHelper.java index f04499c3d..8621359d1 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteOpenHelper.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSQLiteOpenHelper.java @@ -3,7 +3,6 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.O_MR1; import android.database.sqlite.SQLiteOpenHelper; - import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -14,7 +13,7 @@ import org.robolectric.annotation.Implements; @Implements(SQLiteOpenHelper.class) public class ShadowSQLiteOpenHelper { @Implementation(minSdk = O_MR1) - public void setIdleConnectionTimeout(long idleConnectionTimeoutMs) { + protected void setIdleConnectionTimeout(long idleConnectionTimeoutMs) { // Calling the real one currently results in a Robolectric deadlock. Just ignore it. // See b/78464547 . } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScaleGestureDetector.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScaleGestureDetector.java index 42ba07245..c7f920551 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScaleGestureDetector.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScaleGestureDetector.java @@ -17,12 +17,13 @@ public class ShadowScaleGestureDetector { private float focusY; @Implementation - public void __constructor__(Context context, ScaleGestureDetector.OnScaleGestureListener listener) { + protected void __constructor__( + Context context, ScaleGestureDetector.OnScaleGestureListener listener) { this.listener = listener; } @Implementation - public boolean onTouchEvent(MotionEvent event) { + protected boolean onTouchEvent(MotionEvent event) { onTouchEventMotionEvent = event; return true; } @@ -47,7 +48,7 @@ public class ShadowScaleGestureDetector { } @Implementation - public float getScaleFactor() { + protected float getScaleFactor() { return scaleFactor; } @@ -57,12 +58,12 @@ public class ShadowScaleGestureDetector { } @Implementation - public float getFocusX(){ + protected float getFocusX() { return focusX; } @Implementation - public float getFocusY(){ + protected float getFocusY() { return focusY; } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScroller.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScroller.java index 40edd9dad..2a4e28a57 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScroller.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowScroller.java @@ -15,44 +15,44 @@ public class ShadowScroller { private boolean started; @Implementation - public int getStartX() { + protected int getStartX() { return startX; } @Implementation - public int getStartY() { + protected int getStartY() { return startY; } @Implementation - public int getCurrX() { + protected int getCurrX() { long dt = deltaTime(); return dt >= duration ? finalX : startX + (int) ((deltaX() * dt) / duration); } @Implementation - public int getCurrY() { + protected int getCurrY() { long dt = deltaTime(); return dt >= duration ? finalY : startY + (int) ((deltaY() * dt) / duration); } @Implementation - public int getFinalX() { + protected int getFinalX() { return finalX; } @Implementation - public int getFinalY() { + protected int getFinalY() { return finalY; } @Implementation - public int getDuration() { + protected int getDuration() { return (int) duration; } @Implementation - public void startScroll(int startX, int startY, int dx, int dy, int duration) { + protected void startScroll(int startX, int startY, int dx, int dy, int duration) { this.startX = startX; this.startY = startY; finalX = startX + dx; @@ -70,7 +70,7 @@ public class ShadowScroller { } @Implementation - public boolean computeScrollOffset() { + protected boolean computeScrollOffset() { if (!started) { return false; } @@ -79,12 +79,12 @@ public class ShadowScroller { } @Implementation - public boolean isFinished() { + protected boolean isFinished() { return deltaTime() > duration; } @Implementation - public int timePassed() { + protected int timePassed() { return (int) deltaTime(); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSeekBar.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSeekBar.java index 3279cc4cc..2ca148b54 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSeekBar.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSeekBar.java @@ -15,7 +15,7 @@ public class ShadowSeekBar extends ShadowAbsSeekBar { private SeekBar.OnSeekBarChangeListener listener; @Implementation - public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) { + protected void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) { this.listener = listener; Shadow.directlyOn(realSeekBar, SeekBar.class).setOnSeekBarChangeListener(listener); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java index 43149cb23..c37ca3a3d 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensor.java @@ -9,9 +9,6 @@ import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers.ClassParameter; -/** - * Shadow for {@link Sensor}. - */ @Implements(Sensor.class) public class ShadowSensor { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java index c51abec08..68a80cd43 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSensorManager.java @@ -11,7 +11,9 @@ import android.hardware.SensorManager; import android.os.Handler; import android.os.MemoryFile; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -47,7 +49,7 @@ public class ShadowSensorManager { } @Implementation - public Sensor getDefaultSensor(int type) { + protected Sensor getDefaultSensor(int type) { return sensorMap.get(type); } @@ -59,7 +61,7 @@ public class ShadowSensorManager { } @Implementation - public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) { + protected boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) { if (forceListenersToFail) { return false; } @@ -70,12 +72,12 @@ public class ShadowSensorManager { } @Implementation - public void unregisterListener(SensorEventListener listener, Sensor sensor) { + protected void unregisterListener(SensorEventListener listener, Sensor sensor) { listeners.remove(listener); } @Implementation - public void unregisterListener(SensorEventListener listener) { + protected void unregisterListener(SensorEventListener listener) { listeners.remove(listener); } @@ -83,6 +85,14 @@ public class ShadowSensorManager { return listeners.contains(listener); } + /** + * Returns the list of {@link SensorEventListener}s registered on this SensorManager. Note that + * the list is unmodifiable, any attempt to modify it will throw an exception. + */ + public List<SensorEventListener> getListeners() { + return Collections.unmodifiableList(listeners); + } + /** Propagates the {@code event} to all registered listeners. */ public void sendSensorEventToListeners(SensorEvent event) { for (SensorEventListener listener : listeners) { @@ -113,10 +123,8 @@ public class ShadowSensorManager { return ReflectionHelpers.callConstructor(SensorEvent.class, valueArraySizeParam); } - - @Implementation(minSdk = O) - public Object createDirectChannel(MemoryFile mem) { + protected Object createDirectChannel(MemoryFile mem) { return ReflectionHelpers.callConstructor(SensorDirectChannel.class, ClassParameter.from(SensorManager.class, realObject), ClassParameter.from(int.class, 0), diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowService.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowService.java index 4b2023cd2..440e41c3c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowService.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowService.java @@ -21,24 +21,30 @@ public class ShadowService extends ShadowContextWrapper { private boolean notificationShouldRemoved; @Implementation - public void onDestroy() { + protected void onDestroy() { removeForegroundNotification(); } @Implementation - public void stopSelf() { + protected void stopSelf() { selfStopped = true; } @Implementation - public void stopSelf(int id) { + protected void stopSelf(int id) { selfStopped = true; } @Implementation - public final void startForeground(int id, Notification notification) { + protected boolean stopSelfResult(int id) { + selfStopped = true; + return true; + } + + @Implementation + protected final void startForeground(int id, Notification notification) { foregroundStopped = false; - lastForegroundNotificationId = id; + lastForegroundNotificationId = id; lastForegroundNotification = notification; notification.flags |= Notification.FLAG_FOREGROUND_SERVICE; NotificationManager nm = (NotificationManager)RuntimeEnvironment.application.getSystemService(Context.NOTIFICATION_SERVICE); @@ -46,7 +52,7 @@ public class ShadowService extends ShadowContextWrapper { } @Implementation - public void stopForeground(boolean removeNotification) { + protected void stopForeground(boolean removeNotification) { foregroundStopped = true; notificationShouldRemoved = removeNotification; if (removeNotification) { @@ -56,14 +62,14 @@ public class ShadowService extends ShadowContextWrapper { private void removeForegroundNotification() { NotificationManager nm = (NotificationManager)RuntimeEnvironment.application.getSystemService(Context.NOTIFICATION_SERVICE); - nm.cancel(lastForegroundNotificationId); + nm.cancel(lastForegroundNotificationId); lastForegroundNotification = null; } - + public int getLastForegroundNotificationId() { return lastForegroundNotificationId; } - + public Notification getLastForegroundNotification() { return lastForegroundNotification; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java index 3a6b13311..792bd28d8 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowServiceManager.java @@ -8,6 +8,7 @@ import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.N_MR1; import static android.os.Build.VERSION_CODES.O; import static android.os.Build.VERSION_CODES.Q; +import static android.os.Build.VERSION_CODES.P; import android.accounts.IAccountManager; import android.app.IAlarmManager; @@ -15,6 +16,7 @@ import android.app.INotificationManager; import android.app.ISearchManager; import android.app.admin.IDevicePolicyManager; import android.app.job.IJobScheduler; +import android.app.slice.ISliceManager; import android.app.trust.ITrustManager; import android.app.usage.IUsageStatsManager; import android.content.Context; @@ -177,6 +179,11 @@ public class ShadowServiceManager { createBinder( "android.os.storage.IMountService", "android.os.storage.IMountService")); } + if (RuntimeEnvironment.getApiLevel() >= P) { + put( + Context.SLICE_SERVICE, + createBinder(ISliceManager.class, "android.app.slice.SliceManager")); + } // BEGIN-INTERNAL if (RuntimeEnvironment.getApiLevel() >= Q) { put(Context.NOTIFICATION_SERVICE, diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java index 759dbabfe..7b1adeeef 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSettings.java @@ -62,9 +62,6 @@ public class ShadowSettings { } } - /** - * Shadow for {@link Settings.Secure} - */ @Implements(value = Settings.Secure.class) public static class ShadowSecure { private static final Map<ContentResolver, Map<String, String>> dataMap = new WeakHashMap<>(); @@ -192,9 +189,6 @@ public class ShadowSettings { } } - /** - * Shadow for {@link Settings.Global} - */ @Implements(value = Settings.Global.class, minSdk = JELLY_BEAN_MR1) public static class ShadowGlobal { private static final Map<ContentResolver, Map<String, String>> dataMap = new WeakHashMap<>(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSharedPreferences.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSharedPreferences.java new file mode 100644 index 000000000..e0404476d --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSharedPreferences.java @@ -0,0 +1,28 @@ +package org.robolectric.shadows; + +import android.app.QueuedWork; +import android.os.Build.VERSION_CODES; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.RealObject; +import org.robolectric.shadow.api.Shadow; + +/** Dummy container class for nested shadow class */ +public class ShadowSharedPreferences { + + @Implements( + className = "android.app.SharedPreferencesImpl$EditorImpl", + minSdk = VERSION_CODES.O, + isInAndroidSdk = false) + public static class ShadowSharedPreferencesEditorImpl { + + @RealObject Object realObject; + + @Implementation + protected void apply() { + Shadow.directlyOn(realObject, "android.app.SharedPreferencesImpl$EditorImpl", "apply"); + // Flush QueuedWork. This resolves the deadlock of calling 'apply' followed by 'commit'. + QueuedWork.waitToFinish(); + } + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSliceManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSliceManager.java new file mode 100644 index 000000000..e75a8799a --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSliceManager.java @@ -0,0 +1,80 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.P; + +import android.app.slice.SliceManager; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.net.Uri; +import android.os.Handler; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.Resetter; + +/** Shadow of {@link SliceManager}. */ +@Implements(value = SliceManager.class, minSdk = P) +public class ShadowSliceManager { + + private static final Map<Integer, Collection<Uri>> packageUidsToPermissionGrantedSliceUris = + new HashMap<>(); + private Context context; + + @Implementation + protected void __constructor__(Context context, Handler handler) { + this.context = context; + } + + @Implementation + protected synchronized void grantSlicePermission(String toPackage, Uri uri) { + int packageUid = getUidForPackage(toPackage); + Collection<Uri> uris = packageUidsToPermissionGrantedSliceUris.get(packageUid); + if (uris == null) { + uris = new ArrayList<>(); + packageUidsToPermissionGrantedSliceUris.put(packageUid, uris); + } + uris.add(uri); + } + + @Implementation + protected synchronized void revokeSlicePermission(String toPackage, Uri uri) { + int packageUid = getUidForPackage(toPackage); + Collection<Uri> uris = packageUidsToPermissionGrantedSliceUris.get(packageUid); + if (uris != null) { + uris.remove(uri); + if (uris.isEmpty()) { + packageUidsToPermissionGrantedSliceUris.remove(packageUid); + } + } + } + + @Implementation + protected synchronized int checkSlicePermission(Uri uri, int pid, int uid) { + if (uid == 0) { + return PackageManager.PERMISSION_GRANTED; + } + Collection<Uri> uris = packageUidsToPermissionGrantedSliceUris.get(uid); + if (uris != null && uris.contains(uri)) { + return PackageManager.PERMISSION_GRANTED; + } + return PackageManager.PERMISSION_DENIED; + } + + private int getUidForPackage(String packageName) { + PackageManager packageManager = context.getPackageManager(); + try { + return packageManager.getPackageUid(packageName, 0); + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } + } + + @Resetter + public static synchronized void reset() { + packageUidsToPermissionGrantedSliceUris.clear(); + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSmsManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSmsManager.java index aabcbf2b1..1fca7deaf 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSmsManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSmsManager.java @@ -6,33 +6,25 @@ import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; import android.app.PendingIntent; import android.telephony.SmsManager; import android.text.TextUtils; -import android.util.SparseArray; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -import org.robolectric.shadow.api.Shadow; +import org.robolectric.annotation.Resetter; +import org.robolectric.util.ReflectionHelpers; @Implements(value = SmsManager.class, minSdk = JELLY_BEAN_MR2) public class ShadowSmsManager { - private static final SmsManager realManager = Shadow.newInstanceOf(SmsManager.class); - private static final SparseArray<SmsManager> subSmsManagers = new SparseArray<>(1); - - @Implementation - public static SmsManager getDefault() { - return realManager; - } - - @Implementation(minSdk = LOLLIPOP_MR1) - public static SmsManager getSmsManagerForSubscriptionId(int subId) { - SmsManager smsManager = subSmsManagers.get(subId); - if (smsManager == null) { - smsManager = - Shadow.newInstance(SmsManager.class, new Class[] {int.class}, new Object[] {subId}); - subSmsManagers.put(subId, smsManager); + @Resetter + public static void reset() { + if (RuntimeEnvironment.getApiLevel() >= LOLLIPOP_MR1) { + Map<String, Object> sSubInstances = + ReflectionHelpers.getStaticField(SmsManager.class, "sSubInstances"); + sSubInstances.clear(); } - return smsManager; } private TextSmsParams lastTextSmsParams; @@ -40,7 +32,13 @@ public class ShadowSmsManager { private DataMessageParams lastDataParams; @Implementation - public void sendDataMessage(String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { + protected void sendDataMessage( + String destinationAddress, + String scAddress, + short destinationPort, + byte[] data, + PendingIntent sentIntent, + PendingIntent deliveryIntent) { if (TextUtils.isEmpty(destinationAddress)) { throw new IllegalArgumentException("Invalid destinationAddress"); } @@ -49,7 +47,12 @@ public class ShadowSmsManager { } @Implementation - public void sendTextMessage(String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { + protected void sendTextMessage( + String destinationAddress, + String scAddress, + String text, + PendingIntent sentIntent, + PendingIntent deliveryIntent) { if (TextUtils.isEmpty(destinationAddress)) { throw new IllegalArgumentException("Invalid destinationAddress"); } @@ -62,7 +65,12 @@ public class ShadowSmsManager { } @Implementation - public void sendMultipartTextMessage(String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { + protected void sendMultipartTextMessage( + String destinationAddress, + String scAddress, + ArrayList<String> parts, + ArrayList<PendingIntent> sentIntents, + ArrayList<PendingIntent> deliveryIntents) { if (TextUtils.isEmpty(destinationAddress)) { throw new IllegalArgumentException("Invalid destinationAddress"); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSoundPool.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSoundPool.java index f5da20b0b..3bc0eac9c 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSoundPool.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSoundPool.java @@ -8,10 +8,14 @@ import static android.os.Build.VERSION_CODES.N_MR1; import android.content.Context; import android.media.IAudioService; import android.media.SoundPool; +import android.media.SoundPool.OnLoadCompleteListener; import android.util.SparseArray; import android.util.SparseIntArray; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -20,8 +24,7 @@ import org.robolectric.util.ReflectionHelpers; @Implements(SoundPool.class) public class ShadowSoundPool { - @RealObject - SoundPool realObject; + @RealObject SoundPool realObject; /** Generates sound ids when they are loaded. */ private final AtomicInteger soundIds = new AtomicInteger(); @@ -32,7 +35,9 @@ public class ShadowSoundPool { /** Tracks mapping between sound ids and the resource id they refer too. */ private final SparseIntArray idToRes = new SparseIntArray(); - private final List<Integer> playedSounds = new ArrayList<>(); + private final List<Playback> playedSounds = new ArrayList<>(); + + private OnLoadCompleteListener listener; @Implementation(minSdk = N, maxSdk = N_MR1) protected static IAudioService getService() { @@ -45,14 +50,14 @@ public class ShadowSoundPool { @Implementation(maxSdk = LOLLIPOP_MR1) protected int play( int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) { - playedSounds.add(soundID); + playedSounds.add(new Playback(soundID, leftVolume, rightVolume, priority, loop, rate)); return 1; } @Implementation(minSdk = M) protected int _play( int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate) { - playedSounds.add(soundID); + playedSounds.add(new Playback(soundID, leftVolume, rightVolume, priority, loop, rate)); return 1; } @@ -72,10 +77,47 @@ public class ShadowSoundPool { return soundId; } + @Implementation + protected void setOnLoadCompleteListener(OnLoadCompleteListener listener) { + this.listener = listener; + } + + /** Notify the {@link OnLoadCompleteListener}, if present, that the given path was loaded. */ + public void notifyPathLoaded(String path, boolean success) { + boolean soundIsKnown = false; + for (int pathIdx = 0; pathIdx < idToPaths.size(); ++pathIdx) { + if (idToPaths.valueAt(pathIdx).equals(path)) { + if (listener != null) { + listener.onLoadComplete(realObject, idToPaths.keyAt(pathIdx), success ? 0 : 1); + } + soundIsKnown = true; + } + } + if (!soundIsKnown) { + throw new IllegalArgumentException("Unknown sound. You need to call load() first"); + } + } + + /** Notify the {@link OnLoadCompleteListener}, if present, that the given resource was loaded. */ + public void notifyResourceLoaded(int resId, boolean success) { + boolean soundIsKnown = false; + for (int resIdx = 0; resIdx < idToRes.size(); ++resIdx) { + if (idToRes.valueAt(resIdx) == resId) { + if (listener != null) { + listener.onLoadComplete(realObject, idToRes.keyAt(resIdx), success ? 0 : 1); + } + soundIsKnown = true; + } + } + if (!soundIsKnown) { + throw new IllegalArgumentException("Unknown sound. You need to call load() first"); + } + } + /** Returns {@code true} if the given path was played. */ public boolean wasPathPlayed(String path) { - for (int id : playedSounds) { - if (idToPaths.indexOfKey(id) >= 0 && idToPaths.get(id).equals(path)) { + for (Playback playback : playedSounds) { + if (idIsForPath(playback.soundId, path)) { return true; } } @@ -84,16 +126,90 @@ public class ShadowSoundPool { /** Returns {@code true} if the given resource was played. */ public boolean wasResourcePlayed(int resId) { - for (int id : playedSounds) { - if (idToRes.indexOfKey(id) >= 0 && idToRes.get(id) == resId) { + for (Playback playback : playedSounds) { + if (idIsForResource(playback.soundId, resId)) { return true; } } return false; } + /** Return a list of calls to {@code play} made for the given path. */ + public List<Playback> getPathPlaybacks(String path) { + ImmutableList.Builder<Playback> playbacks = ImmutableList.builder(); + for (Playback playback : playedSounds) { + if (idIsForPath(playback.soundId, path)) { + playbacks.add(playback); + } + } + return playbacks.build(); + } + + /** Return a list of calls to {@code play} made for the given resource. */ + public List<Playback> getResourcePlaybacks(int resId) { + ImmutableList.Builder<Playback> playbacks = ImmutableList.builder(); + for (Playback playback : playedSounds) { + if (idIsForResource(playback.soundId, resId)) { + playbacks.add(playback); + } + } + return playbacks.build(); + } + + private boolean idIsForPath(int soundId, String path) { + return idToPaths.indexOfKey(soundId) >= 0 && idToPaths.get(soundId).equals(path); + } + + private boolean idIsForResource(int soundId, int resId) { + return idToRes.indexOfKey(soundId) >= 0 && idToRes.get(soundId) == resId; + } + /** Clears the sounds played by this SoundPool. */ public void clearPlayed() { playedSounds.clear(); } + + /** Record of a single call to {@link SoundPool#play }. */ + public static final class Playback { + public final int soundId; + public final float leftVolume; + public final float rightVolume; + public final int priority; + public final int loop; + public final float rate; + + public Playback( + int soundId, float leftVolume, float rightVolume, int priority, int loop, float rate) { + this.soundId = soundId; + this.leftVolume = leftVolume; + this.rightVolume = rightVolume; + this.priority = priority; + this.loop = loop; + this.rate = rate; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Playback)) { + return false; + } + Playback that = (Playback) o; + return this.soundId == that.soundId + && this.leftVolume == that.leftVolume + && this.rightVolume == that.rightVolume + && this.priority == that.priority + && this.loop == that.loop + && this.rate == that.rate; + } + + @Override + public int hashCode() { + return Objects.hash(soundId, leftVolume, rightVolume, priority, loop, rate); + } + + @Override + public String toString() { + return Arrays.asList(soundId, leftVolume, rightVolume, priority, loop, rate).toString(); + } + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSslErrorHandler.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSslErrorHandler.java index c8ab6ab9c..4e9e19669 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSslErrorHandler.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSslErrorHandler.java @@ -11,7 +11,7 @@ public class ShadowSslErrorHandler extends ShadowHandler { private boolean proceedCalled = false; @Implementation - public void cancel() { + protected void cancel() { cancelCalled = true; } @@ -20,7 +20,7 @@ public class ShadowSslErrorHandler extends ShadowHandler { } @Implementation - public void proceed() { + protected void proceed() { proceedCalled = true; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStatFs.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStatFs.java index 7dfd34875..c066753a1 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStatFs.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStatFs.java @@ -24,51 +24,52 @@ public class ShadowStatFs { private Stats stat; @Implementation - public void __constructor__(String path) { + protected void __constructor__(String path) { restat(path); } @Implementation - public int getBlockSize() { + protected int getBlockSize() { return BLOCK_SIZE; } @Implementation - public int getBlockCount() { + protected int getBlockCount() { return stat.blockCount; } @Implementation - public int getFreeBlocks() { + protected int getFreeBlocks() { return stat.freeBlocks; } @Implementation(minSdk = JELLY_BEAN_MR2) - public long getFreeBlocksLong() { + protected long getFreeBlocksLong() { return stat.freeBlocks; } @Implementation(minSdk = JELLY_BEAN_MR2) - public long getFreeBytes() { + protected long getFreeBytes() { return getBlockSizeLong() * getFreeBlocksLong(); } @Implementation(minSdk = JELLY_BEAN_MR2) - public long getAvailableBytes() { + protected long getAvailableBytes() { return getBlockSizeLong() * getAvailableBlocksLong(); } @Implementation(minSdk = JELLY_BEAN_MR2) - public long getTotalBytes() { + protected long getTotalBytes() { return getBlockSizeLong() * getBlockCountLong(); } + @Implementation - public int getAvailableBlocks() { + protected int getAvailableBlocks() { return stat.availableBlocks; } @Implementation - public void restat(String path) { + protected void restat(String path) { Map.Entry<String, Stats> mapEntry = stats.floorEntry(path); for (;;) { // We will hit all matching paths, longest one first. We may hit non-matching paths before we @@ -86,21 +87,19 @@ public class ShadowStatFs { } } - /** - * Robolectric always uses a block size of `4096`. - */ + /** Robolectric always uses a block size of `4096`. */ @Implementation(minSdk = JELLY_BEAN_MR2) - public long getBlockSizeLong() { + protected long getBlockSizeLong() { return BLOCK_SIZE; } @Implementation(minSdk = JELLY_BEAN_MR2) - public long getBlockCountLong() { + protected long getBlockCountLong() { return stat.blockCount; } @Implementation(minSdk = JELLY_BEAN_MR2) - public long getAvailableBlocksLong() { + protected long getAvailableBlocksLong() { return stat.availableBlocks; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStateListDrawable.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStateListDrawable.java index fca23b1bc..4e387d942 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStateListDrawable.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStateListDrawable.java @@ -24,7 +24,7 @@ public class ShadowStateListDrawable extends ShadowDrawable { } @Implementation - public void addState(int[] stateSet, Drawable drawable) { + protected void addState(int[] stateSet, Drawable drawable) { stateToDrawable.put(createStateList(stateSet), drawable); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStatusBarManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStatusBarManager.java new file mode 100644 index 000000000..9b58618a1 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStatusBarManager.java @@ -0,0 +1,37 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.M; + +import android.app.StatusBarManager; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +/** Robolectric implementation of {@link android.app.StatusBarManager}. */ +@Implements(value = StatusBarManager.class, isInAndroidSdk = false) +public class ShadowStatusBarManager { + + public static final int DEFAULT_DISABLE_MASK = StatusBarManager.DISABLE_MASK; + public static final int DEFAULT_DISABLE2_MASK = StatusBarManager.DISABLE2_MASK; + private int disabled = StatusBarManager.DISABLE_NONE; + private int disabled2 = StatusBarManager.DISABLE2_NONE; + + @Implementation + protected void disable(int what) { + disabled = what; + } + + @Implementation(minSdk = M) + protected void disable2(int what) { + disabled2 = what; + } + + /** Returns the disable flags previously set in {@link #disable}. */ + public int getDisableFlags() { + return disabled; + } + + /** Returns the disable flags previously set in {@link #disable2}. */ + public int getDisable2Flags() { + return disabled2; + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStorageManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStorageManager.java index c53d3bfd3..2614d7e88 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStorageManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStorageManager.java @@ -3,14 +3,18 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.N; import static org.robolectric.RuntimeEnvironment.application; -import static org.robolectric.Shadows.shadowOf; import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; +import com.google.common.base.Preconditions; +import java.io.File; +import java.util.ArrayList; +import java.util.List; import org.robolectric.annotation.HiddenApi; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.shadow.api.Shadow; /** * Fake implementation of {@link android.os.storage.StorageManager} @@ -19,6 +23,7 @@ import org.robolectric.annotation.Implements; public class ShadowStorageManager { private static boolean isFileEncryptionSupported = true; + private final List<StorageVolume> storageVolumeList = new ArrayList<>(); @Implementation(minSdk = M) protected static StorageVolume[] getVolumeList(int userId, int flags) { @@ -34,6 +39,49 @@ public class ShadowStorageManager { return getVolumeList(0, 0); } + /** + * Adds a {@link StorageVolume} to the list returned by {@link #getStorageVolumes()}. + * + * @param StorageVolume to add to list + */ + public void addStorageVolume(StorageVolume storageVolume) { + Preconditions.checkNotNull(storageVolume); + storageVolumeList.add(storageVolume); + } + + /** + * Returns the storage volumes configured via {@link #addStorageVolume()}. + * + * @return StorageVolume list + */ + @Implementation(minSdk = N) + protected List<StorageVolume> getStorageVolumes() { + return storageVolumeList; + } + + /** Clears the storageVolumeList. */ + public void resetStorageVolumeList() { + storageVolumeList.clear(); + } + + /** + * Checks whether File belongs to any {@link StorageVolume} in the list returned by {@link + * #getStorageVolumes()}. + * + * @param File to check + * @return StorageVolume for the file + */ + @Implementation(minSdk = N) + public StorageVolume getStorageVolume(File file) { + for (StorageVolume volume : storageVolumeList) { + File volumeFile = volume.getPathFile(); + if (file.getAbsolutePath().equals(volumeFile.getAbsolutePath())) { + return volume; + } + } + return null; + } + @HiddenApi @Implementation(minSdk = N) protected static boolean isFileEncryptedNativeOrEmulated() { @@ -52,6 +100,7 @@ public class ShadowStorageManager { @HiddenApi @Implementation(minSdk = N) protected static boolean isUserKeyUnlocked(int userId) { - return shadowOf(application.getSystemService(UserManager.class)).isUserUnlocked(); + ShadowUserManager extract = Shadow.extract(application.getSystemService(UserManager.class)); + return extract.isUserUnlocked(); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStrictModeVmPolicy.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStrictModeVmPolicy.java index 51a931a22..32e7be58a 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStrictModeVmPolicy.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowStrictModeVmPolicy.java @@ -8,7 +8,6 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.util.ReflectionHelpers; -/** Shadow for StrictMode.VmPolicy */ @Implements(value=StrictMode.VmPolicy.class, minSdk = Build.VERSION_CODES.P) public class ShadowStrictModeVmPolicy { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSubscriptionManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSubscriptionManager.java index ae949cbbb..24d041516 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSubscriptionManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSubscriptionManager.java @@ -1,61 +1,57 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; import static android.os.Build.VERSION_CODES.N; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import org.robolectric.annotation.HiddenApi; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.Resetter; +import org.robolectric.util.ReflectionHelpers; -/** - * Shadow for {@link SubscriptionManager}. - * - * <p>Although {@link SubscriptionManager} itself has been added in LMR1, this shadow is only - * available since N because all shadowed methods have been added in N. - */ -@Implements(value = SubscriptionManager.class, minSdk = N) +@Implements(value = SubscriptionManager.class, minSdk = LOLLIPOP_MR1) public class ShadowSubscriptionManager { + private static int defaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private static int defaultDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private static int defaultSmsSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private static int defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - private static int defaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - - private List<SubscriptionInfo> mSubscriptionInfoList; - @Implementation - public List<SubscriptionInfo> getActiveSubscriptionInfoList() { - return mSubscriptionInfoList; - } - - public void setActiveSubscriptionInfoList(List<SubscriptionInfo> subscriptionInfoList) { - mSubscriptionInfoList = subscriptionInfoList; + /** Returns value set with {@link #setDefaultSubscriptionId(int)}. */ + @Implementation(minSdk = N) + protected static int getDefaultSubscriptionId() { + return defaultSubscriptionId; } /** Returns value set with {@link #setDefaultDataSubscriptionId(int)}. */ - @Implementation + @Implementation(minSdk = N) protected static int getDefaultDataSubscriptionId() { return defaultDataSubscriptionId; } /** Returns value set with {@link #setDefaultSmsSubscriptionId(int)}. */ - @Implementation + @Implementation(minSdk = N) protected static int getDefaultSmsSubscriptionId() { return defaultSmsSubscriptionId; } /** Returns value set with {@link #setDefaultVoiceSubscriptionId(int)}. */ - @Implementation + @Implementation(minSdk = N) protected static int getDefaultVoiceSubscriptionId() { return defaultVoiceSubscriptionId; } - /** Returns value set with {@link #setDefaultSubscriptionId(int)}. */ - @Implementation - public static int getDefaultSubscriptionId() { - return defaultSubscriptionId; + /** Sets the value that will be returned by {@link #getDefaultSubscriptionId()}. */ + public static void setDefaultSubscriptionId(int defaultDataSubscriptionId) { + ShadowSubscriptionManager.defaultSubscriptionId = defaultDataSubscriptionId; } public static void setDefaultDataSubscriptionId(int defaultDataSubscriptionId) { @@ -70,8 +66,165 @@ public class ShadowSubscriptionManager { ShadowSubscriptionManager.defaultVoiceSubscriptionId = defaultVoiceSubscriptionId; } - public static void setDefaultSubscriptionId(int defaultSubscriptionId) { - ShadowSubscriptionManager.defaultSubscriptionId = defaultSubscriptionId; + /** + * Cache of {@link SubscriptionInfo} used by {@link #getActiveSubscriptionInfoList}. + * Managed by {@link #setActiveSubscriptionInfoList}. + */ + private List<SubscriptionInfo> subscriptionList = new ArrayList<>(); + /** + * List of listeners to be notified if the list of {@link SubscriptionInfo} changes. Managed by + * {@link #addOnSubscriptionsChangedListener} and {@link removeOnSubscriptionsChangedListener}. + */ + private List<OnSubscriptionsChangedListener> listeners = new ArrayList<>(); + /** + * Cache of subscription ids used by {@link #isNetworkRoaming}. Managed by {@link + * #setNetworkRoamingStatus} and {@link #clearNetworkRoamingStatus}. + */ + private Set<Integer> roamingSimSubscriptionIds = new HashSet<>(); + + /** + * Returns the active list of {@link SubscriptionInfo} that were set via {@link + * #setActiveSubscriptionInfoList}. + */ + @Implementation(minSdk = LOLLIPOP_MR1) + protected List<SubscriptionInfo> getActiveSubscriptionInfoList() { + return subscriptionList; + } + + /** + * Returns the size of the list of {@link SubscriptionInfo} that were set via {@link + * #setActiveSubscriptionInfoList}. If no list was set, returns 0. + */ + @Implementation(minSdk = LOLLIPOP_MR1) + protected int getActiveSubscriptionInfoCount() { + return subscriptionList == null ? 0 : subscriptionList.size(); + } + + /** + * Returns subscription that were set via {@link #setActiveSubscriptionInfoList} if it can find + * one with the specified id or null if none found. + */ + @Implementation(minSdk = LOLLIPOP_MR1) + protected SubscriptionInfo getActiveSubscriptionInfo(int subId) { + if (subscriptionList == null) { + return null; + } + for (SubscriptionInfo info : subscriptionList) { + if (info.getSubscriptionId() == subId) { + return info; + } + } + return null; + } + + /** + * Returns subscription that were set via {@link #setActiveSubscriptionInfoList} if it can find + * one with the specified slot index or null if none found. + */ + @Implementation(minSdk = N) + protected SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) { + if (subscriptionList == null) { + return null; + } + for (SubscriptionInfo info : subscriptionList) { + if (info.getSimSlotIndex() == slotIndex) { + return info; + } + } + return null; + } + + /** + * Sets the active list of {@link SubscriptionInfo}. This call internally triggers {@link + * OnSubscriptionsChangedListener#onSubscriptionsChanged()} to all the listeners. + * @param list - The subscription info list, can be null. + */ + public void setActiveSubscriptionInfoList(List<SubscriptionInfo> list) { + subscriptionList = list; + dispatchOnSubscriptionsChanged(); + } + + /** + * Sets the active list of {@link SubscriptionInfo}. This call internally triggers {@link + * OnSubscriptionsChangedListener#onSubscriptionsChanged()} to all the listeners. + */ + public void setActiveSubscriptionInfos(SubscriptionInfo... infos) { + if (infos == null) { + setActiveSubscriptionInfoList(null); + } else { + setActiveSubscriptionInfoList(Arrays.asList(infos)); + } + } + + /** + * Adds a listener to a local list of listeners. Will be triggered by {@link + * #setActiveSubscriptionInfoList} when the local list of {@link SubscriptionInfo} is updated. + */ + @Implementation(minSdk = LOLLIPOP_MR1) + protected void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { + listeners.add(listener); + } + + /** + * Removes a listener from a local list of listeners. Will be triggered by {@link + * #setActiveSubscriptionInfoList} when the local list of {@link SubscriptionInfo} is updated. + */ + @Implementation(minSdk = LOLLIPOP_MR1) + protected void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { + listeners.remove(listener); + } + + /** Returns subscription Ids that were set via {@link #setActiveSubscriptionInfoList}. */ + @Implementation(minSdk = LOLLIPOP_MR1) + @HiddenApi + protected int[] getActiveSubscriptionIdList() { + final List<SubscriptionInfo> infos = getActiveSubscriptionInfoList(); + if (infos == null) { + return new int[0]; + } + int[] ids = new int[infos.size()]; + for (int i = 0; i < infos.size(); i++) { + ids[i] = infos.get(i).getSubscriptionId(); + } + return ids; + } + + /** + * Notifies {@link OnSubscriptionsChangedListener} listeners that the list of {@link + * SubscriptionInfo} has been updated. + */ + private void dispatchOnSubscriptionsChanged() { + for (OnSubscriptionsChangedListener listener : listeners) { + listener.onSubscriptionsChanged(); + } + } + + /** Clears the local cache of roaming subscription Ids used by {@link #isNetworkRoaming}. */ + public void clearNetworkRoamingStatus(){ + roamingSimSubscriptionIds.clear(); + } + + /** + * If isNetworkRoaming is set, it will mark the provided sim subscriptionId as roaming in a local + * cache. If isNetworkRoaming is unset it will remove the subscriptionId from the local cache. The + * local cache is used to provide roaming status returned by {@link #isNetworkRoaming}. + */ + public void setNetworkRoamingStatus(int simSubscriptionId, boolean isNetworkRoaming) { + if (isNetworkRoaming) { + roamingSimSubscriptionIds.add(simSubscriptionId); + } else { + roamingSimSubscriptionIds.remove(simSubscriptionId); + } + } + + /** + * Uses the local cache of roaming sim subscription Ids managed by {@link + * #setNetworkRoamingStatus} to return subscription Ids marked as roaming. Otherwise subscription + * Ids will be considered as non-roaming if they are not in the cache. + */ + @Implementation(minSdk = LOLLIPOP_MR1) + protected boolean isNetworkRoaming(int simSubscriptionId) { + return roamingSimSubscriptionIds.contains(simSubscriptionId); } @Resetter @@ -81,4 +234,66 @@ public class ShadowSubscriptionManager { defaultVoiceSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; defaultSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } + + /** Builder class to create instance of {@link SubscriptionInfo}. */ + public static class SubscriptionInfoBuilder { + private final SubscriptionInfo subscriptionInfo = + ReflectionHelpers.callConstructor(SubscriptionInfo.class); + + public static SubscriptionInfoBuilder newBuilder() { + return new SubscriptionInfoBuilder(); + } + + public SubscriptionInfo buildSubscriptionInfo() { + return subscriptionInfo; + } + + public SubscriptionInfoBuilder setId(int id) { + ReflectionHelpers.setField(subscriptionInfo, "mId", id); + return this; + } + + public SubscriptionInfoBuilder setIccId(String iccId) { + ReflectionHelpers.setField(subscriptionInfo, "mIccId", iccId); + return this; + } + + public SubscriptionInfoBuilder setSimSlotIndex(int index) { + ReflectionHelpers.setField(subscriptionInfo, "mSimSlotIndex", index); + return this; + } + + public SubscriptionInfoBuilder setDisplayName(String name) { + ReflectionHelpers.setField(subscriptionInfo, "mDisplayName", name); + return this; + } + + public SubscriptionInfoBuilder setCarrierName(String carrierName) { + ReflectionHelpers.setField(subscriptionInfo, "mCarrierName", carrierName); + return this; + } + + public SubscriptionInfoBuilder setIconTint(int iconTint) { + ReflectionHelpers.setField(subscriptionInfo, "mIconTint", iconTint); + return this; + } + + public SubscriptionInfoBuilder setNumber(String number) { + ReflectionHelpers.setField(subscriptionInfo, "mNumber", number); + return this; + } + + public SubscriptionInfoBuilder setDataRoaming(int dataRoaming) { + ReflectionHelpers.setField(subscriptionInfo, "mDataRoaming", dataRoaming); + return this; + } + + public SubscriptionInfoBuilder setCountryIso(String countryIso) { + ReflectionHelpers.setField(subscriptionInfo, "mCountryIso", countryIso); + return this; + } + + // Use {@link #newBuilder} to construct builders. + private SubscriptionInfoBuilder() {} + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurface.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurface.java index 0c86799b9..1e9597e6e 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurface.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurface.java @@ -14,7 +14,7 @@ public class ShadowSurface { @RealObject private Surface realSurface; @Implementation - public void __constructor__(SurfaceTexture surfaceTexture) { + protected void __constructor__(SurfaceTexture surfaceTexture) { this.surfaceTexture = surfaceTexture; Shadow.invokeConstructor( Surface.class, realSurface, ClassParameter.from(SurfaceTexture.class, surfaceTexture)); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurfaceView.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurfaceView.java index 99bafe6e5..7a258dad8 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurfaceView.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSurfaceView.java @@ -16,11 +16,10 @@ public class ShadowSurfaceView extends ShadowView { private final FakeSurfaceHolder fakeSurfaceHolder = new FakeSurfaceHolder(); @Implementation - public void onAttachedToWindow() { - } + protected void onAttachedToWindow() {} @Implementation - public SurfaceHolder getHolder() { + protected SurfaceHolder getHolder() { return fakeSurfaceHolder; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java index 7c7dbdac4..6c42c05dd 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowSystemClock.java @@ -1,5 +1,6 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static android.os.Build.VERSION_CODES.P; import android.os.SystemClock; @@ -29,7 +30,7 @@ public class ShadowSystemClock { } @Implementation - public static void sleep(long millis) { + protected static void sleep(long millis) { if (ShadowApplication.getInstance() == null) { return; } @@ -39,7 +40,7 @@ public class ShadowSystemClock { } @Implementation - public static boolean setCurrentTimeMillis(long millis) { + protected static boolean setCurrentTimeMillis(long millis) { if (ShadowApplication.getInstance() == null) { return false; } @@ -53,17 +54,22 @@ public class ShadowSystemClock { } @Implementation - public static long uptimeMillis() { + protected static long uptimeMillis() { return now() - bootedAt; } @Implementation - public static long elapsedRealtime() { + protected static long elapsedRealtime() { return uptimeMillis(); } + @Implementation(minSdk = JELLY_BEAN_MR1) + protected static long elapsedRealtimeNanos() { + return elapsedRealtime() * MILLIS_PER_NANO; + } + @Implementation - public static long currentThreadTimeMillis() { + protected static long currentThreadTimeMillis() { return uptimeMillis(); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabActivity.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabActivity.java index 5bec4db81..d6d0e849f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabActivity.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabActivity.java @@ -14,7 +14,7 @@ public class ShadowTabActivity extends ShadowActivityGroup { private TabHost tabhost; @Implementation - public TabHost getTabHost() { + protected TabHost getTabHost() { if (tabhost==null) { tabhost = new TabHost(realTabActivity); } @@ -22,7 +22,7 @@ public class ShadowTabActivity extends ShadowActivityGroup { } @Implementation - public TabWidget getTabWidget() { + protected TabWidget getTabWidget() { return getTabHost().getTabWidget(); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabHost.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabHost.java index 0cf6eec80..bc8248162 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabHost.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTabHost.java @@ -27,7 +27,7 @@ public class ShadowTabHost extends ShadowViewGroup { private TabHost realObject; @Implementation - public android.widget.TabHost.TabSpec newTabSpec(java.lang.String tag) { + protected android.widget.TabHost.TabSpec newTabSpec(java.lang.String tag) { TabSpec realTabSpec = Shadow.newInstanceOf(TabHost.TabSpec.class); ShadowTabSpec shadowTabSpec = Shadow.extract(realTabSpec); shadowTabSpec.setTag(tag); @@ -35,7 +35,7 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public void addTab(android.widget.TabHost.TabSpec tabSpec) { + protected void addTab(android.widget.TabHost.TabSpec tabSpec) { tabSpecs.add(tabSpec); ShadowTabSpec shadowTabSpec = Shadow.extract(tabSpec); View indicatorAsView = shadowTabSpec.getIndicatorAsView(); @@ -45,7 +45,7 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public void setCurrentTab(int index) { + protected void setCurrentTab(int index) { currentTab = index; if (listener != null) { listener.onTabChanged(getCurrentTabTag()); @@ -53,7 +53,7 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public void setCurrentTabByTag(String tag) { + protected void setCurrentTabByTag(String tag) { for (int x = 0; x < tabSpecs.size(); x++) { TabSpec tabSpec = tabSpecs.get(x); if (tabSpec.getTag().equals(tag)) { @@ -66,7 +66,7 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public int getCurrentTab() { + protected int getCurrentTab() { if (currentTab == -1 && tabSpecs.size() > 0) currentTab = 0; return currentTab; } @@ -76,7 +76,7 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public String getCurrentTabTag() { + protected String getCurrentTabTag() { int i = getCurrentTab(); if (i >= 0 && i < tabSpecs.size()) { return tabSpecs.get(i).getTag(); @@ -85,12 +85,12 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public void setOnTabChangedListener(android.widget.TabHost.OnTabChangeListener listener) { + protected void setOnTabChangedListener(android.widget.TabHost.OnTabChangeListener listener) { this.listener = listener; } @Implementation - public View getCurrentView() { + protected View getCurrentView() { ShadowTabSpec ts = Shadow.extract(getCurrentTabSpec()); View v = ts.getContentView(); if (v == null) { @@ -105,7 +105,7 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public TabWidget getTabWidget() { + protected TabWidget getTabWidget() { Context context = realView.getContext(); if (context instanceof Activity) { return (TabWidget) ((Activity)context).findViewById(R.id.tabs); @@ -147,7 +147,7 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public String getTag() { + protected String getTag() { return tag; } @@ -176,19 +176,19 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public TabSpec setIndicator(View view) { + protected TabSpec setIndicator(View view) { this.indicatorView = view; return realObject; } @Implementation - public TabSpec setIndicator(CharSequence label) { + protected TabSpec setIndicator(CharSequence label) { this.label = label; return realObject; } @Implementation - public TabSpec setIndicator(CharSequence label, Drawable icon) { + protected TabSpec setIndicator(CharSequence label, Drawable icon) { this.label = label; this.icon = icon; return realObject; @@ -202,19 +202,19 @@ public class ShadowTabHost extends ShadowViewGroup { } @Implementation - public TabSpec setContent(Intent intent) { + protected TabSpec setContent(Intent intent) { this.intent = intent; return realObject; } @Implementation - public TabSpec setContent(TabHost.TabContentFactory factory) { + protected TabSpec setContent(TabHost.TabContentFactory factory) { contentView = factory.createTabContent(this.tag); return realObject; } @Implementation - public TabSpec setContent(int viewId) { + protected TabSpec setContent(int viewId) { this.viewId = viewId; return realObject; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java index a7c3c8712..9f600c762 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelecomManager.java @@ -17,6 +17,7 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Set; +import org.robolectric.annotation.HiddenApi; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.RealObject; @@ -35,35 +36,40 @@ public class ShadowTelecomManager { private String defaultDialerPackageName; @Implementation - public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) { + protected PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) { return null; } @Implementation + @HiddenApi public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() { return null; } @Implementation + @HiddenApi public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) { } @Implementation - public PhoneAccountHandle getSimCallManager() { + protected PhoneAccountHandle getSimCallManager() { return simCallManager; } @Implementation(minSdk = M) + @HiddenApi public PhoneAccountHandle getSimCallManager(int userId) { return null; } @Implementation + @HiddenApi public PhoneAccountHandle getConnectionManager() { return this.getSimCallManager(); } @Implementation + @HiddenApi public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) { List<PhoneAccountHandle> result = new ArrayList<>(); @@ -77,11 +83,12 @@ public class ShadowTelecomManager { } @Implementation(minSdk = M) - public List<PhoneAccountHandle> getCallCapablePhoneAccounts() { + protected List<PhoneAccountHandle> getCallCapablePhoneAccounts() { return this.getCallCapablePhoneAccounts(false); } @Implementation(minSdk = M) + @HiddenApi public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) { List<PhoneAccountHandle> result = new ArrayList<>(); @@ -96,6 +103,7 @@ public class ShadowTelecomManager { } @Implementation + @HiddenApi public List<PhoneAccountHandle> getPhoneAccountsForPackage() { Context context = ReflectionHelpers.getField(realObject, "mContext"); @@ -109,44 +117,49 @@ public class ShadowTelecomManager { } @Implementation - public PhoneAccount getPhoneAccount(PhoneAccountHandle account) { + protected PhoneAccount getPhoneAccount(PhoneAccountHandle account) { return accounts.get(account); } @Implementation + @HiddenApi public int getAllPhoneAccountsCount() { return accounts.size(); } @Implementation + @HiddenApi public List<PhoneAccount> getAllPhoneAccounts() { return ImmutableList.copyOf(accounts.values()); } @Implementation + @HiddenApi public List<PhoneAccountHandle> getAllPhoneAccountHandles() { return ImmutableList.copyOf(accounts.keySet()); } @Implementation - public void registerPhoneAccount(PhoneAccount account) { + protected void registerPhoneAccount(PhoneAccount account) { accounts.put(account.getAccountHandle(), account); } @Implementation - public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { + protected void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { accounts.remove(accountHandle); } /** @deprecated */ @Deprecated @Implementation + @HiddenApi public void clearAccounts() { accounts.clear(); } @Implementation(minSdk = LOLLIPOP_MR1) + @HiddenApi public void clearAccountsForPackage(String packageName) { Set<PhoneAccountHandle> phoneAccountHandlesInPackage = new HashSet<>(); @@ -164,81 +177,103 @@ public class ShadowTelecomManager { /** @deprecated */ @Deprecated @Implementation + @HiddenApi public ComponentName getDefaultPhoneApp() { return null; } @Implementation(minSdk = M) - public String getDefaultDialerPackage() { + protected String getDefaultDialerPackage() { return defaultDialerPackageName; } @Implementation(minSdk = M) + @HiddenApi public boolean setDefaultDialer(String packageName) { this.defaultDialerPackageName = packageName; return true; } @Implementation(minSdk = M) + @HiddenApi public String getSystemDialerPackage() { return null; } @Implementation(minSdk = LOLLIPOP_MR1) - public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) { + protected boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) { return false; } @Implementation(minSdk = M) - public String getVoiceMailNumber(PhoneAccountHandle accountHandle) { + protected String getVoiceMailNumber(PhoneAccountHandle accountHandle) { return null; } @Implementation(minSdk = LOLLIPOP_MR1) - public String getLine1Number(PhoneAccountHandle accountHandle) { + protected String getLine1Number(PhoneAccountHandle accountHandle) { return null; } @Implementation - public boolean isInCall() { + protected boolean isInCall() { return false; } @Implementation + @HiddenApi public int getCallState() { return 0; } @Implementation + @HiddenApi public boolean isRinging() { + for (CallRecord callRecord : incomingCalls) { + if (callRecord.isRinging) { + return true; + } + } + for (CallRecord callRecord : unknownCalls) { + if (callRecord.isRinging) { + return true; + } + } return false; } @Implementation + @HiddenApi public boolean endCall() { return false; } @Implementation - public void acceptRingingCall() { - } + protected void acceptRingingCall() {} @Implementation - public void silenceRinger() { + protected void silenceRinger() { + for (CallRecord callRecord : incomingCalls) { + callRecord.isRinging = false; + } + for (CallRecord callRecord : unknownCalls) { + callRecord.isRinging = false; + } } @Implementation - public boolean isTtySupported() { + protected boolean isTtySupported() { return false; } @Implementation + @HiddenApi public int getCurrentTtyMode() { return 0; } @Implementation - public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) { + protected void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) { incomingCalls.add(new CallRecord(phoneAccount, extras)); } @@ -247,6 +282,7 @@ public class ShadowTelecomManager { } @Implementation + @HiddenApi public void addNewUnknownCall(PhoneAccountHandle phoneAccount, Bundle extras) { unknownCalls.add(new CallRecord(phoneAccount, extras)); } @@ -256,33 +292,31 @@ public class ShadowTelecomManager { } @Implementation - public boolean handleMmi(String dialString) { + protected boolean handleMmi(String dialString) { return false; } @Implementation(minSdk = M) - public boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) { + protected boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) { return false; } @Implementation(minSdk = LOLLIPOP_MR1) - public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) { + protected Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) { return Uri.parse("content://icc/adn"); } @Implementation - public void cancelMissedCallsNotification() { - } + protected void cancelMissedCallsNotification() {} @Implementation - public void showInCallScreen(boolean showDialpad) { - } + protected void showInCallScreen(boolean showDialpad) {} @Implementation(minSdk = M) - public void placeCall(Uri address, Bundle extras) { - } + protected void placeCall(Uri address, Bundle extras) {} @Implementation(minSdk = M) + @HiddenApi public void enablePhoneAccount(PhoneAccountHandle handle, boolean isEnabled) { } @@ -293,6 +327,7 @@ public class ShadowTelecomManager { public static class CallRecord { public final PhoneAccountHandle phoneAccount; public final Bundle bundle; + private boolean isRinging = true; public CallRecord(PhoneAccountHandle phoneAccount, Bundle extras) { this.phoneAccount = phoneAccount; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephony.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephony.java new file mode 100644 index 000000000..7f3f57aec --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTelephony.java @@ -0,0 +1,37 @@ +package org.robolectric.shadows; + +import android.annotation.Nullable; +import android.content.Context; +import android.os.Build.VERSION_CODES; +import android.provider.Telephony; +import android.provider.Telephony.Sms; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.Resetter; + +@Implements(value = Telephony.class, minSdk = VERSION_CODES.KITKAT) +public class ShadowTelephony { + @Implements(value = Sms.class, minSdk = VERSION_CODES.KITKAT) + public static class ShadowSms { + @Nullable private static String defaultSmsPackage; + + @Implementation + protected static String getDefaultSmsPackage(Context context) { + return defaultSmsPackage; + } + + /** + * Override the package name returned from calling {@link Sms#getDefaultSmsPackage(Context)}. + * + * <p>This will be reset for the next test. + */ + public static void setDefaultSmsPackage(String defaultSmsPackage) { + ShadowSms.defaultSmsPackage = defaultSmsPackage; + } + + @Resetter + public static synchronized void reset() { + defaultSmsPackage = null; + } + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextToSpeech.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextToSpeech.java index 3ae6f536d..3be350401 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextToSpeech.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextToSpeech.java @@ -1,14 +1,10 @@ package org.robolectric.shadows; -import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1; import static android.os.Build.VERSION_CODES.LOLLIPOP; import android.content.Context; -import android.os.Build.VERSION; import android.os.Bundle; import android.speech.tts.TextToSpeech; -import android.speech.tts.TextToSpeech.Engine; -import android.speech.tts.UtteranceProgressListener; import java.util.HashMap; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; @@ -21,7 +17,6 @@ public class ShadowTextToSpeech { private boolean shutdown = false; private boolean stopped = true; private int queueMode = -1; - private UtteranceProgressListener utteranceProgressListener; @Implementation protected void __constructor__(Context context, TextToSpeech.OnInitListener listener) { @@ -29,41 +24,19 @@ public class ShadowTextToSpeech { this.listener = listener; } - /** - * Speaks the string using the specified queuing strategy and speech parameters. - * - * @param params The real implementation converts the hashmap into a bundle, but the bundle - * argument is not used in the shadow implementation. - */ @Implementation - protected int speak(final String text, final int queueMode, final HashMap<String, String> params) { - return speak( - text, - queueMode, - null, - params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID)); - } - - @Implementation(minSdk = LOLLIPOP) protected int speak( - final CharSequence text, final int queueMode, final Bundle params, final String utteranceId) { + final String text, final int queueMode, final HashMap<String, String> params) { stopped = false; - lastSpokenText = text.toString(); + lastSpokenText = text; this.queueMode = queueMode; - - if (VERSION.SDK_INT >= ICE_CREAM_SANDWICH_MR1) { - if (utteranceId != null && utteranceProgressListener != null) { - utteranceProgressListener.onStart(utteranceId); - utteranceProgressListener.onDone(utteranceId); - } - } return TextToSpeech.SUCCESS; } - @Implementation(minSdk = ICE_CREAM_SANDWICH_MR1) - protected int setOnUtteranceProgressListener(UtteranceProgressListener listener) { - utteranceProgressListener = listener; - return TextToSpeech.SUCCESS; + @Implementation(minSdk = LOLLIPOP) + protected int speak( + final CharSequence text, final int queueMode, final Bundle params, final String utteranceId) { + return speak(text.toString(), queueMode, new HashMap<>()); } @Implementation @@ -105,4 +78,4 @@ public class ShadowTextToSpeech { public int getQueueMode() { return queueMode; } -}
\ No newline at end of file +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java index 2fa8b1e4b..e442a2396 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextUtils.java @@ -14,7 +14,7 @@ import org.robolectric.annotation.Implements; public class ShadowTextUtils { @Implementation - public static CharSequence ellipsize( + protected static CharSequence ellipsize( CharSequence text, TextPaint p, float avail, TruncateAt where) { // This shadow follows the convention of ShadowPaint#measureText where each // characters width is 1.0. diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextView.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextView.java index dfe70ddc0..f970b1078 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextView.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTextView.java @@ -62,20 +62,20 @@ public class ShadowTextView extends ShadowView { private int compoundDrawablesWithIntrinsicBoundsBottom; @Implementation - public void setTextAppearance(Context context, int resid) { + protected void setTextAppearance(Context context, int resid) { textAppearanceId = resid; directlyOn(realTextView, TextView.class).setTextAppearance(context, resid); } @Implementation - public boolean onKeyDown(int keyCode, KeyEvent event) { + protected boolean onKeyDown(int keyCode, KeyEvent event) { previousKeyCodes.add(keyCode); previousKeyEvents.add(event); return directlyOn(realTextView, TextView.class).onKeyDown(keyCode, event); } @Implementation - public boolean onKeyUp(int keyCode, KeyEvent event) { + protected boolean onKeyUp(int keyCode, KeyEvent event) { previousKeyCodes.add(keyCode); previousKeyEvents.add(event); return directlyOn(realTextView, TextView.class).onKeyUp(keyCode, event); @@ -105,13 +105,13 @@ public class ShadowTextView extends ShadowView { } @Implementation - public void addTextChangedListener(TextWatcher watcher) { + protected void addTextChangedListener(TextWatcher watcher) { this.watchers.add(watcher); directlyOn(realTextView, TextView.class).addTextChangedListener(watcher); } @Implementation - public void removeTextChangedListener(TextWatcher watcher) { + protected void removeTextChangedListener(TextWatcher watcher) { this.watchers.remove(watcher); directlyOn(realTextView, TextView.class).removeTextChangedListener(watcher); } @@ -138,17 +138,17 @@ public class ShadowTextView extends ShadowView { } @Implementation - public int getPaintFlags() { + protected int getPaintFlags() { return paintFlags; } @Implementation - public void setPaintFlags(int paintFlags) { + protected void setPaintFlags(int paintFlags) { this.paintFlags = paintFlags; } @Implementation - public void setOnEditorActionListener(TextView.OnEditorActionListener l) { + protected void setOnEditorActionListener(TextView.OnEditorActionListener l) { this.onEditorActionListener = l; directlyOn(realTextView, TextView.class).setOnEditorActionListener(l); } @@ -158,7 +158,7 @@ public class ShadowTextView extends ShadowView { } @Implementation - public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) { + protected void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) { this.compoundDrawablesWithIntrinsicBoundsLeft = left; this.compoundDrawablesWithIntrinsicBoundsTop = top; this.compoundDrawablesWithIntrinsicBoundsRight = right; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowThreadedRenderer.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowThreadedRenderer.java new file mode 100644 index 000000000..82cf66674 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowThreadedRenderer.java @@ -0,0 +1,27 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.O; +import static android.os.Build.VERSION_CODES.P; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.view.ThreadedRenderer; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.shadow.api.Shadow; + +@Implements(value = ThreadedRenderer.class, isInAndroidSdk = false, minSdk = LOLLIPOP, looseSignatures = true) +public class ShadowThreadedRenderer { + + @Implementation(minSdk = O, maxSdk = P) + protected static Bitmap createHardwareBitmap(Object rendererNode, Object width, Object height) { + int w = (int) width; + int h = (int) height; + + Bitmap bitmap = Bitmap.createBitmap(w, h, Config.HARDWARE); + ShadowBitmap shadowBitmap = Shadow.extract(bitmap); + shadowBitmap.setMutable(false); + return bitmap; + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTile.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTile.java index 0b55787ad..df1da4f97 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTile.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTile.java @@ -5,7 +5,6 @@ import android.service.quicksettings.Tile; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -/** Shadow for {@link Tile}. */ @Implements(value = Tile.class, minSdk = Build.VERSION_CODES.N) public final class ShadowTile { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTileService.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTileService.java index 2d05f43da..3b3b7c937 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTileService.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTileService.java @@ -7,7 +7,6 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.shadow.api.Shadow; -/** Shadow for {@link TileService}. */ @Implements(value = TileService.class, minSdk = Build.VERSION_CODES.N) public final class ShadowTileService { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTime.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTime.java index 74a97c4a3..1a649adf4 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTime.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTime.java @@ -23,7 +23,7 @@ public class ShadowTime { private Time time; @Implementation(maxSdk = KITKAT_WATCH) - public void setToNow() { + protected void setToNow() { time.set(ShadowSystemClock.currentTimeMillis()); } @@ -33,12 +33,12 @@ public class ShadowTime { private static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24; @Implementation(maxSdk = KITKAT_WATCH) - public void __constructor__() { + protected void __constructor__() { __constructor__(getCurrentTimezone()); } @Implementation(maxSdk = KITKAT_WATCH) - public void __constructor__(String timezone) { + protected void __constructor__(String timezone) { if (timezone == null) { throw new NullPointerException("timezone is null!"); } @@ -49,12 +49,12 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public void __constructor__(Time other) { + protected void __constructor__(Time other) { set(other); } @Implementation(maxSdk = KITKAT_WATCH) - public void set(Time other) { + protected void set(Time other) { time.timezone = other.timezone; time.second = other.second; time.minute = other.minute; @@ -69,20 +69,20 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public static boolean isEpoch(Time time) { + protected static boolean isEpoch(Time time) { long millis = time.toMillis(true); return getJulianDay(millis, 0) == Time.EPOCH_JULIAN_DAY; } @Implementation(maxSdk = KITKAT_WATCH) - public static int getJulianDay(long millis, long gmtoff) { + protected static int getJulianDay(long millis, long gmtoff) { long offsetMillis = gmtoff * 1000; long julianDay = (millis + offsetMillis) / DAY_IN_MILLIS; return (int) julianDay + Time.EPOCH_JULIAN_DAY; } @Implementation(maxSdk = KITKAT_WATCH) - public long setJulianDay(int julianDay) { + protected long setJulianDay(int julianDay) { // Don't bother with the GMT offset since we don't know the correct // value for the given Julian day. Just get close and then adjust // the day. @@ -105,7 +105,7 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public void set(long millis) { + protected void set(long millis) { Calendar c = getCalendar(); c.setTimeInMillis(millis); set( @@ -119,13 +119,13 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public long toMillis(boolean ignoreDst) { + protected long toMillis(boolean ignoreDst) { Calendar c = getCalendar(); return c.getTimeInMillis(); } @Implementation(maxSdk = KITKAT_WATCH) - public void set(int second, int minute, int hour, int monthDay, int month, int year) { + protected void set(int second, int minute, int hour, int monthDay, int month, int year) { time.second = second; time.minute = minute; time.hour = hour; @@ -139,12 +139,12 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public void set(int monthDay, int month, int year) { + protected void set(int monthDay, int month, int year) { set(0, 0, 0, monthDay, month, year); } @Implementation(maxSdk = KITKAT_WATCH) - public void clear(String timezone) { + protected void clear(String timezone) { if (timezone == null) { throw new NullPointerException("timezone is null!"); } @@ -163,12 +163,12 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public static String getCurrentTimezone() { + protected static String getCurrentTimezone() { return TimeZone.getDefault().getID(); } @Implementation(maxSdk = KITKAT_WATCH) - public void switchTimezone(String timezone) { + protected void switchTimezone(String timezone) { long date = toMillis(true); long gmtoff = TimeZone.getTimeZone(timezone).getOffset(date); set(date + gmtoff); @@ -177,7 +177,7 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public static int compare(Time a, Time b) { + protected static int compare(Time a, Time b) { long ams = a.toMillis(false); long bms = b.toMillis(false); if (ams == bms) { @@ -190,17 +190,17 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public boolean before(Time other) { + protected boolean before(Time other) { return Time.compare(time, other) < 0; } @Implementation(maxSdk = KITKAT_WATCH) - public boolean after(Time other) { + protected boolean after(Time other) { return Time.compare(time, other) > 0; } @Implementation(maxSdk = KITKAT_WATCH) - public boolean parse(String timeString) { + protected boolean parse(String timeString) { TimeZone tz; if (timeString.endsWith("Z")) { timeString = timeString.substring(0, timeString.length() - 1); @@ -226,7 +226,7 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public String format2445() { + protected String format2445() { String value = format("%Y%m%dT%H%M%S"); if ( "UTC".equals(time.timezone)){ value += "Z"; @@ -235,7 +235,7 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public String format3339(boolean allDay) { + protected String format3339(boolean allDay) { if (allDay) { return format("%Y-%m-%d"); } else if ("UTC".equals(time.timezone)) { @@ -251,7 +251,7 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public boolean parse3339(String rfc3339String) { + protected boolean parse3339(String rfc3339String) { SimpleDateFormat formatter = new SimpleDateFormat(); // Special case Date without time first if (rfc3339String.matches("\\d{4}-\\d{2}-\\d{2}")) { @@ -312,7 +312,7 @@ public class ShadowTime { } @Implementation(maxSdk = KITKAT_WATCH) - public String format(String format) { + protected String format(String format) { return Strftime.format(format, new Date(toMillis(false)), Locale.getDefault(), TimeZone.getTimeZone(time.timezone)); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimePickerDialog.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimePickerDialog.java index 5004c0bab..9e8bafb8f 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimePickerDialog.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimePickerDialog.java @@ -17,7 +17,7 @@ public class ShadowTimePickerDialog extends ShadowAlertDialog { private int minute; @Implementation - public void __constructor__( + protected void __constructor__( Context context, int theme, TimePickerDialog.OnTimeSetListener callBack, diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java index c726b050d..8e18444fd 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTimeZoneFinder.java @@ -10,8 +10,7 @@ import libcore.util.TimeZoneFinder; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; -/** Shadow for {@code TimeZoneFinder}. */ -@Implements(value = TimeZoneFinder.class, minSdk = O, isInAndroidSdk = false) +@Implements(value = TimeZoneFinder.class, minSdk = O, isInAndroidSdk = false, looseSignatures = true) public class ShadowTimeZoneFinder { private static final String TZLOOKUP_PATH = "/usr/share/zoneinfo/tzlookup.xml"; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypeface.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypeface.java index 1af038599..6e05dc32b 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypeface.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowTypeface.java @@ -2,6 +2,7 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.os.Build.VERSION_CODES.N_MR1; +import static android.os.Build.VERSION_CODES.O; import static android.os.Build.VERSION_CODES.P; import static org.robolectric.RuntimeEnvironment.getApiLevel; @@ -74,6 +75,11 @@ public class ShadowTypeface { throw new RuntimeException("Font asset not found " + path); } + @Implementation(minSdk = O) + protected static Typeface createFromResources(AssetManager mgr, String path, int cookie) { + return createUnderlyingTypeface(path, Typeface.NORMAL); + } + @Implementation protected static Typeface createFromFile(File path) { String familyName = path.toPath().getFileName().toString(); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java index 39d864fa7..2d2a5af49 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUsageStatsManager.java @@ -15,6 +15,7 @@ import android.os.Parcel; import android.util.ArraySet; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Range; import com.google.common.collect.SetMultimap; import java.util.ArrayList; @@ -151,7 +152,7 @@ public class ShadowUsageStatsManager { /** * Adds an event to be returned by {@link UsageStatsManager#queryEvents}. * - * <p>This method won't affect the results of {@link #queryUsageStats} method. + * This method won't affect the results of {@link #queryUsageStats} method. * * @deprecated Use {@link #addEvent(Event)} and {@link EventBuilder} instead. */ @@ -171,18 +172,40 @@ public class ShadowUsageStatsManager { /** * Adds an event to be returned by {@link UsageStatsManager#queryEvents}. * - * <p>This method won't affect the results of {@link #queryUsageStats} method. + * This method won't affect the results of {@link #queryUsageStats} method. * - * <p>The {@link Event} can be built by {@link EventBuilder}. + * The {@link Event} can be built by {@link EventBuilder}. */ public void addEvent(Event event) { eventsByTimeStamp.put(event.getTimeStamp(), event); } /** + * Simulates the operations done by the framework when there is a time change. If the time is + * changed, the timestamps of all existing usage events will be shifted by the same offset as the + * time change, in order to make sure they remain stable relative to the new time. + * + * This method won't affect the results of {@link #queryUsageStats} method. + * + * @param offsetToAddInMillis the offset to be applied to all events. For example, if {@code + * offsetInMillis} is 60,000, then all {@link Event}s will be shifted forward by 1 minute + * (into the future). Likewise, if {@code offsetInMillis} is -60,000, then all {@link Event}s + * will be shifted backward by 1 minute (into the past). + */ + public void simulateTimeChange(long offsetToAddInMillis) { + ImmutableMap.Builder<Long, Event> eventMapBuilder = ImmutableMap.builder(); + for (Event event : eventsByTimeStamp.values()) { + long newTimestamp = event.getTimeStamp() + offsetToAddInMillis; + eventMapBuilder.put( + newTimestamp, EventBuilder.fromEvent(event).setTimeStamp(newTimestamp).build()); + } + eventsByTimeStamp.putAll(eventMapBuilder.build()); + } + + /** * Returns aggregated UsageStats added by calling {@link #addUsageStats}. * - * <p>The real implementation creates these aggregated objects from individual {@link Event}. This + * The real implementation creates these aggregated objects from individual {@link Event}. This * aggregation logic is nontrivial, so the shadow implementation just returns the aggregate data * added using {@link #addUsageStats}. */ @@ -216,23 +239,27 @@ public class ShadowUsageStatsManager { * UsageStatsManager.STANDBY_BUCKET_ACTIVE}. */ @Implementation(minSdk = Build.VERSION_CODES.P) + @HiddenApi public @StandbyBuckets int getAppStandbyBucket(String packageName) { Integer bucket = appStandbyBuckets.get(packageName); return (bucket == null) ? UsageStatsManager.STANDBY_BUCKET_ACTIVE : bucket; } @Implementation(minSdk = Build.VERSION_CODES.P) + @HiddenApi public Map<String, Integer> getAppStandbyBuckets() { return new HashMap<>(appStandbyBuckets); } /** Sets the standby bucket of the specified app. */ @Implementation(minSdk = Build.VERSION_CODES.P) + @HiddenApi public void setAppStandbyBucket(String packageName, @StandbyBuckets int bucket) { appStandbyBuckets.put(packageName, bucket); } @Implementation(minSdk = Build.VERSION_CODES.P) + @HiddenApi public void setAppStandbyBuckets(Map<String, Integer> appBuckets) { appStandbyBuckets.putAll(appBuckets); } @@ -265,7 +292,7 @@ public class ShadowUsageStatsManager { /** * Triggers a currently registered {@link AppUsageObserver} with {@code observerId}. * - * <p>The observer will be no longer registered afterwards. + * The observer will be no longer registered afterwards. */ public void triggerRegisteredAppUsageObserver(int observerId, long timeUsedInMillis) { AppUsageObserver observer = appUsageObserversById.remove(observerId); @@ -288,7 +315,8 @@ public class ShadowUsageStatsManager { * UsageStatsManager.STANDBY_BUCKET_ACTIVE}. */ @Implementation(minSdk = Build.VERSION_CODES.P) - public @StandbyBuckets int getAppStandbyBucket() { + @StandbyBuckets + protected int getAppStandbyBucket() { return currentAppStandbyBucket; } @@ -359,6 +387,20 @@ public class ShadowUsageStatsManager { private EventBuilder() {} + public static EventBuilder fromEvent(Event event) { + EventBuilder eventBuilder = + new EventBuilder() + .setPackage(event.mPackage) + .setClass(event.mClass) + .setTimeStamp(event.mTimeStamp) + .setEventType(event.mEventType) + .setConfiguration(event.mConfiguration); + if (event.mEventType == Event.CONFIGURATION_CHANGE) { + eventBuilder.setConfiguration(new Configuration()); + } + return eventBuilder; + } + public static EventBuilder buildEvent() { return new EventBuilder(); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java index 6a5804fae..0cbdab7e4 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java @@ -2,11 +2,11 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; -import static android.os.Build.VERSION_CODES.KITKAT_WATCH; import static android.os.Build.VERSION_CODES.LOLLIPOP; import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.N; import static android.os.Build.VERSION_CODES.N_MR1; +import static org.robolectric.shadow.api.Shadow.directlyOn; import android.Manifest.permission; import android.content.Context; @@ -20,11 +20,14 @@ import android.os.UserManager; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.annotation.RealObject; +import org.robolectric.annotation.Resetter; /** * Robolectric implementation of {@link android.os.UserManager}. @@ -32,29 +35,33 @@ import org.robolectric.annotation.Implements; @Implements(value = UserManager.class, minSdk = JELLY_BEAN_MR1) public class ShadowUserManager { + /** + * The default user ID user for secondary user testing, when the ID is not otherwise specified. + */ + public static final int DEFAULT_SECONDARY_USER_ID = 10; + + private static Map<Integer, Integer> userPidMap = new HashMap<>(); + + @RealObject private UserManager realObject; + private boolean userUnlocked = true; private boolean managedProfile = false; - private boolean isDemoUser = false; - private boolean isAdminUser = false; private boolean isSystemUser = true; - private boolean isPrimaryUser = true; - private boolean isLinkedUser = false; - private boolean isGuestUser = false; - private Map<UserHandle, Bundle> userRestrictions = new HashMap<>(); + private Map<Integer, Bundle> userRestrictions = new HashMap<>(); private BiMap<UserHandle, Long> userProfiles = HashBiMap.create(); private Map<String, Bundle> applicationRestrictions = new HashMap<>(); private long nextUserSerial = 0; - private Map<UserHandle, UserState> userState = new HashMap<>(); + private Map<Integer, UserState> userState = new HashMap<>(); + private Map<Integer, UserInfo> userInfoMap = new HashMap<>(); + private Context context; private boolean enforcePermissions; + private boolean canSwitchUser = false; @Implementation protected void __constructor__(Context context, IUserManager service) { this.context = context; - } - - public ShadowUserManager() { - addUserProfile(Process.myUserHandle()); + addUser(UserHandle.USER_SYSTEM, "system_user", UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN); } /** @@ -138,7 +145,7 @@ public class ShadowUserManager { @Implementation(minSdk = LOLLIPOP) protected boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) { - Bundle bundle = userRestrictions.get(userHandle); + Bundle bundle = userRestrictions.get(userHandle.getIdentifier()); return bundle != null && bundle.getBoolean(restrictionKey); } @@ -151,7 +158,7 @@ public class ShadowUserManager { * Removes all user restrictions set of a user identified by {@code userHandle}. */ public void clearUserRestrictions(UserHandle userHandle) { - userRestrictions.remove(userHandle); + userRestrictions.remove(userHandle.getIdentifier()); } @Implementation(minSdk = JELLY_BEAN_MR2) @@ -160,10 +167,10 @@ public class ShadowUserManager { } private Bundle getUserRestrictionsForUser(UserHandle userHandle) { - Bundle bundle = userRestrictions.get(userHandle); + Bundle bundle = userRestrictions.get(userHandle.getIdentifier()); if (bundle == null) { bundle = new Bundle(); - userRestrictions.put(userHandle, bundle); + userRestrictions.put(userHandle.getIdentifier(), bundle); } return bundle; } @@ -212,15 +219,24 @@ public class ShadowUserManager { */ @Implementation(minSdk = N_MR1) protected boolean isDemoUser() { - return isDemoUser; + return getUserInfo(UserHandle.myUserId()).isDemo(); } /** - * Sets that the current user is a demo user; controls the return value of - * {@link UserManager#isDemoUser()}. + * Sets that the current user is a demo user; controls the return value of {@link + * UserManager#isDemoUser()}. + * + * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a demo user + * instead of changing default user flags. */ + @Deprecated public void setIsDemoUser(boolean isDemoUser) { - this.isDemoUser = isDemoUser; + UserInfo userInfo = getUserInfo(UserHandle.myUserId()); + if (isDemoUser) { + userInfo.flags |= UserInfo.FLAG_DEMO; + } else { + userInfo.flags &= ~UserInfo.FLAG_DEMO; + } } /** @@ -228,7 +244,7 @@ public class ShadowUserManager { */ @Implementation(minSdk = N_MR1) public boolean isAdminUser() { - return isAdminUser; + return getUserInfo(UserHandle.myUserId()).isAdmin(); } /** @@ -236,7 +252,12 @@ public class ShadowUserManager { * {@link UserManager#isAdminUser}. */ public void setIsAdminUser(boolean isAdminUser) { - this.isAdminUser = isAdminUser; + UserInfo userInfo = getUserInfo(UserHandle.myUserId()); + if (isAdminUser) { + userInfo.flags |= UserInfo.FLAG_ADMIN; + } else { + userInfo.flags &= ~UserInfo.FLAG_ADMIN; + } } /** @@ -244,31 +265,40 @@ public class ShadowUserManager { */ @Implementation(minSdk = M) protected boolean isSystemUser() { - return isSystemUser; + if (isSystemUser == false) { + return false; + } else { + return directlyOn(realObject, UserManager.class, "isSystemUser"); + } } /** - * Sets that the current user is the system user; controls the return value of - * {@link UserManager#isSystemUser()}. + * Sets that the current user is the system user; controls the return value of {@link + * UserManager#isSystemUser()}. + * + * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a system user + * instead of changing default user flags. */ + @Deprecated public void setIsSystemUser(boolean isSystemUser) { this.isSystemUser = isSystemUser; } /** - * @return 'true' by default, or the value specified via {@link #setIsPrimaryUser(boolean)} - */ - @Implementation(minSdk = N) - protected boolean isPrimaryUser() { - return isPrimaryUser; - } - - /** - * Sets that the current user is the primary user; controls the return value of - * {@link UserManager#isPrimaryUser()}. + * Sets that the current user is the primary user; controls the return value of {@link + * UserManager#isPrimaryUser()}. + * + * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a primary user + * instead of changing default user flags. */ + @Deprecated public void setIsPrimaryUser(boolean isPrimaryUser) { - this.isPrimaryUser = isPrimaryUser; + UserInfo userInfo = getUserInfo(UserHandle.myUserId()); + if (isPrimaryUser) { + userInfo.flags |= UserInfo.FLAG_PRIMARY; + } else { + userInfo.flags &= ~UserInfo.FLAG_PRIMARY; + } } /** @@ -276,31 +306,41 @@ public class ShadowUserManager { */ @Implementation(minSdk = JELLY_BEAN_MR2) protected boolean isLinkedUser() { - return isLinkedUser; - } - - /** - * Sets that the current user is the linked user; controls the return value of - * {@link UserManager#isLinkedUser()}. - */ - public void setIsLinkedUser (boolean isLinkedUser) { - this.isLinkedUser = isLinkedUser; + return getUserInfo(UserHandle.myUserId()).isRestricted(); } /** - * @return 'false' by default, or the value specified via {@link #setIsGuestUser(boolean)} + * Sets that the current user is the linked user; controls the return value of {@link + * UserManager#isLinkedUser()}. + * + * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a linked user + * instead of changing default user flags. */ - @Implementation(minSdk = KITKAT_WATCH) - protected boolean isGuestUser() { - return isGuestUser; + @Deprecated + public void setIsLinkedUser(boolean isLinkedUser) { + UserInfo userInfo = getUserInfo(UserHandle.myUserId()); + if (isLinkedUser) { + userInfo.flags |= UserInfo.FLAG_RESTRICTED; + } else { + userInfo.flags &= ~UserInfo.FLAG_RESTRICTED; + } } /** - * Sets that the current user is the guest user; controls the return value of - * {@link UserManager#isGuestUser()}. + * Sets that the current user is the guest user; controls the return value of {@link + * UserManager#isGuestUser()}. + * + * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a guest user + * instead of changing default user flags. */ - public void setIsGuestUser (boolean isGuestUser) { - this.isGuestUser = isGuestUser; + @Deprecated + public void setIsGuestUser(boolean isGuestUser) { + UserInfo userInfo = getUserInfo(UserHandle.myUserId()); + if (isGuestUser) { + userInfo.flags |= UserInfo.FLAG_GUEST; + } else { + userInfo.flags &= ~UserInfo.FLAG_GUEST; + } } /** @@ -309,7 +349,7 @@ public class ShadowUserManager { @Implementation protected boolean isUserRunning(UserHandle handle) { checkPermissions(); - UserState state = userState.get(handle); + UserState state = userState.get(handle.getIdentifier()); if (state == UserState.STATE_RUNNING_LOCKED || state == UserState.STATE_RUNNING_UNLOCKED @@ -326,7 +366,7 @@ public class ShadowUserManager { @Implementation protected boolean isUserRunningOrStopping(UserHandle handle) { checkPermissions(); - UserState state = userState.get(handle); + UserState state = userState.get(handle.getIdentifier()); if (state == UserState.STATE_RUNNING_LOCKED || state == UserState.STATE_RUNNING_UNLOCKED @@ -362,15 +402,81 @@ public class ShadowUserManager { * and {@link UserManager#isUserRunningOrStopping(UserHandle)} */ public void setUserState(UserHandle handle, UserState state) { - userState.put(handle, state); + userState.put(handle.getIdentifier(), state); } - /** - * @return an empty list - */ @Implementation protected List<UserInfo> getUsers() { - // Implement this - return empty list to avoid NPE from call to getUserCount() - return ImmutableList.of(); + return new ArrayList<UserInfo>(userInfoMap.values()); + } + + @Implementation + protected UserInfo getUserInfo(int userHandle) { + return userInfoMap.get(userHandle); + } + + /** + * Returns {@code true} by default, or the value specified via {@link #setCanSwitchUser(boolean)}. + */ + @Implementation(minSdk = N) + protected boolean canSwitchUsers() { + return canSwitchUser; + } + + /** + * Sets whether switching users is allowed or not; controls the return value of {@link + * UserManager#canSwitchUser()} + */ + public void setCanSwitchUser(boolean canSwitchUser) { + this.canSwitchUser = canSwitchUser; + } + + @Implementation(minSdk = JELLY_BEAN_MR1) + protected boolean removeUser(int userHandle) { + userInfoMap.remove(userHandle); + return true; + } + + /** + * Switches the current user to {@code userHandle}. + * + * @param userId the integer handle of the user, where 0 is the primary user. + */ + public void switchUser(int userId) { + if (!userInfoMap.containsKey(userId)) { + throw new UnsupportedOperationException("Must add user before switching to it"); + } + + ShadowProcess.setUid(userPidMap.get(userId)); + } + + /** + * Creates a user with the specified name, userId and flags. + * + * @param id the unique id of user + * @param name name of the user + * @param flags 16 bits for user type. See {@link UserInfo#flags} + */ + public void addUser(int id, String name, int flags) { + UserHandle userHandle = + id == UserHandle.USER_SYSTEM ? Process.myUserHandle() : new UserHandle(id); + addUserProfile(userHandle); + setSerialNumberForUser(userHandle, (long) id); + userInfoMap.put(id, new UserInfo(id, name, flags)); + userPidMap.put( + id, + id == UserHandle.USER_SYSTEM + ? Process.myUid() + : id * UserHandle.PER_USER_RANGE + ShadowProcess.getRandomApplicationUid()); + } + + @Resetter + public static void reset() { + if (userPidMap != null && userPidMap.isEmpty() == false) { + ShadowProcess.setUid(userPidMap.get(UserHandle.USER_SYSTEM)); + + userPidMap.clear(); + userPidMap.put(UserHandle.USER_SYSTEM, Process.myUid()); + } } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVMRuntime.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVMRuntime.java index 065ac30af..d4bc397da 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVMRuntime.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVMRuntime.java @@ -2,11 +2,13 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.LOLLIPOP; +import android.annotation.TargetApi; import dalvik.system.VMRuntime; import java.lang.reflect.Array; import javax.annotation.Nullable; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.annotation.Resetter; import org.robolectric.res.android.NativeObjRegistry; @Implements(value = VMRuntime.class, isInAndroidSdk = false) @@ -14,6 +16,10 @@ public class ShadowVMRuntime { private final NativeObjRegistry<Object> nativeObjRegistry = new NativeObjRegistry<>("VRRuntime.nativeObjectRegistry"); + // There actually isn't any android JNI code to call through to in Robolectric due to + // cross-platform compatibility issues. We default to a reasonable value that reflects the devices + // that would commonly run this code. + private static boolean is64Bit = true; @Implementation(minSdk = LOLLIPOP) public Object newUnpaddedArray(Class<?> klass, int size) { @@ -43,4 +49,23 @@ public class ShadowVMRuntime { Object getObjectForAddress(long address) { return nativeObjRegistry.getNativeObject(address); } + + /** + * Returns whether the VM is running in 64-bit mode. Available in Android L+. Defaults to true. + */ + @Implementation(minSdk = LOLLIPOP) + protected boolean is64Bit() { + return ShadowVMRuntime.is64Bit; + } + + /** Sets whether the VM is running in 64-bit mode. */ + @TargetApi(LOLLIPOP) + public static void setIs64Bit(boolean is64Bit) { + ShadowVMRuntime.is64Bit = is64Bit; + } + + @Resetter + public static void reset() { + ShadowVMRuntime.is64Bit = true; + } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowValueAnimator.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowValueAnimator.java index 4b4acad27..3a0132a01 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowValueAnimator.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowValueAnimator.java @@ -43,7 +43,7 @@ public class ShadowValueAnimator { } @Implementation - public void setRepeatCount(int count) { + protected void setRepeatCount(int count) { actualRepeatCount = count; if (count == ValueAnimator.INFINITE) { count = 1; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVectorDrawable.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVectorDrawable.java index d48f72a6b..0153f5997 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVectorDrawable.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVectorDrawable.java @@ -79,20 +79,18 @@ public class ShadowVectorDrawable extends ShadowDrawable { return get(pathPtr, Path.class); } - @Implementation - public static long nCreateFullPath() { + protected static long nCreateFullPath() { return put(new Path()); } @Implementation - public static long nCreateFullPath(long nativeFullPathPtr) { + protected static long nCreateFullPath(long nativeFullPathPtr) { return put(getPath(nativeFullPathPtr).clone()); } @Implementation - public static boolean nGetFullPathProperties(long pathPtr, byte[] properties, - int length) { + protected static boolean nGetFullPathProperties(long pathPtr, byte[] properties, int length) { if (length != TOTAL_PROPERTY_COUNT * 4) return false; Path path = getPath(pathPtr); @@ -115,10 +113,20 @@ public class ShadowVectorDrawable extends ShadowDrawable { } @Implementation - public static void nUpdateFullPathProperties(long pathPtr, float strokeWidth, - int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart, - float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap, - int strokeLineJoin, int fillType) { + protected static void nUpdateFullPathProperties( + long pathPtr, + float strokeWidth, + int strokeColor, + float strokeAlpha, + int fillColor, + float fillAlpha, + float trimPathStart, + float trimPathEnd, + float trimPathOffset, + float strokeMiterLimit, + int strokeLineCap, + int strokeLineJoin, + int fillType) { Path path = getPath(pathPtr); path.strokeWidth = strokeWidth; path.strokeColor = strokeColor; @@ -172,21 +180,20 @@ public class ShadowVectorDrawable extends ShadowDrawable { } @Implementation - public static long nCreateGroup() { + protected static long nCreateGroup() { return put(new Group()); } @Implementation - public static long nCreateGroup(long groupPtr) { + protected static long nCreateGroup(long groupPtr) { return put(getGroup(groupPtr).clone()); } -// public static void nSetName(long nodePtr, String name) { -// } + // public static void nSetName(long nodePtr, String name) { + // } @Implementation - public static boolean nGetGroupProperties(long groupPtr, float[] properties, - int length) { + protected static boolean nGetGroupProperties(long groupPtr, float[] properties, int length) { if (length != 7) return false; Group group = getGroup(groupPtr); properties[0] = group.rotation; @@ -200,8 +207,15 @@ public class ShadowVectorDrawable extends ShadowDrawable { } @Implementation - public static void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX, - float pivotY, float scaleX, float scaleY, float translateX, float translateY) { + protected static void nUpdateGroupProperties( + long groupPtr, + float rotate, + float pivotX, + float pivotY, + float scaleX, + float scaleY, + float translateX, + float translateY) { Group group = getGroup(groupPtr); group.rotation = rotate; group.pivotX = pivotX; diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVelocityTracker.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVelocityTracker.java index 478e1f7a5..aed29a460 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVelocityTracker.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVelocityTracker.java @@ -33,7 +33,7 @@ public class ShadowVelocityTracker { } @Implementation - public void clear() { + protected void clear() { maybeInitialize(); curIndex = 0; computedVelocityX.clear(); @@ -44,7 +44,7 @@ public class ShadowVelocityTracker { } @Implementation - public void addMovement(MotionEvent event) { + protected void addMovement(MotionEvent event) { maybeInitialize(); if (event == null) { throw new IllegalArgumentException("event must not be null"); @@ -62,12 +62,12 @@ public class ShadowVelocityTracker { } @Implementation - public void computeCurrentVelocity(int units) { + protected void computeCurrentVelocity(int units) { computeCurrentVelocity(units, Float.MAX_VALUE); } @Implementation - public void computeCurrentVelocity(int units, float maxVelocity) { + protected void computeCurrentVelocity(int units, float maxVelocity) { maybeInitialize(); // Estimation based on AOSP's LegacyVelocityTrackerStrategy @@ -129,17 +129,17 @@ public class ShadowVelocityTracker { } @Implementation - public float getXVelocity() { + protected float getXVelocity() { return getXVelocity(ACTIVE_POINTER_ID); } @Implementation - public float getYVelocity() { + protected float getYVelocity() { return getYVelocity(ACTIVE_POINTER_ID); } @Implementation - public float getXVelocity(int id) { + protected float getXVelocity(int id) { if (id == ACTIVE_POINTER_ID) { id = activePointerId; } @@ -148,7 +148,7 @@ public class ShadowVelocityTracker { } @Implementation - public float getYVelocity(int id) { + protected float getYVelocity(int id) { if (id == ACTIVE_POINTER_ID) { id = activePointerId; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVideoView.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVideoView.java index 157b91236..2b6a10659 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVideoView.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVideoView.java @@ -28,84 +28,84 @@ public class ShadowVideoView extends ShadowSurfaceView { private int currentPosition; @Implementation - public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) { + protected void setOnPreparedListener(MediaPlayer.OnPreparedListener l) { preparedListener = l; } @Implementation - public void setOnErrorListener(MediaPlayer.OnErrorListener l) { + protected void setOnErrorListener(MediaPlayer.OnErrorListener l) { errorListener = l; } @Implementation - public void setOnCompletionListener(MediaPlayer.OnCompletionListener l) { + protected void setOnCompletionListener(MediaPlayer.OnCompletionListener l) { completionListner = l; } @Implementation - public void setVideoPath(String path) { + protected void setVideoPath(String path) { this.path = path; } @Implementation - public void setVideoURI(Uri uri) { + protected void setVideoURI(Uri uri) { this.uri = uri; } @Implementation - public void start() { + protected void start() { savePrevState(); currentState = ShadowVideoView.START; } @Implementation - public void stopPlayback() { + protected void stopPlayback() { savePrevState(); currentState = ShadowVideoView.STOP; } @Implementation - public void suspend() { + protected void suspend() { savePrevState(); currentState = ShadowVideoView.SUSPEND; } @Implementation - public void pause() { + protected void pause() { savePrevState(); currentState = ShadowVideoView.PAUSE; } @Implementation - public void resume() { + protected void resume() { savePrevState(); currentState = ShadowVideoView.RESUME; } @Implementation - public boolean isPlaying() { + protected boolean isPlaying() { return (currentState == ShadowVideoView.START); } @Implementation - public boolean canPause() { + protected boolean canPause() { return (currentState != ShadowVideoView.PAUSE && currentState != ShadowVideoView.STOP && currentState != ShadowVideoView.SUSPEND); } @Implementation - public void seekTo(int msec) { + protected void seekTo(int msec) { currentPosition = msec; } @Implementation - public int getCurrentPosition() { + protected int getCurrentPosition() { return currentPosition; } @Implementation - public int getDuration() { + protected int getDuration() { return duration; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowView.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowView.java index 611e4fd1a..e151e4024 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowView.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowView.java @@ -9,7 +9,6 @@ import static org.robolectric.util.ReflectionHelpers.setField; import android.annotation.SuppressLint; import android.content.Context; -import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; @@ -354,19 +353,21 @@ public class ShadowView { return onCreateContextMenuListener; } - @Implementation - protected Bitmap getDrawingCache() { - return ReflectionHelpers.callConstructor(Bitmap.class); - } + // @Implementation + // protected Bitmap getDrawingCache() { + // return ReflectionHelpers.callConstructor(Bitmap.class); + // } @Implementation - protected void post(Runnable action) { + protected boolean post(Runnable action) { ShadowApplication.getInstance().getForegroundThreadScheduler().post(action); + return true; } @Implementation - protected void postDelayed(Runnable action, long delayMills) { + protected boolean postDelayed(Runnable action, long delayMills) { ShadowApplication.getInstance().getForegroundThreadScheduler().postDelayed(action, delayMills); + return true; } @Implementation @@ -380,9 +381,10 @@ public class ShadowView { } @Implementation - protected void removeCallbacks(Runnable callback) { + protected boolean removeCallbacks(Runnable callback) { ShadowLooper shadowLooper = Shadow.extract(Looper.getMainLooper()); shadowLooper.getScheduler().remove(callback); + return true; } @Implementation @@ -473,9 +475,9 @@ public class ShadowView { if ((animation.getStartTime() == startTime && animation.getStartOffset() == startOffset) && animation.getTransformation(startTime == Animation.START_ON_FIRST_FRAME ? SystemClock.uptimeMillis() : (startTime + startOffset + elapsedTime), new Transformation()) && - // We can't handle infinitely repeating animations in the current scheduling model, - // so abort after one iteration. - !(animation.getRepeatCount() == Animation.INFINITE && elapsedTime >= animation.getDuration())) { + // We can't handle infinitely repeating animations in the current scheduling model, + // so abort after one iteration. + !(animation.getRepeatCount() == Animation.INFINITE && elapsedTime >= animation.getDuration())) { // Update startTime if it had a value of Animation.START_ON_FIRST_FRAME startTime = animation.getStartTime(); elapsedTime += ShadowChoreographer.getFrameInterval() / TimeUtils.NANOS_PER_MS; @@ -504,7 +506,7 @@ public class ShadowView { } @Implementation(minSdk = JELLY_BEAN_MR2) - protected Object getWindowId() { + protected WindowId getWindowId() { return WindowIdHelper.getWindowId(this); } @@ -557,7 +559,7 @@ public class ShadowView { } public static class WindowIdHelper { - public static Object getWindowId(ShadowView shadowView) { + public static WindowId getWindowId(ShadowView shadowView) { if (shadowView.isAttachedToWindow()) { Object attachInfo = shadowView.getAttachInfo(); if (getField(attachInfo, "mWindowId") == null) { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewAnimator.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewAnimator.java index 4abc8bc45..41a66d229 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewAnimator.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewAnimator.java @@ -12,12 +12,12 @@ public class ShadowViewAnimator extends ShadowViewGroup { private int currentChild = 0; @Implementation - public int getDisplayedChild() { + protected int getDisplayedChild() { return currentChild; } @Implementation - public void setDisplayedChild(int whichChild) { + protected void setDisplayedChild(int whichChild) { currentChild = whichChild; for (int i = ((ViewGroup) realView).getChildCount() - 1; i >= 0; i--) { View child = ((ViewGroup) realView).getChildAt(i); @@ -26,17 +26,17 @@ public class ShadowViewAnimator extends ShadowViewGroup { } @Implementation - public View getCurrentView() { + protected View getCurrentView() { return ((ViewGroup) realView).getChildAt(getDisplayedChild()); } @Implementation - public void showNext() { + protected void showNext() { setDisplayedChild((getDisplayedChild() + 1) % ((ViewGroup) realView).getChildCount()); } @Implementation - public void showPrevious() { + protected void showPrevious() { setDisplayedChild(getDisplayedChild() == 0 ? ((ViewGroup) realView).getChildCount() - 1 : getDisplayedChild() - 1); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java index 001c0245a..2a8a414fc 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java @@ -85,7 +85,7 @@ public class ShadowViewConfiguration { } @Implementation - public static ViewConfiguration get(Context context) { + protected static ViewConfiguration get(Context context) { ViewConfiguration viewConfiguration = Shadow.newInstanceOf(ViewConfiguration.class); ShadowViewConfiguration shadowViewConfiguration = Shadow.extract(viewConfiguration); shadowViewConfiguration.setup(context); @@ -93,142 +93,142 @@ public class ShadowViewConfiguration { } @Implementation - public static int getScrollBarSize() { + protected static int getScrollBarSize() { return SCROLL_BAR_SIZE; } @Implementation - public int getScaledScrollBarSize() { + protected int getScaledScrollBarSize() { return scrollbarSize; } @Implementation - public static int getScrollBarFadeDuration() { + protected static int getScrollBarFadeDuration() { return SCROLL_BAR_FADE_DURATION; } @Implementation - public static int getScrollDefaultDelay() { + protected static int getScrollDefaultDelay() { return SCROLL_BAR_DEFAULT_DELAY; } @Implementation - public static int getFadingEdgeLength() { + protected static int getFadingEdgeLength() { return FADING_EDGE_LENGTH; } @Implementation - public int getScaledFadingEdgeLength() { + protected int getScaledFadingEdgeLength() { return fadingEdgeLength; } @Implementation - public static int getPressedStateDuration() { + protected static int getPressedStateDuration() { return PRESSED_STATE_DURATION; } @Implementation - public static int getLongPressTimeout() { + protected static int getLongPressTimeout() { return LONG_PRESS_TIMEOUT; } @Implementation - public static int getTapTimeout() { + protected static int getTapTimeout() { return TAP_TIMEOUT; } @Implementation - public static int getJumpTapTimeout() { + protected static int getJumpTapTimeout() { return JUMP_TAP_TIMEOUT; } @Implementation - public static int getDoubleTapTimeout() { + protected static int getDoubleTapTimeout() { return DOUBLE_TAP_TIMEOUT; } @Implementation - public static int getEdgeSlop() { + protected static int getEdgeSlop() { return EDGE_SLOP; } @Implementation - public int getScaledEdgeSlop() { + protected int getScaledEdgeSlop() { return edgeSlop; } @Implementation - public static int getTouchSlop() { + protected static int getTouchSlop() { return TOUCH_SLOP; } @Implementation - public int getScaledTouchSlop() { + protected int getScaledTouchSlop() { return touchSlop; } @Implementation - public int getScaledPagingTouchSlop() { + protected int getScaledPagingTouchSlop() { return pagingTouchSlop; } @Implementation - public int getScaledDoubleTapSlop() { + protected int getScaledDoubleTapSlop() { return doubleTapSlop; } @Implementation - public static int getWindowTouchSlop() { + protected static int getWindowTouchSlop() { return WINDOW_TOUCH_SLOP; } @Implementation - public int getScaledWindowTouchSlop() { + protected int getScaledWindowTouchSlop() { return windowTouchSlop; } @Implementation - public static int getMinimumFlingVelocity() { + protected static int getMinimumFlingVelocity() { return MINIMUM_FLING_VELOCITY; } @Implementation - public int getScaledMinimumFlingVelocity() { + protected int getScaledMinimumFlingVelocity() { return minimumFlingVelocity; } @Implementation - public static int getMaximumFlingVelocity() { + protected static int getMaximumFlingVelocity() { return MAXIMUM_FLING_VELOCITY; } @Implementation - public int getScaledMaximumFlingVelocity() { + protected int getScaledMaximumFlingVelocity() { return maximumFlingVelocity; } @Implementation - public static int getMaximumDrawingCacheSize() { + protected static int getMaximumDrawingCacheSize() { return MAXIMUM_DRAWING_CACHE_SIZE; } @Implementation - public static long getZoomControlsTimeout() { + protected static long getZoomControlsTimeout() { return ZOOM_CONTROLS_TIMEOUT; } @Implementation - public static long getGlobalActionKeyTimeout() { + protected static long getGlobalActionKeyTimeout() { return GLOBAL_ACTIONS_KEY_TIMEOUT; } @Implementation - public static float getScrollFriction() { + protected static float getScrollFriction() { return SCROLL_FRICTION; } @Implementation - public boolean hasPermanentMenuKey() { + protected boolean hasPermanentMenuKey() { return hasPermanentMenuKey; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewGroup.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewGroup.java index 2bb6c0fe0..e1733a7cc 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewGroup.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewGroup.java @@ -22,7 +22,7 @@ public class ShadowViewGroup extends ShadowView { private MotionEvent interceptedTouchEvent; @Implementation - public void addView(final View child, final int index, final ViewGroup.LayoutParams params) { + protected void addView(final View child, final int index, final ViewGroup.LayoutParams params) { ShadowLooper shadowLooper = Shadow.extract(Looper.getMainLooper()); shadowLooper.runPaused(() -> directlyOn(realViewGroup, ViewGroup.class, "addView", @@ -76,7 +76,7 @@ public class ShadowViewGroup extends ShadowView { } @Implementation - public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { + protected void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { disallowInterceptTouchEvent = disallowIntercept; } @@ -96,7 +96,7 @@ public class ShadowViewGroup extends ShadowView { } @Implementation - public boolean onInterceptTouchEvent(MotionEvent ev) { + protected boolean onInterceptTouchEvent(MotionEvent ev) { interceptedTouchEvent = ev; return false; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRenderNode.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRenderNode.java new file mode 100644 index 000000000..912f28902 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRenderNode.java @@ -0,0 +1,204 @@ +package org.robolectric.shadows; + +import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.P; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(className = "android.view.RenderNode", isInAndroidSdk = false, minSdk = LOLLIPOP, maxSdk = P) +public class ShadowViewRenderNode { + private float alpha = 1f; + private float cameraDistance; + private boolean clipToOutline; + private float elevation; + private boolean overlappingRendering; + private boolean pivotExplicitlySet; + private float pivotX; + private float pivotY; + private float rotation; + private float rotationX; + private float rotationY; + private float scaleX = 1f; + private float scaleY = 1f; + private float translationX; + private float translationY; + private float translationZ; + + @Implementation + public boolean setAlpha(float alpha) { + this.alpha = alpha; + return true; + } + + @Implementation + public float getAlpha() { + return alpha; + } + + @Implementation + public boolean setCameraDistance(float cameraDistance) { + this.cameraDistance = cameraDistance; + return true; + } + + @Implementation + public float getCameraDistance() { + return cameraDistance; + } + + @Implementation + public boolean setClipToOutline(boolean clipToOutline) { + this.clipToOutline = clipToOutline; + return true; + } + + @Implementation + public boolean getClipToOutline() { + return clipToOutline; + } + + @Implementation + public boolean setElevation(float lift) { + elevation = lift; + return true; + } + + @Implementation + public float getElevation() { + return elevation; + } + + @Implementation + public boolean setHasOverlappingRendering(boolean overlappingRendering) { + this.overlappingRendering = overlappingRendering; + return true; + } + + @Implementation + public boolean hasOverlappingRendering() { + return overlappingRendering; + } + + @Implementation + public boolean setRotation(float rotation) { + this.rotation = rotation; + return true; + } + + @Implementation + public float getRotation() { + return rotation; + } + + @Implementation + public boolean setRotationX(float rotationX) { + this.rotationX = rotationX; + return true; + } + + @Implementation + public float getRotationX() { + return rotationX; + } + + @Implementation + public boolean setRotationY(float rotationY) { + this.rotationY = rotationY; + return true; + } + + @Implementation + public float getRotationY() { + return rotationY; + } + + @Implementation + public boolean setScaleX(float scaleX) { + this.scaleX = scaleX; + return true; + } + + @Implementation + public float getScaleX() { + return scaleX; + } + + @Implementation + public boolean setScaleY(float scaleY) { + this.scaleY = scaleY; + return true; + } + + @Implementation + public float getScaleY() { + return scaleY; + } + + @Implementation + public boolean setTranslationX(float translationX) { + this.translationX = translationX; + return true; + } + + @Implementation + public boolean setTranslationY(float translationY) { + this.translationY = translationY; + return true; + } + + @Implementation + public boolean setTranslationZ(float translationZ) { + this.translationZ = translationZ; + return true; + } + + @Implementation + public float getTranslationX() { + return translationX; + } + + @Implementation + public float getTranslationY() { + return translationY; + } + + @Implementation + public float getTranslationZ() { + return translationZ; + } + + @Implementation + public boolean isPivotExplicitlySet() { + return pivotExplicitlySet; + } + + @Implementation + public boolean setPivotX(float pivotX) { + this.pivotX = pivotX; + this.pivotExplicitlySet = true; + return true; + } + + @Implementation + public float getPivotX() { + return pivotX; + } + + @Implementation + public boolean setPivotY(float pivotY) { + this.pivotY = pivotY; + this.pivotExplicitlySet = true; + return true; + } + + @Implementation + public float getPivotY() { + return pivotY; + } + + @Implementation + protected boolean isValid() { + return true; + } +}
\ No newline at end of file diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java index 5f5952b49..9638427ef 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewRootImpl.java @@ -10,6 +10,7 @@ import android.os.Build; import android.os.Looper; import android.util.MergedConfiguration; import android.view.Display; +import android.view.IWindowSession; import android.view.ViewRootImpl; import android.view.WindowManager; import java.util.ArrayList; @@ -27,7 +28,7 @@ public class ShadowViewRootImpl { @RealObject private ViewRootImpl realObject; @Implementation(maxSdk = JELLY_BEAN) - public static Object getWindowSession(Looper mainLooper) { + public static IWindowSession getWindowSession(Looper mainLooper) { return null; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVisualVoicemailSms.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVisualVoicemailSms.java index debe0998e..17478d6dc 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVisualVoicemailSms.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowVisualVoicemailSms.java @@ -29,7 +29,7 @@ public class ShadowVisualVoicemailSms { } @Implementation - public PhoneAccountHandle getPhoneAccountHandle() { + protected PhoneAccountHandle getPhoneAccountHandle() { return phoneAccountHandle; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWallpaperManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWallpaperManager.java index a8b021484..341ae0221 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWallpaperManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWallpaperManager.java @@ -12,11 +12,11 @@ import org.robolectric.shadow.api.Shadow; public class ShadowWallpaperManager { @Implementation - public static WallpaperManager getInstance(Context context) { + protected static WallpaperManager getInstance(Context context) { return Shadow.newInstanceOf(WallpaperManager.class); } @Implementation - public void sendWallpaperCommand(IBinder windowToken, String action, int x, int y, int z, Bundle extras) { - } + protected void sendWallpaperCommand( + IBinder windowToken, String action, int x, int y, int z, Bundle extras) {} } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebStorage.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebStorage.java new file mode 100644 index 000000000..abfdba2ee --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebStorage.java @@ -0,0 +1,18 @@ +package org.robolectric.shadows; + +import android.webkit.WebStorage; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +/** + * Shadow of {@link WebStorage} which constructs a stub instance rather than attempting to create a + * full Chromium-backed instance. + */ +@Implements(value = WebStorage.class) +public class ShadowWebStorage { + + @Implementation + protected static WebStorage getInstance() { + return new WebStorage(); + } +} diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebSyncManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebSyncManager.java index bd7a52453..e46fd9635 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebSyncManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebSyncManager.java @@ -8,7 +8,7 @@ public class ShadowWebSyncManager { protected boolean synced = false; @Implementation - public void sync() { + protected void sync() { synced = true; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebView.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebView.java index 8a41248a4..9599e91f8 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebView.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebView.java @@ -1,7 +1,5 @@ package org.robolectric.shadows; -import static android.os.Build.VERSION_CODES.N_MR1; - import android.content.pm.PackageInfo; import android.graphics.Bitmap; import android.os.Build; @@ -26,6 +24,7 @@ import org.robolectric.annotation.HiddenApi; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.annotation.RealObject; +import org.robolectric.annotation.Resetter; import org.robolectric.fakes.RoboWebSettings; import org.robolectric.util.ReflectionHelpers; @@ -36,6 +35,8 @@ public class ShadowWebView extends ShadowViewGroup { private static final String HISTORY_KEY = "ShadowWebView.History"; + private static PackageInfo packageInfo = null; + private String lastUrl; private Map<String, String> lastAdditionalHttpHeaders; private HashMap<String, Object> javascriptInterfaces = new HashMap<>(); @@ -314,14 +315,28 @@ public class ShadowWebView extends ShadowViewGroup { } @Implementation + protected WebBackForwardList copyBackForwardList() { + return new BackForwardList(history); + } + + @Implementation protected static String findAddress(String addr) { return null; } - /** Overrides the system implementation for getting the webview package. Always returns null. */ - @Implementation(minSdk = Build.VERSION_CODES.O, maxSdk = N_MR1) - protected static PackageInfo getCurrentWebviewPackage() { - return null; + /** + * Overrides the system implementation for getting the WebView package. + * + * <p>Returns null by default, but this can be changed with {@code #setCurrentWebviewPackage()}. + */ + @Implementation(minSdk = Build.VERSION_CODES.O) + protected static PackageInfo getCurrentWebViewPackage() { + return packageInfo; + } + + /** Sets the value to return from {@code #getCurrentWebviewPackage()}. */ + public static void setCurrentWebViewPackage(PackageInfo webViewPackageInfo) { + packageInfo = webViewPackageInfo; } @Implementation(minSdk = Build.VERSION_CODES.KITKAT) @@ -381,6 +396,11 @@ public class ShadowWebView extends ShadowViewGroup { return null; } + @Resetter + public static void reset() { + packageInfo = null; + } + public static void setWebContentsDebuggingEnabled(boolean enabled) {} public static class LoadDataWithBaseURL { @@ -433,6 +453,10 @@ public class ShadowWebView extends ShadowViewGroup { @Override public HistoryItem getCurrentItem() { + if (history.isEmpty()) { + return null; + } + return new HistoryItem(history.get(getCurrentIndex())); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebViewDatabase.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebViewDatabase.java index c8b401fe5..91b2430da 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebViewDatabase.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWebViewDatabase.java @@ -10,7 +10,7 @@ import org.robolectric.shadow.api.Shadow; public class ShadowWebViewDatabase { @Implementation - public static WebViewDatabase getInstance(Context ignored) { + protected static WebViewDatabase getInstance(Context ignored) { return Shadow.newInstanceOf(WebViewDatabase.class); } } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiManager.java index bcb3cc31b..92484a38d 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiManager.java @@ -3,6 +3,7 @@ package org.robolectric.shadows; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; import static android.os.Build.VERSION_CODES.KITKAT; import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static org.robolectric.Shadows.shadowOf; import android.content.Context; import android.net.ConnectivityManager; @@ -18,10 +19,12 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.HiddenApi; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.annotation.RealObject; import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers; @@ -44,22 +47,24 @@ public class ShadowWifiManager { private boolean isScanAlwaysAvailable = true; private boolean startScanSucceeds = true; private boolean is5GHzBandSupported = false; + private AtomicInteger activeLockCount = new AtomicInteger(0); + @RealObject WifiManager wifiManager; @Implementation - public boolean setWifiEnabled(boolean wifiEnabled) { + protected boolean setWifiEnabled(boolean wifiEnabled) { checkAccessWifiStatePermission(); this.wifiEnabled = wifiEnabled; return true; } @Implementation - public boolean isWifiEnabled() { + protected boolean isWifiEnabled() { checkAccessWifiStatePermission(); return wifiEnabled; } @Implementation - public int getWifiState() { + protected int getWifiState() { if (isWifiEnabled()) { return WifiManager.WIFI_STATE_ENABLED; } else { @@ -68,7 +73,7 @@ public class ShadowWifiManager { } @Implementation - public WifiInfo getConnectionInfo() { + protected WifiInfo getConnectionInfo() { checkAccessWifiStatePermission(); if (wifiInfo == null) { wifiInfo = ReflectionHelpers.callConstructor(WifiInfo.class); @@ -77,7 +82,7 @@ public class ShadowWifiManager { } @Implementation(minSdk = LOLLIPOP) - public boolean is5GHzBandSupported() { + protected boolean is5GHzBandSupported() { return is5GHzBandSupported; } @@ -99,12 +104,12 @@ public class ShadowWifiManager { } @Implementation - public List<ScanResult> getScanResults() { + protected List<ScanResult> getScanResults() { return scanResults; } @Implementation - public List<WifiConfiguration> getConfiguredNetworks() { + protected List<WifiConfiguration> getConfiguredNetworks() { final ArrayList<WifiConfiguration> wifiConfigurations = new ArrayList<>(); for (WifiConfiguration wifiConfiguration : networkIdToConfiguredNetworks.values()) { wifiConfigurations.add(wifiConfiguration); @@ -113,12 +118,12 @@ public class ShadowWifiManager { } @Implementation(minSdk = LOLLIPOP) - public List<WifiConfiguration> getPrivilegedConfiguredNetworks() { + protected List<WifiConfiguration> getPrivilegedConfiguredNetworks() { return getConfiguredNetworks(); } @Implementation - public int addNetwork(WifiConfiguration config) { + protected int addNetwork(WifiConfiguration config) { int networkId = networkIdToConfiguredNetworks.size(); config.networkId = -1; networkIdToConfiguredNetworks.put(networkId, makeCopy(config, networkId)); @@ -126,13 +131,13 @@ public class ShadowWifiManager { } @Implementation - public boolean removeNetwork(int netId) { + protected boolean removeNetwork(int netId) { networkIdToConfiguredNetworks.remove(netId); return true; } @Implementation - public int updateNetwork(WifiConfiguration config) { + protected int updateNetwork(WifiConfiguration config) { if (config == null || config.networkId < 0) { return -1; } @@ -141,29 +146,38 @@ public class ShadowWifiManager { } @Implementation - public boolean saveConfiguration() { + protected boolean saveConfiguration() { wasSaved = true; return true; } @Implementation - public boolean enableNetwork(int netId, boolean disableOthers) { + protected boolean enableNetwork(int netId, boolean disableOthers) { lastEnabledNetwork = new Pair<>(netId, disableOthers); return true; } @Implementation - public WifiManager.WifiLock createWifiLock(int lockType, java.lang.String tag) { - return ReflectionHelpers.callConstructor(WifiManager.WifiLock.class); + protected WifiManager.WifiLock createWifiLock(int lockType, String tag) { + WifiManager.WifiLock wifiLock = ReflectionHelpers.callConstructor(WifiManager.WifiLock.class); + shadowOf(wifiLock).setWifiManager(wifiManager); + return wifiLock; } @Implementation - public WifiManager.WifiLock createWifiLock(java.lang.String tag) { + protected WifiManager.WifiLock createWifiLock(String tag) { return createWifiLock(WifiManager.WIFI_MODE_FULL, tag); } @Implementation - public static int calculateSignalLevel(int rssi, int numLevels) { + protected MulticastLock createMulticastLock(String tag) { + MulticastLock multicastLock = ReflectionHelpers.callConstructor(MulticastLock.class); + shadowOf(multicastLock).setWifiManager(wifiManager); + return multicastLock; + } + + @Implementation + protected static int calculateSignalLevel(int rssi, int numLevels) { return (int) (sSignalLevelInPercent * (numLevels - 1)); } @@ -177,17 +191,17 @@ public class ShadowWifiManager { * was never called. */ @Implementation - public boolean startScan() { + protected boolean startScan() { return startScanSucceeds; } @Implementation - public DhcpInfo getDhcpInfo() { + protected DhcpInfo getDhcpInfo() { return dhcpInfo; } @Implementation(minSdk = JELLY_BEAN_MR2) - public boolean isScanAlwaysAvailable() { + protected boolean isScanAlwaysAvailable() { return isScanAlwaysAvailable; } @@ -222,7 +236,7 @@ public class ShadowWifiManager { true /* isConnected */); ShadowConnectivityManager connectivityManager = Shadow.extract( - RuntimeEnvironment.application.getSystemService(Context.CONNECTIVITY_SERVICE)); + RuntimeEnvironment.application.getSystemService(Context.CONNECTIVITY_SERVICE)); connectivityManager.setActiveNetworkInfo(networkInfo); if (listener != null) { @@ -230,8 +244,18 @@ public class ShadowWifiManager { } } + @HiddenApi + @Implementation(minSdk = KITKAT) + protected void connect(int networkId, WifiManager.ActionListener listener) { + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.networkId = networkId; + wifiConfiguration.SSID = ""; + wifiConfiguration.BSSID = ""; + connect(wifiConfiguration, listener); + } + private static boolean isQuoted(String str) { - if (str.length() < 2) { + if (str == null || str.length() < 2) { return false; } @@ -284,6 +308,11 @@ public class ShadowWifiManager { return lastEnabledNetwork; } + /** Returns the number of WifiLocks and MulticastLocks that are currently acquired. */ + public int getActiveLockCount() { + return activeLockCount.get(); + } + public boolean wasConfigurationSaved() { return wasSaved; } @@ -314,10 +343,18 @@ public class ShadowWifiManager { private int refCount; private boolean refCounted = true; private boolean locked; + private WifiManager wifiManager; public static final int MAX_ACTIVE_LOCKS = 50; + private void setWifiManager(WifiManager wifiManager) { + this.wifiManager = wifiManager; + } + @Implementation - public synchronized void acquire() { + protected synchronized void acquire() { + if (wifiManager != null) { + shadowOf(wifiManager).activeLockCount.getAndIncrement(); + } if (refCounted) { if (++refCount >= MAX_ACTIVE_LOCKS) throw new UnsupportedOperationException("Exceeded maximum number of wifi locks"); } else { @@ -326,7 +363,10 @@ public class ShadowWifiManager { } @Implementation - public synchronized void release() { + protected synchronized void release() { + if (wifiManager != null) { + shadowOf(wifiManager).activeLockCount.getAndDecrement(); + } if (refCounted) { if (--refCount < 0) throw new RuntimeException("WifiLock under-locked"); } else { @@ -335,12 +375,12 @@ public class ShadowWifiManager { } @Implementation - public synchronized boolean isHeld() { + protected synchronized boolean isHeld() { return refCounted ? refCount > 0 : locked; } @Implementation - public void setReferenceCounted(boolean refCounted) { + protected void setReferenceCounted(boolean refCounted) { this.refCounted = refCounted; } } @@ -351,9 +391,17 @@ public class ShadowWifiManager { private boolean refCounted = true; private boolean locked; static final int MAX_ACTIVE_LOCKS = 50; + private WifiManager wifiManager; + + private void setWifiManager(WifiManager wifiManager) { + this.wifiManager = wifiManager; + } @Implementation protected void acquire() { + if (wifiManager != null) { + shadowOf(wifiManager).activeLockCount.getAndIncrement(); + } if (refCounted) { if (++refCount >= MAX_ACTIVE_LOCKS) throw new UnsupportedOperationException("Exceeded maximum number of wifi locks"); } else { @@ -363,6 +411,9 @@ public class ShadowWifiManager { @Implementation protected synchronized void release() { + if (wifiManager != null) { + shadowOf(wifiManager).activeLockCount.getAndDecrement(); + } if (refCounted) { if (--refCount < 0) throw new RuntimeException("WifiLock under-locked"); } else { diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiP2pManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiP2pManager.java index 9a50f8582..54e6b2800 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiP2pManager.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWifiP2pManager.java @@ -41,7 +41,7 @@ public class ShadowWifiP2pManager { } @Implementation(minSdk = KITKAT) - public void setWifiP2pChannels( + protected void setWifiP2pChannels( Channel c, int listeningChannel, int operatingChannel, ActionListener al) { Preconditions.checkNotNull(c); Preconditions.checkNotNull(al); @@ -50,13 +50,14 @@ public class ShadowWifiP2pManager { } @Implementation - public Channel initialize(Context context, Looper looper, WifiP2pManager.ChannelListener listener) { + protected Channel initialize( + Context context, Looper looper, WifiP2pManager.ChannelListener listener) { handler = new Handler(looper); return ReflectionHelpers.newInstance(Channel.class); } @Implementation - public void createGroup(Channel c, ActionListener al) { + protected void createGroup(Channel c, ActionListener al) { postActionListener(al); } @@ -79,7 +80,7 @@ public class ShadowWifiP2pManager { } @Implementation - public void requestGroupInfo(final Channel c, final WifiP2pManager.GroupInfoListener gl) { + protected void requestGroupInfo(final Channel c, final WifiP2pManager.GroupInfoListener gl) { if (gl == null) { return; } @@ -93,7 +94,7 @@ public class ShadowWifiP2pManager { } @Implementation - public void removeGroup(Channel c, ActionListener al) { + protected void removeGroup(Channel c, ActionListener al) { postActionListener(al); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindow.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindow.java index 52f0954b2..29be74859 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindow.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindow.java @@ -34,13 +34,13 @@ public class ShadowWindow { } @Implementation - public void setFlags(int flags, int mask) { + protected void setFlags(int flags, int mask) { this.flags = (this.flags & ~mask) | (flags & mask); directlyOn(realWindow, Window.class, "setFlags", ClassParameter.from(int.class, flags), ClassParameter.from(int.class, mask)); } @Implementation - public void setSoftInputMode(int softInputMode) { + protected void setSoftInputMode(int softInputMode) { this.softInputMode = softInputMode; directlyOn(realWindow, Window.class, "setSoftInputMode", ClassParameter.from(int.class, softInputMode)); } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java index e7f78c538..a6aeaf2a9 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerGlobal.java @@ -10,12 +10,14 @@ import org.robolectric.annotation.Implements; import org.robolectric.annotation.Resetter; import org.robolectric.util.ReflectionHelpers; -@Implements(value = WindowManagerGlobal.class, isInAndroidSdk = false, minSdk = JELLY_BEAN_MR1) +@Implements(value = WindowManagerGlobal.class, isInAndroidSdk = false, + minSdk = JELLY_BEAN_MR1, looseSignatures = true) public class ShadowWindowManagerGlobal { @Resetter public static void reset() { - ReflectionHelpers.setStaticField(WindowManagerGlobal.class, "sDefaultWindowManager", null); + ReflectionHelpers.setStaticField( + WindowManagerGlobal.class, "sDefaultWindowManager", null); } @Implementation(minSdk = JELLY_BEAN_MR2) diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerImpl.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerImpl.java index 7ff5e210f..f324b5ecf 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerImpl.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowWindowManagerImpl.java @@ -44,11 +44,11 @@ public class ShadowWindowManagerImpl extends ShadowWindowManager { @RealObject WindowManagerImpl realObject; - private static Multimap<Display, View> views = ArrayListMultimap.create(); + private static final Multimap<Integer, View> views = ArrayListMultimap.create(); @Implementation public void addView(View view, android.view.ViewGroup.LayoutParams layoutParams) { - views.put(realObject.getDefaultDisplay(), view); + views.put(realObject.getDefaultDisplay().getDisplayId(), view); // views.add(view); directlyOn( realObject, @@ -60,13 +60,13 @@ public class ShadowWindowManagerImpl extends ShadowWindowManager { @Implementation public void removeView(View view) { - views.remove(realObject.getDefaultDisplay(), view); + views.remove(realObject.getDefaultDisplay().getDisplayId(), view); directlyOn(realObject, WindowManagerImpl.class, "removeView", ClassParameter.from(View.class, view)); } public List<View> getViews() { - return ImmutableList.copyOf(views.get(realObject.getDefaultDisplay())); + return ImmutableList.copyOf(views.get(realObject.getDefaultDisplay().getDisplayId())); } @Implementation(maxSdk = JELLY_BEAN) @@ -81,7 +81,7 @@ public class ShadowWindowManagerImpl extends ShadowWindowManager { @Implements(className = "android.view.WindowManagerImpl$CompatModeWrapper", maxSdk = JELLY_BEAN) public static class ShadowCompatModeWrapper { @Implementation(maxSdk = JELLY_BEAN) - public Display getDefaultDisplay() { + protected Display getDefaultDisplay() { return defaultDisplayJB; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowZoomButtonsController.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowZoomButtonsController.java index 3be32d012..2642083aa 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowZoomButtonsController.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowZoomButtonsController.java @@ -11,10 +11,10 @@ public class ShadowZoomButtonsController { private ZoomButtonsController.OnZoomListener listener; @Implementation - public void __constructor__(View ownerView) {} + protected void __constructor__(View ownerView) {} @Implementation - public void setOnZoomListener(ZoomButtonsController.OnZoomListener listener) { + protected void setOnZoomListener(ZoomButtonsController.OnZoomListener listener) { this.listener = listener; } diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/StorageVolumeBuilder.java b/shadows/framework/src/main/java/org/robolectric/shadows/StorageVolumeBuilder.java new file mode 100644 index 000000000..b31eae199 --- /dev/null +++ b/shadows/framework/src/main/java/org/robolectric/shadows/StorageVolumeBuilder.java @@ -0,0 +1,101 @@ +package org.robolectric.shadows; + +import static org.robolectric.util.ReflectionHelpers.ClassParameter.from; + +import android.os.Build; +import android.os.Build.VERSION_CODES; +import android.os.UserHandle; +import android.os.storage.StorageVolume; +import java.io.File; +import org.robolectric.util.ReflectionHelpers; + +/** Class to build {@link StorageVolume} */ +public final class StorageVolumeBuilder { + + private String id; + private int storageId = 0; + private File path; + private String description; + private boolean primary = true; + private boolean removable = false; + private boolean emulated = false; + private long mtpReserveSize = 00L; + private boolean allowMassStorage = false; + private long maxFileSize = 100L; + private UserHandle owner; + private String fsUuid = "4213-3435:"; + private String state; + + public StorageVolumeBuilder( + String id, File path, String description, UserHandle owner, String state) { + this.id = id; + this.path = path; + this.description = description; + this.owner = owner; + this.state = state; + } + + void setStorageId(int storageId) { + this.storageId = storageId; + } + + void setIsPrimary(boolean isPrimary) { + this.primary = isPrimary; + } + + void setIsRemovable(boolean isRemovable) { + this.removable = isRemovable; + } + + void setIsEmulated(boolean isEmulated) { + this.emulated = isEmulated; + } + + void setMtpReserveSize(long mtpReserveSize) { + this.mtpReserveSize = mtpReserveSize; + } + + void setAllowMassStorage(boolean allowMassStorage) { + this.allowMassStorage = allowMassStorage; + } + + void setMaxFileSize(long maxFileSize) { + this.maxFileSize = maxFileSize; + } + + public StorageVolume build() throws IllegalStateException { + if (Build.VERSION.SDK_INT >= VERSION_CODES.N && Build.VERSION.SDK_INT < VERSION_CODES.P) { + return ReflectionHelpers.callConstructor( + StorageVolume.class, + from(String.class, id), // String id, + from(int.class, storageId), // int storageId + from(File.class, path), // File path, + from(String.class, description), // String description + from(boolean.class, primary), // boolean primary, + from(boolean.class, removable), // boolean removable, + from(boolean.class, emulated), // boolean emulated, + from(long.class, mtpReserveSize), // long mtpReserveSize, + from(boolean.class, allowMassStorage), + from(long.class, maxFileSize), // long maxFileSize, + from(UserHandle.class, owner), // UserHandle owner, + from(String.class, fsUuid), // String fsUuid, + from(String.class, state)); // String state + } else if (Build.VERSION.SDK_INT >= VERSION_CODES.P) { + return ReflectionHelpers.callConstructor( + StorageVolume.class, + from(String.class, id), // String id, + from(File.class, path), // File path, + from(File.class, path), // File internalPath + from(String.class, description), // String description + from(boolean.class, primary), // boolean primary, + from(boolean.class, removable), // boolean removable, + from(boolean.class, emulated), // boolean emulated, + from(boolean.class, allowMassStorage), // boolean allowMassStorage, + from(long.class, maxFileSize), // long maxFileSize, + from(UserHandle.class, owner), // UserHandle owner, + from(String.class, fsUuid), // String fsUuid, + from(String.class, state)); // String state + } + throw new IllegalStateException("StorageVolume hidden constructor not found"); + } +} diff --git a/shadows/httpclient/build.gradle b/shadows/httpclient/build.gradle index 07bd97389..8ace567b5 100644 --- a/shadows/httpclient/build.gradle +++ b/shadows/httpclient/build.gradle @@ -1,7 +1,3 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) @@ -17,19 +13,16 @@ configurations { } dependencies { - // Project dependencies compileOnly project(":shadows:framework") - // Compile dependencies earlyRuntime "org.apache.httpcomponents:httpcore:4.0.1" - compile "org.apache.httpcomponents:httpclient:4.0.3" + api "org.apache.httpcomponents:httpclient:4.0.3" compileOnly(AndroidSdk.LOLLIPOP_MR1.coordinates) { force = true } - // Testing dependencies - testCompile project(":robolectric") - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" + testImplementation project(":robolectric") + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" testRuntime AndroidSdk.LOLLIPOP_MR1.coordinates } diff --git a/shadows/httpclient/src/main/java/org/robolectric/shadows/ShadowAndroidHttpClient.java b/shadows/httpclient/src/main/java/org/robolectric/shadows/ShadowAndroidHttpClient.java index d2c9601d6..3da6bd7f4 100644 --- a/shadows/httpclient/src/main/java/org/robolectric/shadows/ShadowAndroidHttpClient.java +++ b/shadows/httpclient/src/main/java/org/robolectric/shadows/ShadowAndroidHttpClient.java @@ -26,62 +26,80 @@ public class ShadowAndroidHttpClient { private HttpClient httpClient = new DefaultHttpClient(); @Implementation - public static AndroidHttpClient newInstance(String userAgent) { + protected static AndroidHttpClient newInstance(String userAgent) { return ReflectionHelpers.callConstructor(AndroidHttpClient.class); } @Implementation - public static AndroidHttpClient newInstance(String userAgent, Context context) { + protected static AndroidHttpClient newInstance(String userAgent, Context context) { return ReflectionHelpers.callConstructor(AndroidHttpClient.class); } @Implementation - public HttpParams getParams() { + protected HttpParams getParams() { return httpClient.getParams(); } @Implementation - public ClientConnectionManager getConnectionManager() { + protected ClientConnectionManager getConnectionManager() { return httpClient.getConnectionManager(); } @Implementation - public HttpResponse execute(HttpUriRequest httpUriRequest) throws IOException, ClientProtocolException { + protected HttpResponse execute(HttpUriRequest httpUriRequest) + throws IOException, ClientProtocolException { return httpClient.execute(httpUriRequest); } @Implementation - public HttpResponse execute(HttpUriRequest httpUriRequest, HttpContext httpContext) throws IOException, ClientProtocolException { + protected HttpResponse execute(HttpUriRequest httpUriRequest, HttpContext httpContext) + throws IOException, ClientProtocolException { return httpClient.execute(httpUriRequest, httpContext); } @Implementation - public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest) throws IOException, ClientProtocolException { + protected HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest) + throws IOException, ClientProtocolException { return httpClient.execute(httpHost, httpRequest); } @Implementation - public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) throws IOException, ClientProtocolException { + protected HttpResponse execute( + HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) + throws IOException, ClientProtocolException { return httpClient.execute(httpHost, httpRequest, httpContext); } @Implementation - public <T> T execute(HttpUriRequest httpUriRequest, ResponseHandler<? extends T> responseHandler) throws IOException, ClientProtocolException { + protected <T> T execute( + HttpUriRequest httpUriRequest, ResponseHandler<? extends T> responseHandler) + throws IOException, ClientProtocolException { return httpClient.execute(httpUriRequest, responseHandler); } @Implementation - public <T> T execute(HttpUriRequest httpUriRequest, ResponseHandler<? extends T> responseHandler, HttpContext httpContext) throws IOException, ClientProtocolException { + protected <T> T execute( + HttpUriRequest httpUriRequest, + ResponseHandler<? extends T> responseHandler, + HttpContext httpContext) + throws IOException, ClientProtocolException { return httpClient.execute(httpUriRequest, responseHandler, httpContext); } @Implementation - public <T> T execute(HttpHost httpHost, HttpRequest httpRequest, ResponseHandler<? extends T> responseHandler) throws IOException, ClientProtocolException { + protected <T> T execute( + HttpHost httpHost, HttpRequest httpRequest, ResponseHandler<? extends T> responseHandler) + throws IOException, ClientProtocolException { return httpClient.execute(httpHost, httpRequest, responseHandler); } @Implementation - public <T> T execute(HttpHost httpHost, HttpRequest httpRequest, ResponseHandler<? extends T> responseHandler, HttpContext httpContext) throws IOException, ClientProtocolException { + protected <T> T execute( + HttpHost httpHost, + HttpRequest httpRequest, + ResponseHandler<? extends T> responseHandler, + HttpContext httpContext) + throws IOException, ClientProtocolException { return httpClient.execute(httpHost, httpRequest, responseHandler, httpContext); } }
\ No newline at end of file diff --git a/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirector.java b/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirector.java index dadad5040..580eae406 100644 --- a/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirector.java +++ b/shadows/httpclient/src/main/java/org/robolectric/shadows/httpclient/ShadowDefaultRequestDirector.java @@ -54,7 +54,7 @@ public class ShadowDefaultRequestDirector { org.robolectric.shadows.httpclient.DefaultRequestDirector redirector; @Implementation - public void __constructor__( + protected void __constructor__( Log log, HttpRequestExecutor requestExec, ClientConnectionManager conman, @@ -104,7 +104,7 @@ public class ShadowDefaultRequestDirector { } @Implementation - public void __constructor__( + protected void __constructor__( HttpRequestExecutor requestExec, ClientConnectionManager conman, ConnectionReuseStrategy reustrat, @@ -163,7 +163,9 @@ public class ShadowDefaultRequestDirector { } @Implementation - public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) throws HttpException, IOException { + protected HttpResponse execute( + HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) + throws HttpException, IOException { if (FakeHttp.getFakeHttpLayer().isInterceptingHttpRequests()) { return FakeHttp.getFakeHttpLayer().emulateRequest(httpHost, httpRequest, httpContext, realObject); } else { diff --git a/shadows/httpclient/src/test/java/org/robolectric/util/TestRunnerWithManifest.java b/shadows/httpclient/src/test/java/org/robolectric/util/TestRunnerWithManifest.java index 9a3ae2798..9ed0b2f6e 100644 --- a/shadows/httpclient/src/test/java/org/robolectric/util/TestRunnerWithManifest.java +++ b/shadows/httpclient/src/test/java/org/robolectric/util/TestRunnerWithManifest.java @@ -3,10 +3,12 @@ package org.robolectric.util; import java.io.File; import java.net.URI; import java.net.URL; +import java.util.Collections; import org.junit.runners.model.InitializationError; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import org.robolectric.manifest.AndroidManifest; +import org.robolectric.internal.ManifestFactory; +import org.robolectric.internal.ManifestIdentifier; import org.robolectric.res.Fs; import org.robolectric.res.FsFile; @@ -36,7 +38,13 @@ public class TestRunnerWithManifest extends RobolectricTestRunner { } @Override - protected AndroidManifest getAppManifest(Config config) { - return new AndroidManifest(resourceFile("AndroidManifest.xml"), resourceFile("res"), resourceFile("assets")); + protected ManifestFactory getManifestFactory(Config config) { + return c -> new ManifestIdentifier( + "org.robolectric", + resourceFile("AndroidManifest.xml"), + resourceFile("res"), + resourceFile("assets"), + Collections.emptyList() + ); } } diff --git a/shadows/multidex/build.gradle b/shadows/multidex/build.gradle index 66fd25e67..141300477 100644 --- a/shadows/multidex/build.gradle +++ b/shadows/multidex/build.gradle @@ -1,7 +1,3 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) @@ -19,5 +15,5 @@ dependencies { compileOnly AndroidSdk.MAX_SDK.coordinates - testCompile project(":robolectric") + testImplementation project(":robolectric") } diff --git a/shadows/playservices/build.gradle b/shadows/playservices/build.gradle index 6418644ea..c843b7c37 100644 --- a/shadows/playservices/build.gradle +++ b/shadows/playservices/build.gradle @@ -1,7 +1,3 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) @@ -21,11 +17,10 @@ dependencies { compileOnly AndroidSdk.MAX_SDK.coordinates - // Testing dependencies - testCompile project(":robolectric") - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" + testImplementation project(":robolectric") + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" testRuntime "com.android.support:support-fragment:26.0.1" testRuntime "com.google.android.gms:play-services-base:8.4.0" testRuntime "com.google.android.gms:play-services-basement:8.4.0" diff --git a/shadows/supportv4/build.gradle b/shadows/supportv4/build.gradle index 3a6978eeb..e0c276045 100644 --- a/shadows/supportv4/build.gradle +++ b/shadows/supportv4/build.gradle @@ -1,7 +1,3 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) @@ -17,11 +13,9 @@ configurations { } dependencies { - // Project dependencies compileOnly project(":robolectric") compileOnly project(":shadows:framework") - // Compile dependencies compileOnly AndroidSdk.MAX_SDK.coordinates compileOnly "com.android.support:support-annotations:26.0.1" compileOnly "com.android.support:support-v4:26.0.1" @@ -31,12 +25,11 @@ dependencies { compileOnly "com.android.support:support-fragment:26.0.1" compileOnly "com.android.support:support-media-compat:26.0.1" - // Testing dependencies - testCompile project(":robolectric") - testCompile "junit:junit:4.12" - testCompile "org.hamcrest:hamcrest-junit:2.0.0.0" - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" + testImplementation project(":robolectric") + testImplementation "junit:junit:4.12" + testImplementation "org.hamcrest:hamcrest-junit:2.0.0.0" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" earlyTestRuntime "org.hamcrest:hamcrest-junit:2.0.0.0" testRuntime AndroidSdk.MAX_SDK.coordinates diff --git a/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowAsyncTaskLoader.java b/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowAsyncTaskLoader.java index 3403bbe6a..8d01034e4 100644 --- a/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowAsyncTaskLoader.java +++ b/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowAsyncTaskLoader.java @@ -16,12 +16,12 @@ public class ShadowAsyncTaskLoader<D> { private BackgroundWorker worker; @Implementation - public void __constructor__(Context context) { + protected void __constructor__(Context context) { worker = new BackgroundWorker(); } @Implementation - public void onForceLoad() { + protected void onForceLoad() { FutureTask<D> future = new FutureTask<D>(worker) { @Override protected void done() { try { diff --git a/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowDrawerLayout.java b/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowDrawerLayout.java index b687e72e6..261671b45 100644 --- a/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowDrawerLayout.java +++ b/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowDrawerLayout.java @@ -15,7 +15,7 @@ public class ShadowDrawerLayout extends ShadowViewGroup { private DrawerLayout.DrawerListener drawerListener; @Implementation - public void setDrawerListener(DrawerLayout.DrawerListener drawerListener) { + protected void setDrawerListener(DrawerLayout.DrawerListener drawerListener) { this.drawerListener = drawerListener; directlyOn(realDrawerLayout, DrawerLayout.class).setDrawerListener(drawerListener); } @@ -24,19 +24,15 @@ public class ShadowDrawerLayout extends ShadowViewGroup { return drawerListener; } - /** - * Drawer animations are disabled in unit tests. - */ + /** Drawer animations are disabled in unit tests. */ @Implementation - public void openDrawer(View drawerView, boolean animate) { + protected void openDrawer(View drawerView, boolean animate) { directlyOn(realDrawerLayout, DrawerLayout.class).openDrawer(drawerView, false); } - /** - * Drawer animations are disabled in unit tests. - */ + /** Drawer animations are disabled in unit tests. */ @Implementation - public void closeDrawer(View drawerView, boolean animate) { + protected void closeDrawer(View drawerView, boolean animate) { directlyOn(realDrawerLayout, DrawerLayout.class).closeDrawer(drawerView, false); } } diff --git a/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowLocalBroadcastManager.java b/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowLocalBroadcastManager.java index dda0d6ef7..5a97abc46 100644 --- a/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowLocalBroadcastManager.java +++ b/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowLocalBroadcastManager.java @@ -23,7 +23,7 @@ public class ShadowLocalBroadcastManager { private final List<Wrapper> registeredReceivers = new ArrayList<>(); @Implementation - public static LocalBroadcastManager getInstance(final Context context) { + protected static LocalBroadcastManager getInstance(final Context context) { return ShadowApplication.getInstance().getSingleton(LocalBroadcastManager.class, new Provider<LocalBroadcastManager>() { @Override public LocalBroadcastManager get() { @@ -33,12 +33,12 @@ public class ShadowLocalBroadcastManager { } @Implementation - public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { + protected void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { registeredReceivers.add(new Wrapper(receiver, filter)); } @Implementation - public void unregisterReceiver(BroadcastReceiver receiver) { + protected void unregisterReceiver(BroadcastReceiver receiver) { Iterator<Wrapper> iterator = registeredReceivers.iterator(); while (iterator.hasNext()) { Wrapper wrapper = iterator.next(); @@ -49,7 +49,7 @@ public class ShadowLocalBroadcastManager { } @Implementation - public boolean sendBroadcast(Intent intent) { + protected boolean sendBroadcast(Intent intent) { boolean sent = false; sentBroadcastIntents.add(intent); List<Wrapper> copy = new ArrayList<>(); diff --git a/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowSwipeRefreshLayout.java b/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowSwipeRefreshLayout.java index be0a10099..b9d559663 100644 --- a/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowSwipeRefreshLayout.java +++ b/shadows/supportv4/src/main/java/org/robolectric/shadows/support/v4/ShadowSwipeRefreshLayout.java @@ -14,7 +14,7 @@ public class ShadowSwipeRefreshLayout extends ShadowViewGroup { private OnRefreshListener listener; @Implementation - public void setOnRefreshListener(OnRefreshListener listener) { + protected void setOnRefreshListener(OnRefreshListener listener) { this.listener = listener; Shadow.directlyOn(realObject, SwipeRefreshLayout.class).setOnRefreshListener(listener); } diff --git a/shadows/supportv4/src/test/java/org/robolectric/util/TestRunnerWithManifest.java b/shadows/supportv4/src/test/java/org/robolectric/util/TestRunnerWithManifest.java index 9a3ae2798..9ed0b2f6e 100644 --- a/shadows/supportv4/src/test/java/org/robolectric/util/TestRunnerWithManifest.java +++ b/shadows/supportv4/src/test/java/org/robolectric/util/TestRunnerWithManifest.java @@ -3,10 +3,12 @@ package org.robolectric.util; import java.io.File; import java.net.URI; import java.net.URL; +import java.util.Collections; import org.junit.runners.model.InitializationError; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import org.robolectric.manifest.AndroidManifest; +import org.robolectric.internal.ManifestFactory; +import org.robolectric.internal.ManifestIdentifier; import org.robolectric.res.Fs; import org.robolectric.res.FsFile; @@ -36,7 +38,13 @@ public class TestRunnerWithManifest extends RobolectricTestRunner { } @Override - protected AndroidManifest getAppManifest(Config config) { - return new AndroidManifest(resourceFile("AndroidManifest.xml"), resourceFile("res"), resourceFile("assets")); + protected ManifestFactory getManifestFactory(Config config) { + return c -> new ManifestIdentifier( + "org.robolectric", + resourceFile("AndroidManifest.xml"), + resourceFile("res"), + resourceFile("assets"), + Collections.emptyList() + ); } } diff --git a/testapp/build.gradle b/testapp/build.gradle index 85ed6e596..92279db5d 100644 --- a/testapp/build.gradle +++ b/testapp/build.gradle @@ -17,7 +17,3 @@ android { abortOnError false } } - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) -} diff --git a/testapp/src/main/AndroidManifest.xml b/testapp/src/main/AndroidManifest.xml index 41187d199..ae269f867 100644 --- a/testapp/src/main/AndroidManifest.xml +++ b/testapp/src/main/AndroidManifest.xml @@ -3,9 +3,11 @@ package="org.robolectric" android:versionCode="123" android:versionName="aVersionName"> - <uses-sdk android:targetSdkVersion="23"/> - - <application - android:theme="@style/Theme.Robolectric"/> + <uses-sdk android:targetSdkVersion="23"/> + <application + android:theme="@style/Theme.Robolectric"> + <activity android:name=".DisabledTestActivity" android:enabled="false"/> + <activity android:name=".TestActivity"/> + </application> </manifest> diff --git a/testapp/src/main/java/org/robolectric/DisabledTestActivity.java b/testapp/src/main/java/org/robolectric/DisabledTestActivity.java new file mode 100644 index 000000000..8b7b81a24 --- /dev/null +++ b/testapp/src/main/java/org/robolectric/DisabledTestActivity.java @@ -0,0 +1,6 @@ +package org.robolectric; + +import android.app.Activity; + +/** Test activity that is disabled in the manifest. */ +public class DisabledTestActivity extends Activity {} diff --git a/testapp/src/main/java/org/robolectric/TestActivity.java b/testapp/src/main/java/org/robolectric/TestActivity.java new file mode 100644 index 000000000..b53f24585 --- /dev/null +++ b/testapp/src/main/java/org/robolectric/TestActivity.java @@ -0,0 +1,6 @@ +package org.robolectric; + +import android.app.Activity; + +/** Test activity that is enabled in the manifest. */ +public class TestActivity extends Activity {} diff --git a/testapp/src/main/res/font/vt323_regular.ttf b/testapp/src/main/res/font/vt323_regular.ttf Binary files differnew file mode 100644 index 000000000..afa69098f --- /dev/null +++ b/testapp/src/main/res/font/vt323_regular.ttf diff --git a/testapp/src/main/res/values/ids.xml b/testapp/src/main/res/values/ids.xml index 5e485d50b..3975c1c46 100644 --- a/testapp/src/main/res/values/ids.xml +++ b/testapp/src/main/res/values/ids.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <item name="id_declared_in_item_tag" type="id"/> - <item name="id_with_string_value" type="id">string value</item> -</resources>
\ No newline at end of file + <item name="id_with_string_value" type="id"/> +</resources> diff --git a/testapp/src/main/res/values/plurals.xml b/testapp/src/main/res/values/plurals.xml index c0ef236b6..823968a14 100644 --- a/testapp/src/main/res/values/plurals.xml +++ b/testapp/src/main/res/values/plurals.xml @@ -1,10 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="beer"> - <item quantity="zero">@string/howdy</item> - <item quantity="one">One beer</item> - <item quantity="two">Two beers</item> - <item quantity="other">%d beers, yay!</item> + <!-- + In us-en locale, only one and other plurals are used because there are only two possible + variants: singular vs plural tense. + --> + <item quantity="one">a beer</item> + <item quantity="other">some beers</item> </plurals> <plurals name="minute"> <item quantity="one">@string/minute_singular</item> diff --git a/utils/build.gradle b/utils/build.gradle index 3a3440f79..3c6ed75c5 100644 --- a/utils/build.gradle +++ b/utils/build.gradle @@ -1,17 +1,11 @@ -plugins { - id "net.ltgt.errorprone" version "0.0.13" -} - new RoboJavaModulePlugin( deploy: true ).apply(project) dependencies { - // Compile dependencies - compile project(":annotations") + api project(":annotations") - // Testing dependencies - testCompile "junit:junit:4.12" - testCompile "com.google.truth:truth:0.39" - testCompile "org.mockito:mockito-core:2.5.4" -}
\ No newline at end of file + testImplementation "junit:junit:4.12" + testImplementation "com.google.truth:truth:0.42" + testImplementation "org.mockito:mockito-core:2.5.4" +} diff --git a/utils/src/main/java/org/robolectric/util/Scheduler.java b/utils/src/main/java/org/robolectric/util/Scheduler.java index d027af673..3813a4358 100644 --- a/utils/src/main/java/org/robolectric/util/Scheduler.java +++ b/utils/src/main/java/org/robolectric/util/Scheduler.java @@ -4,27 +4,27 @@ import static org.robolectric.util.Scheduler.IdleState.CONSTANT_IDLE; import static org.robolectric.util.Scheduler.IdleState.PAUSED; import static org.robolectric.util.Scheduler.IdleState.UNPAUSED; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.ListIterator; +import java.util.Iterator; +import java.util.PriorityQueue; import java.util.concurrent.TimeUnit; /** - * Class that manages a queue of Runnables that are scheduled to run now (or at some time in - * the future). Runnables that are scheduled to run on the UI thread (tasks, animations, etc) - * eventually get routed to a Scheduler instance. - * - * The execution of a scheduler can be in one of three states: - * <ul><li>paused ({@link #pause()}): if paused, then no posted events will be run unless the Scheduler - * is explicitly instructed to do so.</li> - * <li>normal ({@link #unPause()}): if not paused but not set to idle constantly, then the Scheduler will - * automatically run any {@link Runnable}s that are scheduled to run at or before the - * Scheduler's current time, but it won't automatically run any future events. To - * run future events the Scheduler needs to have its clock advanced.</li> - * <li>idling constantly: if {@link #idleConstantly(boolean)} is called with - * <tt>true</tt>, then the Scheduler will continue looping through posted events - * (including future events), advancing its clock as it goes.</li> + * Class that manages a queue of Runnables that are scheduled to run now (or at some time in the + * future). Runnables that are scheduled to run on the UI thread (tasks, animations, etc) eventually + * get routed to a Scheduler instance. + * + * <p>The execution of a scheduler can be in one of three states: + * + * <ul> + * <li>paused ({@link #pause()}): if paused, then no posted events will be run unless the + * Scheduler is explicitly instructed to do so, correctly matching Android's behavior. + * <li>normal ({@link #unPause()}): if not paused but not set to idle constantly, then the + * Scheduler will automatically run any {@link Runnable}s that are scheduled to run at or + * before the Scheduler's current time, but it won't automatically run any future events. To + * run future events the Scheduler needs to have its clock advanced. + * <li>idling constantly: if {@link #idleConstantly(boolean)} is called with <tt>true</tt>, then + * the Scheduler will continue looping through posted events (including future events), + * advancing its clock as it goes. * </ul> */ public class Scheduler { @@ -49,11 +49,17 @@ public class Scheduler { CONSTANT_IDLE } - private final static long START_TIME = 100; + private static final long START_TIME = 100; private volatile long currentTime = START_TIME; + /** + * PriorityQueue doesn't maintain ordering based on insertion; track that ourselves to preserve + * FIFO order for posted runnables with the same scheduled time. + */ + private long nextTimeDisambiguator = 0; + private boolean isExecutingRunnable = false; private final Thread associatedThread = Thread.currentThread(); - private final List<ScheduledRunnable> runnables = new ArrayList<>(); + private final PriorityQueue<ScheduledRunnable> runnables = new PriorityQueue<>(); private volatile IdleState idleState = UNPAUSED; /** @@ -151,7 +157,7 @@ public class Scheduler { public synchronized void postDelayed(Runnable runnable, long delay, TimeUnit unit) { long delayMillis = unit.toMillis(delay); if ((idleState != CONSTANT_IDLE && (isPaused() || delayMillis > 0)) || Thread.currentThread() != associatedThread) { - queueRunnableAndSort(runnable, currentTime + delayMillis); + runnables.add(new ScheduledRunnable(runnable, currentTime + delayMillis)); } else { runOrQueueRunnable(runnable, currentTime + delayMillis); } @@ -164,7 +170,13 @@ public class Scheduler { */ public synchronized void postAtFrontOfQueue(Runnable runnable) { if (isPaused() || Thread.currentThread() != associatedThread) { - runnables.add(0, new ScheduledRunnable(runnable, currentTime)); + final long timeDisambiguator; + if (runnables.isEmpty()) { + timeDisambiguator = nextTimeDisambiguator++; + } else { + timeDisambiguator = runnables.peek().timeDisambiguator - 1; + } + runnables.add(new ScheduledRunnable(runnable, 0, timeDisambiguator)); } else { runOrQueueRunnable(runnable, currentTime); } @@ -176,22 +188,28 @@ public class Scheduler { * @param runnable Runnable to remove. */ public synchronized void remove(Runnable runnable) { - ListIterator<ScheduledRunnable> iterator = runnables.listIterator(); + Iterator<ScheduledRunnable> iterator = runnables.iterator(); while (iterator.hasNext()) { - ScheduledRunnable next = iterator.next(); - if (next.runnable == runnable) { + if (iterator.next().runnable == runnable) { iterator.remove(); } } } /** - * Run all runnables in the queue. + * Run all runnables in the queue, and any additional runnables they schedule that are scheduled + * before the latest scheduled runnable currently in the queue. * - * @return True if a runnable was executed. + * @return True if a runnable was executed. */ public synchronized boolean advanceToLastPostedRunnable() { - return size() >= 1 && advanceTo(runnables.get(runnables.size() - 1).scheduledTime); + long currentMaxTime = currentTime; + for (ScheduledRunnable scheduled : runnables) { + if (currentMaxTime < scheduled.scheduledTime) { + currentMaxTime = scheduled.scheduledTime; + } + } + return advanceTo(currentMaxTime); } /** @@ -200,7 +218,7 @@ public class Scheduler { * @return True if a runnable was executed. */ public synchronized boolean advanceToNextPostedRunnable() { - return size() >= 1 && advanceTo(runnables.get(0).scheduledTime); + return !runnables.isEmpty() && advanceTo(runnables.peek().scheduledTime); } /** @@ -232,7 +250,7 @@ public class Scheduler { * @return True if a runnable was executed. */ public synchronized boolean advanceTo(long endTime) { - if (endTime - currentTime < 0 || size() < 1) { + if (endTime < currentTime || runnables.isEmpty()) { currentTime = endTime; return false; } @@ -252,14 +270,15 @@ public class Scheduler { * @return True if a runnable was executed. */ public synchronized boolean runOneTask() { - if (size() < 1) { - return false; + ScheduledRunnable postedRunnable = runnables.poll(); + if (postedRunnable != null) { + if (postedRunnable.scheduledTime > currentTime) { + currentTime = postedRunnable.scheduledTime; + } + postedRunnable.run(); + return true; } - - ScheduledRunnable postedRunnable = runnables.remove(0); - currentTime = postedRunnable.scheduledTime; - postedRunnable.run(); - return true; + return false; } /** @@ -306,12 +325,12 @@ public class Scheduler { } private boolean nextTaskIsScheduledBefore(long endingTime) { - return size() > 0 && runnables.get(0).scheduledTime <= endingTime; + return !runnables.isEmpty() && runnables.peek().scheduledTime <= endingTime; } private void runOrQueueRunnable(Runnable runnable, long scheduledTime) { if (isExecutingRunnable) { - queueRunnableAndSort(runnable, scheduledTime); + runnables.add(new ScheduledRunnable(runnable, scheduledTime)); return; } isExecutingRunnable = true; @@ -337,23 +356,28 @@ public class Scheduler { } } - private void queueRunnableAndSort(Runnable runnable, long scheduledTime) { - runnables.add(new ScheduledRunnable(runnable, scheduledTime)); - Collections.sort(runnables); - } - private class ScheduledRunnable implements Comparable<ScheduledRunnable> { private final Runnable runnable; private final long scheduledTime; + private final long timeDisambiguator; private ScheduledRunnable(Runnable runnable, long scheduledTime) { + this(runnable, scheduledTime, nextTimeDisambiguator++); + } + + private ScheduledRunnable(Runnable runnable, long scheduledTime, long timeDisambiguator) { this.runnable = runnable; this.scheduledTime = scheduledTime; + this.timeDisambiguator = timeDisambiguator; } @Override public int compareTo(ScheduledRunnable runnable) { - return Long.compare(scheduledTime, runnable.scheduledTime); + int timeCompare = Long.compare(scheduledTime, runnable.scheduledTime); + if (timeCompare == 0) { + return Long.compare(timeDisambiguator, runnable.timeDisambiguator); + } + return timeCompare; } public void run() { diff --git a/utils/src/test/java/org/robolectric/util/SchedulerTest.java b/utils/src/test/java/org/robolectric/util/SchedulerTest.java index 4fcfe1110..df3e583c2 100644 --- a/utils/src/test/java/org/robolectric/util/SchedulerTest.java +++ b/utils/src/test/java/org/robolectric/util/SchedulerTest.java @@ -5,8 +5,13 @@ import static org.robolectric.util.Scheduler.IdleState.CONSTANT_IDLE; import static org.robolectric.util.Scheduler.IdleState.PAUSED; import static org.robolectric.util.Scheduler.IdleState.UNPAUSED; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.TreeMap; import java.util.concurrent.atomic.AtomicLong; import org.junit.Before; import org.junit.Test; @@ -456,6 +461,52 @@ public class SchedulerTest { assertThat(runnablesThatWereRun).containsExactly(1, 2); } + @Test + public void testTimeNotChangedByNegativeDelay() throws Exception { + long currentTime = scheduler.getCurrentTime(); + long[] observedTime = new long[1]; + scheduler.postDelayed( + new Runnable() { + @Override + public void run() { + observedTime[0] = scheduler.getCurrentTime(); + } + }, + -1000); + scheduler.advanceToLastPostedRunnable(); + assertThat(observedTime[0]).isEqualTo(currentTime); + assertThat(scheduler.getCurrentTime()).isEqualTo(currentTime); + } + + /** Tests for quadractic or exponential behavior in the scheduler, and stable sorting */ + @Test(timeout = 1000) + public void schedulerWithManyRunnables() { + Random random = new Random(0); + Map<Integer, List<Integer>> orderCheck = new TreeMap<>(); + List<Integer> actualOrder = new ArrayList<>(); + for (int i = 0; i < 20_000; i++) { + int delay = random.nextInt(10); + List<Integer> list = orderCheck.get(delay); + if (list == null) { + list = new ArrayList<>(); + orderCheck.put(delay, list); + } + list.add(i); + final int localI = i; + scheduler.postDelayed( + new Runnable() { + @Override + public void run() { + actualOrder.add(localI); + } + }, + delay); + } + assertThat(actualOrder).isEmpty(); + scheduler.advanceToLastPostedRunnable(); + assertThat(actualOrder).isEqualTo(ImmutableList.copyOf(Iterables.concat(orderCheck.values()))); + } + @Test(timeout=1000) public void schedulerAllowsConcurrentTimeRead_whileLockIsHeld() throws InterruptedException { final AtomicLong l = new AtomicLong(); |