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

Commit 69d4a083 authored by George Hodulik's avatar George Hodulik
Browse files

Use App Prediction Service to get share suggestions.

Bug: 111701043
Test: Manual test with an AppPredictionService that just queries ShortcutManager.

Change-Id: I7faa904d0446e9045017d2dd893dd6b4dbee85a1
parent 9de1f4e9
Loading
Loading
Loading
Loading
+96 −32
Original line number Diff line number Diff line
@@ -18,6 +18,10 @@ package com.android.internal.app;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionManager;
import android.app.prediction.AppPredictor;
import android.app.prediction.AppTarget;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -98,6 +102,20 @@ public class ChooserActivity extends ResolverActivity {

    private static final boolean DEBUG = false;


    /**
     * If {@link #USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS} and this is set to true,
     * {@link AppPredictionManager} will be queried for direct share targets.
     */
    // TODO(b/123089490): Replace with system flag
    private static final boolean USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS = false;
    // TODO(b/123088566) Share these in a better way.
    private static final String APP_PREDICTION_SHARE_UI_SURFACE = "share";
    private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
    public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
    private AppPredictor mAppPredictor;
    private AppPredictor.Callback mAppPredictorCallback;

    /**
     * If set to true, use ShortcutManager to retrieve the matching direct share targets, instead of
     * binding to every ChooserTargetService implementation.
@@ -309,6 +327,35 @@ public class ChooserActivity extends ResolverActivity {
        mChooserShownTime = System.currentTimeMillis();
        final long systemCost = mChooserShownTime - intentReceivedTime;
        MetricsLogger.histogram(null, "system_cost_for_smart_sharing", (int) systemCost);

        if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
            final IntentFilter filter = getTargetIntentFilter();
            Bundle extras = new Bundle();
            extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter);
            AppPredictionManager appPredictionManager =
                    getSystemService(AppPredictionManager.class);
            mAppPredictor = appPredictionManager.createAppPredictionSession(
                new AppPredictionContext.Builder(this)
                    .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT)
                    .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE)
                    .setExtras(extras)
                    .build());
            mAppPredictorCallback = resultList -> {
                final List<DisplayResolveInfo> driList =
                        getDisplayResolveInfos(mChooserListAdapter);
                final List<ShortcutManager.ShareShortcutInfo> shareShortcutInfos =
                        new ArrayList<>();
                for (AppTarget appTarget : resultList) {
                    shareShortcutInfos.add(new ShortcutManager.ShareShortcutInfo(
                            appTarget.getShortcutInfo(),
                            new ComponentName(
                                appTarget.getPackageName(), appTarget.getClassName())));
                }
                sendShareShortcutInfoList(shareShortcutInfos, driList);
            };
            mAppPredictor.registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback);
        }

        if (DEBUG) {
            Log.d(TAG, "System Time Cost is " + systemCost);
        }
@@ -339,6 +386,10 @@ public class ChooserActivity extends ResolverActivity {
        }
        unbindRemainingServices();
        mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_RESULT);
        if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
            mAppPredictor.unregisterPredictionUpdates(mAppPredictorCallback);
            mAppPredictor.destroy();
        }
    }

    @Override
@@ -600,15 +651,10 @@ public class ChooserActivity extends ResolverActivity {
        }
    }

    private void queryDirectShareTargets(ChooserListAdapter adapter) {
        final IntentFilter filter = getTargetIntentFilter();
        if (filter == null) {
            return;
        }

    private List<DisplayResolveInfo> getDisplayResolveInfos(ChooserListAdapter adapter) {
        // Need to keep the original DisplayResolveInfos to be able to reconstruct ServiceResultInfo
        // and use the old code path. This Ugliness should go away when Sharesheet is refactored.
        final List<DisplayResolveInfo> driList = new ArrayList<>();
        List<DisplayResolveInfo> driList = new ArrayList<>();
        int targetsToQuery = 0;
        for (int i = 0, n = adapter.getDisplayResolveInfoCount(); i < n; i++) {
            final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i);
@@ -628,11 +674,30 @@ public class ChooserActivity extends ResolverActivity {
                break;
            }
        }
        return driList;
    }

    private void queryDirectShareTargets(ChooserListAdapter adapter) {
        if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
            mAppPredictor.requestPredictionUpdate();
            return;
        }
        final IntentFilter filter = getTargetIntentFilter();
        if (filter == null) {
            return;
        }
        final List<DisplayResolveInfo> driList = getDisplayResolveInfos(adapter);

        AsyncTask.execute(() -> {
            ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE);
            List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter);
            sendShareShortcutInfoList(resultList, driList);
        });
    }

    private void sendShareShortcutInfoList(
                List<ShortcutManager.ShareShortcutInfo> resultList,
                List<DisplayResolveInfo> driList) {
        // Match ShareShortcutInfos with DisplayResolveInfos to be able to use the old code path
        // for direct share targets. After ShareSheet is refactored we should use the
        // ShareShortcutInfos directly.
@@ -648,7 +713,6 @@ public class ChooserActivity extends ResolverActivity {
            if (chooserTargets.isEmpty()) {
                continue;
            }

            final Message msg = Message.obtain();
            msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT;
            msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null);
@@ -661,7 +725,6 @@ public class ChooserActivity extends ResolverActivity {
            msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED;
            mChooserHandler.sendMessage(msg);
        }
        });
    }

    private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut) {
@@ -718,6 +781,7 @@ public class ChooserActivity extends ResolverActivity {
        // Do nothing. We'll send the voice stuff ourselves.
    }

    // TODO(b/123377860) Send clicked ShortcutInfo to mAppPredictor
    void updateModelAndChooserCounts(TargetInfo info) {
        if (info != null) {
            final ResolveInfo ri = info.getResolveInfo();