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

Commit 8e0ed4b0 authored by Saumya Prakash's avatar Saumya Prakash
Browse files

Add "New Window" option to Taskbar menu.

This change adds a new menu option to Taskbar that is invoked when long
pressing an icon. It createds a new instance for an app if the app
supports multi instance in Desktop Mode.

Bug: 315344726
Test: Manual
Flag: com.android.launcher3.enable_multi_instance_menu_taskbar
Change-Id: Ibc42fbb1ad485496cd938af730b86e051cea559a
parent e6eca9c1
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.launcher3.taskbar

import android.content.Context
import android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK
import android.view.View
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.R
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.popup.SystemShortcut
import com.android.launcher3.views.ActivityContext

/**
 * A single menu item shortcut to execute creating a new instance of an app. Default interaction for
 * [onClick] is to launch the app in full screen or as a floating window in Desktop Mode.
 */
class NewWindowTaskbarShortcut<T>(target: T, itemInfo: ItemInfo?, originalView: View?) :
    SystemShortcut<T>(
        R.drawable.desktop_mode_ic_taskbar_menu_new_window,
        R.string.new_window_option_taskbar,
        target,
        itemInfo,
        originalView
    ) where T : Context?, T : ActivityContext? {

    override fun onClick(v: View?) {
        val intent = mItemInfo.intent ?: return
        intent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
        mTarget?.startActivitySafely(v, intent, mItemInfo)
        AbstractFloatingView.closeAllOpenViews(mTarget)
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -250,6 +250,7 @@ public class TaskbarModelCallbacks implements
            Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
        Preconditions.assertUIThread();
        mControllers.taskbarAllAppsController.setApps(apps, flags, packageUserKeytoUidMap);
        mControllers.taskbarPopupController.setApps(apps);
    }

    protected void dumpLogs(String prefix, PrintWriter pw) {
+59 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.launcher3.taskbar;

import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;

import android.content.Intent;
@@ -29,11 +30,13 @@ import androidx.annotation.NonNull;
import com.android.internal.logging.InstanceId;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -51,9 +54,11 @@ import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.LogUtils;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@@ -79,6 +84,7 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba
    // Initialized in init.
    private TaskbarControllers mControllers;
    private boolean mAllowInitialSplitSelection;
    private AppInfo[] mAppInfosList;

    public TaskbarPopupController(TaskbarActivityContext context) {
        mContext = context;
@@ -195,6 +201,10 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba
        if (com.android.wm.shell.Flags.enableBubbleAnything()) {
            shortcuts.add(BUBBLE);
        }
        if (Flags.enableMultiInstanceMenuTaskbar()
                && DesktopModeStatus.canEnterDesktopMode(mContext)) {
            shortcuts.addAll(getMultiInstanceMenuOptions().toList());
        }
        return shortcuts.stream();
    }

@@ -258,6 +268,54 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba
                originalView, position, mAllowInitialSplitSelection);
    }

    /**
     * Set the list of AppInfos to be able to pull from later
     */
    public void setApps(AppInfo[] apps) {
        mAppInfosList = apps;
    }

    /**
     * Finds and returns an AppInfo object from a list, using its ComponentKey for identification.
     * Based off of {@link com.android.launcher3.allapps.AllAppsStore#getApp(ComponentKey)}
     * since we cannot access AllAppsStore from here.
     */
    public AppInfo getApp(ComponentKey key) {
        if (key == null) {
            return null;
        }
        AppInfo tempInfo = new AppInfo();
        tempInfo.componentName = key.componentName;
        tempInfo.user = key.user;
        int index = Arrays.binarySearch(mAppInfosList, tempInfo, COMPONENT_KEY_COMPARATOR);
        return index < 0 ? null : mAppInfosList[index];
    }

    /**
     * Returns a stream of Multi Instance menu options if an app supports it.
     */
    Stream<SystemShortcut.Factory<BaseTaskbarContext>> getMultiInstanceMenuOptions() {
        SystemShortcut.Factory<BaseTaskbarContext> factory = createNewWindowShortcutFactory();
        return factory != null ? Stream.of(factory) : Stream.empty();

    }

    /**
     * Creates a factory function representing a "New Window" menu item only if the calling app
     * supports multi-instance.
     * @return A factory function to be used in populating the long-press menu.
     */
    SystemShortcut.Factory<BaseTaskbarContext> createNewWindowShortcutFactory() {
        return (context, itemInfo, originalView) -> {
            ComponentKey key = itemInfo.getComponentKey();
            AppInfo app = getApp(key);
            if (app != null && app.supportsMultiInstance()) {
                return new NewWindowTaskbarShortcut<>(context, itemInfo, originalView);
            }
            return null;
        };
    }

    /**
     * A single menu item ("Split left," "Split right," or "Split top") that executes a split
     * from the taskbar, as if the user performed a drag and drop split.
+25 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2024 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.
  -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="20dp"
    android:height="20dp"
    android:viewportWidth="20"
    android:viewportHeight="20">
    <path
        android:pathData="M15 16V14H13V12.5H15V10.5H16.5V12.5H18.5V14H16.5V16H15ZM3.5 17C3.09722 17 2.74306 16.8542 2.4375 16.5625C2.14583 16.2569 2 15.9028 2 15.5V4.5C2 4.08333 2.14583 3.72917 2.4375 3.4375C2.74306 3.14583 3.09722 3 3.5 3H14.5C14.9167 3 15.2708 3.14583 15.5625 3.4375C15.8542 3.72917 16 4.08333 16 4.5V9H14.5V7H3.5V15.5H13.625V17H3.5ZM3.5 5.5H14.5V4.5H3.5V5.5ZM3.5 5.5V4.5V5.5Z"
        android:fillColor="#1C1C14"/>
</vector>
+3 −0
Original line number Diff line number Diff line
@@ -45,6 +45,9 @@
    <string name="split_app_info_accessibility">App info for %1$s</string>
    <string name="split_app_usage_settings">Usage settings for %1$s</string>

    <!-- Title for an option to open a new window for a given app   -->
    <string name="new_window_option_taskbar">New Window</string>

    <!-- App pairs -->
    <string name="save_app_pair">Save app pair</string>
    <!-- App pair default title -->