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

Commit 93803d3f authored by Song Hu's avatar Song Hu Committed by Automerger Merge Worker
Browse files

Merge "Factor freqeuncy and mimetype of past sharings, foreground app into...

Merge "Factor freqeuncy and mimetype of past sharings, foreground app into sharesheet model. Promote most frequent sharable apps to tackle cold start issue when device doesn't hold enough sharing history." into rvc-dev am: 7abd9be7 am: 68cea0b1 am: 55fab9cd am: ede8782c

Change-Id: If959a44bcc52bc9c0a306af6ef2ca9a9da956de6
parents 364d73d8 ede8782c
Loading
Loading
Loading
Loading
+30 −1
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.app.NotificationManager;
import android.app.Person;
import android.app.Person;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetEvent;
import android.app.usage.UsageEvents;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentResolver;
@@ -70,6 +71,7 @@ import com.android.server.notification.NotificationManagerInternal;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Executors;
@@ -237,6 +239,27 @@ public class DataManager {
        eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType));
        eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType));
    }
    }


    /**
     * Queries events for moving app to foreground between {@code startTime} and {@code endTime}.
     */
    @NonNull
    public List<UsageEvents.Event> queryAppMovingToForegroundEvents(@UserIdInt int callingUserId,
            long startTime, long endTime) {
        return UsageStatsQueryHelper.queryAppMovingToForegroundEvents(callingUserId, startTime,
                endTime);
    }

    /**
     * Queries launch counts of apps within {@code packageNameFilter} between {@code startTime}
     * and {@code endTime}.
     */
    @NonNull
    public Map<String, Integer> queryAppLaunchCount(@UserIdInt int callingUserId, long startTime,
            long endTime, Set<String> packageNameFilter) {
        return UsageStatsQueryHelper.queryAppLaunchCount(callingUserId, startTime, endTime,
                packageNameFilter);
    }

    /** Prunes the data for the specified user. */
    /** Prunes the data for the specified user. */
    public void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal) {
    public void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal) {
        UserData userData = getUnlockedUserData(userId);
        UserData userData = getUnlockedUserData(userId);
@@ -382,7 +405,13 @@ public class DataManager {
        }
        }
    }
    }


    private int mimeTypeToShareEventType(String mimeType) {
    /**
     * Converts {@code mimeType} to {@link Event.EventType}.
     */
    public int mimeTypeToShareEventType(String mimeType) {
        if (mimeType == null) {
            return Event.TYPE_SHARE_OTHER;
        }
        if (mimeType.startsWith("text/")) {
        if (mimeType.startsWith("text/")) {
            return Event.TYPE_SHARE_TEXT;
            return Event.TYPE_SHARE_TEXT;
        } else if (mimeType.startsWith("image/")) {
        } else if (mimeType.startsWith("image/")) {
+57 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.server.people.data;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.app.usage.UsageEvents;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.LocusId;
import android.content.LocusId;
@@ -27,7 +29,10 @@ import android.util.ArrayMap;


import com.android.server.LocalServices;
import com.android.server.LocalServices;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Function;


/** A helper class that queries {@link UsageStatsManagerInternal}. */
/** A helper class that queries {@link UsageStatsManagerInternal}. */
@@ -46,7 +51,7 @@ class UsageStatsQueryHelper {
     */
     */
    UsageStatsQueryHelper(@UserIdInt int userId,
    UsageStatsQueryHelper(@UserIdInt int userId,
            Function<String, PackageData> packageDataGetter) {
            Function<String, PackageData> packageDataGetter) {
        mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
        mUsageStatsManagerInternal = getUsageStatsManagerInternal();
        mUserId = userId;
        mUserId = userId;
        mPackageDataGetter = packageDataGetter;
        mPackageDataGetter = packageDataGetter;
    }
    }
@@ -106,6 +111,53 @@ class UsageStatsQueryHelper {
        return mLastEventTimestamp;
        return mLastEventTimestamp;
    }
    }


    /**
     * Queries {@link UsageStatsManagerInternal} events for moving app to foreground between
     * {@code startTime} and {@code endTime}.
     *
     * @return a list containing events moving app to foreground.
     */
    static List<UsageEvents.Event> queryAppMovingToForegroundEvents(@UserIdInt int userId,
            long startTime, long endTime) {
        List<UsageEvents.Event> res = new ArrayList<>();
        UsageEvents usageEvents = getUsageStatsManagerInternal().queryEventsForUser(userId,
                startTime, endTime,
                UsageEvents.HIDE_SHORTCUT_EVENTS | UsageEvents.HIDE_LOCUS_EVENTS);
        if (usageEvents == null) {
            return res;
        }
        while (usageEvents.hasNextEvent()) {
            UsageEvents.Event e = new UsageEvents.Event();
            usageEvents.getNextEvent(e);
            if (e.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED) {
                res.add(e);
            }
        }
        return res;
    }

    /**
     * Queries {@link UsageStatsManagerInternal} for launch count of apps within {@code
     * packageNameFilter} between {@code startTime} and {@code endTime}.obfuscateInstantApps
     *
     * @return a map which keys are package names and values are app launch counts.
     */
    static Map<String, Integer> queryAppLaunchCount(@UserIdInt int userId, long startTime,
            long endTime, Set<String> packageNameFilter) {
        List<UsageStats> stats = getUsageStatsManagerInternal().queryUsageStatsForUser(userId,
                UsageStatsManager.INTERVAL_BEST, startTime, endTime,
                /* obfuscateInstantApps= */ false);
        Map<String, Integer> aggregatedStats = new ArrayMap<>();
        for (UsageStats stat : stats) {
            String packageName = stat.getPackageName();
            if (packageNameFilter.contains(packageName)) {
                aggregatedStats.put(packageName,
                        aggregatedStats.getOrDefault(packageName, 0) + stat.getAppLaunchCount());
            }
        }
        return aggregatedStats;
    }

    private void onInAppConversationEnded(@NonNull PackageData packageData,
    private void onInAppConversationEnded(@NonNull PackageData packageData,
            @NonNull UsageEvents.Event endEvent) {
            @NonNull UsageEvents.Event endEvent) {
        ComponentName activityName =
        ComponentName activityName =
@@ -138,4 +190,8 @@ class UsageStatsQueryHelper {
                EventStore.CATEGORY_LOCUS_ID_BASED, locusId.getId());
                EventStore.CATEGORY_LOCUS_ID_BASED, locusId.getId());
        eventHistory.addEvent(event);
        eventHistory.addEvent(event);
    }
    }

    private static UsageStatsManagerInternal getUsageStatsManagerInternal() {
        return LocalServices.getService(UsageStatsManagerInternal.class);
    }
}
}
+30 −29
Original line number Original line Diff line number Diff line
@@ -27,13 +27,11 @@ import android.app.prediction.AppTargetId;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager.ShareShortcutInfo;
import android.content.pm.ShortcutManager.ShareShortcutInfo;
import android.util.Range;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ChooserActivity;
import com.android.internal.app.ChooserActivity;
import com.android.server.people.data.ConversationInfo;
import com.android.server.people.data.ConversationInfo;
import com.android.server.people.data.DataManager;
import com.android.server.people.data.DataManager;
import com.android.server.people.data.Event;
import com.android.server.people.data.EventHistory;
import com.android.server.people.data.EventHistory;
import com.android.server.people.data.PackageData;
import com.android.server.people.data.PackageData;


@@ -42,6 +40,9 @@ import java.util.Collections;
import java.util.List;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Consumer;


/**
 * Predictor that predicts the {@link AppTarget} the user is most likely to open on share sheet.
 */
class ShareTargetPredictor extends AppTargetPredictor {
class ShareTargetPredictor extends AppTargetPredictor {


    private final IntentFilter mIntentFilter;
    private final IntentFilter mIntentFilter;
@@ -66,7 +67,9 @@ class ShareTargetPredictor extends AppTargetPredictor {
    @Override
    @Override
    void predictTargets() {
    void predictTargets() {
        List<ShareTarget> shareTargets = getDirectShareTargets();
        List<ShareTarget> shareTargets = getDirectShareTargets();
        rankTargets(shareTargets);
        SharesheetModelScorer.computeScore(shareTargets, getShareEventType(mIntentFilter),
                System.currentTimeMillis());
        Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore()));
        List<AppTarget> res = new ArrayList<>();
        List<AppTarget> res = new ArrayList<>();
        for (int i = 0; i < Math.min(getPredictionContext().getPredictedTargetCount(),
        for (int i = 0; i < Math.min(getPredictionContext().getPredictedTargetCount(),
                shareTargets.size()); i++) {
                shareTargets.size()); i++) {
@@ -80,36 +83,16 @@ class ShareTargetPredictor extends AppTargetPredictor {
    @Override
    @Override
    void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) {
    void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) {
        List<ShareTarget> shareTargets = getAppShareTargets(targets);
        List<ShareTarget> shareTargets = getAppShareTargets(targets);
        rankTargets(shareTargets);
        SharesheetModelScorer.computeScoreForAppShare(shareTargets,
                getShareEventType(mIntentFilter), getPredictionContext().getPredictedTargetCount(),
                System.currentTimeMillis(), getDataManager(),
                mCallingUserId);
        Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore()));
        List<AppTarget> appTargetList = new ArrayList<>();
        List<AppTarget> appTargetList = new ArrayList<>();
        shareTargets.forEach(t -> appTargetList.add(t.getAppTarget()));
        shareTargets.forEach(t -> appTargetList.add(t.getAppTarget()));
        callback.accept(appTargetList);
        callback.accept(appTargetList);
    }
    }


    private void rankTargets(List<ShareTarget> shareTargets) {
        // Rank targets based on recency of sharing history only for the moment.
        // TODO: Take more factors into ranking, e.g. frequency, mime type, foreground app.
        Collections.sort(shareTargets, (t1, t2) -> {
            if (t1.getEventHistory() == null) {
                return 1;
            }
            if (t2.getEventHistory() == null) {
                return -1;
            }
            Range<Long> timeSlot1 = t1.getEventHistory().getEventIndex(
                    Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
            Range<Long> timeSlot2 = t2.getEventHistory().getEventIndex(
                    Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
            if (timeSlot1 == null) {
                return 1;
            } else if (timeSlot2 == null) {
                return -1;
            } else {
                return -Long.compare(timeSlot1.getUpper(), timeSlot2.getUpper());
            }
        });
    }

    private List<ShareTarget> getDirectShareTargets() {
    private List<ShareTarget> getDirectShareTargets() {
        List<ShareTarget> shareTargets = new ArrayList<>();
        List<ShareTarget> shareTargets = new ArrayList<>();
        List<ShareShortcutInfo> shareShortcuts =
        List<ShareShortcutInfo> shareShortcuts =
@@ -153,6 +136,11 @@ class ShareTargetPredictor extends AppTargetPredictor {
        return shareTargets;
        return shareTargets;
    }
    }


    private int getShareEventType(IntentFilter intentFilter) {
        String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
        return getDataManager().mimeTypeToShareEventType(mimeType);
    }

    @VisibleForTesting
    @VisibleForTesting
    static class ShareTarget {
    static class ShareTarget {


@@ -162,13 +150,16 @@ class ShareTargetPredictor extends AppTargetPredictor {
        private final EventHistory mEventHistory;
        private final EventHistory mEventHistory;
        @Nullable
        @Nullable
        private final ConversationInfo mConversationInfo;
        private final ConversationInfo mConversationInfo;
        private float mScore;


        private ShareTarget(@NonNull AppTarget appTarget,
        @VisibleForTesting
        ShareTarget(@NonNull AppTarget appTarget,
                @Nullable EventHistory eventHistory,
                @Nullable EventHistory eventHistory,
                @Nullable ConversationInfo conversationInfo) {
                @Nullable ConversationInfo conversationInfo) {
            mAppTarget = appTarget;
            mAppTarget = appTarget;
            mEventHistory = eventHistory;
            mEventHistory = eventHistory;
            mConversationInfo = conversationInfo;
            mConversationInfo = conversationInfo;
            mScore = 0f;
        }
        }


        @NonNull
        @NonNull
@@ -188,5 +179,15 @@ class ShareTargetPredictor extends AppTargetPredictor {
        ConversationInfo getConversationInfo() {
        ConversationInfo getConversationInfo() {
            return mConversationInfo;
            return mConversationInfo;
        }
        }

        @VisibleForTesting
        float getScore() {
            return mScore;
        }

        @VisibleForTesting
        void setScore(float score) {
            mScore = score;
        }
    }
    }
}
}
Loading