Merge "Open dialog panel after long pressing a direct share target to allow pin/unpin the target. Communicate with ShortcutManager/Launcherapps to store pin info in ShortcutService." into tm-dev am: a9012710e0

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17871086

Change-Id: I00f9805695f7aac1c1398bff5d0fce4b72d97c9a
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Song Hu
2022-04-21 00:21:09 +00:00
committed by Automerger Merge Worker
4 changed files with 129 additions and 38 deletions

View File

@@ -1616,29 +1616,48 @@ public class ChooserActivity extends ResolverActivity implements
return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, true); return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, true);
} }
private void showTargetDetails(DisplayResolveInfo ti) { private void showTargetDetails(TargetInfo targetInfo) {
if (ti == null) return; if (targetInfo == null) return;
ArrayList<DisplayResolveInfo> targetList; ArrayList<DisplayResolveInfo> targetList;
ChooserTargetActionsDialogFragment fragment = new ChooserTargetActionsDialogFragment();
Bundle bundle = new Bundle();
if (targetInfo instanceof SelectableTargetInfo) {
SelectableTargetInfo selectableTargetInfo = (SelectableTargetInfo) targetInfo;
if (selectableTargetInfo.getDisplayResolveInfo() == null
|| selectableTargetInfo.getChooserTarget() == null) {
Log.e(TAG, "displayResolveInfo or chooserTarget in selectableTargetInfo are null");
return;
}
targetList = new ArrayList<>();
targetList.add(selectableTargetInfo.getDisplayResolveInfo());
bundle.putString(ChooserTargetActionsDialogFragment.SHORTCUT_ID_KEY,
selectableTargetInfo.getChooserTarget().getIntentExtras().getString(
Intent.EXTRA_SHORTCUT_ID));
bundle.putBoolean(ChooserTargetActionsDialogFragment.IS_SHORTCUT_PINNED_KEY,
selectableTargetInfo.isPinned());
bundle.putParcelable(ChooserTargetActionsDialogFragment.INTENT_FILTER_KEY,
getTargetIntentFilter());
if (selectableTargetInfo.getDisplayLabel() != null) {
bundle.putString(ChooserTargetActionsDialogFragment.SHORTCUT_TITLE_KEY,
selectableTargetInfo.getDisplayLabel().toString());
}
} else if (targetInfo instanceof MultiDisplayResolveInfo) {
// For multiple targets, include info on all targets // For multiple targets, include info on all targets
if (ti instanceof MultiDisplayResolveInfo) { MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) targetInfo;
MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) ti;
targetList = mti.getTargets(); targetList = mti.getTargets();
} else { } else {
targetList = new ArrayList<DisplayResolveInfo>(); targetList = new ArrayList<DisplayResolveInfo>();
targetList.add(ti); targetList.add((DisplayResolveInfo) targetInfo);
} }
bundle.putParcelable(ChooserTargetActionsDialogFragment.USER_HANDLE_KEY,
ChooserTargetActionsDialogFragment f = new ChooserTargetActionsDialogFragment();
Bundle b = new Bundle();
b.putParcelable(ChooserTargetActionsDialogFragment.USER_HANDLE_KEY,
mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); mChooserMultiProfilePagerAdapter.getCurrentUserHandle());
b.putParcelableArrayList(ChooserTargetActionsDialogFragment.TARGET_INFOS_KEY, bundle.putParcelableArrayList(ChooserTargetActionsDialogFragment.TARGET_INFOS_KEY,
targetList); targetList);
f.setArguments(b); fragment.setArguments(bundle);
f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG); fragment.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG);
} }
private void modifyTargetIntent(Intent in) { private void modifyTargetIntent(Intent in) {
@@ -2864,8 +2883,10 @@ public class ChooserActivity extends ResolverActivity implements
private boolean shouldShowTargetDetails(TargetInfo ti) { private boolean shouldShowTargetDetails(TargetInfo ti) {
ComponentName nearbyShare = getNearbySharingComponent(); ComponentName nearbyShare = getNearbySharingComponent();
// Suppress target details for nearby share to hide pin/unpin action // Suppress target details for nearby share to hide pin/unpin action
return !(nearbyShare != null && nearbyShare.equals(ti.getResolvedComponentName()) boolean isNearbyShare = nearbyShare != null && nearbyShare.equals(
&& shouldNearbyShareBeFirstInRankedRow()); ti.getResolvedComponentName()) && shouldNearbyShareBeFirstInRankedRow();
return ti instanceof SelectableTargetInfo
|| (ti instanceof DisplayResolveInfo && !isNearbyShare);
} }
/** /**
@@ -2962,8 +2983,6 @@ public class ChooserActivity extends ResolverActivity implements
private DirectShareViewHolder mDirectShareViewHolder; private DirectShareViewHolder mDirectShareViewHolder;
private int mChooserTargetWidth = 0; private int mChooserTargetWidth = 0;
private boolean mShowAzLabelIfPoss; private boolean mShowAzLabelIfPoss;
private boolean mHideContentPreview = false;
private boolean mLayoutRequested = false; private boolean mLayoutRequested = false;
private int mFooterHeight = 0; private int mFooterHeight = 0;
@@ -3034,7 +3053,6 @@ public class ChooserActivity extends ResolverActivity implements
* personal and work tabs. * personal and work tabs.
*/ */
public void hideContentPreview() { public void hideContentPreview() {
mHideContentPreview = true;
mLayoutRequested = true; mLayoutRequested = true;
notifyDataSetChanged(); notifyDataSetChanged();
} }
@@ -3224,18 +3242,15 @@ public class ChooserActivity extends ResolverActivity implements
} }
}); });
// Direct Share targets should not show any menu // Show menu for both direct share and app share targets after long click.
if (!isDirectShare) {
v.setOnLongClickListener(v1 -> { v.setOnLongClickListener(v1 -> {
final TargetInfo ti = mChooserListAdapter.targetInfoForPosition( TargetInfo ti = mChooserListAdapter.targetInfoForPosition(
holder.getItemIndex(column), true); holder.getItemIndex(column), true);
// This should always be the case for non-DS targets, check for validity if (shouldShowTargetDetails(ti)) {
if (ti instanceof DisplayResolveInfo && shouldShowTargetDetails(ti)) { showTargetDetails(ti);
showTargetDetails((DisplayResolveInfo) ti);
} }
return true; return true;
}); });
}
holder.addView(i, v); holder.addView(i, v);

