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

Commit 3623756d authored by Alina Zaidi's avatar Alina Zaidi Committed by Automerger Merge Worker
Browse files

Merge "Send widget added and removed events to AiAi." into sc-v2-dev am: 29c3f23b am: 5c09d7e4

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/16006577

Change-Id: I68a7562ec2dd9ee355dcf5dda10e6481092024df
parents 5562e7e7 5c09d7e4
Loading
Loading
Loading
Loading
+7 −67
Original line number Diff line number Diff line
@@ -16,33 +16,25 @@
package com.android.launcher3.hybridhotseat;

import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;

import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;

import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Workspace;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;

import java.util.ArrayList;
import java.util.Locale;

/**
 * Model helper for app predictions in workspace
 */
public class HotseatPredictionModel {
    private static final String APP_LOCATION_HOTSEAT = "hotseat";
    private static final String APP_LOCATION_WORKSPACE = "workspace";

    private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events";
    private static final String BUNDLE_KEY_CURRENT_ITEMS = "current_items";

@@ -54,15 +46,15 @@ public class HotseatPredictionModel {
        ArrayList<AppTargetEvent> events = new ArrayList<>();
        ArrayList<ItemInfo> workspaceItems = dataModel.getAllWorkspaceItems();
        for (ItemInfo item : workspaceItems) {
            AppTarget target = getAppTargetFromInfo(context, item);
            if (target != null && !isTrackedForPrediction(item)) continue;
            events.add(wrapAppTargetWithLocation(target, AppTargetEvent.ACTION_PIN, item));
            AppTarget target = getAppTargetFromItemInfo(context, item);
            if (target != null && !isTrackedForHotseatPrediction(item)) continue;
            events.add(wrapAppTargetWithItemLocation(target, AppTargetEvent.ACTION_PIN, item));
        }
        ArrayList<AppTarget> currentTargets = new ArrayList<>();
        FixedContainerItems hotseatItems = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION);
        if (hotseatItems != null) {
            for (ItemInfo itemInfo : hotseatItems.items) {
                AppTarget target = getAppTargetFromInfo(context, itemInfo);
                AppTarget target = getAppTargetFromItemInfo(context, itemInfo);
                if (target != null) currentTargets.add(target);
            }
        }
@@ -70,56 +62,4 @@ public class HotseatPredictionModel {
        bundle.putParcelableArrayList(BUNDLE_KEY_CURRENT_ITEMS, currentTargets);
        return bundle;
    }

    /**
     * Creates and returns for {@link AppTarget} object given an {@link ItemInfo}. Returns null
     * if item is not supported prediction
     */
    public static AppTarget getAppTargetFromInfo(Context context, ItemInfo info) {
        if (info == null) return null;
        if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
                && info instanceof LauncherAppWidgetInfo
                && ((LauncherAppWidgetInfo) info).providerName != null) {
            ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
            return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
                    cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
                && info.getTargetComponent() != null) {
            ComponentName cn = info.getTargetComponent();
            return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
                    cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
                && info instanceof WorkspaceItemInfo) {
            ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
            //TODO: switch to using full shortcut info
            return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
                    shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
            return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
                    context.getPackageName(), info.user).build();
        }
        return null;
    }

    /**
     * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
     * location using {@link ItemInfo}
     */
    public static AppTargetEvent wrapAppTargetWithLocation(
            AppTarget target, int action, ItemInfo info) {
        String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
                info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
                        ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
                info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
        return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
    }

    /**
     * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors
     */
    public static boolean isTrackedForPrediction(ItemInfo info) {
        return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
                info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
                        && info.screenId == Workspace.FIRST_SCREEN_ID);
    }
}
+9 −16
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.prediction.AppTargetEvent.ACTION_UNPIN;

import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED;
@@ -35,6 +36,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
import static com.android.launcher3.model.PredictionHelper.isTrackedForWidgetPrediction;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;

import android.annotation.TargetApi;
@@ -62,7 +65,6 @@ import com.android.launcher3.logger.LauncherAtom.FolderContainer;
import com.android.launcher3.logger.LauncherAtom.HotseatContainer;
import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer;
import com.android.launcher3.logging.StatsLogManager.EventEnum;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer;
@@ -141,6 +143,9 @@ public class AppEventProducer implements StatsLogConsumer {
            if (isTrackedForHotseatPrediction(mLastDragItem)) {
                sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
            }
            if (isTrackedForWidgetPrediction(atomInfo)) {
                sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION);
            }
            mLastDragItem = null;
        } else if (event == LAUNCHER_ITEM_DROP_FOLDER_CREATED) {
            if (isTrackedForHotseatPrediction(atomInfo)) {
@@ -158,6 +163,9 @@ public class AppEventProducer implements StatsLogConsumer {
            if (mLastDragItem != null && isTrackedForHotseatPrediction(mLastDragItem)) {
                sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
            }
            if (mLastDragItem != null && isTrackedForWidgetPrediction(mLastDragItem)) {
                sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_WIDGETS_PREDICTION);
            }
        } else if (event == LAUNCHER_HOTSEAT_PREDICTION_PINNED) {
            if (isTrackedForHotseatPrediction(atomInfo)) {
                sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION);
@@ -302,19 +310,4 @@ public class AppEventProducer implements StatsLogConsumer {
        return TextUtils.isEmpty(componentNameString)
                ? null : ComponentName.unflattenFromString(componentNameString);
    }

    /**
     * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors
     */
    private static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
        ContainerInfo ci = info.getContainerInfo();
        switch (ci.getContainerCase()) {
            case HOTSEAT:
                return true;
            case WORKSPACE:
                return ci.getWorkspace().getPageIndex() == 0;
            default:
                return false;
        }
    }
}
+130 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.model;

