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

Commit 1fd47150 authored by Alison Cichowlas's avatar Alison Cichowlas
Browse files

Restore app pinning.

Bug: 143229724
Test: atest AbstractResolverComparatorTest; atest ChooserActivityTest
Change-Id: I71d4334c8d3beed94495b41d5264a95cbbd132ff
parent 5fdaa0c9
Loading
Loading
Loading
Loading
+44 −2
Original line number Diff line number Diff line
@@ -30,14 +30,17 @@ import android.util.Log;

import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * Used to sort resolved activities in {@link ResolverListController}.
 *
 * @hide
 */
abstract class AbstractResolverComparator implements Comparator<ResolvedComponentInfo> {
public abstract class AbstractResolverComparator implements Comparator<ResolvedComponentInfo> {

    private static final int NUM_OF_TOP_ANNOTATIONS_TO_USE = 3;
    private static final boolean DEBUG = false;
@@ -62,6 +65,8 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen
    // predicting ranking scores.
    private static final int WATCHDOG_TIMEOUT_MILLIS = 500;

    private final Comparator<ResolveInfo> mAzComparator;

    protected final Handler mHandler = new Handler(Looper.getMainLooper()) {
        public void handleMessage(Message msg) {
            switch (msg.what) {
@@ -90,7 +95,7 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen
        }
    };

    AbstractResolverComparator(Context context, Intent intent) {
    public AbstractResolverComparator(Context context, Intent intent) {
        String scheme = intent.getScheme();
        mHttp = "http".equals(scheme) || "https".equals(scheme);
        mContentType = intent.getType();
@@ -100,6 +105,7 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen
        mDefaultBrowserPackageName = mHttp
                ? mPm.getDefaultBrowserPackageNameAsUser(UserHandle.myUserId())
                : null;
        mAzComparator = new AzInfoComparator(context);
    }

    // get annotations of content from intent.
@@ -168,6 +174,20 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen
                return lhsSpecific ? -1 : 1;
            }
        }

        final boolean lPinned = lhsp.isPinned();
        final boolean rPinned = rhsp.isPinned();

        // Pinned items always receive priority.
        if (lPinned && !rPinned) {
            return -1;
        } else if (!lPinned && rPinned) {
            return 1;
        } else if (lPinned && rPinned) {
            // If both items are pinned, resolve the tie alphabetically.
            return mAzComparator.compare(lhsp.getResolveInfoAt(0), rhsp.getResolveInfoAt(0));
        }

        return compare(lhs, rhs);
    }

@@ -258,4 +278,26 @@ abstract class AbstractResolverComparator implements Comparator<ResolvedComponen
        }
        return false;
    }


    /**
     * Sort intents alphabetically based on package name.
     */
    class AzInfoComparator implements Comparator<ResolveInfo> {
        Collator mCollator;
        AzInfoComparator(Context context) {
            mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
        }

        @Override
        public int compare(ResolveInfo lhsp, ResolveInfo rhsp) {
            if (lhsp == null) {
                return -1;
            } else if (rhsp == null) {
                return 1;
            }
            return mCollator.compare(lhsp.activityInfo.packageName, rhsp.activityInfo.packageName);
        }
    }

}
+32 −2
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -64,6 +65,7 @@ import android.metrics.LogMaker;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -73,6 +75,7 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
import android.provider.DocumentsContract;
import android.provider.Downloads;
@@ -122,6 +125,7 @@ import com.android.internal.widget.ResolverDrawerLayout;

