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

Commit cf8f6834 authored by Andrii Kulian's avatar Andrii Kulian
Browse files

Set ActivityView background to current top task's color

When ActivityView is being resized to a bigger region and an app
in it hasn't received new configuration yet, it will continue
drawing in old smaller size for some time. This results in black
bars being drawn in expanded area.
This CL tracks the topmost task launched on the ActivityView and
uses its background color to fill this expanded area.

Bug: 72220802
Test: Launch activity on ActivityView, resize and observe background
Change-Id: Id7090a1ad5ec49a31c19fe185fb3815b1788e77f
parent 811c3765
Loading
Loading
Loading
Loading
+60 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.app;

import android.annotation.NonNull;
import android.app.ActivityManager.StackInfo;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DisplayManager;
@@ -38,6 +39,8 @@ import android.view.WindowManagerGlobal;

import dalvik.system.CloseGuard;

import java.util.List;

/**
 * Activity container that allows launching activities into itself and does input forwarding.
 * <p>Creation of this view is only allowed to callers who have
@@ -58,10 +61,13 @@ public class ActivityView extends ViewGroup {
    private final SurfaceCallback mSurfaceCallback;
    private StateCallback mActivityViewCallback;

    private IActivityManager mActivityManager;
    private IInputForwarder mInputForwarder;
    // Temp container to store view coordinates on screen.
    private final int[] mLocationOnScreen = new int[2];

    private TaskStackListener mTaskStackListener;

    private final CloseGuard mGuard = CloseGuard.get();
    private boolean mOpened; // Protected by mGuard.

@@ -76,6 +82,7 @@ public class ActivityView extends ViewGroup {
    public ActivityView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mActivityManager = ActivityManager.getService();
        mSurfaceView = new SurfaceView(context);
        mSurfaceCallback = new SurfaceCallback();
        mSurfaceView.getHolder().addCallback(mSurfaceCallback);
@@ -303,6 +310,12 @@ public class ActivityView extends ViewGroup {

        mInputForwarder = InputManager.getInstance().createInputForwarder(
                mVirtualDisplay.getDisplay().getDisplayId());
        mTaskStackListener = new TaskBackgroundChangeListener();
        try {
            mActivityManager.registerTaskStackListener(mTaskStackListener);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to register task stack listener", e);
        }
    }

    private void performRelease() {
@@ -317,6 +330,15 @@ public class ActivityView extends ViewGroup {
        }
        cleanTapExcludeRegion();

        if (mTaskStackListener != null) {
            try {
                mActivityManager.unregisterTaskStackListener(mTaskStackListener);
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to unregister task stack listener", e);
            }
            mTaskStackListener = null;
        }

        final boolean displayReleased;
        if (mVirtualDisplay != null) {
            mVirtualDisplay.release();
@@ -369,4 +391,42 @@ public class ActivityView extends ViewGroup {
            super.finalize();
        }
    }

    /**
     * A task change listener that detects background color change of the topmost stack on our
     * virtual display and updates the background of the surface view. This background will be shown
     * when surface view is resized, but the app hasn't drawn its content in new size yet.
     */
    private class TaskBackgroundChangeListener extends TaskStackListener {

        @Override
        public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
                throws RemoteException {
            if (mVirtualDisplay == null) {
                return;
            }

            // Find the topmost task on our virtual display - it will define the background
            // color of the surface view during resizing.
            final int displayId = mVirtualDisplay.getDisplay().getDisplayId();
            final List<StackInfo> stackInfoList = mActivityManager.getAllStackInfos();

            // Iterate through stacks from top to bottom.
            final int stackCount = stackInfoList.size();
            for (int i = 0; i < stackCount; i++) {
                final StackInfo stackInfo = stackInfoList.get(i);
                // Only look for stacks on our virtual display.
                if (stackInfo.displayId != displayId) {
                    continue;
                }
                // Found the topmost stack on target display. Now check if the topmost task's
                // description changed.
                if (taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
                    mSurfaceView.setResizeBackgroundColor(td.getBackgroundColor());
                }
                break;
            }
        }
    }

}
+26 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.res.CompatibilityInfo.Translator;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
@@ -114,7 +115,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
    final Rect mScreenRect = new Rect();
    SurfaceSession mSurfaceSession;

    SurfaceControl mSurfaceControl;
    SurfaceControlWithBackground mSurfaceControl;
    // In the case of format changes we switch out the surface in-place
    // we need to preserve the old one until the new one has drawn.
    SurfaceControl mDeferredDestroySurfaceControl;
@@ -925,6 +926,17 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
        return mSubLayer >= 0;
    }

    /**
     * Set an opaque background color to use with this {@link SurfaceView} when it's being resized
     * and size of the content hasn't updated yet. This color will fill the expanded area when the
     * view becomes larger.
     * @param bgColor An opaque color to fill the background. Alpha component will be ignored.
     * @hide
     */
    public void setResizeBackgroundColor(int bgColor) {
        mSurfaceControl.setBackgroundColor(bgColor);
    }

    private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
        private static final String LOG_TAG = "SurfaceHolder";

@@ -1219,6 +1231,19 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
            mBackgroundControl.deferTransactionUntil(barrier, frame);
        }

        /** Set the color to fill the background with. */
        private void setBackgroundColor(int bgColor) {
            final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
                    Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };

            SurfaceControl.openTransaction();
            try {
                mBackgroundControl.setColor(colorComponents);
            } finally {
                SurfaceControl.closeTransaction();
            }
        }

        void updateBackgroundVisibility() {
            if (mOpaque && mVisible) {
                mBackgroundControl.show();