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

Commit 03dd48c8 authored by Adrian Roos's avatar Adrian Roos
Browse files

ActivityThread: Preserve windows when relaunching all activities

Fixes flickers that occur during overlay changes.

Bug: 130415897
Test: atest ActivityThreadTest
Change-Id: Iaa52b706bd8426ea34689e21b82e558cb700d5d8
parent c53df3a9
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS;
import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
import static android.view.Display.INVALID_DISPLAY;

import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
@@ -4561,7 +4563,7 @@ public final class ActivityThread extends ClientTransactionHandler {
    private void onCoreSettingsChange() {
        if (updateDebugViewAttributeState()) {
            // request all activities to relaunch for the changes to take place
            relaunchAllActivities();
            relaunchAllActivities(false /* preserveWindows */);
        }
    }

@@ -4578,10 +4580,13 @@ public final class ActivityThread extends ClientTransactionHandler {
        return previousState != View.sDebugViewAttributes;
    }

    private void relaunchAllActivities() {
    private void relaunchAllActivities(boolean preserveWindows) {
        for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
            final Activity activity = entry.getValue().activity;
            if (!activity.mFinished) {
            final ActivityClientRecord r = entry.getValue();
            if (!r.activity.mFinished) {
                if (preserveWindows && r.window != null) {
                    r.mPreserveWindow = true;
                }
                scheduleRelaunchActivity(entry.getKey());
            }
        }
@@ -5414,7 +5419,8 @@ public final class ActivityThread extends ClientTransactionHandler {
        }
    }

    void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
    @VisibleForTesting(visibility = PACKAGE)
    public void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
        // Updates triggered by package installation go through a package update
        // receiver. Here we try to capture ApplicationInfo changes that are
        // caused by other sources, such as overlays. That means we want to be as conservative
@@ -5460,7 +5466,8 @@ public final class ActivityThread extends ClientTransactionHandler {
        newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1;
        handleConfigurationChanged(newConfig, null);

        relaunchAllActivities();
        // Preserve windows to avoid black flickers when overlays change.
        relaunchAllActivities(true /* preserveWindows */);
    }

    static void freeTextLayoutCachesIfNeeded(int configDiff) {
+29 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.content.res.Configuration;
import android.os.IBinder;
import android.util.MergedConfiguration;
import android.view.Display;
import android.view.View;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
@@ -152,6 +153,34 @@ public class ActivityThreadTest {
        });
    }

    @Test
    public void testHandleActivity_assetsChanged() {
        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());

        final IBinder[] token = new IBinder[1];
        final View[] decorView = new View[1];

        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            final ActivityThread activityThread = activity.getActivityThread();

            token[0] = activity.getActivityToken();
            decorView[0] = activity.getWindow().getDecorView();

            // Relaunches all activities
            activityThread.handleApplicationInfoChanged(activity.getApplicationInfo());
        });

        final View[] newDecorView = new View[1];
        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
            final ActivityThread activityThread = activity.getActivityThread();

            final Activity newActivity = activityThread.getActivity(token[0]);
            newDecorView[0] = activity.getWindow().getDecorView();
        });

        assertEquals("Window must be preserved", decorView[0], newDecorView[0]);
    }

    @Test
    public void testHandleActivityConfigurationChanged_DropStaleConfigurations() {
        final TestActivity activity = mActivityTestRule.launchActivity(new Intent());