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

Commit 5dbd289f authored by Merissa Tan's avatar Merissa Tan Committed by Winson Chung
Browse files

Add running apps icons to taskbar for desktop environment.

This CL adds app icons for launched/running apps to the Launcher
taskbar hotseat. When the activity is closed, the app icon is
removed. The apps that are added to the taskbar on boot are never
removed.

Recall: http://recall/clips/ad6d3cfc-7358-4b37-846e-de843ad3000d

Bug: 183906774
Test: Launch an app and verify the app icon is added on the taskbar.
Close the app and verify the icon is removed from the taskbar.
Test: Switch navigation modes on the emulator and ensure that running
app icons are added to the taskbar after it is reinitialized.
Test: atest NexusLauncherTests:com.android.quickstep.RecentTasksListTest RecentTasksControllerTest

Change-Id: Ieaaf001530b5778871fb7a8d18cdcaa1ccbf0e31
Merged-In: Ieaaf001530b5778871fb7a8d18cdcaa1ccbf0e31
parent f61e7bb4
Loading
Loading
Loading
Loading
+153 −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.launcher3.taskbar;

import android.app.ActivityManager;
import android.content.ComponentName;
import android.util.SparseArray;

import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.quickstep.RecentsModel;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Provides recent apps functionality specifically in a desktop environment.
 */
public class DesktopTaskbarRecentAppsController extends TaskbarRecentAppsController {

    private final TaskbarActivityContext mContext;
    private ArrayList<ItemInfo> mRunningApps = new ArrayList<>();
    private AppInfo[] mApps;

    public DesktopTaskbarRecentAppsController(TaskbarActivityContext context) {
        mContext = context;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mApps = null;
    }

    @Override
    protected void setApps(AppInfo[] apps) {
        mApps = apps;
    }

    @Override
    protected boolean isEnabled() {
        return true;
    }

    /**
     * Set mRunningApps to hold currently running applications using the list of currently running
     * tasks. Filtering is also done to ignore applications that are already on the taskbar in the
     * original hotseat.
     */
    @Override
    protected void updateRunningApps(SparseArray<ItemInfo> hotseatItems) {
        ArrayList<AppInfo> runningApps = getRunningAppsFromTasks();
        ArrayList<ItemInfo> filteredRunningApps = new ArrayList<>();
        for (AppInfo runningApp : runningApps) {
            boolean shouldAddOnTaskbar = true;
            for (int i = 0; i < hotseatItems.size(); i++) {
                if (hotseatItems.keyAt(i) >= mControllers.taskbarActivityContext.getDeviceProfile()
                        .numShownHotseatIcons) {
                    break;
                }
                if (hotseatItems.valueAt(i).getTargetPackage()
                        .equals(runningApp.getTargetPackage())) {
                    shouldAddOnTaskbar = false;
                    break;
                }
            }
            if (shouldAddOnTaskbar) {
                filteredRunningApps.add(new WorkspaceItemInfo(runningApp));
            }
        }
        mRunningApps = filteredRunningApps;
        mControllers.taskbarViewController.commitRunningAppsToUI();
    }

    /**
     * Returns a copy of hotseatItems with the addition of currently running applications.
     */
    @Override
    protected ItemInfo[] updateHotseatItemInfos(ItemInfo[] hotseatItemInfos) {
        // hotseatItemInfos.length would be 0 if deviceProfile.numShownHotseatIcons is 0, so we
        // don't want to show anything in the hotseat
        if (hotseatItemInfos.length == 0) return hotseatItemInfos;

        int runningAppsIndex = 0;
        ItemInfo[] newHotseatItemsInfo = Arrays.copyOf(
                hotseatItemInfos, hotseatItemInfos.length + mRunningApps.size());
        for (int i = hotseatItemInfos.length; i < newHotseatItemsInfo.length; i++) {
            newHotseatItemsInfo[i] = mRunningApps.get(runningAppsIndex);
            runningAppsIndex++;
        }
        return newHotseatItemsInfo;
    }


