Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 079a5d21 authored by Tyler Freeman's avatar Tyler Freeman
Browse files

feat(non linear font scaling): add test activity for end-to-end tests

Fix: 256929929
Test: atest FrameworksCoreTests:android.content.res.FontScaleConverterActivityTest

Change-Id: I260b939a568ee47ac9d5c8620b93f16c756339eb
parent 33561629
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -1691,6 +1691,10 @@
                  android:exported="true">
        </activity>

        <activity android:name="android.content.res.FontScaleConverterActivityTest$TestActivity"
                  android:exported="true">
        </activity>

        <service android:name="android.view.stylus.HandwritingImeService"
                 android:label="Handwriting IME"
                 android:permission="android.permission.BIND_INPUT_METHOD"
+41 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2023 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView android:id="@+id/text8sp"
        android:text="@string/view"
        android:textSize="8sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView android:id="@+id/text18sp"
        android:text="@string/view"
        android:textSize="18sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView android:id="@+id/text35sp"
        android:text="@string/view"
        android:textSize="35sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
+188 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.content.res;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.withId;

import static com.google.common.truth.Truth.assertThat;

import android.app.Activity;
import android.compat.testing.PlatformCompatChangeRule;
import android.os.Bundle;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.view.View;
import android.widget.TextView;

import androidx.test.core.app.ActivityScenario;
import androidx.test.espresso.matcher.BoundedMatcher;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;

import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.frameworks.coretests.R;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;

import java.util.concurrent.atomic.AtomicReference;

/**
 * Test for verifying non-linear font scaling behavior.
 * Build/Install/Run:
 *  atest FrameworksCoreTests:android.content.res.FontScaleConverterActivityTest
 */
@RunWith(AndroidJUnit4.class)
@LargeTest
@Presubmit
public class FontScaleConverterActivityTest {
    @Rule
    public ActivityScenarioRule<TestActivity> rule = new ActivityScenarioRule<>(TestActivity.class);
    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();

    private float mOriginalFontScale = Float.MIN_VALUE;

    @Before
    public void setup() {
        mOriginalFontScale = Settings.System.getFloat(
            InstrumentationRegistry.getInstrumentation().getContext().getContentResolver(),
            Settings.System.FONT_SCALE,
            Float.MIN_VALUE
        );
    }

    @After
    public void teardown() {
        if (mOriginalFontScale != Float.MIN_VALUE) {
            setSystemFontScale(mOriginalFontScale);
        }
    }

    @Test
    public void testFontsScaleNonLinearly() {
        final ActivityScenario<TestActivity> scenario = rule.getScenario();

        setSystemFontScale(2f);

        var densityRef = new AtomicReference<Float>();
        scenario.onActivity(activity -> {
            densityRef.compareAndSet(null, activity.getResources().getDisplayMetrics().density);
        });
        var density = densityRef.get();
        assertThat(density).isNotNull();

        onView(withId(R.id.text8sp)).check(matches(withTextSizeInRange(
                15f * density,
                16f * density
        )));
        onView(withId(R.id.text18sp)).check(matches(withTextSizeInRange(
                20f * density,
                36f * density
        )));
        onView(withId(R.id.text35sp)).check(matches(withTextSizeInRange(
                35 * density,
                60 * density
        )));
    }

    @Test
    public void testOnConfigurationChanged_doesNotCrash() {
        final ActivityScenario<TestActivity> scenario = rule.getScenario();

        scenario.onActivity(activity -> {
            var config = new Configuration(activity.getResources().getConfiguration());
            config.fontScale = 1.2f;

            activity.onConfigurationChanged(config);
            activity.finish();
        });
    }

    @Test
    public void testUpdateConfiguration_doesNotCrash() {
        final ActivityScenario<TestActivity> scenario = rule.getScenario();

        scenario.onActivity(activity -> {
            activity.updateConfiguration();
            activity.finish();
        });
    }

    private static void setSystemFontScale(float fontScale) {
        ShellIdentityUtils.invokeWithShellPermissions(() -> {
            Settings.System.putFloat(
                    InstrumentationRegistry.getInstrumentation().getContext().getContentResolver(),
                    Settings.System.FONT_SCALE,
                    fontScale
            );
        });
    }

    private Matcher<View> withTextSizeInRange(float sizeStartPx, float sizeEndPx) {
        return new BoundedMatcher<>(TextView.class) {
            private static final float TOLERANCE = 0.05f;

            @Override
            public void describeMismatch(Object item, Description description) {
                super.describeMismatch(item, description);
                description.appendText("was ").appendValue(((TextView) item).getTextSize());
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("withTextSize between " + sizeStartPx + " and " + sizeEndPx);
            }

            @Override
            protected boolean matchesSafely(TextView textView) {
                var textSize = textView.getTextSize();
                return sizeStartPx - TOLERANCE < textSize && textSize < sizeEndPx + TOLERANCE;
            }
        };
    }

    /** Test Activity */
    public static class TestActivity extends Activity {
        final Configuration mConfig = new Configuration();

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getWindow().getDecorView().setKeepScreenOn(true);
            setShowWhenLocked(true);
            setTurnScreenOn(true);

            setContentView(R.layout.font_scale_converter_activity);
        }

        public Configuration updateConfiguration() {
            Settings.System.getConfiguration(getContentResolver(), mConfig);
            return mConfig;
        }
    }
}