Skip to content

Commit

Permalink
Merge pull request #26 from sergio-sastre/release/1.2.2
Browse files Browse the repository at this point in the history
Release/1.2.2
  • Loading branch information
sergio-sastre authored Nov 1, 2022
2 parents 5a9d476 + 50d97c7 commit 8e6fe37
Show file tree
Hide file tree
Showing 13 changed files with 181 additions and 134 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ You can find out why verifying our design under such configurations is important

In the near future, there are plans to also support, among others:

1. Enable **framework-agnostic** & **shared screenshot testing** i.e. same test running either on device or on JVM
1. **framework-agnostic** & **shared screenshot testing** i.e. same test running either on device or on JVM
2. Reduce snapshot testing flakiness
3. Folding features
4. Enable Accessibility features
4. Accessibility features

## Sponsors

Expand Down Expand Up @@ -93,7 +93,7 @@ dependencies {
First, you need to add the following permission and activities to your `debug/manifest`

```xml
<!-- Required for ActivityScenarios -->
<!-- Required for ActivityScenarios only -->
<application...
<activity
android:name="sergio.sastre.uitesting.utils.activityscenario.ActivityScenarioConfigurator$PortraitSnapshotConfiguredActivity"
Expand Down Expand Up @@ -124,7 +124,7 @@ android {
To change the System Locale, you also need to add the following permission to your `debug/manifest`

```xml
<!-- Required to change the Locale via SystemLocaleTestRule (required for snapshot testing Activities only) -->
<!-- Required to change the Locale via SystemLocaleTestRule (e.g. for snapshot testing Activities) -->
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION"
tools:ignore="ProtectedPermissions" />
```
Expand All @@ -133,10 +133,10 @@ To change the App Locale via `LocaleTestRule`, you need to add the following dep
```kotlin
compileSdkVersion 33
...
androidTestImplementation 'androidx.appcompat:appcompat:1.6.0-rc01'
androidTestImplementation 'androidx.appcompat:appcompat:1.6.0-alpha04' //or higher version!
```
**Warning**: `LocaleTestRule` does ONLY work with **ActivityScenarioConfigurator.ForActivity()**, i.e. it
does not work with **ActivityScenarioForActivityRule**. Moreover, for **Fragments**, **Views** and **Composables** call the
does not work with **ActivityScenarioForActivityRule**. However, for **Fragments**, **Views** and **Composables** call the
`setLocale("my_locale")` of their corresponding Fragment/ActivityScenarioConfigurator or the `ConfigItem(locale = "myLocale")` of their corresponding TestRule e.g. to achieve it:
```kotlin
ActivityScenarioConfigurator.ForView().setLocale("my_locale")
Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ android {

dependencies {
implementation project(':utils')
implementation 'com.google.android.material:material:1.6.1'
implementation 'com.google.android.material:material:1.7.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package sergio.sastre.uitesting.myapplication

import org.junit.Test
import sergio.sastre.uitesting.utils.common.LocaleUtil

class LocaleUtilTests {

@Test
fun testLocaleWithAllVariants(){
val localeString = "zh-Latn-TW-pinyin"
val locale = LocaleUtil.localeFromString(localeString)
assert(locale.language == "zh")
assert(locale.script == "Latn")
assert(locale.country == "TW")
assert(locale.variant == "pinyin")
}

@Test
fun testSerbianLatin(){
val localeString = "sr-Latn-RS"
val locale = LocaleUtil.localeFromString(localeString)
assert(locale.language == "sr")
assert(locale.script == "Latn")
assert(locale.country == "RS")
}

@Test
fun testSerbianCyrillic(){
val localeString = "sr-Cyrl-RS"
val locale = LocaleUtil.localeFromString(localeString)
assert(locale.language == "sr")
assert(locale.script == "Cyrl")
assert(locale.country == "RS")
}

@Test
fun testSerbianRegion(){
val localeString = "sr-RS"
val locale = LocaleUtil.localeFromString(localeString)
assert(locale.language == "sr")
assert(locale.country == "RS")
}

@Test
fun testISOLocale(){
val localeString = "en_US"
val locale = LocaleUtil.localeFromString(localeString)
assert(locale.language == "en")
assert(locale.country == "US")
}

@Test
fun testPseudolocale(){
val localeString = "en_XA"
val locale = LocaleUtil.localeFromString(localeString)
assert(locale.language == "en")
assert(locale.country == "XA")
}
}
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
maven { url 'https://jitpack.io' }
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0"

// NOTE: Do not place your application dependencies here; they belong
Expand Down
19 changes: 10 additions & 9 deletions utils/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
minSdk 21
targetSdk 33

versionCode 9
versionName "1.2.1"
versionCode 10
versionName "1.2.2"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
Expand All @@ -30,19 +30,20 @@ android {
}
kotlinOptions {
jvmTarget = '1.8'
freeCompilerArgs +=["-Xjvm-default=all",]
freeCompilerArgs += ["-Xjvm-default=all"]
}
}

dependencies {
api 'androidx.appcompat:appcompat:1.6.0-rc01'
api 'com.google.android.material:material:1.6.1'
api 'androidx.appcompat:appcompat:1.7.0-alpha01'
api 'com.google.android.material:material:1.7.0'
api 'androidx.test:core:1.5.0-rc01'
api 'androidx.core:core-ktx:1.9.0'
api 'androidx.test.ext:junit:1.1.3'
api 'androidx.test.espresso:espresso-core:3.4.0'
api 'androidx.compose.ui:ui-test-junit4:1.2.1'
api 'androidx.fragment:fragment-ktx:1.5.3'
api 'org.lsposed.hiddenapibypass:hiddenapibypass:4.3'
api 'androidx.compose.ui:ui-test-junit4:1.3.0'
api 'androidx.fragment:fragment-ktx:1.5.4'
implementation 'org.lsposed.hiddenapibypass:hiddenapibypass:4.3'
}

//https://www.talentica.com/blogs/publish-your-android-library-on-jitpack-for-better-reachability/
Expand All @@ -53,7 +54,7 @@ afterEvaluate {
from components.release
groupId = 'sergio.sastre'
artifactId = 'uitesting.utils'
version = '1.2.1'
version = '1.2.2'
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package sergio.sastre.uitesting.utils.common;

import static androidx.test.platform.app.InstrumentationRegistry.getArguments;

import android.annotation.SuppressLint;
import android.content.res.Configuration;
import android.os.Build;
import android.os.LocaleList;
import android.util.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;

import org.lsposed.hiddenapibypass.HiddenApiBypass;

/**
* Code strongly based on that from fastlane Screengrab, but adding a bugfix for calling the
* updateConfiguration method, which was added to the non-SDK interface list since API 28:
* https://github.com/fastlane/fastlane/blob/master/screengrab/screengrab-lib/src/main/java/tools.fastlane.screengrab/locale
* Code strongly based on that from fastlane Screengrab, but
* 1. adding a bugfix for calling the updateConfiguration method, which was added to
* the non-SDK interface list since API 28:
* https://github.com/fastlane/fastlane/blob/master/screengrab/screengrab-lib/src/main/java/tools.fastlane.screengrab/locale
* 2. Add support for complex Locales like "sr-Latn-RS", "sr-Cyrl-RS" or "zh-Latn-TW-pinyin"
*
* Converting it to Kotlin led to errors while using pseudlocales
*/
Expand Down Expand Up @@ -51,35 +52,8 @@ public static LocaleListCompat changeDeviceLocaleTo(LocaleListCompat locale) {
Configuration config =
(Configuration) methodGetConfiguration.invoke(activityManagerNative);

config.getClass().getField("userSetLocale").setBoolean(config, true);
LocaleListCompat ret;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ret = new LocaleListCompat(config.getLocales());
} else {
ret = new LocaleListCompat(config.locale);
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
config.setLocales(locale.getLocaleList());
} else {
config.locale = locale.getLocale();
}

config.setLayoutDirection(locale.getPreferredLocale());

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
HiddenApiBypass.invoke(
amnClass,
activityManagerNative,
"updateConfiguration",
config
);
} else {
Method updateConfigurationMethod =
amnClass.getMethod("updateConfiguration", Configuration.class);
updateConfigurationMethod.setAccessible(true);
updateConfigurationMethod.invoke(activityManagerNative, config);
}
LocaleListCompat ret = updateLocale(locale, config);
updateConfiguration(amnClass, activityManagerNative, config);
Log.d(TAG, "Locale changed to " + locale);
return ret;
} catch (Exception var8) {
Expand All @@ -88,15 +62,52 @@ public static LocaleListCompat changeDeviceLocaleTo(LocaleListCompat locale) {
}
}

/**
* @deprecated
*/
@Deprecated
private static LocaleListCompat updateLocale(
LocaleListCompat locale,
Configuration config
) throws NoSuchFieldException, IllegalAccessException {
config.getClass().getField("userSetLocale").setBoolean(config, true);
LocaleListCompat ret;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ret = new LocaleListCompat(config.getLocales());
} else {
ret = new LocaleListCompat(config.locale);
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
config.setLocales(locale.getLocaleList());
} else {
config.locale = locale.getLocale();
}
config.setLayoutDirection(locale.getPreferredLocale());
return ret;
}

