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

Commit 145b3a51 authored by George Hodulik's avatar George Hodulik
Browse files

Add AppPredictionServiceExists check.

When the flag is set, Chooser will check if APS exists and use it for
direct share ranking. Otherwise, Chooser defaults to just querying ShortcutManager
itself. ResolverActivity will register an appPredictor with ui surface
"resolver" and ChooserActivity will use ui surface "share".

Later, we will add a similar behavior to use the AppPredictor to
sort actvities by default (if it exists), otherwise use the old
API ResolverRankerService.

Test: atest frameworks/base/core/tests/coretests/src/com/android/internal/app
Test: Added parameterized tests for case when there is no AppPredictionService.
Bug:129014961
Change-Id: I6109aa8f2436cf0b3c3b4fbc36e571b2b00fe45c
parent 9b92030a
Loading
Loading
Loading
Loading
+57 −26
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.prediction.AppPredictionContext;
@@ -131,6 +132,7 @@ import java.util.List;
public class ChooserActivity extends ResolverActivity {
    private static final String TAG = "ChooserActivity";


    /**
     * Boolean extra to change the following behavior: Normally, ChooserActivity finishes itself
     * in onStop when launched in a new task. If this extra is set to true, we do not finish
@@ -141,7 +143,6 @@ 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.
@@ -433,18 +434,8 @@ public class ChooserActivity extends ResolverActivity {
                .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
                .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, 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());
        AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
        if (appPredictor != null) {
            mAppPredictorCallback = resultList -> {
                if (isFinishing() || isDestroyed()) {
                    return;
@@ -467,8 +458,10 @@ public class ChooserActivity extends ResolverActivity {
                                appTarget.getPackageName(), appTarget.getClassName())));
                }
                sendShareShortcutInfoList(shareShortcutInfos, driList);
                sendShortcutManagerShareTargetResultCompleted();
            };
            mAppPredictor.registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback);
            appPredictor
                .registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback);
        }

        mChooserRowLayer = getResources().getDrawable(R.drawable.chooser_row_layer_list, null);
@@ -872,7 +865,7 @@ public class ChooserActivity extends ResolverActivity {
        mChooserHandler.removeMessages(LIST_VIEW_UPDATE_MESSAGE);
        mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
        mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_RESULT);
        if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
        if (mAppPredictor != null) {
            mAppPredictor.unregisterPredictionUpdates(mAppPredictorCallback);
            mAppPredictor.destroy();
        }
@@ -1205,10 +1198,12 @@ public class ChooserActivity extends ResolverActivity {
    }

    private void queryDirectShareTargets(ChooserListAdapter adapter) {
        if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
            mAppPredictor.requestPredictionUpdate();
        AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
        if (appPredictor != null) {
            appPredictor.requestPredictionUpdate();
            return;
        }
        // Default to just querying ShortcutManager if AppPredictor not present.
        final IntentFilter filter = getTargetIntentFilter();
        if (filter == null) {
            return;
@@ -1248,11 +1243,15 @@ public class ChooserActivity extends ResolverActivity {
        }

        if (resultMessageSent) {
            sendShortcutManagerShareTargetResultCompleted();
        }
    }

    private void sendShortcutManagerShareTargetResultCompleted() {
        final Message msg = Message.obtain();
        msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED;
        mChooserHandler.sendMessage(msg);
    }
    }

    private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut) {
        ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo();
@@ -1309,9 +1308,7 @@ public class ChooserActivity extends ResolverActivity {

    void updateModelAndChooserCounts(TargetInfo info) {
        if (info != null) {
            if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
            sendClickToAppPredictor(info);
            }
            final ResolveInfo ri = info.getResolveInfo();
            Intent targetIntent = getTargetIntent();
            if (ri != null && ri.activityInfo != null && targetIntent != null) {
@@ -1332,6 +1329,10 @@ public class ChooserActivity extends ResolverActivity {
    }

    private void sendClickToAppPredictor(TargetInfo targetInfo) {
        AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
        if (appPredictor == null) {
            return;
        }
        if (!(targetInfo instanceof ChooserTargetInfo)) {
            return;
        }
@@ -1345,8 +1346,9 @@ public class ChooserActivity extends ResolverActivity {
        if (shortcutId == null) {
            return;
        }
        mAppPredictor.notifyAppTargetEvent(
        appPredictor.notifyAppTargetEvent(
                new AppTargetEvent.Builder(
                    // TODO(b/124404997) Send full shortcut info, not just Id with AppTargetId.
                    new AppTarget.Builder(new AppTargetId(shortcutId))
                        .setTarget(componentName.getPackageName(), getUser())
                        .setClassName(componentName.getClassName())
@@ -1356,6 +1358,34 @@ public class ChooserActivity extends ResolverActivity {
                .build());
    }

    @Nullable
    private AppPredictor getAppPredictor() {
        if (mAppPredictor == null
                    && getPackageManager().getAppPredictionServicePackageName() != null) {
            final IntentFilter filter = getTargetIntentFilter();
            Bundle extras = new Bundle();
            extras.putParcelable(APP_PREDICTION_INTENT_FILTER_KEY, filter);
            AppPredictionContext appPredictionContext = new AppPredictionContext.Builder(this)
                .setUiSurface(APP_PREDICTION_SHARE_UI_SURFACE)
                .setPredictedTargetCount(APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT)
                .setExtras(extras)
                .build();
            AppPredictionManager appPredictionManager
                    = getSystemService(AppPredictionManager.class);
            mAppPredictor = appPredictionManager.createAppPredictionSession(appPredictionContext);
        }
        return mAppPredictor;
    }

    /**
     * This will return an app predictor if it is enabled for direct share sorting
     * and if one exists. Otherwise, it returns null.
     */
    @Nullable
    private AppPredictor getAppPredictorForDirectShareIfEnabled() {
        return USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS ? getAppPredictor() : null;
    }

