diff options
| author | 2020-05-28 16:06:14 +0000 | |
|---|---|---|
| committer | 2020-05-28 16:06:14 +0000 | |
| commit | 29dfff4228a72ba1dc64c91b5747382a3480d076 (patch) | |
| tree | 4f908d7b54a43d54e49460a78f7aca9ca9e19a99 | |
| parent | 527765e44b392a6d60bb4aad87fbc6539165f529 (diff) | |
| parent | dc29479df4e8c9930730660fa4315d1023bc4365 (diff) | |
Merge "Add icons to Sharesheet pin and group selection UI" into rvc-dev
7 files changed, 283 insertions, 176 deletions
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 7a033bc23cee..5533e1eda52d 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1614,7 +1614,7 @@ public class ChooserActivity extends ResolverActivity implements targetList = Collections.singletonList(ti); } - ResolverTargetActionsDialogFragment f = new ResolverTargetActionsDialogFragment( + ChooserTargetActionsDialogFragment f = new ChooserTargetActionsDialogFragment( targetList, mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG); @@ -1674,15 +1674,9 @@ public class ChooserActivity extends ResolverActivity implements if (targetInfo instanceof MultiDisplayResolveInfo) { MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) targetInfo; if (!mti.hasSelected()) { - // Stacked apps get a disambiguation first - CharSequence[] labels = new CharSequence[mti.getTargets().size()]; - int i = 0; - for (TargetInfo ti : mti.getTargets()) { - labels[i++] = ti.getResolveInfo().loadLabel(getPackageManager()); - } ChooserStackedAppDialogFragment f = new ChooserStackedAppDialogFragment( - targetInfo.getDisplayLabel(), - ((MultiDisplayResolveInfo) targetInfo), labels, which); + mti, which, + mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG); return; @@ -2973,16 +2967,16 @@ public class ChooserActivity extends ResolverActivity implements itemView.setOnClickListener(v -> startSelected(mListPosition, false/* always */, true/* filterd */)); - TargetInfo ti = mChooserMultiProfilePagerAdapter.getActiveListAdapter() - .targetInfoForPosition(mListPosition, /* filtered */ true); + itemView.setOnLongClickListener(v -> { + final TargetInfo ti = mChooserMultiProfilePagerAdapter.getActiveListAdapter() + .targetInfoForPosition(mListPosition, /* filtered */ true); - // This should always be the case for ItemViewHolder, check for sanity - if (ti instanceof DisplayResolveInfo) { - itemView.setOnLongClickListener(v -> { + // This should always be the case for ItemViewHolder, check for sanity + if (ti instanceof DisplayResolveInfo) { showTargetDetails((DisplayResolveInfo) ti); - return true; - }); - } + } + return true; + }); } } } @@ -3310,16 +3304,15 @@ public class ChooserActivity extends ResolverActivity implements // Direct Share targets should not show any menu if (!isDirectShare) { - final TargetInfo ti = mChooserListAdapter.targetInfoForPosition( - holder.getItemIndex(column), true); - - // This should always be the case for non-DS targets, check for sanity - if (ti instanceof DisplayResolveInfo) { - v.setOnLongClickListener(v1 -> { + v.setOnLongClickListener(v1 -> { + final TargetInfo ti = mChooserListAdapter.targetInfoForPosition( + holder.getItemIndex(column), true); + // This should always be the case for non-DS targets, check for sanity + if (ti instanceof DisplayResolveInfo) { showTargetDetails((DisplayResolveInfo) ti); - return true; - }); - } + } + return true; + }); } holder.addView(i, v); diff --git a/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java b/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java index f4c69a51ece1..fdeba8f67cc1 100644 --- a/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java +++ b/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java @@ -17,64 +17,50 @@ package com.android.internal.app; -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.app.DialogFragment; import android.content.DialogInterface; -import android.content.res.Configuration; -import android.os.Bundle; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import com.android.internal.app.chooser.DisplayResolveInfo; import com.android.internal.app.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 DialogFragment +public class ChooserStackedAppDialogFragment extends ChooserTargetActionsDialogFragment implements DialogInterface.OnClickListener { - private static final String TITLE_KEY = "title"; - private static final String PINNED_KEY = "pinned"; - private MultiDisplayResolveInfo mTargetInfos; - private CharSequence[] mLabels; + private MultiDisplayResolveInfo mMultiDisplayResolveInfo; private int mParentWhich; public ChooserStackedAppDialogFragment() { } - public ChooserStackedAppDialogFragment(CharSequence title, - MultiDisplayResolveInfo targets, CharSequence[] labels, int parentWhich) { - Bundle args = new Bundle(); - args.putCharSequence(TITLE_KEY, title); - mTargetInfos = targets; - mLabels = labels; + public ChooserStackedAppDialogFragment(MultiDisplayResolveInfo targets, + int parentWhich, UserHandle userHandle) { + super(targets.getTargets(), userHandle); + mMultiDisplayResolveInfo = targets; mParentWhich = parentWhich; - setArguments(args); } @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - return new Builder(getContext()) - .setCancelable(true) - .setItems(mLabels, this) - .setTitle(args.getCharSequence(TITLE_KEY)) - .create(); + protected CharSequence getItemLabel(DisplayResolveInfo dri) { + final PackageManager pm = getContext().getPackageManager(); + return dri.getResolveInfo().loadLabel(pm); } @Override - public void onClick(DialogInterface dialog, int which) { - final Bundle args = getArguments(); - mTargetInfos.setSelected(which); - ((ChooserActivity) getActivity()).startSelected(mParentWhich, false, true); - dismiss(); + protected Drawable getItemIcon(DisplayResolveInfo dri) { + // Show no icon for the group disambig dialog, null hides the imageview + return null; } @Override - public void onConfigurationChanged(Configuration newConfig) { - // Dismiss on config changed (eg: rotation) - // TODO: Maintain state on config change - super.onConfigurationChanged(newConfig); + public void onClick(DialogInterface dialog, int which) { + mMultiDisplayResolveInfo.setSelected(which); + ((ChooserActivity) getActivity()).startSelected(mParentWhich, false, true); dismiss(); } } diff --git a/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java new file mode 100644 index 000000000000..3991a7674f38 --- /dev/null +++ b/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.internal.app; + +import static android.content.Context.ACTIVITY_SERVICE; + +import static com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter; + +import static java.util.stream.Collectors.toList; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.AlertDialog.Builder; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.ComponentName; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.UserHandle; +import android.util.Pair; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.internal.R; +import com.android.internal.app.chooser.DisplayResolveInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * Shows a dialog with actions to take on a chooser target. + */ +public class ChooserTargetActionsDialogFragment extends DialogFragment + implements DialogInterface.OnClickListener { + + protected List<DisplayResolveInfo> mTargetInfos = new ArrayList<>(); + protected UserHandle mUserHandle; + + public ChooserTargetActionsDialogFragment() { + } + + public ChooserTargetActionsDialogFragment(List<DisplayResolveInfo> targets, + UserHandle userHandle) { + mUserHandle = userHandle; + mTargetInfos = targets; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + // Fetch UI details from target info + List<Pair<CharSequence, Drawable>> items = mTargetInfos.stream().map(dri -> { + return new Pair<>(getItemLabel(dri), getItemIcon(dri)); + }).collect(toList()); + + final ResolveInfoPresentationGetter pg = getProvidingAppPresentationGetter(); + return new Builder(getContext()) + .setTitle(pg.getLabel()) + .setIcon(pg.getIcon(mUserHandle)) + .setCancelable(true) + .setAdapter(getAdapterForContent(items), this) + .create(); + } + + protected ArrayAdapter<Pair<CharSequence, Drawable>> getAdapterForContent( + List<Pair<CharSequence, Drawable>> items) { + return new ArrayAdapter<Pair<CharSequence, Drawable>>(getContext(), + R.layout.chooser_dialog_item, R.id.text, items) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = super.getView(position, convertView, parent); // super recycles views + TextView label = v.findViewById(R.id.text); + ImageView icon = v.findViewById(R.id.icon); + + Pair<CharSequence, Drawable> pair = getItem(position); + label.setText(pair.first); + + // Hide icon view if one isn't available + if (pair.second == null) { + icon.setVisibility(View.GONE); + } else { + icon.setImageDrawable(pair.second); + icon.setVisibility(View.VISIBLE); + } + + return v; + } + }; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + pinComponent(mTargetInfos.get(which).getResolvedComponentName()); + ((ChooserActivity) getActivity()).handlePackagesChanged(); + dismiss(); + } + + private void pinComponent(ComponentName name) { + SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext()); + final String key = name.flattenToString(); + boolean currentVal = sp.getBoolean(name.flattenToString(), false); + if (currentVal) { + sp.edit().remove(key).apply(); + } else { + sp.edit().putBoolean(key, true).apply(); + } + } + + private Drawable getPinIcon(boolean isPinned) { + return isPinned + ? getContext().getDrawable(R.drawable.ic_close) + : getContext().getDrawable(R.drawable.ic_chooser_pin_dialog); + } + + private CharSequence getPinLabel(boolean isPinned, CharSequence targetLabel) { + return isPinned + ? getResources().getString(R.string.unpin_specific_target, targetLabel) + : getResources().getString(R.string.pin_specific_target, targetLabel); + } + + @NonNull + protected CharSequence getItemLabel(DisplayResolveInfo dri) { + final PackageManager pm = getContext().getPackageManager(); + return getPinLabel(dri.isPinned(), dri.getResolveInfo().loadLabel(pm)); + } + + @Nullable + protected Drawable getItemIcon(DisplayResolveInfo dri) { + return getPinIcon(dri.isPinned()); + } + + private ResolveInfoPresentationGetter getProvidingAppPresentationGetter() { + final ActivityManager am = (ActivityManager) getContext() + .getSystemService(ACTIVITY_SERVICE); + final int iconDpi = am.getLauncherLargeIconDensity(); + + // Use the matching application icon and label for the title, any TargetInfo will do + return new ResolveInfoPresentationGetter(getContext(), iconDpi, + mTargetInfos.get(0).getResolveInfo()); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + // Dismiss on config changed (eg: rotation) + // TODO: Maintain state on config change + super.onConfigurationChanged(newConfig); + dismiss(); + } + +} diff --git a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java deleted file mode 100644 index cdc600c51451..000000000000 --- a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package com.android.internal.app; - -import static android.content.Context.ACTIVITY_SERVICE; - -import static com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter; - -import android.app.ActivityManager; -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.ComponentName; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.UserHandle; - -import com.android.internal.R; -import com.android.internal.app.chooser.DisplayResolveInfo; -import com.android.internal.app.chooser.TargetInfo; - -import java.util.ArrayList; -import java.util.List; - -/** - * Shows a dialog with actions to take on a chooser target. - */ -public class ResolverTargetActionsDialogFragment extends DialogFragment - implements DialogInterface.OnClickListener { - - private List<DisplayResolveInfo> mTargetInfos = new ArrayList<>(); - private UserHandle mUserHandle; - - public ResolverTargetActionsDialogFragment() { - } - - public ResolverTargetActionsDialogFragment(List<DisplayResolveInfo> targets, - UserHandle userHandle) { - mUserHandle = userHandle; - mTargetInfos = targets; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - final PackageManager pm = getContext().getPackageManager(); - - // Pin item for each sub-item - CharSequence[] items = new CharSequence[mTargetInfos.size()]; - for (int i = 0; i < mTargetInfos.size(); i++) { - final TargetInfo ti = mTargetInfos.get(i); - final CharSequence label = ti.getResolveInfo().loadLabel(pm); - items[i] = ti.isPinned() - ? getResources().getString(R.string.unpin_specific_target, label) - : getResources().getString(R.string.pin_specific_target, label); - } - - // Use the matching application icon and label for the title, any TargetInfo will do - final ActivityManager am = (ActivityManager) getContext() - .getSystemService(ACTIVITY_SERVICE); - final int iconDpi = am.getLauncherLargeIconDensity(); - final ResolveInfoPresentationGetter pg = new ResolveInfoPresentationGetter(getContext(), - iconDpi, mTargetInfos.get(0).getResolveInfo()); - - return new Builder(getContext()) - .setTitle(pg.getLabel()) - .setIcon(pg.getIcon(mUserHandle)) - .setCancelable(true) - .setItems(items, this) - .create(); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - pinComponent(mTargetInfos.get(which).getResolvedComponentName()); - ((ChooserActivity) getActivity()).handlePackagesChanged(); - dismiss(); - } - - private void pinComponent(ComponentName name) { - SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext()); - final String key = name.flattenToString(); - boolean currentVal = sp.getBoolean(name.flattenToString(), false); - if (currentVal) { - sp.edit().remove(key).apply(); - } else { - sp.edit().putBoolean(key, true).apply(); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - // Dismiss on config changed (eg: rotation) - // TODO: Maintain state on config change - super.onConfigurationChanged(newConfig); - dismiss(); - } - -} diff --git a/core/res/res/drawable/ic_chooser_pin_dialog.xml b/core/res/res/drawable/ic_chooser_pin_dialog.xml new file mode 100644 index 000000000000..2ac01c79e316 --- /dev/null +++ b/core/res/res/drawable/ic_chooser_pin_dialog.xml @@ -0,0 +1,25 @@ +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14,4v5c0,1.12 0.37,2.16 1,3H9c0.65,-0.86 1,-1.9 1,-3V4H14M17,2H7C6.45,2 6,2.45 6,3c0,0.55 0.45,1 1,1c0,0 0,0 0,0l1,0v5c0,1.66 -1.34,3 -3,3v2h5.97v7l1,1l1,-1v-7H19v-2c0,0 0,0 0,0c-1.66,0 -3,-1.34 -3,-3V4l1,0c0,0 0,0 0,0c0.55,0 1,-0.45 1,-1C18,2.45 17.55,2 17,2L17,2z" + android:fillColor="#FF000000"/> +</vector> diff --git a/core/res/res/layout/chooser_dialog_item.xml b/core/res/res/layout/chooser_dialog_item.xml new file mode 100644 index 000000000000..1d6369793bfb --- /dev/null +++ b/core/res/res/layout/chooser_dialog_item.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:gravity="start|center_vertical" + android:paddingStart="?attr/dialogPreferredPadding" + android:paddingEnd="?attr/dialogPreferredPadding" + android:minHeight="48dp" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <!-- Icon and text aligns with aligns with alert_dialog_title_material --> + <ImageView android:id="@+id/icon" + android:tint="?android:attr/textColorAlertDialogListItem" + android:padding="4dp" + android:layout_marginEnd="8dp" + android:layout_width="32dp" + android:layout_height="32dp"/> + + <!-- Using text style from select_dialog_item_material --> + <TextView android:id="@+id/text" + android:textAppearance="?android:attr/textAppearanceListItemSmall" + android:textColor="?android:attr/textColorAlertDialogListItem" + android:lines="1" + android:ellipsize="end" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + +</LinearLayout>
\ No newline at end of file diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 2c0959b7a944..878b8db3f1e8 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2747,6 +2747,7 @@ <java-symbol type="drawable" name="ic_chooser_group_arrow"/> <java-symbol type="drawable" name="chooser_group_background"/> <java-symbol type="drawable" name="ic_chooser_pin"/> + <java-symbol type="drawable" name="ic_chooser_pin_dialog"/> <java-symbol type="drawable" name="chooser_pinned_background"/> <java-symbol type="integer" name="config_maxShortcutTargetsPerApp" /> <java-symbol type="layout" name="resolve_grid_item" /> @@ -3833,10 +3834,12 @@ <java-symbol type="string" name="config_factoryResetPackage" /> <java-symbol type="array" name="config_highRefreshRateBlacklist" /> + <java-symbol type="layout" name="chooser_dialog_item" /> <java-symbol type="id" name="chooser_copy_button" /> <java-symbol type="layout" name="chooser_action_button" /> <java-symbol type="dimen" name="chooser_action_button_icon_size" /> <java-symbol type="string" name="config_defaultNearbySharingComponent" /> + <java-symbol type="drawable" name="ic_close" /> <java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" /> |