Loading services/people/java/com/android/server/people/SessionInfo.java +5 −5 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import android.os.RemoteException; import android.util.Slog; import com.android.server.people.data.DataManager; import com.android.server.people.prediction.ConversationPredictor; import com.android.server.people.prediction.AppTargetPredictor; import java.util.List; Loading @@ -34,12 +34,12 @@ class SessionInfo { private static final String TAG = "SessionInfo"; private final ConversationPredictor mConversationPredictor; private final AppTargetPredictor mAppTargetPredictor; private final RemoteCallbackList<IPredictionCallback> mCallbacks = new RemoteCallbackList<>(); SessionInfo(AppPredictionContext predictionContext, DataManager dataManager) { mConversationPredictor = new ConversationPredictor(predictionContext, mAppTargetPredictor = AppTargetPredictor.create(predictionContext, this::updatePredictions, dataManager); } Loading @@ -51,8 +51,8 @@ class SessionInfo { mCallbacks.unregister(callback); } ConversationPredictor getPredictor() { return mConversationPredictor; AppTargetPredictor getPredictor() { return mAppTargetPredictor; } void onDestroy() { Loading services/people/java/com/android/server/people/data/DataManager.java +14 −31 Original line number Diff line number Diff line Loading @@ -59,7 +59,6 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.telephony.SmsApplication; import com.android.server.LocalServices; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; Loading Loading @@ -199,6 +198,13 @@ public class DataManager { } } /** Gets the {@link PackageData} for the given package and user. */ @Nullable public PackageData getPackage(@NonNull String packageName, @UserIdInt int userId) { UserData userData = getUnlockedUserData(userId); return userData != null ? userData.getPackageData(packageName) : null; } /** Gets the {@link ShortcutInfo} for the given shortcut ID. */ @Nullable public ShortcutInfo getShortcut(@NonNull String packageName, @UserIdInt int userId, Loading @@ -212,20 +218,11 @@ public class DataManager { } /** * Gets the conversation {@link ShareShortcutInfo}s from all packages owned by the calling user * that match the specified {@link IntentFilter}. * Gets the {@link ShareShortcutInfo}s from all packages owned by the calling user that match * the specified {@link IntentFilter}. */ public List<ShareShortcutInfo> getConversationShareTargets( @NonNull IntentFilter intentFilter) { List<ShareShortcutInfo> shareShortcuts = mShortcutManager.getShareTargets(intentFilter); List<ShareShortcutInfo> result = new ArrayList<>(); for (ShareShortcutInfo shareShortcut : shareShortcuts) { ShortcutInfo si = shareShortcut.getShortcutInfo(); if (getConversationInfo(si.getPackage(), si.getUserId(), si.getId()) != null) { result.add(shareShortcut); } } return result; public List<ShareShortcutInfo> getShareShortcuts(@NonNull IntentFilter intentFilter) { return mShortcutManager.getShareTargets(intentFilter); } /** Reports the {@link AppTargetEvent} from App Prediction Manager. */ Loading @@ -236,7 +233,7 @@ public class DataManager { if (shortcutInfo == null || event.getAction() != AppTargetEvent.ACTION_LAUNCH) { return; } PackageData packageData = getPackageData(appTarget.getPackageName(), PackageData packageData = getPackage(appTarget.getPackageName(), appTarget.getUser().getIdentifier()); if (packageData == null) { return; Loading Loading @@ -283,20 +280,6 @@ public class DataManager { return userData != null && userData.isUnlocked() ? userData : null; } @Nullable private PackageData getPackageData(@NonNull String packageName, int userId) { UserData userData = getUnlockedUserData(userId); return userData != null ? userData.getPackageData(packageName) : null; } @Nullable private ConversationInfo getConversationInfo(@NonNull String packageName, @UserIdInt int userId, @NonNull String shortcutId) { PackageData packageData = getPackageData(packageName, userId); return packageData != null ? packageData.getConversationStore().getConversation(shortcutId) : null; } private void updateDefaultDialer(@NonNull UserData userData) { TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); String defaultDialer = telecomManager != null Loading @@ -318,7 +301,7 @@ public class DataManager { if (shortcutId == null) { return null; } PackageData packageData = getPackageData(sbn.getPackageName(), PackageData packageData = getPackage(sbn.getPackageName(), sbn.getUser().getIdentifier()); if (packageData == null || packageData.getConversationStore().getConversation(shortcutId) == null) { Loading Loading @@ -382,7 +365,7 @@ public class DataManager { usageEvents.getNextEvent(e); String packageName = e.getPackageName(); PackageData packageData = getPackageData(packageName, userId); PackageData packageData = getPackage(packageName, userId); if (packageData == null) { continue; } Loading services/people/java/com/android/server/people/data/PackageData.java +10 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.people.data; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.LocusId; import android.text.TextUtils; Loading Loading @@ -67,6 +68,15 @@ public class PackageData { return getEventStore().getPackageEventHistory(); } /** * Gets the {@link ConversationInfo} for a given shortcut ID. Returns null if such as {@link * ConversationInfo} does not exist. */ @Nullable public ConversationInfo getConversationInfo(@NonNull String shortcutId) { return getConversationStore().getConversation(shortcutId); } /** * Gets the combined {@link EventHistory} for a given shortcut ID. This returned {@link * EventHistory} has events of all types, no matter whether they're annotated with shortcut ID, Loading services/people/java/com/android/server/people/prediction/ConversationPredictor.java→services/people/java/com/android/server/people/prediction/AppTargetPredictor.java +128 −0 Original line number Diff line number Diff line Loading @@ -18,53 +18,50 @@ package com.android.server.people.prediction; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ChooserActivity; import com.android.server.people.data.DataManager; import com.android.server.people.data.EventHistory; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; /** * Predictor that predicts the conversations or apps the user is most likely to open. * Predictor that predicts the {@link AppTarget} the user is most likely to open. */ public class ConversationPredictor { public class AppTargetPredictor { private static final String UI_SURFACE_SHARE = "share"; /** Creates a {@link AppTargetPredictor} instance based on the prediction context. */ public static AppTargetPredictor create(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, @NonNull DataManager dataManager) { if (UI_SURFACE_SHARE.equals(predictionContext.getUiSurface())) { return new ShareTargetPredictor( predictionContext, updatePredictionsMethod, dataManager); } return new AppTargetPredictor(predictionContext, updatePredictionsMethod, dataManager); } private final AppPredictionContext mPredictionContext; private final Consumer<List<AppTarget>> mUpdatePredictionsMethod; private final DataManager mDataManager; private final ExecutorService mCallbackExecutor; @Nullable private final IntentFilter mIntentFilter; public ConversationPredictor(@NonNull AppPredictionContext predictionContext, AppTargetPredictor(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, @NonNull DataManager dataManager) { mPredictionContext = predictionContext; mUpdatePredictionsMethod = updatePredictionsMethod; mDataManager = dataManager; mCallbackExecutor = Executors.newSingleThreadExecutor(); if (UI_SURFACE_SHARE.equals(mPredictionContext.getUiSurface())) { mIntentFilter = mPredictionContext.getExtras().getParcelable( ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY); } else { mIntentFilter = null; } } /** Loading @@ -72,14 +69,14 @@ public class ConversationPredictor { */ @MainThread public void onAppTargetEvent(AppTargetEvent event) { mDataManager.reportAppTargetEvent(event, mIntentFilter); } /** * Called by the client app to indicate a particular location has been shown to the user. */ @MainThread public void onLaunchLocationShown(String launchLocation, List<AppTargetId> targetIds) {} public void onLaunchLocationShown(String launchLocation, List<AppTargetId> targetIds) { } /** * Called by the client app to request sorting of the provided targets based on the prediction Loading @@ -87,7 +84,7 @@ public class ConversationPredictor { */ @MainThread public void onSortAppTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) { mCallbackExecutor.execute(() -> callback.accept(targets)); mCallbackExecutor.execute(() -> sortTargets(targets, callback)); } /** Loading @@ -95,48 +92,37 @@ public class ConversationPredictor { */ @MainThread public void onRequestPredictionUpdate() { // TODO: Re-route the call to different ranking classes for different surfaces. mCallbackExecutor.execute(() -> { List<AppTarget> targets = new ArrayList<>(); if (mIntentFilter != null) { List<ShareShortcutInfo> shareShortcuts = mDataManager.getConversationShareTargets(mIntentFilter); for (ShareShortcutInfo shareShortcut : shareShortcuts) { ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); AppTargetId appTargetId = new AppTargetId(shortcutInfo.getId()); String shareTargetClass = shareShortcut.getTargetComponent().getClassName(); targets.add(new AppTarget.Builder(appTargetId, shortcutInfo) .setClassName(shareTargetClass) .build()); mCallbackExecutor.execute(this::predictTargets); } @VisibleForTesting public Consumer<List<AppTarget>> getUpdatePredictionsMethod() { return mUpdatePredictionsMethod; } } else { List<ConversationData> conversationDataList = new ArrayList<>(); mDataManager.forAllPackages(packageData -> packageData.forAllConversations(conversationInfo -> { EventHistory eventHistory = packageData.getEventHistory( conversationInfo.getShortcutId()); ConversationData conversationData = new ConversationData( packageData.getPackageName(), packageData.getUserId(), conversationInfo, eventHistory); conversationDataList.add(conversationData); })); for (ConversationData conversationData : conversationDataList) { String shortcutId = conversationData.getConversationInfo().getShortcutId(); ShortcutInfo shortcut = mDataManager.getShortcut( conversationData.getPackageName(), conversationData.getUserId(), shortcutId); if (shortcut != null) { AppTargetId appTargetId = new AppTargetId(shortcut.getId()); targets.add(new AppTarget.Builder(appTargetId, shortcut).build()); /** To be overridden by the subclass to predict the targets. */ @WorkerThread void predictTargets() { } /** * To be overridden by the subclass to sort the provided targets based on the prediction * ranking. */ @WorkerThread void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) { callback.accept(targets); } AppPredictionContext getPredictionContext() { return mPredictionContext; } mUpdatePredictionsMethod.accept(targets); }); DataManager getDataManager() { return mDataManager; } @VisibleForTesting public Consumer<List<AppTarget>> getUpdatePredictionsMethod() { return mUpdatePredictionsMethod; void updatePredictions(List<AppTarget> targets) { mUpdatePredictionsMethod.accept(targets); } } services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java 0 → 100644 +139 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.server.people.prediction; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ChooserActivity; import com.android.server.people.data.ConversationInfo; import com.android.server.people.data.DataManager; import com.android.server.people.data.EventHistory; import com.android.server.people.data.PackageData; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; class ShareTargetPredictor extends AppTargetPredictor { private final IntentFilter mIntentFilter; ShareTargetPredictor(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, @NonNull DataManager dataManager) { super(predictionContext, updatePredictionsMethod, dataManager); mIntentFilter = predictionContext.getExtras().getParcelable( ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY); } @MainThread @Override public void onAppTargetEvent(AppTargetEvent event) { getDataManager().reportAppTargetEvent(event, mIntentFilter); } @WorkerThread @Override protected void predictTargets() { List<ShareTarget> shareTargets = getShareTargets(); // TODO: Rank the share targets with the data in ShareTarget.mConversationData. List<AppTarget> appTargets = new ArrayList<>(); for (ShareTarget shareTarget : shareTargets) { ShortcutInfo shortcutInfo = shareTarget.getShareShortcutInfo().getShortcutInfo(); AppTargetId appTargetId = new AppTargetId(shortcutInfo.getId()); String shareTargetClassName = shareTarget.getShareShortcutInfo().getTargetComponent().getClassName(); AppTarget appTarget = new AppTarget.Builder(appTargetId, shortcutInfo) .setClassName(shareTargetClassName) .build(); appTargets.add(appTarget); if (appTargets.size() >= getPredictionContext().getPredictedTargetCount()) { break; } } updatePredictions(appTargets); } @VisibleForTesting List<ShareTarget> getShareTargets() { List<ShareTarget> shareTargets = new ArrayList<>(); List<ShareShortcutInfo> shareShortcuts = getDataManager().getShareShortcuts(mIntentFilter); for (ShareShortcutInfo shareShortcut : shareShortcuts) { ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); String packageName = shortcutInfo.getPackage(); int userId = shortcutInfo.getUserId(); PackageData packageData = getDataManager().getPackage(packageName, userId); ConversationData conversationData = null; if (packageData != null) { String shortcutId = shortcutInfo.getId(); ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId); if (conversationInfo != null) { EventHistory eventHistory = packageData.getEventHistory(shortcutId); conversationData = new ConversationData( packageName, userId, conversationInfo, eventHistory); } } shareTargets.add(new ShareTarget(shareShortcut, conversationData)); } return shareTargets; } @VisibleForTesting static class ShareTarget { @NonNull private final ShareShortcutInfo mShareShortcutInfo; @Nullable private final ConversationData mConversationData; private ShareTarget(@NonNull ShareShortcutInfo shareShortcutInfo, @Nullable ConversationData conversationData) { mShareShortcutInfo = shareShortcutInfo; mConversationData = conversationData; } @NonNull @VisibleForTesting ShareShortcutInfo getShareShortcutInfo() { return mShareShortcutInfo; } @Nullable @VisibleForTesting ConversationData getConversationData() { return mConversationData; } } } Loading
services/people/java/com/android/server/people/SessionInfo.java +5 −5 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import android.os.RemoteException; import android.util.Slog; import com.android.server.people.data.DataManager; import com.android.server.people.prediction.ConversationPredictor; import com.android.server.people.prediction.AppTargetPredictor; import java.util.List; Loading @@ -34,12 +34,12 @@ class SessionInfo { private static final String TAG = "SessionInfo"; private final ConversationPredictor mConversationPredictor; private final AppTargetPredictor mAppTargetPredictor; private final RemoteCallbackList<IPredictionCallback> mCallbacks = new RemoteCallbackList<>(); SessionInfo(AppPredictionContext predictionContext, DataManager dataManager) { mConversationPredictor = new ConversationPredictor(predictionContext, mAppTargetPredictor = AppTargetPredictor.create(predictionContext, this::updatePredictions, dataManager); } Loading @@ -51,8 +51,8 @@ class SessionInfo { mCallbacks.unregister(callback); } ConversationPredictor getPredictor() { return mConversationPredictor; AppTargetPredictor getPredictor() { return mAppTargetPredictor; } void onDestroy() { Loading
services/people/java/com/android/server/people/data/DataManager.java +14 −31 Original line number Diff line number Diff line Loading @@ -59,7 +59,6 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.telephony.SmsApplication; import com.android.server.LocalServices; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; Loading Loading @@ -199,6 +198,13 @@ public class DataManager { } } /** Gets the {@link PackageData} for the given package and user. */ @Nullable public PackageData getPackage(@NonNull String packageName, @UserIdInt int userId) { UserData userData = getUnlockedUserData(userId); return userData != null ? userData.getPackageData(packageName) : null; } /** Gets the {@link ShortcutInfo} for the given shortcut ID. */ @Nullable public ShortcutInfo getShortcut(@NonNull String packageName, @UserIdInt int userId, Loading @@ -212,20 +218,11 @@ public class DataManager { } /** * Gets the conversation {@link ShareShortcutInfo}s from all packages owned by the calling user * that match the specified {@link IntentFilter}. * Gets the {@link ShareShortcutInfo}s from all packages owned by the calling user that match * the specified {@link IntentFilter}. */ public List<ShareShortcutInfo> getConversationShareTargets( @NonNull IntentFilter intentFilter) { List<ShareShortcutInfo> shareShortcuts = mShortcutManager.getShareTargets(intentFilter); List<ShareShortcutInfo> result = new ArrayList<>(); for (ShareShortcutInfo shareShortcut : shareShortcuts) { ShortcutInfo si = shareShortcut.getShortcutInfo(); if (getConversationInfo(si.getPackage(), si.getUserId(), si.getId()) != null) { result.add(shareShortcut); } } return result; public List<ShareShortcutInfo> getShareShortcuts(@NonNull IntentFilter intentFilter) { return mShortcutManager.getShareTargets(intentFilter); } /** Reports the {@link AppTargetEvent} from App Prediction Manager. */ Loading @@ -236,7 +233,7 @@ public class DataManager { if (shortcutInfo == null || event.getAction() != AppTargetEvent.ACTION_LAUNCH) { return; } PackageData packageData = getPackageData(appTarget.getPackageName(), PackageData packageData = getPackage(appTarget.getPackageName(), appTarget.getUser().getIdentifier()); if (packageData == null) { return; Loading Loading @@ -283,20 +280,6 @@ public class DataManager { return userData != null && userData.isUnlocked() ? userData : null; } @Nullable private PackageData getPackageData(@NonNull String packageName, int userId) { UserData userData = getUnlockedUserData(userId); return userData != null ? userData.getPackageData(packageName) : null; } @Nullable private ConversationInfo getConversationInfo(@NonNull String packageName, @UserIdInt int userId, @NonNull String shortcutId) { PackageData packageData = getPackageData(packageName, userId); return packageData != null ? packageData.getConversationStore().getConversation(shortcutId) : null; } private void updateDefaultDialer(@NonNull UserData userData) { TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); String defaultDialer = telecomManager != null Loading @@ -318,7 +301,7 @@ public class DataManager { if (shortcutId == null) { return null; } PackageData packageData = getPackageData(sbn.getPackageName(), PackageData packageData = getPackage(sbn.getPackageName(), sbn.getUser().getIdentifier()); if (packageData == null || packageData.getConversationStore().getConversation(shortcutId) == null) { Loading Loading @@ -382,7 +365,7 @@ public class DataManager { usageEvents.getNextEvent(e); String packageName = e.getPackageName(); PackageData packageData = getPackageData(packageName, userId); PackageData packageData = getPackage(packageName, userId); if (packageData == null) { continue; } Loading
services/people/java/com/android/server/people/data/PackageData.java +10 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.people.data; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.LocusId; import android.text.TextUtils; Loading Loading @@ -67,6 +68,15 @@ public class PackageData { return getEventStore().getPackageEventHistory(); } /** * Gets the {@link ConversationInfo} for a given shortcut ID. Returns null if such as {@link * ConversationInfo} does not exist. */ @Nullable public ConversationInfo getConversationInfo(@NonNull String shortcutId) { return getConversationStore().getConversation(shortcutId); } /** * Gets the combined {@link EventHistory} for a given shortcut ID. This returned {@link * EventHistory} has events of all types, no matter whether they're annotated with shortcut ID, Loading
services/people/java/com/android/server/people/prediction/ConversationPredictor.java→services/people/java/com/android/server/people/prediction/AppTargetPredictor.java +128 −0 Original line number Diff line number Diff line Loading @@ -18,53 +18,50 @@ package com.android.server.people.prediction; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ChooserActivity; import com.android.server.people.data.DataManager; import com.android.server.people.data.EventHistory; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; /** * Predictor that predicts the conversations or apps the user is most likely to open. * Predictor that predicts the {@link AppTarget} the user is most likely to open. */ public class ConversationPredictor { public class AppTargetPredictor { private static final String UI_SURFACE_SHARE = "share"; /** Creates a {@link AppTargetPredictor} instance based on the prediction context. */ public static AppTargetPredictor create(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, @NonNull DataManager dataManager) { if (UI_SURFACE_SHARE.equals(predictionContext.getUiSurface())) { return new ShareTargetPredictor( predictionContext, updatePredictionsMethod, dataManager); } return new AppTargetPredictor(predictionContext, updatePredictionsMethod, dataManager); } private final AppPredictionContext mPredictionContext; private final Consumer<List<AppTarget>> mUpdatePredictionsMethod; private final DataManager mDataManager; private final ExecutorService mCallbackExecutor; @Nullable private final IntentFilter mIntentFilter; public ConversationPredictor(@NonNull AppPredictionContext predictionContext, AppTargetPredictor(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, @NonNull DataManager dataManager) { mPredictionContext = predictionContext; mUpdatePredictionsMethod = updatePredictionsMethod; mDataManager = dataManager; mCallbackExecutor = Executors.newSingleThreadExecutor(); if (UI_SURFACE_SHARE.equals(mPredictionContext.getUiSurface())) { mIntentFilter = mPredictionContext.getExtras().getParcelable( ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY); } else { mIntentFilter = null; } } /** Loading @@ -72,14 +69,14 @@ public class ConversationPredictor { */ @MainThread public void onAppTargetEvent(AppTargetEvent event) { mDataManager.reportAppTargetEvent(event, mIntentFilter); } /** * Called by the client app to indicate a particular location has been shown to the user. */ @MainThread public void onLaunchLocationShown(String launchLocation, List<AppTargetId> targetIds) {} public void onLaunchLocationShown(String launchLocation, List<AppTargetId> targetIds) { } /** * Called by the client app to request sorting of the provided targets based on the prediction Loading @@ -87,7 +84,7 @@ public class ConversationPredictor { */ @MainThread public void onSortAppTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) { mCallbackExecutor.execute(() -> callback.accept(targets)); mCallbackExecutor.execute(() -> sortTargets(targets, callback)); } /** Loading @@ -95,48 +92,37 @@ public class ConversationPredictor { */ @MainThread public void onRequestPredictionUpdate() { // TODO: Re-route the call to different ranking classes for different surfaces. mCallbackExecutor.execute(() -> { List<AppTarget> targets = new ArrayList<>(); if (mIntentFilter != null) { List<ShareShortcutInfo> shareShortcuts = mDataManager.getConversationShareTargets(mIntentFilter); for (ShareShortcutInfo shareShortcut : shareShortcuts) { ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); AppTargetId appTargetId = new AppTargetId(shortcutInfo.getId()); String shareTargetClass = shareShortcut.getTargetComponent().getClassName(); targets.add(new AppTarget.Builder(appTargetId, shortcutInfo) .setClassName(shareTargetClass) .build()); mCallbackExecutor.execute(this::predictTargets); } @VisibleForTesting public Consumer<List<AppTarget>> getUpdatePredictionsMethod() { return mUpdatePredictionsMethod; } } else { List<ConversationData> conversationDataList = new ArrayList<>(); mDataManager.forAllPackages(packageData -> packageData.forAllConversations(conversationInfo -> { EventHistory eventHistory = packageData.getEventHistory( conversationInfo.getShortcutId()); ConversationData conversationData = new ConversationData( packageData.getPackageName(), packageData.getUserId(), conversationInfo, eventHistory); conversationDataList.add(conversationData); })); for (ConversationData conversationData : conversationDataList) { String shortcutId = conversationData.getConversationInfo().getShortcutId(); ShortcutInfo shortcut = mDataManager.getShortcut( conversationData.getPackageName(), conversationData.getUserId(), shortcutId); if (shortcut != null) { AppTargetId appTargetId = new AppTargetId(shortcut.getId()); targets.add(new AppTarget.Builder(appTargetId, shortcut).build()); /** To be overridden by the subclass to predict the targets. */ @WorkerThread void predictTargets() { } /** * To be overridden by the subclass to sort the provided targets based on the prediction * ranking. */ @WorkerThread void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) { callback.accept(targets); } AppPredictionContext getPredictionContext() { return mPredictionContext; } mUpdatePredictionsMethod.accept(targets); }); DataManager getDataManager() { return mDataManager; } @VisibleForTesting public Consumer<List<AppTarget>> getUpdatePredictionsMethod() { return mUpdatePredictionsMethod; void updatePredictions(List<AppTarget> targets) { mUpdatePredictionsMethod.accept(targets); } }
services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java 0 → 100644 +139 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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.server.people.prediction; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; import android.app.prediction.AppTargetId; import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ChooserActivity; import com.android.server.people.data.ConversationInfo; import com.android.server.people.data.DataManager; import com.android.server.people.data.EventHistory; import com.android.server.people.data.PackageData; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; class ShareTargetPredictor extends AppTargetPredictor { private final IntentFilter mIntentFilter; ShareTargetPredictor(@NonNull AppPredictionContext predictionContext, @NonNull Consumer<List<AppTarget>> updatePredictionsMethod, @NonNull DataManager dataManager) { super(predictionContext, updatePredictionsMethod, dataManager); mIntentFilter = predictionContext.getExtras().getParcelable( ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY); } @MainThread @Override public void onAppTargetEvent(AppTargetEvent event) { getDataManager().reportAppTargetEvent(event, mIntentFilter); } @WorkerThread @Override protected void predictTargets() { List<ShareTarget> shareTargets = getShareTargets(); // TODO: Rank the share targets with the data in ShareTarget.mConversationData. List<AppTarget> appTargets = new ArrayList<>(); for (ShareTarget shareTarget : shareTargets) { ShortcutInfo shortcutInfo = shareTarget.getShareShortcutInfo().getShortcutInfo(); AppTargetId appTargetId = new AppTargetId(shortcutInfo.getId()); String shareTargetClassName = shareTarget.getShareShortcutInfo().getTargetComponent().getClassName(); AppTarget appTarget = new AppTarget.Builder(appTargetId, shortcutInfo) .setClassName(shareTargetClassName) .build(); appTargets.add(appTarget); if (appTargets.size() >= getPredictionContext().getPredictedTargetCount()) { break; } } updatePredictions(appTargets); } @VisibleForTesting List<ShareTarget> getShareTargets() { List<ShareTarget> shareTargets = new ArrayList<>(); List<ShareShortcutInfo> shareShortcuts = getDataManager().getShareShortcuts(mIntentFilter); for (ShareShortcutInfo shareShortcut : shareShortcuts) { ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); String packageName = shortcutInfo.getPackage(); int userId = shortcutInfo.getUserId(); PackageData packageData = getDataManager().getPackage(packageName, userId); ConversationData conversationData = null; if (packageData != null) { String shortcutId = shortcutInfo.getId(); ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId); if (conversationInfo != null) { EventHistory eventHistory = packageData.getEventHistory(shortcutId); conversationData = new ConversationData( packageName, userId, conversationInfo, eventHistory); } } shareTargets.add(new ShareTarget(shareShortcut, conversationData)); } return shareTargets; } @VisibleForTesting static class ShareTarget { @NonNull private final ShareShortcutInfo mShareShortcutInfo; @Nullable private final ConversationData mConversationData; private ShareTarget(@NonNull ShareShortcutInfo shareShortcutInfo, @Nullable ConversationData conversationData) { mShareShortcutInfo = shareShortcutInfo; mConversationData = conversationData; } @NonNull @VisibleForTesting ShareShortcutInfo getShareShortcutInfo() { return mShareShortcutInfo; } @Nullable @VisibleForTesting ConversationData getConversationData() { return mConversationData; } } }