Loading core/java/com/android/internal/app/AbstractResolverComparator.java +44 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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(); Loading @@ -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. Loading Loading @@ -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); } Loading Loading @@ -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); } } } core/java/com/android/internal/app/ChooserActivity.java +32 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -121,6 +124,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; Loading Loading @@ -241,6 +245,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 { Loading Loading @@ -580,6 +587,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]; Loading Loading @@ -710,6 +719,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. */ Loading Loading @@ -1272,9 +1297,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); } Loading Loading @@ -1697,7 +1723,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()); Loading Loading @@ -1945,6 +1970,11 @@ public class ChooserActivity extends ResolverActivity implements } return false; } @Override public boolean isComponentPinned(ComponentName name) { return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false); } } @Override Loading core/java/com/android/internal/app/ResolverActivity.java +9 −0 Original line number Diff line number Diff line Loading @@ -1263,6 +1263,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; Loading Loading @@ -1303,6 +1304,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, Loading core/java/com/android/internal/app/ResolverListAdapter.java +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading core/java/com/android/internal/app/ResolverListController.java +10 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
core/java/com/android/internal/app/AbstractResolverComparator.java +44 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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(); Loading @@ -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. Loading Loading @@ -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); } Loading Loading @@ -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); } } }
core/java/com/android/internal/app/ChooserActivity.java +32 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -121,6 +124,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; Loading Loading @@ -241,6 +245,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 { Loading Loading @@ -580,6 +587,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]; Loading Loading @@ -710,6 +719,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. */ Loading Loading @@ -1272,9 +1297,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); } Loading Loading @@ -1697,7 +1723,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()); Loading Loading @@ -1945,6 +1970,11 @@ public class ChooserActivity extends ResolverActivity implements } return false; } @Override public boolean isComponentPinned(ComponentName name) { return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false); } } @Override Loading
core/java/com/android/internal/app/ResolverActivity.java +9 −0 Original line number Diff line number Diff line Loading @@ -1263,6 +1263,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; Loading Loading @@ -1303,6 +1304,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, Loading
core/java/com/android/internal/app/ResolverListAdapter.java +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
core/java/com/android/internal/app/ResolverListController.java +10 −0 Original line number Diff line number Diff line Loading @@ -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