Loading core/java/com/android/internal/app/AbstractResolverComparator.java +0 −6 Original line number Diff line number Diff line Loading @@ -228,12 +228,6 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC */ abstract float getScore(ComponentName name); /** * Returns the list of top K component names which have highest * {@link #getScore(ComponentName)} */ abstract List<ComponentName> getTopComponentNames(int topK); /** Handles result message sent to mHandler. */ abstract void handleResultMessage(Message message); Loading core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java +101 −50 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.app; import static android.app.prediction.AppTargetEvent.ACTION_LAUNCH; import android.annotation.Nullable; import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; Loading @@ -33,12 +34,11 @@ import android.util.Log; import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Executors; import java.util.stream.Collectors; /** * Uses an {@link AppPredictor} to sort Resolver targets. If the AppPredictionService appears to be Loading @@ -58,7 +58,9 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator private final String mReferrerPackage; // If this is non-null (and this is not destroyed), it means APS is disabled and we should fall // back to using the ResolverRankerService. // TODO: responsibility for this fallback behavior can live outside of the AppPrediction client. private ResolverRankerServiceResolverComparator mResolverRankerService; private AppPredictionServiceComparatorModel mComparatorModel; AppPredictionServiceResolverComparator( Context context, Loading @@ -74,25 +76,12 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator mUser = user; mReferrerPackage = referrerPackage; setChooserActivityLogger(chooserActivityLogger); mComparatorModel = buildUpdatedModel(); } @Override int compare(ResolveInfo lhs, ResolveInfo rhs) { if (mResolverRankerService != null) { return mResolverRankerService.compare(lhs, rhs); } Integer lhsRank = mTargetRanks.get(new ComponentName(lhs.activityInfo.packageName, lhs.activityInfo.name)); Integer rhsRank = mTargetRanks.get(new ComponentName(rhs.activityInfo.packageName, rhs.activityInfo.name)); if (lhsRank == null && rhsRank == null) { return 0; } else if (lhsRank == null) { return -1; } else if (rhsRank == null) { return 1; } return lhsRank - rhsRank; return mComparatorModel.getComparator().compare(lhs, rhs); } @Override Loading Loading @@ -121,6 +110,7 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator mContext, mIntent, mReferrerPackage, () -> mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT), getChooserActivityLogger()); mComparatorModel = buildUpdatedModel(); mResolverRankerService.compute(targets); } else { Log.i(TAG, "AppPredictionService response received"); Loading Loading @@ -163,6 +153,7 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator mTargetRanks.put(componentName, i); Log.i(TAG, "handleSortedAppTargets, sortedAppTargets #" + i + ": " + componentName); } mComparatorModel = buildUpdatedModel(); } private boolean checkAppTargetRankValid(List<AppTarget> sortedAppTargets) { Loading @@ -176,6 +167,85 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator @Override float getScore(ComponentName name) { return mComparatorModel.getScore(name); } @Override void updateModel(ComponentName componentName) { mComparatorModel.notifyOnTargetSelected(componentName); } @Override void destroy() { if (mResolverRankerService != null) { mResolverRankerService.destroy(); mResolverRankerService = null; mComparatorModel = buildUpdatedModel(); } } /** * Re-construct an {@code AppPredictionServiceComparatorModel} to replace the current model * instance (if any) using the up-to-date {@code AppPredictionServiceResolverComparator} ivar * values. * * TODO: each time we replace the model instance, we're either updating the model to use * adjusted data (which is appropriate), or we're providing a (late) value for one of our ivars * that wasn't available the last time the model was updated. For those latter cases, we should * just avoid creating the model altogether until we have all the prerequisites we'll need. Then * we can probably simplify the logic in {@code AppPredictionServiceComparatorModel} since we * won't need to handle edge cases when the model data isn't fully prepared. * (In some cases, these kinds of "updates" might interleave -- e.g., we might have finished * initializing the first time and now want to adjust some data, but still need to wait for * changes to propagate to the other ivars before rebuilding the model.) */ private AppPredictionServiceComparatorModel buildUpdatedModel() { return new AppPredictionServiceComparatorModel( mAppPredictor, mResolverRankerService, mUser, mTargetRanks); } // TODO: Finish separating behaviors of AbstractResolverComparator, then (probably) make this a // standalone class once clients are written in terms of ResolverComparatorModel. static class AppPredictionServiceComparatorModel implements ResolverComparatorModel { private final AppPredictor mAppPredictor; private final ResolverRankerServiceResolverComparator mResolverRankerService; private final UserHandle mUser; private final Map<ComponentName, Integer> mTargetRanks; // Treat as immutable. AppPredictionServiceComparatorModel( AppPredictor appPredictor, @Nullable ResolverRankerServiceResolverComparator resolverRankerService, UserHandle user, Map<ComponentName, Integer> targetRanks) { mAppPredictor = appPredictor; mResolverRankerService = resolverRankerService; mUser = user; mTargetRanks = targetRanks; } @Override public Comparator<ResolveInfo> getComparator() { return (lhs, rhs) -> { if (mResolverRankerService != null) { return mResolverRankerService.compare(lhs, rhs); } Integer lhsRank = mTargetRanks.get(new ComponentName(lhs.activityInfo.packageName, lhs.activityInfo.name)); Integer rhsRank = mTargetRanks.get(new ComponentName(rhs.activityInfo.packageName, rhs.activityInfo.name)); if (lhsRank == null && rhsRank == null) { return 0; } else if (lhsRank == null) { return -1; } else if (rhsRank == null) { return 1; } return lhsRank - rhsRank; }; } @Override public float getScore(ComponentName name) { if (mResolverRankerService != null) { return mResolverRankerService.getScore(name); } Loading @@ -189,19 +259,7 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator } @Override List<ComponentName> getTopComponentNames(int topK) { if (mResolverRankerService != null) { return mResolverRankerService.getTopComponentNames(topK); } return mTargetRanks.entrySet().stream() .sorted(Entry.comparingByValue()) .limit(topK) .map(Entry::getKey) .collect(Collectors.toList()); } @Override void updateModel(ComponentName componentName) { public void notifyOnTargetSelected(ComponentName componentName) { if (mResolverRankerService != null) { mResolverRankerService.updateModel(componentName); return; Loading @@ -214,12 +272,5 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator .setClassName(componentName.getClassName()).build(), ACTION_LAUNCH).build()); } @Override void destroy() { if (mResolverRankerService != null) { mResolverRankerService.destroy(); mResolverRankerService = null; } } } core/java/com/android/internal/app/ResolverComparatorModel.java 0 → 100644 +57 −0 Original line number Diff line number Diff line /* * Copyright 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.internal.app; import android.content.ComponentName; import android.content.pm.ResolveInfo; import java.util.Comparator; import java.util.List; /** * A ranking model for resolver targets, providing ordering and (optionally) numerical scoring. * * As required by the {@link Comparator} contract, objects returned by {@code getComparator()} must * apply a total ordering on its inputs consistent across all calls to {@code Comparator#compare()}. * Other query methods and ranking feedback should refer to that same ordering, so implementors are * generally advised to "lock in" an immutable snapshot of their model data when this object is * initialized (preferring to replace the entire {@code ResolverComparatorModel} instance if the * backing data needs to be updated in the future). */ interface ResolverComparatorModel { /** * Get a {@code Comparator} that can be used to sort {@code ResolveInfo} targets according to * the model ranking. */ Comparator<ResolveInfo> getComparator(); /** * Get the numerical score, if any, that the model assigns to the component with the specified * {@code name}. Scores range from zero to one, with one representing the highest possible * likelihood that the user will select that component as the target. Implementations that don't * assign numerical scores are <em>recommended</em> to return a value of 0 for all components. */ float getScore(ComponentName name); /** * Notify the model that the user selected a target. (Models may log this information, use it as * a feedback signal for their ranking, etc.) Because the data in this * {@code ResolverComparatorModel} instance is immutable, clients will need to get an up-to-date * instance in order to see any changes in the ranking that might result from this feedback. */ void notifyOnTargetSelected(ComponentName componentName); } core/java/com/android/internal/app/ResolverListAdapter.java +0 −8 Original line number Diff line number Diff line Loading @@ -155,14 +155,6 @@ public class ResolverListAdapter extends BaseAdapter { return mResolverListController.getScore(componentName); } /** * Returns the list of top K component names which have highest * {@link #getScore(DisplayResolveInfo)} */ public List<ComponentName> getTopComponentNames(int topK) { return mResolverListController.getTopComponentNames(topK); } public void updateModel(ComponentName componentName) { mResolverListController.updateModel(componentName); } Loading core/java/com/android/internal/app/ResolverListController.java +0 −8 Original line number Diff line number Diff line Loading @@ -393,14 +393,6 @@ public class ResolverListController { return mResolverComparator.getScore(componentName); } /** * Returns the list of top K component names which have highest * {@link #getScore(DisplayResolveInfo)} */ public List<ComponentName> getTopComponentNames(int topK) { return mResolverComparator.getTopComponentNames(topK); } public void updateModel(ComponentName componentName) { mResolverComparator.updateModel(componentName); } Loading Loading
core/java/com/android/internal/app/AbstractResolverComparator.java +0 −6 Original line number Diff line number Diff line Loading @@ -228,12 +228,6 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC */ abstract float getScore(ComponentName name); /** * Returns the list of top K component names which have highest * {@link #getScore(ComponentName)} */ abstract List<ComponentName> getTopComponentNames(int topK); /** Handles result message sent to mHandler. */ abstract void handleResultMessage(Message message); Loading
core/java/com/android/internal/app/AppPredictionServiceResolverComparator.java +101 −50 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.app; import static android.app.prediction.AppTargetEvent.ACTION_LAUNCH; import android.annotation.Nullable; import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; Loading @@ -33,12 +34,11 @@ import android.util.Log; import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.Executors; import java.util.stream.Collectors; /** * Uses an {@link AppPredictor} to sort Resolver targets. If the AppPredictionService appears to be Loading @@ -58,7 +58,9 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator private final String mReferrerPackage; // If this is non-null (and this is not destroyed), it means APS is disabled and we should fall // back to using the ResolverRankerService. // TODO: responsibility for this fallback behavior can live outside of the AppPrediction client. private ResolverRankerServiceResolverComparator mResolverRankerService; private AppPredictionServiceComparatorModel mComparatorModel; AppPredictionServiceResolverComparator( Context context, Loading @@ -74,25 +76,12 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator mUser = user; mReferrerPackage = referrerPackage; setChooserActivityLogger(chooserActivityLogger); mComparatorModel = buildUpdatedModel(); } @Override int compare(ResolveInfo lhs, ResolveInfo rhs) { if (mResolverRankerService != null) { return mResolverRankerService.compare(lhs, rhs); } Integer lhsRank = mTargetRanks.get(new ComponentName(lhs.activityInfo.packageName, lhs.activityInfo.name)); Integer rhsRank = mTargetRanks.get(new ComponentName(rhs.activityInfo.packageName, rhs.activityInfo.name)); if (lhsRank == null && rhsRank == null) { return 0; } else if (lhsRank == null) { return -1; } else if (rhsRank == null) { return 1; } return lhsRank - rhsRank; return mComparatorModel.getComparator().compare(lhs, rhs); } @Override Loading Loading @@ -121,6 +110,7 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator mContext, mIntent, mReferrerPackage, () -> mHandler.sendEmptyMessage(RANKER_SERVICE_RESULT), getChooserActivityLogger()); mComparatorModel = buildUpdatedModel(); mResolverRankerService.compute(targets); } else { Log.i(TAG, "AppPredictionService response received"); Loading Loading @@ -163,6 +153,7 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator mTargetRanks.put(componentName, i); Log.i(TAG, "handleSortedAppTargets, sortedAppTargets #" + i + ": " + componentName); } mComparatorModel = buildUpdatedModel(); } private boolean checkAppTargetRankValid(List<AppTarget> sortedAppTargets) { Loading @@ -176,6 +167,85 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator @Override float getScore(ComponentName name) { return mComparatorModel.getScore(name); } @Override void updateModel(ComponentName componentName) { mComparatorModel.notifyOnTargetSelected(componentName); } @Override void destroy() { if (mResolverRankerService != null) { mResolverRankerService.destroy(); mResolverRankerService = null; mComparatorModel = buildUpdatedModel(); } } /** * Re-construct an {@code AppPredictionServiceComparatorModel} to replace the current model * instance (if any) using the up-to-date {@code AppPredictionServiceResolverComparator} ivar * values. * * TODO: each time we replace the model instance, we're either updating the model to use * adjusted data (which is appropriate), or we're providing a (late) value for one of our ivars * that wasn't available the last time the model was updated. For those latter cases, we should * just avoid creating the model altogether until we have all the prerequisites we'll need. Then * we can probably simplify the logic in {@code AppPredictionServiceComparatorModel} since we * won't need to handle edge cases when the model data isn't fully prepared. * (In some cases, these kinds of "updates" might interleave -- e.g., we might have finished * initializing the first time and now want to adjust some data, but still need to wait for * changes to propagate to the other ivars before rebuilding the model.) */ private AppPredictionServiceComparatorModel buildUpdatedModel() { return new AppPredictionServiceComparatorModel( mAppPredictor, mResolverRankerService, mUser, mTargetRanks); } // TODO: Finish separating behaviors of AbstractResolverComparator, then (probably) make this a // standalone class once clients are written in terms of ResolverComparatorModel. static class AppPredictionServiceComparatorModel implements ResolverComparatorModel { private final AppPredictor mAppPredictor; private final ResolverRankerServiceResolverComparator mResolverRankerService; private final UserHandle mUser; private final Map<ComponentName, Integer> mTargetRanks; // Treat as immutable. AppPredictionServiceComparatorModel( AppPredictor appPredictor, @Nullable ResolverRankerServiceResolverComparator resolverRankerService, UserHandle user, Map<ComponentName, Integer> targetRanks) { mAppPredictor = appPredictor; mResolverRankerService = resolverRankerService; mUser = user; mTargetRanks = targetRanks; } @Override public Comparator<ResolveInfo> getComparator() { return (lhs, rhs) -> { if (mResolverRankerService != null) { return mResolverRankerService.compare(lhs, rhs); } Integer lhsRank = mTargetRanks.get(new ComponentName(lhs.activityInfo.packageName, lhs.activityInfo.name)); Integer rhsRank = mTargetRanks.get(new ComponentName(rhs.activityInfo.packageName, rhs.activityInfo.name)); if (lhsRank == null && rhsRank == null) { return 0; } else if (lhsRank == null) { return -1; } else if (rhsRank == null) { return 1; } return lhsRank - rhsRank; }; } @Override public float getScore(ComponentName name) { if (mResolverRankerService != null) { return mResolverRankerService.getScore(name); } Loading @@ -189,19 +259,7 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator } @Override List<ComponentName> getTopComponentNames(int topK) { if (mResolverRankerService != null) { return mResolverRankerService.getTopComponentNames(topK); } return mTargetRanks.entrySet().stream() .sorted(Entry.comparingByValue()) .limit(topK) .map(Entry::getKey) .collect(Collectors.toList()); } @Override void updateModel(ComponentName componentName) { public void notifyOnTargetSelected(ComponentName componentName) { if (mResolverRankerService != null) { mResolverRankerService.updateModel(componentName); return; Loading @@ -214,12 +272,5 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator .setClassName(componentName.getClassName()).build(), ACTION_LAUNCH).build()); } @Override void destroy() { if (mResolverRankerService != null) { mResolverRankerService.destroy(); mResolverRankerService = null; } } }
core/java/com/android/internal/app/ResolverComparatorModel.java 0 → 100644 +57 −0 Original line number Diff line number Diff line /* * Copyright 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.internal.app; import android.content.ComponentName; import android.content.pm.ResolveInfo; import java.util.Comparator; import java.util.List; /** * A ranking model for resolver targets, providing ordering and (optionally) numerical scoring. * * As required by the {@link Comparator} contract, objects returned by {@code getComparator()} must * apply a total ordering on its inputs consistent across all calls to {@code Comparator#compare()}. * Other query methods and ranking feedback should refer to that same ordering, so implementors are * generally advised to "lock in" an immutable snapshot of their model data when this object is * initialized (preferring to replace the entire {@code ResolverComparatorModel} instance if the * backing data needs to be updated in the future). */ interface ResolverComparatorModel { /** * Get a {@code Comparator} that can be used to sort {@code ResolveInfo} targets according to * the model ranking. */ Comparator<ResolveInfo> getComparator(); /** * Get the numerical score, if any, that the model assigns to the component with the specified * {@code name}. Scores range from zero to one, with one representing the highest possible * likelihood that the user will select that component as the target. Implementations that don't * assign numerical scores are <em>recommended</em> to return a value of 0 for all components. */ float getScore(ComponentName name); /** * Notify the model that the user selected a target. (Models may log this information, use it as * a feedback signal for their ranking, etc.) Because the data in this * {@code ResolverComparatorModel} instance is immutable, clients will need to get an up-to-date * instance in order to see any changes in the ranking that might result from this feedback. */ void notifyOnTargetSelected(ComponentName componentName); }
core/java/com/android/internal/app/ResolverListAdapter.java +0 −8 Original line number Diff line number Diff line Loading @@ -155,14 +155,6 @@ public class ResolverListAdapter extends BaseAdapter { return mResolverListController.getScore(componentName); } /** * Returns the list of top K component names which have highest * {@link #getScore(DisplayResolveInfo)} */ public List<ComponentName> getTopComponentNames(int topK) { return mResolverListController.getTopComponentNames(topK); } public void updateModel(ComponentName componentName) { mResolverListController.updateModel(componentName); } Loading
core/java/com/android/internal/app/ResolverListController.java +0 −8 Original line number Diff line number Diff line Loading @@ -393,14 +393,6 @@ public class ResolverListController { return mResolverComparator.getScore(componentName); } /** * Returns the list of top K component names which have highest * {@link #getScore(DisplayResolveInfo)} */ public List<ComponentName> getTopComponentNames(int topK) { return mResolverComparator.getTopComponentNames(topK); } public void updateModel(ComponentName componentName) { mResolverComparator.updateModel(componentName); } Loading