diff options
| author | 2022-11-02 21:49:15 +0000 | |
|---|---|---|
| committer | 2022-11-02 21:49:15 +0000 | |
| commit | 349cac312bb06df359699eff522b61e12e3e59c5 (patch) | |
| tree | 9eb5c50707f80a1149de6b519a9facfae55b7a1e /java/src/com | |
| parent | 25d6a129ba6b8f805e520584af1c0cc82b8c0b6a (diff) | |
| parent | 13c54bc6fc60fb1d4330f75824ed756157bdff71 (diff) | |
Merge "Chooser fragments shouldn't save instance state." into tm-qpr-dev
Diffstat (limited to 'java/src/com')
4 files changed, 125 insertions, 151 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index 6735ab4e..96f2f9c6 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -271,8 +271,6 @@ public class ChooserActivity extends ResolverActivity implements private int mLastNumberOfChildren = -1; private int mMaxTargetsPerRow = 1; - private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment"; - private static final int MAX_LOG_RANK_POSITION = 12; private static final int MAX_EXTRA_INITIAL_INTENTS = 2; @@ -1718,33 +1716,28 @@ public class ChooserActivity extends ResolverActivity implements return; } - ChooserTargetActionsDialogFragment fragment = new ChooserTargetActionsDialogFragment(); - Bundle bundle = new Bundle(); - - bundle.putParcelable(ChooserTargetActionsDialogFragment.USER_HANDLE_KEY, - mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); - bundle.putParcelableArrayList(ChooserTargetActionsDialogFragment.TARGET_INFOS_KEY, - new ArrayList<>(targetList)); - - if (targetInfo.isSelectableTargetInfo()) { - // TODO: migrate this condition to polymorphic calls on TargetInfo (maybe in some cases - // we can safely drop the `isSelectableTargetInfo()` condition and populate the bundle - // with any non-null values we find, regardless of the target type?) - bundle.putString(ChooserTargetActionsDialogFragment.SHORTCUT_ID_KEY, - targetInfo.getChooserTarget().getIntentExtras().getString( - Intent.EXTRA_SHORTCUT_ID)); - bundle.putBoolean(ChooserTargetActionsDialogFragment.IS_SHORTCUT_PINNED_KEY, - targetInfo.isPinned()); - bundle.putParcelable(ChooserTargetActionsDialogFragment.INTENT_FILTER_KEY, - getTargetIntentFilter()); - if (targetInfo.getDisplayLabel() != null) { - bundle.putString(ChooserTargetActionsDialogFragment.SHORTCUT_TITLE_KEY, - targetInfo.getDisplayLabel().toString()); - } - } - - fragment.setArguments(bundle); - fragment.show(getSupportFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG); + // TODO: implement these type-conditioned behaviors polymorphically, and consider moving + // the logic into `ChooserTargetActionsDialogFragment.show()`. + boolean isShortcutPinned = targetInfo.isSelectableTargetInfo() && targetInfo.isPinned(); + IntentFilter intentFilter = + targetInfo.isSelectableTargetInfo() ? getTargetIntentFilter() : null; + String shortcutTitle = targetInfo.isSelectableTargetInfo() + ? targetInfo.getDisplayLabel().toString() : null; + String shortcutIdKey = targetInfo.isSelectableTargetInfo() + ? targetInfo + .getChooserTarget() + .getIntentExtras() + .getString(Intent.EXTRA_SHORTCUT_ID) + : null; + + ChooserTargetActionsDialogFragment.show( + getSupportFragmentManager(), + targetList, + mChooserMultiProfilePagerAdapter.getCurrentUserHandle(), + shortcutIdKey, + shortcutTitle, + isShortcutPinned, + intentFilter); } private void modifyTargetIntent(Intent in) { @@ -1801,16 +1794,11 @@ public class ChooserActivity extends ResolverActivity implements if (targetInfo.isMultiDisplayResolveInfo()) { MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) targetInfo; if (!mti.hasSelected()) { - ChooserStackedAppDialogFragment f = new ChooserStackedAppDialogFragment(); - Bundle b = new Bundle(); - b.putParcelable(ChooserTargetActionsDialogFragment.USER_HANDLE_KEY, + ChooserStackedAppDialogFragment.show( + getSupportFragmentManager(), + mti, + which, mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); - b.putObject(ChooserStackedAppDialogFragment.MULTI_DRI_KEY, - mti); - b.putInt(ChooserStackedAppDialogFragment.WHICH_KEY, which); - f.setArguments(b); - - f.show(getSupportFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG); return; } } diff --git a/java/src/com/android/intentresolver/ChooserStackedAppDialogFragment.java b/java/src/com/android/intentresolver/ChooserStackedAppDialogFragment.java index b4e427a1..2cfceeae 100644 --- a/java/src/com/android/intentresolver/ChooserStackedAppDialogFragment.java +++ b/java/src/com/android/intentresolver/ChooserStackedAppDialogFragment.java @@ -20,9 +20,10 @@ package com.android.intentresolver; import android.content.DialogInterface; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; -import android.os.Bundle; import android.os.UserHandle; +import androidx.fragment.app.FragmentManager; + import com.android.intentresolver.chooser.DisplayResolveInfo; import com.android.intentresolver.chooser.MultiDisplayResolveInfo; @@ -30,29 +31,39 @@ import com.android.intentresolver.chooser.MultiDisplayResolveInfo; * Shows individual actions for a "stacked" app target - such as an app with multiple posting * streams represented in the Sharesheet. */ -public class ChooserStackedAppDialogFragment extends ChooserTargetActionsDialogFragment - implements DialogInterface.OnClickListener { - - static final String WHICH_KEY = "which_key"; - static final String MULTI_DRI_KEY = "multi_dri_key"; - - private MultiDisplayResolveInfo mMultiDisplayResolveInfo; - private int mParentWhich; - - public ChooserStackedAppDialogFragment() {} +public class ChooserStackedAppDialogFragment extends ChooserTargetActionsDialogFragment { - void setStateFromBundle(Bundle b) { - mMultiDisplayResolveInfo = (MultiDisplayResolveInfo) b.get(MULTI_DRI_KEY); - mTargetInfos = mMultiDisplayResolveInfo.getAllDisplayTargets(); - mUserHandle = (UserHandle) b.get(USER_HANDLE_KEY); - mParentWhich = b.getInt(WHICH_KEY); + /** + * Display a fragment for the user to select one of the members of a target "stack." + * @param stackedTarget The display info for the full stack to select within. + * @param stackedTargetParentWhich The "which" value that the {@link ChooserActivity} uses to + * identify the {@code stackedTarget} as presented in the chooser menu UI. If the user selects + * a target in this fragment, the selection will be saved in the {@link MultiDisplayResolveInfo} + * and then the {@link ChooserActivity} will receive a {@code #startSelected()} callback using + * this "which" value to identify the stack that's now unambiguously resolved. + * @param userHandle + * + * TODO: consider taking a client-provided callback instead of {@code stackedTargetParentWhich} + * to avoid coupling with {@link ChooserActivity}'s mechanism for handling the selection. + */ + public static void show( + FragmentManager fragmentManager, + MultiDisplayResolveInfo stackedTarget, + int stackedTargetParentWhich, + UserHandle userHandle) { + ChooserStackedAppDialogFragment fragment = new ChooserStackedAppDialogFragment( + stackedTarget, stackedTargetParentWhich, userHandle); + fragment.show(fragmentManager, TARGET_DETAILS_FRAGMENT_TAG); } + private final MultiDisplayResolveInfo mMultiDisplayResolveInfo; + private final int mParentWhich; + @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(WHICH_KEY, mParentWhich); - outState.putParcelable(MULTI_DRI_KEY, mMultiDisplayResolveInfo); + public void onClick(DialogInterface dialog, int which) { + mMultiDisplayResolveInfo.setSelected(which); + ((ChooserActivity) getActivity()).startSelected(mParentWhich, false, true); + dismiss(); } @Override @@ -63,15 +74,16 @@ public class ChooserStackedAppDialogFragment extends ChooserTargetActionsDialogF @Override protected Drawable getItemIcon(DisplayResolveInfo dri) { - // Show no icon for the group disambig dialog, null hides the imageview return null; } - @Override - public void onClick(DialogInterface dialog, int which) { - mMultiDisplayResolveInfo.setSelected(which); - ((ChooserActivity) getActivity()).startSelected(mParentWhich, false, true); - dismiss(); + private ChooserStackedAppDialogFragment( + MultiDisplayResolveInfo stackedTarget, + int stackedTargetParentWhich, + UserHandle userHandle) { + super(stackedTarget.getAllDisplayTargets(), userHandle); + mMultiDisplayResolveInfo = stackedTarget; + mParentWhich = stackedTargetParentWhich; } } diff --git a/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java b/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java index 61b54fa9..f4d4a6d1 100644 --- a/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java +++ b/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java @@ -49,11 +49,11 @@ import android.widget.ImageView; import android.widget.TextView; import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; import androidx.recyclerview.widget.RecyclerView; import com.android.intentresolver.chooser.DisplayResolveInfo; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -64,68 +64,61 @@ import java.util.stream.Collectors; public class ChooserTargetActionsDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { - protected ArrayList<DisplayResolveInfo> mTargetInfos = new ArrayList<>(); - protected UserHandle mUserHandle; - protected String mShortcutId; - protected String mShortcutTitle; - protected boolean mIsShortcutPinned; - protected IntentFilter mIntentFilter; + protected final static String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment"; - public static final String USER_HANDLE_KEY = "user_handle"; - 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"; + private final List<DisplayResolveInfo> mTargetInfos; + private final UserHandle mUserHandle; + private final boolean mIsShortcutPinned; - public ChooserTargetActionsDialogFragment() {} + @Nullable + private final String mShortcutId; + + @Nullable + private final String mShortcutTitle; + + @Nullable + private final IntentFilter mIntentFilter; + + public static void show( + FragmentManager fragmentManager, + List<DisplayResolveInfo> targetInfos, + UserHandle userHandle, + @Nullable String shortcutId, + @Nullable String shortcutTitle, + boolean isShortcutPinned, + @Nullable IntentFilter intentFilter) { + ChooserTargetActionsDialogFragment fragment = new ChooserTargetActionsDialogFragment( + targetInfos, + userHandle, + shortcutId, + shortcutTitle, + isShortcutPinned, + intentFilter); + fragment.show(fragmentManager, TARGET_DETAILS_FRAGMENT_TAG); + } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (savedInstanceState != null) { - setStateFromBundle(savedInstanceState); - } else { - setStateFromBundle(getArguments()); + // Bail. It's probably not possible to trigger reloading our fragments from a saved + // instance since Sharesheet isn't kept in history and the entire session will probably + // be lost under any conditions that would've triggered our retention. Nevertheless, if + // we ever *did* try to load from a saved state, we wouldn't be able to populate valid + // data (since we wouldn't be able to get back our original TargetInfos if we had to + // restore them from a Bundle). + dismissAllowingStateLoss(); } } - void setStateFromBundle(Bundle b) { - mTargetInfos = (ArrayList<DisplayResolveInfo>) b.get(TARGET_INFOS_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 - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - outState.putParcelable(ChooserTargetActionsDialogFragment.USER_HANDLE_KEY, - mUserHandle); - outState.putParcelableArrayList(ChooserTargetActionsDialogFragment.TARGET_INFOS_KEY, - 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); - } - /** - * Recreate the layout from scratch to match new Sharesheet redlines + * Build the menu UI according to our design spec. */ @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { - if (savedInstanceState != null) { - setStateFromBundle(savedInstanceState); - } else { - setStateFromBundle(getArguments()); - } // Make the background transparent to show dialog rounding Optional.of(getDialog()).map(Dialog::getWindow) .ifPresent(window -> { @@ -294,4 +287,24 @@ public class ChooserTargetActionsDialogFragment extends DialogFragment private boolean isShortcutTarget() { return mShortcutId != null; } + + protected ChooserTargetActionsDialogFragment( + List<DisplayResolveInfo> targetInfos, UserHandle userHandle) { + this(targetInfos, userHandle, null, null, false, null); + } + + private ChooserTargetActionsDialogFragment( + List<DisplayResolveInfo> targetInfos, + UserHandle userHandle, + @Nullable String shortcutId, + @Nullable String shortcutTitle, + boolean isShortcutPinned, + @Nullable IntentFilter intentFilter) { + mTargetInfos = targetInfos; + mUserHandle = userHandle; + mShortcutId = shortcutId; + mShortcutTitle = shortcutTitle; + mIsShortcutPinned = isShortcutPinned; + mIntentFilter = intentFilter; + } } diff --git a/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java b/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java index cd6828c7..daa69152 100644 --- a/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java +++ b/java/src/com/android/intentresolver/chooser/DisplayResolveInfo.java @@ -27,8 +27,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; import android.os.UserHandle; import com.android.intentresolver.ResolverActivity; @@ -42,7 +40,7 @@ import java.util.List; * A TargetInfo plus additional information needed to render it (such as icon and label) and * resolve it to an activity. */ -public class DisplayResolveInfo implements TargetInfo, Parcelable { +public class DisplayResolveInfo implements TargetInfo { private final ResolveInfo mResolveInfo; private CharSequence mDisplayLabel; private Drawable mDisplayIcon; @@ -237,41 +235,4 @@ public class DisplayResolveInfo implements TargetInfo, Parcelable { public void setPinned(boolean pinned) { mPinned = pinned; } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeCharSequence(mDisplayLabel); - dest.writeCharSequence(mExtendedInfo); - dest.writeParcelable(mResolvedIntent, 0); - dest.writeTypedList(mSourceIntents); - dest.writeBoolean(mIsSuspended); - dest.writeBoolean(mPinned); - dest.writeParcelable(mResolveInfo, 0); - } - - public static final Parcelable.Creator<DisplayResolveInfo> CREATOR = - new Parcelable.Creator<DisplayResolveInfo>() { - public DisplayResolveInfo createFromParcel(Parcel in) { - return new DisplayResolveInfo(in); - } - - public DisplayResolveInfo[] newArray(int size) { - return new DisplayResolveInfo[size]; - } - }; - - private DisplayResolveInfo(Parcel in) { - mDisplayLabel = in.readCharSequence(); - mExtendedInfo = in.readCharSequence(); - mResolvedIntent = in.readParcelable(null /* ClassLoader */, android.content.Intent.class); - in.readTypedList(mSourceIntents, Intent.CREATOR); - mIsSuspended = in.readBoolean(); - mPinned = in.readBoolean(); - mResolveInfo = in.readParcelable(null /* ClassLoader */, android.content.pm.ResolveInfo.class); - } } |