private static void updateConfiguration(
Class<?> amnClass,
Object activityManagerNative,
Configuration config
) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
HiddenApiBypass.invoke(
amnClass,
activityManagerNative,
"updateConfiguration",
config
);
} else {
Method updateConfigurationMethod =
amnClass.getMethod("updateConfiguration", Configuration.class);
updateConfigurationMethod.setAccessible(true);
updateConfigurationMethod.invoke(activityManagerNative, config);
}
}

public static void changeDeviceLocaleTo(Locale locale) {
changeDeviceLocaleTo(new LocaleListCompat(locale));
}

public static String[] localePartsFrom(String localeString) {
private static String[] localePartsFrom(String localeString) {
if (localeString == null) {
return null;
} else {
Expand All @@ -105,7 +116,7 @@ public static String[] localePartsFrom(String localeString) {
}
}

public static Locale localeFromParts(String[] localeParts) {
private static Locale localeFromParts(String[] localeParts) {
if (localeParts != null && localeParts.length != 0) {
if (localeParts.length == 1) {
return new Locale(localeParts[0]);
Expand All @@ -120,11 +131,13 @@ public static Locale localeFromParts(String[] localeParts) {
}

public static Locale localeFromString(String locale) {
return localeFromParts(localePartsFrom(locale));
}

public static String getTestLocale() {
return getArguments().getString("testLocale");
Locale localeForTag = Locale.forLanguageTag(locale);
if (localeForTag.toString().isEmpty()) {
return localeFromParts(localePartsFrom(locale));
} else {
// Locales passed in ISO form like "en_US" or pseudolocales "en_XA", "ar_XB"
return localeForTag;
}
}

private LocaleUtil() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,34 @@ package sergio.sastre.uitesting.utils.testrules.displaysize

import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import sergio.sastre.uitesting.utils.common.DisplaySize
import sergio.sastre.uitesting.utils.utils.waitForExecuteShellCommand

class DisplayScaleSetting internal constructor() {

private val resources
get() = getInstrumentation().targetContext.resources

fun getDensityDpi(): Int {
return resources.configuration.densityDpi
}
val densityDpi: Int
get() = resources.configuration.densityDpi

fun setDisplaySizeScale(originalDensity: Int) {
fun resetDisplaySizeScale(originalDensity: Int) {
try {
getInstrumentation().uiAutomation.executeShellCommand("wm density reset")
getInstrumentation().waitForExecuteShellCommand("wm density reset")
} catch (e: Exception) {
throw RuntimeException("Unable to reset densityDpi to $originalDensity")
}
}

fun setDisplaySizeScale(scale: DisplaySize) {
fun setDisplaySizeScale(targetDensity: Int) {
try {
val targetDensityDpi = resources.configuration.densityDpi * (scale.value).toFloat()
getInstrumentation().uiAutomation
.executeShellCommand("wm density " + targetDensityDpi.toInt())
getInstrumentation().waitForExecuteShellCommand("wm density $targetDensity")
} catch (e: Exception) {
throw RuntimeException("Unable to set display size with scale ${scale.name} = ${scale.value}")
throw RuntimeException("Unable to set display size with density $targetDensity")
}
}

fun setDisplaySizeScale(scale: DisplaySize) {
val targetDensity = densityDpi * (scale.value).toFloat()
setDisplaySizeScale(targetDensity.toInt())
}
}
Loading

0 comments on commit 8e6fe37

Please sign in to comment.