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

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

Merge changes from topic "desktop-windowing-hide" into tm-qpr-dev

* changes:
  Hide some options when desktop mode is available
  Handle desktop mode setting change
parents aa19ed35 10f2250f
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -16,14 +16,20 @@

package com.android.wm.shell;

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

import android.app.WindowConfiguration;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;
import android.window.WindowContainerTransaction;

import androidx.annotation.NonNull;

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

import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.Executor;
@@ -102,10 +108,44 @@ public class RootDisplayAreaOrganizer extends DisplayAreaOrganizer {
        mDisplayAreasInfo.put(displayId, displayAreaInfo);
    }

    /**
     * Create a {@link WindowContainerTransaction} to update display windowing mode.
     *
     * @param displayId display id to update windowing mode for
     * @param windowingMode target {@link WindowConfiguration.WindowingMode}
     * @return {@link WindowContainerTransaction} with pending operation to set windowing mode
     */
    public WindowContainerTransaction prepareWindowingModeChange(int displayId,
            @WindowConfiguration.WindowingMode int windowingMode) {
        WindowContainerTransaction wct = new WindowContainerTransaction();
        DisplayAreaInfo displayAreaInfo = mDisplayAreasInfo.get(displayId);
        if (displayAreaInfo == null) {
            ProtoLog.e(WM_SHELL_DESKTOP_MODE,
                    "unable to update windowing mode for display %d display not found", displayId);
            return wct;
        }

        ProtoLog.d(WM_SHELL_DESKTOP_MODE,
                "setWindowingMode: displayId=%d current wmMode=%d new wmMode=%d", displayId,
                displayAreaInfo.configuration.windowConfiguration.getWindowingMode(),
                windowingMode);

        wct.setWindowingMode(displayAreaInfo.token, windowingMode);
        return wct;
    }

    public void dump(@NonNull PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
        final String childPrefix = innerPrefix + "  ";
        pw.println(prefix + this);

        for (int i = 0; i < mDisplayAreasInfo.size(); i++) {
            int displayId = mDisplayAreasInfo.keyAt(i);
            DisplayAreaInfo displayAreaInfo = mDisplayAreasInfo.get(displayId);
            int windowingMode =
                    displayAreaInfo.configuration.windowConfiguration.getWindowingMode();
            pw.println(innerPrefix + "# displayId=" + displayId + " wmMode=" + windowingMode);
        }
    }

    @Override
+54 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;

import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;

@@ -46,6 +47,7 @@ import android.window.StartingWindowInfo;
import android.window.StartingWindowRemovalInfo;
import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
import android.window.WindowContainerTransaction;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -690,6 +692,49 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
        taskListener.reparentChildSurfaceToTask(taskId, sc, t);
    }

    /**
     * Create a {@link WindowContainerTransaction} to clear task bounds.
     *
     * @param displayId display id for tasks that will have bounds cleared
     * @return {@link WindowContainerTransaction} with pending operations to clear bounds
     */
    public WindowContainerTransaction prepareClearBoundsForTasks(int displayId) {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks: displayId=%d", displayId);
        WindowContainerTransaction wct = new WindowContainerTransaction();
        for (int i = 0; i < mTasks.size(); i++) {
            RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
            if (taskInfo.displayId == displayId) {
                ProtoLog.d(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s",
                        taskInfo.token, taskInfo);
                wct.setBounds(taskInfo.token, null);
            }
        }
        return wct;
    }

    /**
     * Create a {@link WindowContainerTransaction} to clear task level freeform setting.
     *
     * @param displayId display id for tasks that will have windowing mode reset to {@link
     *                  WindowConfiguration#WINDOWING_MODE_UNDEFINED}
     * @return {@link WindowContainerTransaction} with pending operations to clear windowing mode
     */
    public WindowContainerTransaction prepareClearFreeformForTasks(int displayId) {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks: displayId=%d", displayId);
        WindowContainerTransaction wct = new WindowContainerTransaction();
        for (int i = 0; i < mTasks.size(); i++) {
            RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
            if (taskInfo.displayId == displayId
                    && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
                ProtoLog.d(WM_SHELL_DESKTOP_MODE,
                        "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token,
                        taskInfo);
                wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
            }
        }
        return wct;
    }

    private void logSizeCompatRestartButtonEventReported(@NonNull TaskAppearedInfo info,
            int event) {
        ActivityInfo topActivityInfo = info.getTaskInfo().topActivityInfo;
@@ -816,7 +861,14 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
                final int key = mTasks.keyAt(i);
                final TaskAppearedInfo info = mTasks.valueAt(i);
                final TaskListener listener = getTaskListener(info.getTaskInfo());
                pw.println(innerPrefix + "#" + i + " task=" + key + " listener=" + listener);
                final int windowingMode = info.getTaskInfo().getWindowingMode();
                String pkg = "";
                if (info.getTaskInfo().baseActivity != null) {
                    pkg = info.getTaskInfo().baseActivity.getPackageName();
                }
                Rect bounds = info.getTaskInfo().getConfiguration().windowConfiguration.getBounds();
                pw.println(innerPrefix + "#" + i + " task=" + key + " listener=" + listener
                        + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds);
            }

            pw.println();
