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

Commit df2bdd51 authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Add support to show apps on desktop in sysui proxy" into tm-qpr-dev

parents bf338c76 d849498a
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
import com.android.wm.shell.compatui.CompatUIController;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
@@ -716,15 +718,36 @@ public abstract class WMShellBaseModule {
    // Desktop mode (optional feature)
    //

    @WMSingleton
    @Provides
    static Optional<DesktopMode> provideDesktopMode(
            Optional<DesktopModeController> desktopModeController) {
        return desktopModeController.map(DesktopModeController::asDesktopMode);
    }

    @BindsOptionalOf
    @DynamicOverride
    abstract DesktopModeController optionalDesktopModeController();

    @WMSingleton
    @Provides
    static Optional<DesktopModeController> providesDesktopModeController(
            @DynamicOverride Optional<DesktopModeController> desktopModeController) {
        if (DesktopModeStatus.IS_SUPPORTED) {
            return desktopModeController;
        }
        return Optional.empty();
    }

    @BindsOptionalOf
    @DynamicOverride
    abstract DesktopModeTaskRepository optionalDesktopModeTaskRepository();

    @WMSingleton
    @Provides
    static Optional<DesktopModeTaskRepository> providesDesktopModeTaskRepository(
    static Optional<DesktopModeTaskRepository> providesDesktopTaskRepository(
            @DynamicOverride Optional<DesktopModeTaskRepository> desktopModeTaskRepository) {
        if (DesktopMode.IS_SUPPORTED) {
        if (DesktopModeStatus.IS_SUPPORTED) {
            return desktopModeTaskRepository;
        }
        return Optional.empty();
+8 −10
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.draganddrop.DragAndDropController;
@@ -595,19 +594,18 @@ public abstract class WMShellModule {

    @WMSingleton
    @Provides
    static Optional<DesktopModeController> provideDesktopModeController(
            Context context, ShellInit shellInit,
    @DynamicOverride
    static DesktopModeController provideDesktopModeController(Context context, ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            Transitions transitions,
            @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
            @ShellMainThread Handler mainHandler,
            Transitions transitions
            @ShellMainThread ShellExecutor mainExecutor
    ) {
        if (DesktopMode.IS_SUPPORTED) {
            return Optional.of(new DesktopModeController(context, shellInit, shellTaskOrganizer,
                    rootTaskDisplayAreaOrganizer, mainHandler, transitions));
        } else {
            return Optional.empty();
        }
        return new DesktopModeController(context, shellInit, shellTaskOrganizer,
                rootTaskDisplayAreaOrganizer, transitions, desktopModeTaskRepository, mainHandler,
                mainExecutor);
    }

    @WMSingleton
+7 −34
Original line number Diff line number Diff line
@@ -16,43 +16,16 @@

package com.android.wm.shell.desktopmode;

import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;

import android.content.Context;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;

import com.android.internal.protolog.common.ProtoLog;

/**
 * Constants for desktop mode feature
 */
public class DesktopMode {
import com.android.wm.shell.common.annotations.ExternalThread;

/**
     * Flag to indicate whether desktop mode is available on the device
 * Interface to interact with desktop mode feature in shell.
 */
    public static final boolean IS_SUPPORTED = SystemProperties.getBoolean(
            "persist.wm.debug.desktop_mode", false);
@ExternalThread
public interface DesktopMode {

    /**
     * Check if desktop mode is active
     *
     * @return {@code true} if active
     */
    public static boolean isActive(Context context) {
        if (!IS_SUPPORTED) {
            return false;
        }
        try {
            int result = Settings.System.getIntForUser(context.getContentResolver(),
                    Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
            ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
            return result != 0;
        } catch (Exception e) {
            ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
            return false;
        }
    /** Returns a binder that can be passed to an external process to manipulate DesktopMode. */
    default IDesktopMode createExternalInterface() {
        return null;
    }
}
+105 −6
Original line number Diff line number Diff line
@@ -20,8 +20,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.TRANSIT_CHANGE;

import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;

import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.content.Context;
import android.database.ContentObserver;
@@ -29,51 +31,83 @@ import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArraySet;
import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;

import androidx.annotation.BinderThread;
import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;

import java.util.ArrayList;
import java.util.Comparator;

/**
 * Handles windowing changes when desktop mode system setting changes
 */
public class DesktopModeController {
public class DesktopModeController implements RemoteCallable<DesktopModeController> {

    private final Context mContext;
    private final ShellTaskOrganizer mShellTaskOrganizer;
    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
    private final SettingsObserver mSettingsObserver;
    private final Transitions mTransitions;
    private final DesktopModeTaskRepository mDesktopModeTaskRepository;
    private final ShellExecutor mMainExecutor;
    private final DesktopMode mDesktopModeImpl = new DesktopModeImpl();
    private final SettingsObserver mSettingsObserver;

    public DesktopModeController(Context context, ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            Transitions transitions,
            DesktopModeTaskRepository desktopModeTaskRepository,
            @ShellMainThread Handler mainHandler,
            Transitions transitions) {
            @ShellMainThread ShellExecutor mainExecutor) {
        mContext = context;
        mShellTaskOrganizer = shellTaskOrganizer;
        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
        mSettingsObserver = new SettingsObserver(mContext, mainHandler);
        mTransitions = transitions;
        mDesktopModeTaskRepository = desktopModeTaskRepository;
        mMainExecutor = mainExecutor;
        mSettingsObserver = new SettingsObserver(mContext, mainHandler);
        shellInit.addInitCallback(this::onInit, this);
    }

    private void onInit() {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopModeController");
        mSettingsObserver.observe();
        if (DesktopMode.isActive(mContext)) {
        if (DesktopModeStatus.isActive(mContext)) {
            updateDesktopModeActive(true);
        }
    }

    @Override
    public Context getContext() {
        return mContext;
    }

    @Override
    public ShellExecutor getRemoteCallExecutor() {
        return mMainExecutor;
    }

    /**
     * Get connection interface between sysui and shell
     */
    public DesktopMode asDesktopMode() {
        return mDesktopModeImpl;
    }

    @VisibleForTesting
    void updateDesktopModeActive(boolean active) {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeActive: active=%s", active);
@@ -120,6 +154,28 @@ public class DesktopModeController {
        wct.setWindowingMode(displayAreaInfo.token, windowingMode);
    }

    /**
     * Show apps on desktop
     */
    public void showDesktopApps() {
        ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks();
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront: tasks=%s", activeTasks.size());
        ArrayList<RunningTaskInfo> taskInfos = new ArrayList<>();
        for (Integer taskId : activeTasks) {
            RunningTaskInfo taskInfo = mShellTaskOrganizer.getRunningTaskInfo(taskId);
            if (taskInfo != null) {
                taskInfos.add(taskInfo);
            }
        }
        // Order by lastActiveTime, descending
        taskInfos.sort(Comparator.comparingLong(task -> -task.lastActiveTime));
        WindowContainerTransaction wct = new WindowContainerTransaction();
        for (RunningTaskInfo task : taskInfos) {
            wct.reorder(task.token, true);
        }
        mShellTaskOrganizer.applyTransaction(wct);
    }

    /**
     * A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
     */
@@ -150,8 +206,51 @@ public class DesktopModeController {
        }

        private void desktopModeSettingChanged() {
            boolean enabled = DesktopMode.isActive(mContext);
            boolean enabled = DesktopModeStatus.isActive(mContext);
            updateDesktopModeActive(enabled);
        }
    }

    /**
     * The interface for calls from outside the shell, within the host process.
     */
    @ExternalThread
    private final class DesktopModeImpl implements DesktopMode {

        private IDesktopModeImpl mIDesktopMode;

        @Override
        public IDesktopMode createExternalInterface() {
            if (mIDesktopMode != null) {
                mIDesktopMode.invalidate();
            }
            mIDesktopMode = new IDesktopModeImpl(DesktopModeController.this);
            return mIDesktopMode;
        }
    }

    /**
     * The interface for calls from outside the host process.
     */
    @BinderThread
    private static class IDesktopModeImpl extends IDesktopMode.Stub {

        private DesktopModeController mController;

        IDesktopModeImpl(DesktopModeController controller) {
            mController = controller;
        }

        /**
         * Invalidates this instance, preventing future calls from updating the controller.
         */
        void invalidate() {
            mController = null;
        }

        public void showDesktopApps() {
            executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
                    DesktopModeController::showDesktopApps);
        }
    }
}
+58 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.desktopmode;

import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;

import android.content.Context;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;

import com.android.internal.protolog.common.ProtoLog;

/**
 * Constants for desktop mode feature
 */
public class DesktopModeStatus {

    /**
     * Flag to indicate whether desktop mode is available on the device
     */
    public static final boolean IS_SUPPORTED = SystemProperties.getBoolean(
            "persist.wm.debug.desktop_mode", false);

    /**
     * Check if desktop mode is active
     *
     * @return {@code true} if active
     */
    public static boolean isActive(Context context) {
        if (!IS_SUPPORTED) {
            return false;
        }
        try {
            int result = Settings.System.getIntForUser(context.getContentResolver(),
                    Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
            ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
            return result != 0;
        } catch (Exception e) {
            ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
            return false;
        }
    }
}
Loading