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

Commit 80978a28 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Prototype for Sharesheet direct share row append mechanism" into...

Merge "Prototype for Sharesheet direct share row append mechanism" into rvc-dev am: e9851d5f am: a95b4bfc am: 65196e70

Change-Id: Id17c4d7fbd06c84246722bffe9c86922c94dbf63
parents 9bbcf0f5 65196e70
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -221,6 +221,12 @@ 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);

+11 −0
Original line number Diff line number Diff line
@@ -36,7 +36,9 @@ import java.util.ArrayList;
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
@@ -159,6 +161,15 @@ class AppPredictionServiceResolverComparator extends AbstractResolverComparator
        return 1.0f - (((float) rank) / consecutiveSumOfRanks);
    }

    @Override
    List<ComponentName> getTopComponentNames(int topK) {
        return mTargetRanks.entrySet().stream()
                .sorted(Entry.comparingByValue())
                .limit(topK)
                .map(Entry::getKey)
                .collect(Collectors.toList());
    }

    @Override
    void updateModel(ComponentName componentName) {
        if (mResolverRankerService != null) {
+21 −6
Original line number Diff line number Diff line
@@ -223,6 +223,11 @@ public class ChooserActivity extends ResolverActivity implements
            SystemUiDeviceConfigFlags.HASH_SALT_MAX_DAYS,
            DEFAULT_SALT_EXPIRATION_DAYS);

    private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean(
            DeviceConfig.NAMESPACE_SYSTEMUI,
            SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED,
            false);

    private Bundle mReplacementExtras;
    private IntentSender mChosenComponentSender;
    private IntentSender mRefinementIntentSender;
@@ -409,6 +414,11 @@ public class ChooserActivity extends ResolverActivity implements
        private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 10000;
        private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 3000;

        private static final int DEFAULT_DIRECT_SHARE_TIMEOUT_MILLIS = 1500;
        private int mDirectShareTimeout = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.SHARE_SHEET_DIRECT_SHARE_TIMEOUT,
                DEFAULT_DIRECT_SHARE_TIMEOUT_MILLIS);

        private boolean mMinTimeoutPassed = false;

        private void removeAllMessages() {
@@ -427,15 +437,14 @@ public class ChooserActivity extends ResolverActivity implements

            if (DEBUG) {
                Log.d(TAG, "queryTargets setting watchdog timer for "
                        + WATCHDOG_TIMEOUT_MIN_MILLIS + "-"
                        + mDirectShareTimeout + "-"
                        + WATCHDOG_TIMEOUT_MAX_MILLIS + "ms");
            }

            sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT,
                    WATCHDOG_TIMEOUT_MIN_MILLIS);
            sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT,
                    WATCHDOG_TIMEOUT_MAX_MILLIS);

                    mAppendDirectShareEnabled ? mDirectShareTimeout : WATCHDOG_TIMEOUT_MAX_MILLIS);
        }

        private void maybeStopServiceRequestTimer() {
@@ -463,6 +472,7 @@ public class ChooserActivity extends ResolverActivity implements
                    final ServiceResultInfo sri = (ServiceResultInfo) msg.obj;
                    if (!mServiceConnections.contains(sri.connection)) {
                        Log.w(TAG, "ChooserTargetServiceConnection " + sri.connection
                                + sri.originalTarget.getResolveInfo().activityInfo.packageName
                                + " returned after being removed from active connections."
                                + " Have you considered returning results faster?");
                        break;
@@ -474,7 +484,7 @@ public class ChooserActivity extends ResolverActivity implements
                        if (adapterForUserHandle != null) {
                            adapterForUserHandle.addServiceResults(sri.originalTarget,
                                    sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET,
                                    /* directShareShortcutInfoCache */ null);
                                    /* directShareShortcutInfoCache */ null, mServiceConnections);
                        }
                    }
                    unbindService(sri.connection);
@@ -489,6 +499,7 @@ public class ChooserActivity extends ResolverActivity implements
                    break;

                case CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT:
                    mMinTimeoutPassed = true;
                    unbindRemainingServices();
                    maybeStopServiceRequestTimer();
                    break;
@@ -513,7 +524,7 @@ public class ChooserActivity extends ResolverActivity implements
                        if (adapterForUserHandle != null) {
                            adapterForUserHandle.addServiceResults(
                                    resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1,
                                    mDirectShareShortcutInfoCache);
                                    mDirectShareShortcutInfoCache, mServiceConnections);
                        }
                    }
                    break;
@@ -1481,7 +1492,7 @@ public class ChooserActivity extends ResolverActivity implements
                    /* origTarget */ null,
                    Lists.newArrayList(mCallerChooserTargets),
                    TARGET_TYPE_DEFAULT,
                    /* directShareShortcutInfoCache */ null);
                    /* directShareShortcutInfoCache */ null, mServiceConnections);
        }
    }