    void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) {
        if (mRefinementResultReceiver != null) {
            mRefinementResultReceiver.destroy();
@@ -2014,7 +2044,8 @@ public class ChooserActivity extends ResolverActivity {
                }
            }

            if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) {
            if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
                        || USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
                if (DEBUG) {
                    Log.d(TAG, "querying direct share targets from ShortcutManager");
                }
@@ -2242,7 +2273,7 @@ public class ChooserActivity extends ResolverActivity {
                return CALLER_TARGET_SCORE_BOOST;
            }

            if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
            if (getAppPredictorForDirectShareIfEnabled() != null) {
                return SHORTCUT_TARGET_SCORE_BOOST;
            }

+33 −2
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
@@ -53,7 +54,6 @@ import android.metrics.LogMaker;
import android.net.Uri;
import android.service.chooser.ChooserTarget;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;

@@ -62,10 +62,14 @@ import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;

import java.util.Arrays;
import java.util.Collection;
import java.util.function.Function;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

@@ -75,21 +79,48 @@ import java.util.List;
/**
 * Chooser activity instrumentation tests
 */
@RunWith(AndroidJUnit4.class)
@RunWith(Parameterized.class)
public class ChooserActivityTest {

    private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm;
    private static final Function<PackageManager, PackageManager> NO_APP_PREDICTION_SERVICE_PM =
            pm -> {
                PackageManager mock = Mockito.spy(pm);
                when(mock.getAppPredictionServicePackageName()).thenReturn(null);
                return mock;
            };

    @Parameterized.Parameters
    public static Collection packageManagers() {
        return Arrays.asList(new Object[][] {
                {0, "Default PackageManager", DEFAULT_PM},
                {1, "No App Prediction Service", NO_APP_PREDICTION_SERVICE_PM}
        });
    }

    private static final int CONTENT_PREVIEW_IMAGE = 1;
    private static final int CONTENT_PREVIEW_FILE = 2;
    private static final int CONTENT_PREVIEW_TEXT = 3;
    private Function<PackageManager, PackageManager> mPackageManagerOverride;
    private int mTestNum;

    @Rule
    public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
            new ActivityTestRule<>(ChooserWrapperActivity.class, false,
                    false);

    public ChooserActivityTest(
                int testNum,
                String testName,
                Function<PackageManager, PackageManager> packageManagerOverride) {
        mPackageManagerOverride = packageManagerOverride;
        mTestNum = testNum;
    }

    @Before
    public void cleanOverrideData() {
        sOverrides.reset();
        sOverrides.createPackageManager = mPackageManagerOverride;
    }

    @Test