@@ -826,6 +878,7 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
                final TaskListener listener = mLaunchCookieToListener.valueAt(i);
                pw.println(innerPrefix + "#" + i + " cookie=" + key + " listener=" + listener);
            }

        }
    }
}
+26 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootDisplayAreaOrganizer;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions;
@@ -48,6 +49,8 @@ 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.DesktopModeConstants;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformComponents;
import com.android.wm.shell.freeform.FreeformTaskListener;
@@ -573,6 +576,27 @@ public abstract class WMShellModule {
        );
    }

    //
    // Desktop mode (optional feature)
    //

    @WMSingleton
    @Provides
    static Optional<DesktopModeController> provideDesktopModeController(
            Context context, ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            RootDisplayAreaOrganizer rootDisplayAreaOrganizer,
            @ShellMainThread Handler mainHandler
    ) {
        if (DesktopModeConstants.IS_FEATURE_ENABLED) {
            return Optional.of(new DesktopModeController(context, shellInit, shellTaskOrganizer,
                    rootDisplayAreaOrganizer,
                    mainHandler));
        } else {
            return Optional.empty();
        }
    }

    //
    // Misc
    //
@@ -583,7 +607,8 @@ public abstract class WMShellModule {
    @ShellCreateTriggerOverride
    @Provides
    static Object provideIndependentShellComponentsToCreate(
            SplitscreenPipMixedHandler splitscreenPipMixedHandler) {
            SplitscreenPipMixedHandler splitscreenPipMixedHandler,
            Optional<DesktopModeController> desktopModeController) {
        return new Object();
    }
}
+31 −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 android.os.SystemProperties;

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

    /**
     * Flag to indicate whether desktop mode is available on the device
     */
    public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
            "persist.wm.debug.desktop_mode", false);
}
+137 −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 android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;

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

import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.window.WindowContainerTransaction;

import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.RootDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ShellInit;

/**
 * Handles windowing changes when desktop mode system setting changes
 */
public class DesktopModeController {

    private final Context mContext;
    private final ShellTaskOrganizer mShellTaskOrganizer;
    private final RootDisplayAreaOrganizer mRootDisplayAreaOrganizer;
    private final SettingsObserver mSettingsObserver;

    public DesktopModeController(Context context, ShellInit shellInit,
            ShellTaskOrganizer shellTaskOrganizer,
            RootDisplayAreaOrganizer rootDisplayAreaOrganizer,
            @ShellMainThread Handler mainHandler) {
        mContext = context;
        mShellTaskOrganizer = shellTaskOrganizer;
        mRootDisplayAreaOrganizer = rootDisplayAreaOrganizer;
        mSettingsObserver = new SettingsObserver(mContext, mainHandler);
        shellInit.addInitCallback(this::onInit, this);
    }

    private void onInit() {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopModeController");
        mSettingsObserver.observe();
    }

    @VisibleForTesting
    void updateDesktopModeEnabled(boolean enabled) {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeState: enabled=%s", enabled);

        int displayId = mContext.getDisplayId();

        WindowContainerTransaction wct = new WindowContainerTransaction();
        // Reset freeform windowing mode that is set per task level (tasks should inherit
        // container value)
        wct.merge(mShellTaskOrganizer.prepareClearFreeformForTasks(displayId), true /* transfer */);
        int targetWindowingMode;
        if (enabled) {
            targetWindowingMode = WINDOWING_MODE_FREEFORM;
        } else {
            targetWindowingMode = WINDOWING_MODE_FULLSCREEN;
            // Clear any resized bounds
            wct.merge(mShellTaskOrganizer.prepareClearBoundsForTasks(displayId),
                    true /* transfer */);
        }
        wct.merge(mRootDisplayAreaOrganizer.prepareWindowingModeChange(displayId,
                targetWindowingMode), true /* transfer */);
        mRootDisplayAreaOrganizer.applyTransaction(wct);
    }

    /**
     * A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
     */
    private final class SettingsObserver extends ContentObserver {

        private final Uri mDesktopModeSetting = Settings.System.getUriFor(
                Settings.System.DESKTOP_MODE);

        private final Context mContext;

        SettingsObserver(Context context, Handler handler) {
            super(handler);
            mContext = context;
        }

        public void observe() {
            // TODO(b/242867463): listen for setting change for all users
            mContext.getContentResolver().registerContentObserver(mDesktopModeSetting,
                    false /* notifyForDescendants */, this /* observer */, UserHandle.USER_CURRENT);
        }

        @Override
        public void onChange(boolean selfChange, @Nullable Uri uri) {
            if (mDesktopModeSetting.equals(uri)) {
                ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Received update for desktop mode setting");
                desktopModeSettingChanged();
            }
        }

        private void desktopModeSettingChanged() {
            boolean enabled = isDesktopModeEnabled();
            updateDesktopModeEnabled(enabled);
        }

        private boolean isDesktopModeEnabled() {
            try {
                int result = Settings.System.getIntForUser(mContext.getContentResolver(),
                        Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
                ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
                return result != 0;
            } catch (Settings.SettingNotFoundException e) {
                ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
                return false;
            }
        }
    }
}
Loading