import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.WORKSPACE;

import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
import android.content.ComponentName;
import android.content.Context;

import androidx.annotation.Nullable;

import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Workspace;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;

import java.util.Locale;

/** Helper class with methods for converting launcher items to form usable by predictors */
public final class PredictionHelper {
    private static final String APP_LOCATION_HOTSEAT = "hotseat";
    private static final String APP_LOCATION_WORKSPACE = "workspace";

    /**
     * Creates and returns an {@link AppTarget} object for an {@link ItemInfo}. Returns null
     * if item type is not supported in predictions
     */
    @Nullable
    public static AppTarget getAppTargetFromItemInfo(Context context, ItemInfo info) {
        if (info == null) return null;
        if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
                && info instanceof LauncherAppWidgetInfo
                && ((LauncherAppWidgetInfo) info).providerName != null) {
            ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
            return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
                    cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
                && info.getTargetComponent() != null) {
            ComponentName cn = info.getTargetComponent();
            return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
                    cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
                && info instanceof WorkspaceItemInfo) {
            ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
            //TODO: switch to using full shortcut info
            return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
                    shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
            return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
                    context.getPackageName(), info.user).build();
        }
        return null;
    }

    /**
     * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
     * location using {@link ItemInfo}
     */
    public static AppTargetEvent wrapAppTargetWithItemLocation(
            AppTarget target, int action, ItemInfo info) {
        String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
                info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
                        ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
                info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
        return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
    }

    /**
     * Helper method to determine if {@link ItemInfo} should be tracked and reported to hotseat
     * predictors
     */
    public static boolean isTrackedForHotseatPrediction(ItemInfo info) {
        return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
                info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
                        && info.screenId == Workspace.FIRST_SCREEN_ID);
    }

    /**
     * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported to
     * hotseat predictors
     */
    public static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
        LauncherAtom.ContainerInfo ci = info.getContainerInfo();
        switch (ci.getContainerCase()) {
            case HOTSEAT:
                return true;
            case WORKSPACE:
                return ci.getWorkspace().getPageIndex() == 0;
            default:
                return false;
        }
    }

    /**
     * Helper method to determine if {@link ItemInfo} should be tracked and reported to widget
     * predictors
     */
    public static boolean isTrackedForWidgetPrediction(ItemInfo info) {
        return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
                && info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP;
    }

    /**
     * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported
     * to widget predictors
     */
    public static boolean isTrackedForWidgetPrediction(LauncherAtom.ItemInfo info) {
        return info.getItemCase() == LauncherAtom.ItemInfo.ItemCase.WIDGET
                && info.getContainerInfo().getContainerCase() == WORKSPACE;
    }
}
+38 −1
Original line number Diff line number Diff line
@@ -25,8 +25,12 @@ import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICA
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.Utilities.getDevicePrefs;
import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle;
import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;

import static java.util.stream.Collectors.toCollection;

import android.app.StatsManager;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionManager;
@@ -39,6 +43,7 @@ import android.content.SharedPreferences;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
import android.util.StatsEvent;
@@ -62,6 +67,7 @@ import com.android.launcher3.util.PersistedItemArray;
import com.android.quickstep.logging.StatsLogCompatManager;
import com.android.systemui.shared.system.SysUiStatsLog;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -75,6 +81,7 @@ public class QuickstepModelDelegate extends ModelDelegate {

    public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
    private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS";
    private static final String BUNDLE_KEY_ADDED_APP_WIDGETS = "added_app_widgets";
    private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20;

    private static final boolean IS_DEBUG = false;
@@ -272,6 +279,7 @@ public class QuickstepModelDelegate extends ModelDelegate {
        registerWidgetsPredictor(apm.createAppPredictionSession(
                new AppPredictionContext.Builder(context)
                        .setUiSurface("widgets")
                        .setExtras(getBundleForWidgetsOnWorkspace(context, mDataModel))
                        .setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION)
                        .build()));
    }
@@ -306,12 +314,41 @@ public class QuickstepModelDelegate extends ModelDelegate {
    }

    private void onAppTargetEvent(AppTargetEvent event, int client) {
        PredictorState state = client == CONTAINER_PREDICTION ? mAllAppsState : mHotseatState;
        PredictorState state;
        switch(client) {
            case CONTAINER_PREDICTION:
                state = mAllAppsState;
                break;
            case CONTAINER_WIDGETS_PREDICTION:
                state = mWidgetsRecommendationState;
                break;
            case CONTAINER_HOTSEAT_PREDICTION:
            default:
                state = mHotseatState;
                break;
        }
        if (state.predictor != null) {
            state.predictor.notifyAppTargetEvent(event);
        }
    }

    private Bundle getBundleForWidgetsOnWorkspace(Context context, BgDataModel dataModel) {
        Bundle bundle = new Bundle();
        ArrayList<AppTargetEvent> widgetEvents =
                dataModel.getAllWorkspaceItems().stream()
                        .filter(PredictionHelper::isTrackedForWidgetPrediction)
                        .map(item -> {
                            AppTarget target = getAppTargetFromItemInfo(context, item);
                            if (target == null) return null;
                            return wrapAppTargetWithItemLocation(
                                    target, AppTargetEvent.ACTION_PIN, item);
                        })
                        .filter(Objects::nonNull)
                        .collect(toCollection(ArrayList::new));
        bundle.putParcelableArrayList(BUNDLE_KEY_ADDED_APP_WIDGETS, widgetEvents);
        return bundle;
    }

    static class PredictorState {

        public final FixedContainerItems items;