@@ -3584,6 +3595,10 @@ public class ChooserActivity extends ResolverActivity implements
                    ? mOriginalTarget.getResolveInfo().activityInfo.toString()
                    : "<connection destroyed>") + "}";
        }

        public ComponentName getComponentName() {
            return mOriginalTarget.getResolveInfo().activityInfo.getComponentName();
        }
    }

    static class ServiceResultInfo {
+156 −4
Original line number Diff line number Diff line
@@ -32,8 +32,10 @@ import android.content.pm.ShortcutInfo;
import android.os.AsyncTask;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.service.chooser.ChooserTarget;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;

@@ -44,17 +46,26 @@ import com.android.internal.app.chooser.DisplayResolveInfo;
import com.android.internal.app.chooser.MultiDisplayResolveInfo;
import com.android.internal.app.chooser.SelectableTargetInfo;
import com.android.internal.app.chooser.TargetInfo;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class ChooserListAdapter extends ResolverListAdapter {
    private static final String TAG = "ChooserListAdapter";
    private static final boolean DEBUG = false;

    private boolean mAppendDirectShareEnabled = DeviceConfig.getBoolean(
            DeviceConfig.NAMESPACE_SYSTEMUI,
            SystemUiDeviceConfigFlags.APPEND_DIRECT_SHARE_ENABLED,
            false);

    private boolean mEnableStackedApps = true;

    public static final int NO_POSITION = -1;
@@ -84,6 +95,11 @@ public class ChooserListAdapter extends ResolverListAdapter {
    // Reserve spots for incoming direct share targets by adding placeholders
    private ChooserTargetInfo
            mPlaceHolderTargetInfo = new ChooserActivity.PlaceHolderTargetInfo();
    private int mValidServiceTargetsNum = 0;
    private final Map<ComponentName, Pair<List<ChooserTargetInfo>, Integer>>
            mParkingDirectShareTargets = new HashMap<>();
    private Set<ComponentName> mPendingChooserTargetService = new HashSet<>();
    private Set<ComponentName> mShortcutComponents = new HashSet<>();
    private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
    private final List<TargetInfo> mCallerTargets = new ArrayList<>();

@@ -189,6 +205,9 @@ public class ChooserListAdapter extends ResolverListAdapter {

    void refreshListView() {
        if (mListViewDataChanged) {
            if (mAppendDirectShareEnabled) {
                appendServiceTargetsWithQuota();
            }
            super.notifyDataSetChanged();
        }
        mListViewDataChanged = false;
@@ -198,6 +217,10 @@ public class ChooserListAdapter extends ResolverListAdapter {
    private void createPlaceHolders() {
        mNumShortcutResults = 0;
        mServiceTargets.clear();
        mValidServiceTargetsNum = 0;
        mParkingDirectShareTargets.clear();
        mPendingChooserTargetService.clear();
        mShortcutComponents.clear();
        for (int i = 0; i < MAX_SERVICE_TARGETS; i++) {
            mServiceTargets.add(mPlaceHolderTargetInfo);
        }
@@ -393,12 +416,19 @@ public class ChooserListAdapter extends ResolverListAdapter {
     */
    public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets,
            @ChooserActivity.ShareTargetType int targetType,
            Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos) {
            Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos,
            List<ChooserActivity.ChooserTargetServiceConnection>
                    pendingChooserTargetServiceConnections) {
        if (DEBUG) {
            Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
            Log.d(TAG, "addServiceResults " + origTarget.getResolvedComponentName() + ", "
                    + targets.size()
                    + " targets");
        }

        if (mAppendDirectShareEnabled) {
            parkTargetIntoMemory(origTarget, targets, targetType, directShareToShortcutInfos,
                    pendingChooserTargetServiceConnections);
            return;
        }
        if (targets.size() == 0) {
            return;
        }
@@ -449,6 +479,126 @@ public class ChooserListAdapter extends ResolverListAdapter {
        }
    }

    /**
     * Park {@code targets} into memory for the moment to surface them later when view is refreshed.
     * Components pending on ChooserTargetService query are also recorded.
     */
    private void parkTargetIntoMemory(DisplayResolveInfo origTarget, List<ChooserTarget> targets,
            @ChooserActivity.ShareTargetType int targetType,
            Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos,
            List<ChooserActivity.ChooserTargetServiceConnection>
                    pendingChooserTargetServiceConnections) {
        ComponentName origComponentName = origTarget.getResolvedComponentName();
        mPendingChooserTargetService = pendingChooserTargetServiceConnections.stream()
                .map(ChooserActivity.ChooserTargetServiceConnection::getComponentName)
                .filter(componentName -> !componentName.equals(origComponentName))
                .collect(Collectors.toSet());
        // Park targets in memory
        if (!targets.isEmpty() && !mParkingDirectShareTargets.containsKey(origComponentName)) {
            final boolean isShortcutResult =
                    (targetType == TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER
                            || targetType == TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE);
            Context contextAsUser = mContext.createContextAsUser(getUserHandle(),
                    0 /* flags */);
            List<ChooserTargetInfo> parkingTargetInfos = targets.stream()
                    .map(target ->
                            new SelectableTargetInfo(
                                    contextAsUser, origTarget, target, target.getScore(),
                                    mSelectableTargetInfoComunicator,
                                    (isShortcutResult ? directShareToShortcutInfos.get(target)
                                            : null))
                    )
                    .collect(Collectors.toList());
            mParkingDirectShareTargets.put(origComponentName,
                    new Pair<>(parkingTargetInfos, 0));
            if (isShortcutResult) {
                mShortcutComponents.add(origComponentName);
            }
        }
        notifyDataSetChanged();
    }

    /**
     * Append targets of top ranked share app into direct share row with quota limit. Remove
     * appended ones from memory.
     */
    private void appendServiceTargetsWithQuota() {
        int maxRankedTargets = mChooserListCommunicator.getMaxRankedTargets();
        List<ComponentName> topComponentNames = getTopComponentNames(maxRankedTargets);
        int appRank = 0;
        for (ComponentName component : topComponentNames) {
            if (!mPendingChooserTargetService.contains(component)
                    && !mParkingDirectShareTargets.containsKey(component)) {
                continue;
            }
            appRank++;
            Pair<List<ChooserTargetInfo>, Integer> parkingTargetsItem =
                    mParkingDirectShareTargets.get(component);
            if (parkingTargetsItem != null && parkingTargetsItem.second == 0) {
                List<ChooserTargetInfo> parkingTargets = parkingTargetsItem.first;
                int initTargetsQuota = appRank <= maxRankedTargets / 2 ? 2 : 1;
                int insertedNum = 0;
                while (insertedNum < initTargetsQuota && !parkingTargets.isEmpty()) {
                    if (!checkDuplicateTarget(parkingTargets.get(0))) {
                        mServiceTargets.add(mValidServiceTargetsNum, parkingTargets.get(0));
                        mValidServiceTargetsNum++;
                        insertedNum++;
                    }
                    parkingTargets.remove(0);
                }
                mParkingDirectShareTargets.put(component, new Pair<>(parkingTargets, insertedNum));
                if (mShortcutComponents.contains(component)) {
                    mNumShortcutResults += insertedNum;
                }
            }
        }
    }

    /**
     * Append all remaining targets (parking in memory) into direct share row as per their ranking.
     */
    private void fillAllServiceTargets() {
        int maxRankedTargets = mChooserListCommunicator.getMaxRankedTargets();
        List<ComponentName> topComponentNames = getTopComponentNames(maxRankedTargets);
        // Append all remaining targets of top recommended components into direct share row.
        for (ComponentName component : topComponentNames) {
            if (!mParkingDirectShareTargets.containsKey(component)) {
                continue;
            }
            mParkingDirectShareTargets.get(component).first.stream()
                    .filter(target -> !checkDuplicateTarget(target))
                    .forEach(target -> {
                        if (mShortcutComponents.contains(component)) {
                            mNumShortcutResults++;
                        }
                        mServiceTargets.add(target);
                    });
            mParkingDirectShareTargets.remove(component);
        }
        // Append all remaining shortcuts targets into direct share row.
        List<ChooserTargetInfo> remainingTargets = new ArrayList<>();
        mParkingDirectShareTargets.entrySet().stream()
                .filter(entry -> mShortcutComponents.contains(entry.getKey()))
                .map(entry -> entry.getValue())
                .map(pair -> pair.first)
                .forEach(remainingTargets::addAll);
        remainingTargets.sort(
                (t1, t2) -> -Float.compare(t1.getModifiedScore(), t2.getModifiedScore()));
        mServiceTargets.addAll(remainingTargets);
        mNumShortcutResults += remainingTargets.size();
        mParkingDirectShareTargets.clear();
    }

    private boolean checkDuplicateTarget(ChooserTargetInfo chooserTargetInfo) {
        // Check for duplicates and abort if found
        for (ChooserTargetInfo otherTargetInfo : mServiceTargets) {
            if (chooserTargetInfo.isSimilar(otherTargetInfo)) {
                return true;
            }
        }
        return false;
    }

    int getNumShortcutResults() {
        return mNumShortcutResults;
    }
@@ -487,7 +637,9 @@ public class ChooserListAdapter extends ResolverListAdapter {
     */
    public void completeServiceTargetLoading() {
        mServiceTargets.removeIf(o -> o instanceof ChooserActivity.PlaceHolderTargetInfo);

        if (mAppendDirectShareEnabled) {
            fillAllServiceTargets();
        }
        if (mServiceTargets.isEmpty()) {
            mServiceTargets.add(new ChooserActivity.EmptyTargetInfo());
        }
+8 −0
Original line number Diff line number Diff line
@@ -153,6 +153,14 @@ public class ResolverListAdapter extends BaseAdapter {
        return mResolverListController.getScore(target);
    }

    /**
     * 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