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

Commit 6eb44a97 authored by Yuncheol Heo's avatar Yuncheol Heo Committed by Android (Google) Code Review
Browse files

Merge changes Ib0324ec0,I15b019cb

* changes:
  Add TaskViewFactory.
  Migrate touchable inset calulation from BubbleStackView to TaskView.
parents 94f87a8e f3929238
Loading
Loading
Loading
Loading
+115 −69
Original line number Diff line number Diff line
@@ -29,11 +29,14 @@ import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
import android.util.CloseGuard;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewTreeObserver;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

@@ -44,7 +47,7 @@ import java.util.concurrent.Executor;
 * View that can display a task.
 */
public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
        ShellTaskOrganizer.TaskListener {
        ShellTaskOrganizer.TaskListener, ViewTreeObserver.OnComputeInternalInsetsListener {

    /** Callback for listening task state. */
    public interface Listener {
@@ -70,6 +73,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
    private final CloseGuard mGuard = new CloseGuard();

    private final ShellTaskOrganizer mTaskOrganizer;
    private final Executor mShellExecutor;

    private ActivityManager.RunningTaskInfo mTaskInfo;
    private WindowContainerToken mTaskToken;
@@ -78,16 +82,17 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
    private boolean mSurfaceCreated;
    private boolean mIsInitialized;
    private Listener mListener;
    private Executor mExecutor;
    private Executor mListenerExecutor;

    private final Rect mTmpRect = new Rect();
    private final Rect mTmpRootRect = new Rect();
    private final int[] mTmpLocation = new int[2];

    public TaskView(Context context, ShellTaskOrganizer organizer) {
        super(context, null, 0, 0, true /* disableBackgroundLayer */);

        mTaskOrganizer = organizer;
        mExecutor = organizer.getExecutor();
        mShellExecutor = organizer.getExecutor();
        setUseAlpha();
        getHolder().addCallback(this);
        mGuard.open("release");
@@ -96,12 +101,13 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
    /**
     * Only one listener may be set on the view, throws an exception otherwise.
     */
    public void setListener(Listener listener) {
    public void setListener(@NonNull Executor executor, Listener listener) {
        if (mListener != null) {
            throw new IllegalStateException(
                    "Trying to set a listener when one has already been set");
        }
        mListener = listener;
        mListenerExecutor = executor;
    }

    /**
@@ -146,7 +152,9 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,

    private void prepareActivityOptions(ActivityOptions options) {
        final Binder launchCookie = new Binder();
        mShellExecutor.execute(() -> {
            mTaskOrganizer.setPendingLaunchCookieListener(launchCookie, this);
        });
        options.setLaunchCookie(launchCookie);
        options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        options.setTaskAlwaysOnTop(true);
@@ -193,11 +201,15 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,

    private void performRelease() {
        getHolder().removeCallback(this);
        mShellExecutor.execute(() -> {
            mTaskOrganizer.removeListener(this);
            resetTaskInfo();
        });
        mGuard.close();
        if (mListener != null && mIsInitialized) {
            mListenerExecutor.execute(() -> {
                mListener.onReleased();
            });
            mIsInitialized = false;
        }
    }
@@ -214,15 +226,15 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
        mTaskOrganizer.applyTransaction(wct);
        // TODO(b/151449487): Only call callback once we enable synchronization
        if (mListener != null) {
            mListenerExecutor.execute(() -> {
                mListener.onTaskVisibilityChanged(mTaskInfo.taskId, mSurfaceCreated);
            });
        }
    }

    @Override
    public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl leash) {
        if (mExecutor == null) return;
        mExecutor.execute(() -> {
        mTaskInfo = taskInfo;
        mTaskToken = taskInfo.token;
        mTaskLeash = leash;
@@ -243,47 +255,43 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
        setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());

        if (mListener != null) {
            mListenerExecutor.execute(() -> {
                mListener.onTaskCreated(taskInfo.taskId, taskInfo.baseActivity);
            }
            });
        }
    }

    @Override
    public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
        if (mExecutor == null) return;
        mExecutor.execute(() -> {
        if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;

        if (mListener != null) {
            mListenerExecutor.execute(() -> {
                mListener.onTaskRemovalStarted(taskInfo.taskId);
            });
        }
        mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mTaskToken, false);

        // Unparent the task when this surface is destroyed
        mTransaction.reparent(mTaskLeash, null).apply();
        resetTaskInfo();
        });
    }

    @Override
    public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
        if (mExecutor == null) return;
        mExecutor.execute(() -> {
        mTaskInfo.taskDescription = taskInfo.taskDescription;
        setResizeBackgroundColor(taskInfo.taskDescription.getBackgroundColor());
        });
    }

    @Override
    public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
        if (mExecutor == null) return;
        mExecutor.execute(() -> {
        if (mTaskToken == null || !mTaskToken.equals(taskInfo.token)) return;
        if (mListener != null) {
            mListenerExecutor.execute(() -> {
                mListener.onBackPressedOnTaskRoot(taskInfo.taskId);
            }
            });
        }
    }

    @Override
    public void dump(@androidx.annotation.NonNull PrintWriter pw, String prefix) {
@@ -302,8 +310,11 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
        mSurfaceCreated = true;
        if (mListener != null && !mIsInitialized) {
            mIsInitialized = true;
            mListenerExecutor.execute(() -> {
                mListener.onInitialized();
            });
        }
        mShellExecutor.execute(() -> {
            if (mTaskToken == null) {
                // Nothing to update, task is not yet available
                return;
@@ -313,6 +324,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
                    .show(mTaskLeash)
                    .apply();
            updateTaskVisibility();
        });
    }

    @Override
@@ -326,6 +338,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mSurfaceCreated = false;
        mShellExecutor.execute(() -> {
            if (mTaskToken == null) {
                // Nothing to update, task is not yet available
                return;
@@ -334,5 +347,38 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
            // Unparent the task when this surface is destroyed
            mTransaction.reparent(mTaskLeash, null).apply();
            updateTaskVisibility();
        });
    }

    @Override
    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
        // TODO(b/176854108): Consider to move the logic into gatherTransparentRegions since this
        //   is dependent on the order of listener.
        // If there are multiple TaskViews, we'll set the touchable area as the root-view, then
        // subtract each TaskView from it.
        if (inoutInfo.touchableRegion.isEmpty()) {
            inoutInfo.setTouchableInsets(
                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
            View root = getRootView();
            root.getLocationInWindow(mTmpLocation);
            mTmpRootRect.set(mTmpLocation[0], mTmpLocation[1], root.getWidth(), root.getHeight());
            inoutInfo.touchableRegion.set(mTmpRootRect);
        }
        getLocationInWindow(mTmpLocation);
        mTmpRect.set(mTmpLocation[0], mTmpLocation[1],
                mTmpLocation[0] + getWidth(), mTmpLocation[1] + getHeight());
        inoutInfo.touchableRegion.op(mTmpRect, Region.Op.DIFFERENCE);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnComputeInternalInsetsListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
    }
}
+32 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.wm.shell;

import android.annotation.UiContext;
import android.content.Context;

import com.android.wm.shell.common.annotations.ExternalThread;

import java.util.concurrent.Executor;
import java.util.function.Consumer;

/** Interface to create TaskView. */
@ExternalThread
public interface TaskViewFactory {
    /** Creates an {@link TaskView} */
    void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate);
}
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.wm.shell;

import android.annotation.UiContext;
import android.content.Context;

import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.annotations.ShellMainThread;

import java.util.concurrent.Executor;
import java.util.function.Consumer;

/** Factory controller which can create {@link TaskView} */
public class TaskViewFactoryController {
    private final ShellTaskOrganizer mTaskOrganizer;
    private final ShellExecutor mShellExecutor;

    public TaskViewFactoryController(ShellTaskOrganizer taskOrganizer,
            ShellExecutor shellExecutor) {
        mTaskOrganizer = taskOrganizer;
        mShellExecutor = shellExecutor;
    }

    /** Creates an {@link TaskView} */
    @ShellMainThread
    public void create(@UiContext Context context, Executor executor, Consumer<TaskView> onCreate) {
        TaskView taskView = new TaskView(context, mTaskOrganizer);
        executor.execute(() -> {
            onCreate.accept(taskView);
        });
    }

    public TaskViewFactory getTaskViewFactory() {
        return new TaskViewFactoryImpl();
    }

    private class TaskViewFactoryImpl implements TaskViewFactory {
        @ExternalThread
        public void create(@UiContext Context context,
                Executor executor, Consumer<TaskView> onCreate) {
            mShellExecutor.execute(() -> {
                TaskViewFactoryController.this.create(context, executor, onCreate);
            });
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -314,7 +314,7 @@ public class BubbleExpandedView extends LinearLayout {
        mTaskView = new TaskView(mContext, mController.getTaskOrganizer());
        mExpandedViewContainer.addView(mTaskView);
        bringChildToFront(mTaskView);
        mTaskView.setListener(mTaskViewListener);
        mTaskView.setListener(mContext.getMainExecutor(), mTaskViewListener);
        mPositioner = mController.getPositioner();
    }

+1 −9
Original line number Diff line number Diff line
@@ -1201,16 +1201,8 @@ public class BubbleStackView extends FrameLayout

        mTempRect.setEmpty();
        getTouchableRegion(mTempRect);
        if (mIsExpanded && mExpandedBubble != null
                && mExpandedBubble.getExpandedView() != null
                && mExpandedBubble.getExpandedView().getTaskView() != null) {
            inoutInfo.touchableRegion.set(mTempRect);
            mExpandedBubble.getExpandedView().getTaskView().getBoundsOnScreen(mTempRect);
            inoutInfo.touchableRegion.op(mTempRect, Region.Op.DIFFERENCE);
        } else {
        inoutInfo.touchableRegion.set(mTempRect);
    }
    }

    @Override
    protected void onAttachedToWindow() {
Loading