View File

@@ -74,6 +74,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
public static final float CALLER_TARGET_SCORE_BOOST = 900.f; public static final float CALLER_TARGET_SCORE_BOOST = 900.f;
/** {@link #getBaseScore} */ /** {@link #getBaseScore} */
public static final float SHORTCUT_TARGET_SCORE_BOOST = 90.f; public static final float SHORTCUT_TARGET_SCORE_BOOST = 90.f;
private static final float PINNED_SHORTCUT_TARGET_SCORE_BOOST = 1000.f;
private final int mMaxShortcutTargetsPerApp; private final int mMaxShortcutTargetsPerApp;
private final ChooserListCommunicator mChooserListCommunicator; private final ChooserListCommunicator mChooserListCommunicator;
@@ -275,8 +276,10 @@ public class ChooserListAdapter extends ResolverListAdapter {
Drawable bkg = mContext.getDrawable(R.drawable.chooser_group_background); Drawable bkg = mContext.getDrawable(R.drawable.chooser_group_background);
holder.text.setPaddingRelative(0, 0, bkg.getIntrinsicWidth() /* end */, 0); holder.text.setPaddingRelative(0, 0, bkg.getIntrinsicWidth() /* end */, 0);
holder.text.setBackground(bkg); holder.text.setBackground(bkg);
} else if (info.isPinned() && getPositionTargetType(position) == TARGET_STANDARD) { } else if (info.isPinned() && (getPositionTargetType(position) == TARGET_STANDARD
// If the target is pinned and in the suggested row show a pinned indicator || getPositionTargetType(position) == TARGET_SERVICE)) {
// If the appShare or directShare target is pinned and in the suggested row show a
// pinned indicator
Drawable bkg = mContext.getDrawable(R.drawable.chooser_pinned_background); Drawable bkg = mContext.getDrawable(R.drawable.chooser_pinned_background);
holder.text.setPaddingRelative(bkg.getIntrinsicWidth() /* start */, 0, 0, 0); holder.text.setPaddingRelative(bkg.getIntrinsicWidth() /* start */, 0, 0, 0);
holder.text.setBackground(bkg); holder.text.setBackground(bkg);
@@ -523,11 +526,16 @@ public class ChooserListAdapter extends ResolverListAdapter {
targetScore = lastScore * 0.95f; targetScore = lastScore * 0.95f;
} }
} }
ShortcutInfo shortcutInfo = isShortcutResult ? directShareToShortcutInfos.get(target)
: null;
if ((shortcutInfo != null) && shortcutInfo.isPinned()) {
targetScore += PINNED_SHORTCUT_TARGET_SCORE_BOOST;
}
UserHandle userHandle = getUserHandle(); UserHandle userHandle = getUserHandle();
Context contextAsUser = mContext.createContextAsUser(userHandle, 0 /* flags */); Context contextAsUser = mContext.createContextAsUser(userHandle, 0 /* flags */);
boolean isInserted = insertServiceTarget(new SelectableTargetInfo(contextAsUser, boolean isInserted = insertServiceTarget(new SelectableTargetInfo(contextAsUser,
origTarget, target, targetScore, mSelectableTargetInfoCommunicator, origTarget, target, targetScore, mSelectableTargetInfoCommunicator,
(isShortcutResult ? directShareToShortcutInfos.get(target) : null))); shortcutInfo));
if (isInserted && isShortcutResult) { if (isInserted && isShortcutResult) {
mNumShortcutResults++; mNumShortcutResults++;

View File

@@ -29,9 +29,14 @@ import android.app.ActivityManager;
import android.app.Dialog; import android.app.Dialog;
import android.app.DialogFragment; import android.app.DialogFragment;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -51,6 +56,7 @@ import com.android.internal.widget.RecyclerView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
/** /**
* Shows a dialog with actions to take on a chooser target. * Shows a dialog with actions to take on a chooser target.
@@ -60,9 +66,17 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
protected ArrayList<DisplayResolveInfo> mTargetInfos = new ArrayList<>(); protected ArrayList<DisplayResolveInfo> mTargetInfos = new ArrayList<>();
protected UserHandle mUserHandle; protected UserHandle mUserHandle;
protected String mShortcutId;
protected String mShortcutTitle;
protected boolean mIsShortcutPinned;
protected IntentFilter mIntentFilter;
public static final String USER_HANDLE_KEY = "user_handle"; public static final String USER_HANDLE_KEY = "user_handle";
public static final String TARGET_INFOS_KEY = "target_infos"; public static final String TARGET_INFOS_KEY = "target_infos";
public static final String SHORTCUT_ID_KEY = "shortcut_id";
public static final String SHORTCUT_TITLE_KEY = "shortcut_title";
public static final String IS_SHORTCUT_PINNED_KEY = "is_shortcut_pinned";
public static final String INTENT_FILTER_KEY = "intent_filter";
public ChooserTargetActionsDialogFragment() {} public ChooserTargetActionsDialogFragment() {}
@@ -79,6 +93,10 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
void setStateFromBundle(Bundle b) { void setStateFromBundle(Bundle b) {
mTargetInfos = (ArrayList<DisplayResolveInfo>) b.get(TARGET_INFOS_KEY); mTargetInfos = (ArrayList<DisplayResolveInfo>) b.get(TARGET_INFOS_KEY);
mUserHandle = (UserHandle) b.get(USER_HANDLE_KEY); mUserHandle = (UserHandle) b.get(USER_HANDLE_KEY);
mShortcutId = b.getString(SHORTCUT_ID_KEY);
mShortcutTitle = b.getString(SHORTCUT_TITLE_KEY);
mIsShortcutPinned = b.getBoolean(IS_SHORTCUT_PINNED_KEY);
mIntentFilter = (IntentFilter) b.get(INTENT_FILTER_KEY);
} }
@Override @Override
@@ -89,6 +107,11 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
mUserHandle); mUserHandle);
outState.putParcelableArrayList(ChooserTargetActionsDialogFragment.TARGET_INFOS_KEY, outState.putParcelableArrayList(ChooserTargetActionsDialogFragment.TARGET_INFOS_KEY,
mTargetInfos); mTargetInfos);
outState.putString(ChooserTargetActionsDialogFragment.SHORTCUT_ID_KEY, mShortcutId);
outState.putBoolean(ChooserTargetActionsDialogFragment.IS_SHORTCUT_PINNED_KEY,
mIsShortcutPinned);
outState.putString(ChooserTargetActionsDialogFragment.SHORTCUT_TITLE_KEY, mShortcutTitle);
outState.putParcelable(ChooserTargetActionsDialogFragment.INTENT_FILTER_KEY, mIntentFilter);
} }
/** /**
@@ -121,7 +144,7 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
RecyclerView rv = v.findViewById(R.id.listContainer); RecyclerView rv = v.findViewById(R.id.listContainer);
final ResolveInfoPresentationGetter pg = getProvidingAppPresentationGetter(); final ResolveInfoPresentationGetter pg = getProvidingAppPresentationGetter();
title.setText(pg.getLabel()); title.setText(isShortcutTarget() ? mShortcutTitle : pg.getLabel());
icon.setImageDrawable(pg.getIcon(mUserHandle)); icon.setImageDrawable(pg.getIcon(mUserHandle));
rv.setAdapter(new VHAdapter(items)); rv.setAdapter(new VHAdapter(items));
@@ -180,11 +203,45 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (isShortcutTarget()) {
toggleShortcutPinned(mTargetInfos.get(which).getResolvedComponentName());
} else {
pinComponent(mTargetInfos.get(which).getResolvedComponentName()); pinComponent(mTargetInfos.get(which).getResolvedComponentName());
}
((ChooserActivity) getActivity()).handlePackagesChanged(); ((ChooserActivity) getActivity()).handlePackagesChanged();
dismiss(); dismiss();
} }
private void toggleShortcutPinned(ComponentName name) {
if (mIntentFilter == null) {
return;
}
// Fetch existing pinned shortcuts of the given package.
List<String> pinnedShortcuts = getPinnedShortcutsFromPackageAsUser(getContext(),
mUserHandle, mIntentFilter, name.getPackageName());
// If the shortcut has already been pinned, unpin it; otherwise, pin it.
if (mIsShortcutPinned) {
pinnedShortcuts.remove(mShortcutId);
} else {
pinnedShortcuts.add(mShortcutId);
}
// Update pinned shortcut list in ShortcutService via LauncherApps
getContext().getSystemService(LauncherApps.class).pinShortcuts(
name.getPackageName(), pinnedShortcuts, mUserHandle);
}
private static List<String> getPinnedShortcutsFromPackageAsUser(Context context,
UserHandle user, IntentFilter filter, String packageName) {
Context contextAsUser = context.createContextAsUser(user, 0 /* flags */);
List<ShortcutManager.ShareShortcutInfo> targets = contextAsUser.getSystemService(
ShortcutManager.class).getShareTargets(filter);
return targets.stream()
.map(ShortcutManager.ShareShortcutInfo::getShortcutInfo)
.filter(s -> s.isPinned() && s.getPackage().equals(packageName))
.map(ShortcutInfo::getId)
.collect(Collectors.toList());
}
private void pinComponent(ComponentName name) { private void pinComponent(ComponentName name) {
SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext()); SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext());
final String key = name.flattenToString(); final String key = name.flattenToString();
@@ -211,12 +268,13 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
@NonNull @NonNull
protected CharSequence getItemLabel(DisplayResolveInfo dri) { protected CharSequence getItemLabel(DisplayResolveInfo dri) {
final PackageManager pm = getContext().getPackageManager(); final PackageManager pm = getContext().getPackageManager();
return getPinLabel(dri.isPinned(), dri.getResolveInfo().loadLabel(pm)); return getPinLabel(isPinned(dri),
isShortcutTarget() ? "" : dri.getResolveInfo().loadLabel(pm));
} }
@Nullable @Nullable
protected Drawable getItemIcon(DisplayResolveInfo dri) { protected Drawable getItemIcon(DisplayResolveInfo dri) {
return getPinIcon(dri.isPinned()); return getPinIcon(isPinned(dri));
} }
private ResolveInfoPresentationGetter getProvidingAppPresentationGetter() { private ResolveInfoPresentationGetter getProvidingAppPresentationGetter() {
@@ -229,4 +287,11 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment
mTargetInfos.get(0).getResolveInfo()); mTargetInfos.get(0).getResolveInfo());
} }
private boolean isPinned(DisplayResolveInfo dri) {
return isShortcutTarget() ? mIsShortcutPinned : dri.isPinned();
}
private boolean isShortcutTarget() {
return mShortcutId != null;
}
} }