import com.google.android.collect.Lists;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -240,6 +244,9 @@ public class ChooserActivity extends ResolverActivity implements
    private static final int MAX_EXTRA_INITIAL_INTENTS = 2;
    private static final int MAX_EXTRA_CHOOSER_TARGETS = 2;

    private SharedPreferences mPinnedSharedPrefs;
    private static final String PINNED_SHARED_PREFS_NAME = "chooser_pin_settings";

    @Retention(SOURCE)
    @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT})
    private @interface ContentPreviewType {
@@ -579,6 +586,8 @@ public class ChooserActivity extends ResolverActivity implements
                Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER);
        setSafeForwardingMode(true);

        mPinnedSharedPrefs = getPinnedSharedPrefs(this);

        pa = intent.getParcelableArrayExtra(Intent.EXTRA_EXCLUDE_COMPONENTS);
        if (pa != null) {
            ComponentName[] names = new ComponentName[pa.length];
@@ -709,6 +718,22 @@ public class ChooserActivity extends ResolverActivity implements
        }
    }

    static SharedPreferences getPinnedSharedPrefs(Context context) {
        // The code below is because in the android:ui process, no one can hear you scream.
        // The package info in the context isn't initialized in the way it is for normal apps,
        // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
        // build the path manually below using the same policy that appears in ContextImpl.
        // This fails silently under the hood if there's a problem, so if we find ourselves in
        // the case where we don't have access to credential encrypted storage we just won't
        // have our pinned target info.
        final File prefsFile = new File(new File(
                Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
                        context.getUserId(), context.getPackageName()),
                "shared_prefs"),
                PINNED_SHARED_PREFS_NAME + ".xml");
        return context.getSharedPreferences(prefsFile, MODE_PRIVATE);
    }

    /**
     * Returns true if app prediction service is defined and the component exists on device.
     */
@@ -1260,9 +1285,10 @@ public class ChooserActivity extends ResolverActivity implements
        }

        ComponentName name = ri.activityInfo.getComponentName();
        boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
        ResolverTargetActionsDialogFragment f =
                new ResolverTargetActionsDialogFragment(ri.loadLabel(getPackageManager()),
                        name);
                        name, pinned);
        f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG);
    }

@@ -1685,7 +1711,6 @@ public class ChooserActivity extends ResolverActivity implements
                        allAppTargets.get(indexInAllShortcuts));
            }
        }

        // Sort ChooserTargets by score in descending order
        Comparator<ChooserTarget> byScore =
                (ChooserTarget a, ChooserTarget b) -> -Float.compare(a.getScore(), b.getScore());
@@ -1933,6 +1958,11 @@ public class ChooserActivity extends ResolverActivity implements
            }
            return false;
        }

        @Override
        public boolean isComponentPinned(ComponentName name) {
            return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
        }
    }

    @Override
+9 −0
Original line number Diff line number Diff line
@@ -1247,6 +1247,7 @@ public class ResolverActivity extends Activity implements
        public final ComponentName name;
        private final List<Intent> mIntents = new ArrayList<>();
        private final List<ResolveInfo> mResolveInfos = new ArrayList<>();
        private boolean mPinned;

        public ResolvedComponentInfo(ComponentName name, Intent intent, ResolveInfo info) {
            this.name = name;
@@ -1287,6 +1288,14 @@ public class ResolverActivity extends Activity implements
            }
            return -1;
        }

        public boolean isPinned() {
            return mPinned;
        }

        public void setPinned(boolean pinned) {
            mPinned = pinned;
        }
    }

    class ItemClickListener implements AdapterView.OnItemClickListener,
+4 −0
Original line number Diff line number Diff line
@@ -376,6 +376,10 @@ public class ResolverListAdapter extends BaseAdapter {
        final DisplayResolveInfo
                dri = new DisplayResolveInfo(intent, add,
                replaceIntent != null ? replaceIntent : defaultIntent, makePresentationGetter(add));
        dri.setPinned(rci.isPinned());
        if (rci.isPinned()) {
            Log.i(TAG, "Pinned item: " + rci.name);
        }
        addResolveInfo(dri);
        if (replaceIntent == intent) {
            // Only add alternates if we didn't get a specific replacement from
+10 −0
Original line number Diff line number Diff line
@@ -150,11 +150,21 @@ public class ResolverListController {
                        newInfo.activityInfo.packageName, newInfo.activityInfo.name);
                final ResolverActivity.ResolvedComponentInfo rci =
                        new ResolverActivity.ResolvedComponentInfo(name, intent, newInfo);
                rci.setPinned(isComponentPinned(name));
                into.add(rci);
            }
        }
    }


    /**
     * Whether this component is pinned by the user. Always false for resolver; overridden in
     * Chooser.
     */
    public boolean isComponentPinned(ComponentName name) {
        return false;
    }

    // Filter out any activities that the launched uid does not have permission for.
    // To preserve the inputList, optionally will return the original list if any modification has
    // been made.
Loading