    /**
     * Returns a list of running applications from the list of currently running tasks.
     */
    private ArrayList<AppInfo> getRunningAppsFromTasks() {
        ArrayList<ActivityManager.RunningTaskInfo> tasks =
                RecentsModel.INSTANCE.get(mContext).getRunningTasks();
        ArrayList<AppInfo> runningApps = new ArrayList<>();
        // early return if apps is empty, since we would have no AppInfo to compare
        if (mApps == null)  {
            return runningApps;
        }

        Set<String> seenPackages = new HashSet<>();
        for (ActivityManager.RunningTaskInfo taskInfo : tasks) {
            if (taskInfo.realActivity == null) continue;

            // If a different task for the same package has already been handled, skip this one
            String taskPackage = taskInfo.realActivity.getPackageName();
            if (seenPackages.contains(taskPackage)) continue;

            // Otherwise, get the corresponding AppInfo and add it to the list
            seenPackages.add(taskPackage);
            AppInfo app = getAppInfo(taskInfo.realActivity);
            if (app == null) continue;
            runningApps.add(app);
        }
        return runningApps;
    }

    /**
     * Retrieves the corresponding AppInfo for the activity.
     */
    private AppInfo getAppInfo(ComponentName activity) {
        String packageName = activity.getPackageName();
        for (AppInfo app : mApps) {
            if (!packageName.equals(app.getTargetPackage())) {
                continue;
            }
            return app;
        }
        return null;
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -32,11 +32,14 @@ public class DesktopTaskbarUIController extends TaskbarUIController {

    @Override
    protected void init(TaskbarControllers taskbarControllers) {
        super.init(taskbarControllers);
        mLauncher.getHotseat().setIconsAlpha(0f);
        mControllers.taskbarViewController.updateRunningApps();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLauncher.getHotseat().setIconsAlpha(1f);
    }

+9 −4
Original line number Diff line number Diff line
@@ -173,13 +173,15 @@ public class TaskbarActivityContext extends BaseTaskbarContext {

        mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);

        final boolean isDesktopMode = getPackageManager().hasSystemFeature(FEATURE_PC);

        // Construct controllers.
        mControllers = new TaskbarControllers(this,
                new TaskbarDragController(this),
                buttonController,
                getPackageManager().hasSystemFeature(FEATURE_PC)
                        ? new DesktopNavbarButtonsViewController(this, navButtonsView) :
                        new NavbarButtonsViewController(this, navButtonsView),
                isDesktopMode
                        ? new DesktopNavbarButtonsViewController(this, navButtonsView)
                        : new NavbarButtonsViewController(this, navButtonsView),
                new RotationButtonController(this,
                        c.getColor(R.color.taskbar_nav_icon_light_color),
                        c.getColor(R.color.taskbar_nav_icon_dark_color),
@@ -202,7 +204,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
                new TaskbarForceVisibleImmersiveController(this),
                new TaskbarAllAppsController(this, dp),
                new TaskbarInsetsController(this),
                new VoiceInteractionWindowController(this));
                new VoiceInteractionWindowController(this),
                isDesktopMode
                        ? new DesktopTaskbarRecentAppsController(this)
                        : TaskbarRecentAppsController.DEFAULT);
    }

    public void init(@NonNull TaskbarSharedState sharedState) {
+6 −1
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ public class TaskbarControllers {
    public final TaskbarAllAppsController taskbarAllAppsController;
    public final TaskbarInsetsController taskbarInsetsController;
    public final VoiceInteractionWindowController voiceInteractionWindowController;
    public final TaskbarRecentAppsController taskbarRecentAppsController;

    @Nullable private LoggableTaskbarController[] mControllersToLog = null;

@@ -82,7 +83,8 @@ public class TaskbarControllers {
            TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController,
            TaskbarAllAppsController taskbarAllAppsController,
            TaskbarInsetsController taskbarInsetsController,
            VoiceInteractionWindowController voiceInteractionWindowController) {
            VoiceInteractionWindowController voiceInteractionWindowController,
            TaskbarRecentAppsController taskbarRecentAppsController) {
        this.taskbarActivityContext = taskbarActivityContext;
        this.taskbarDragController = taskbarDragController;
        this.navButtonController = navButtonController;
@@ -102,6 +104,7 @@ public class TaskbarControllers {
        this.taskbarAllAppsController = taskbarAllAppsController;
        this.taskbarInsetsController = taskbarInsetsController;
        this.voiceInteractionWindowController = voiceInteractionWindowController;
        this.taskbarRecentAppsController = taskbarRecentAppsController;
    }

    /**
@@ -130,6 +133,7 @@ public class TaskbarControllers {
        navButtonController.init(this);
        taskbarInsetsController.init(this);
        voiceInteractionWindowController.init(this);
        taskbarRecentAppsController.init(this);

        mControllersToLog = new LoggableTaskbarController[] {
                taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -178,6 +182,7 @@ public class TaskbarControllers {
        navButtonController.onDestroy();
        taskbarInsetsController.onDestroy();
        voiceInteractionWindowController.onDestroy();
        taskbarRecentAppsController.onDestroy();

        mControllersToLog = null;
    }
+30 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.quickstep.RecentsModel;

import java.io.PrintWriter;
import java.util.ArrayList;
@@ -42,7 +43,7 @@ import java.util.function.Predicate;
 * Launcher model Callbacks for rendering taskbar.
 */
public class TaskbarModelCallbacks implements
        BgDataModel.Callbacks, LauncherBindableItemsContainer {
        BgDataModel.Callbacks, LauncherBindableItemsContainer, RecentsModel.RunningTasksListener {

    private final SparseArray<ItemInfo> mHotseatItems = new SparseArray<>();
    private List<ItemInfo> mPredictedItems = Collections.emptyList();
@@ -61,6 +62,16 @@ public class TaskbarModelCallbacks implements

    public void init(TaskbarControllers controllers) {
        mControllers = controllers;
        if (mControllers.taskbarRecentAppsController.isEnabled()) {
            RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
        }
    }

    /**
     * Unregisters listeners in this class.
     */
    public void unregisterListeners() {
        RecentsModel.INSTANCE.get(mContext).unregisterRunningTasksListener();
    }

    @Override
@@ -185,6 +196,8 @@ public class TaskbarModelCallbacks implements
                isHotseatEmpty = false;
            }
        }
        hotseatItemInfos = mControllers.taskbarRecentAppsController
                .updateHotseatItemInfos(hotseatItemInfos);
        mContainer.updateHotseatItems(hotseatItemInfos);

        final boolean finalIsHotseatEmpty = isHotseatEmpty;
@@ -195,6 +208,21 @@ public class TaskbarModelCallbacks implements
        });
    }

    @Override
    public void onRunningTasksChanged() {
        updateRunningApps();
    }

    /** Called when there's a change in running apps to update the UI. */
    public void commitRunningAppsToUI() {
        commitItemsToUI();
    }

    /** Call TaskbarRecentAppsController to update running apps with mHotseatItems. */
    public void updateRunningApps() {
        mControllers.taskbarRecentAppsController.updateRunningApps(mHotseatItems);
    }

    @Override
    public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
        mControllers.taskbarPopupController.setDeepShortcutMap(deepShortcutMapCopy);
@@ -203,6 +231,7 @@ public class TaskbarModelCallbacks implements
    @Override
    public void bindAllApplications(AppInfo[] apps, int flags) {
        mControllers.taskbarAllAppsController.setApps(apps, flags);
        mControllers.taskbarRecentAppsController.setApps(apps);
    }

    protected void dumpLogs(String prefix, PrintWriter pw) {
Loading