View File

@@ -64,6 +64,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo {
private Drawable mDisplayIcon; private Drawable mDisplayIcon;
private final Intent mFillInIntent; private final Intent mFillInIntent;
private final int mFillInFlags; private final int mFillInFlags;
private final boolean mIsPinned;
private final float mModifiedScore; private final float mModifiedScore;
private boolean mIsSuspended = false; private boolean mIsSuspended = false;
@@ -77,6 +78,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo {
mModifiedScore = modifiedScore; mModifiedScore = modifiedScore;
mPm = mContext.getPackageManager(); mPm = mContext.getPackageManager();
mSelectableTargetInfoCommunicator = selectableTargetInfoComunicator; mSelectableTargetInfoCommunicator = selectableTargetInfoComunicator;
mIsPinned = shortcutInfo != null && shortcutInfo.isPinned();
if (sourceInfo != null) { if (sourceInfo != null) {
final ResolveInfo ri = sourceInfo.getResolveInfo(); final ResolveInfo ri = sourceInfo.getResolveInfo();
if (ri != null) { if (ri != null) {
@@ -120,6 +122,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo {
mFillInIntent = fillInIntent; mFillInIntent = fillInIntent;
mFillInFlags = flags; mFillInFlags = flags;
mModifiedScore = other.mModifiedScore; mModifiedScore = other.mModifiedScore;
mIsPinned = other.mIsPinned;
mDisplayLabel = sanitizeDisplayLabel(mChooserTarget.getTitle()); mDisplayLabel = sanitizeDisplayLabel(mChooserTarget.getTitle());
} }
@@ -292,7 +295,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo {
@Override @Override
public boolean isPinned() { public boolean isPinned() {
return mSourceInfo != null && mSourceInfo.isPinned(); return mIsPinned;
} }
/** /**