Loading core/java/android/app/slice/Slice.java +14 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.StringDef; import android.app.PendingIntent; import android.app.RemoteInput; import android.app.slice.widget.SliceView; import android.content.ContentResolver; import android.content.IContentProvider; import android.graphics.drawable.Icon; Loading Loading @@ -54,7 +55,12 @@ public final class Slice implements Parcelable { public @interface SliceHint{ } /** * Hint that this content is a title of other content in the slice. * Hint that this content is a title of other content in the slice. This can also indicate that * the content should be used in the shortcut representation of the slice (icon, label, action), * normally this should be indicated by adding the hint on the action containing that content. * * @see SliceView#MODE_SHORTCUT * @see SliceItem#TYPE_ACTION */ public static final String HINT_TITLE = "title"; /** Loading Loading @@ -99,6 +105,13 @@ public final class Slice implements Parcelable { * Hint to indicate that this content should not be tinted. */ public static final String HINT_NO_TINT = "no_tint"; /** * Hint to indicate that this content should not be shown in the {@link SliceView#MODE_SMALL} * and {@link SliceView#MODE_LARGE} modes of SliceView. This content may be used to populate * the {@link SliceView#MODE_SHORTCUT} format of the slice. * @hide */ public static final String HINT_HIDDEN = "hidden"; /** * Hint to indicate that this slice is incomplete and an update will be sent once * loading is complete. Slices which contain HINT_PARTIAL will not be cached by the Loading core/java/android/app/slice/widget/GridView.java +6 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,9 @@ public class GridView extends LinearLayout implements SliceListView { * Returns true if this item is just an image. */ private boolean addItem(SliceItem item) { if (item.hasHint(Slice.HINT_HIDDEN)) { return false; } if (item.getType() == SliceItem.TYPE_IMAGE) { ImageView v = new ImageView(getContext()); v.setImageIcon(item.getIcon()); Loading @@ -145,6 +148,9 @@ public class GridView extends LinearLayout implements SliceListView { items.addAll(item.getSlice().getItems()); } items.forEach(i -> { if (i.hasHint(Slice.HINT_HIDDEN)) { return; } Context context = getContext(); switch (i.getType()) { case SliceItem.TYPE_TEXT: Loading core/java/android/app/slice/widget/LargeTemplateView.java +12 −3 Original line number Diff line number Diff line Loading @@ -85,9 +85,14 @@ public class LargeTemplateView extends SliceModeView { addList(slice, items); } else { slice.getItems().forEach(item -> { if (item.hasHint(Slice.HINT_ACTIONS)) { if (item.hasHint(Slice.HINT_HIDDEN)) { // If it's hidden we don't show it return; } else if (item.hasHint(Slice.HINT_ACTIONS)) { // Action groups don't show in lists return; } else if (item.getType() == SliceItem.TYPE_COLOR) { // A color is not a list item return; } else if (item.getType() == SliceItem.TYPE_SLICE && item.hasHint(Slice.HINT_LIST)) { Loading @@ -108,8 +113,12 @@ public class LargeTemplateView extends SliceModeView { private void addList(Slice slice, List<SliceItem> items) { List<SliceItem> sliceItems = slice.getItems(); sliceItems.forEach(i -> i.addHint(Slice.HINT_LIST_ITEM)); items.addAll(sliceItems); sliceItems.forEach(i -> { if (!i.hasHint(Slice.HINT_HIDDEN) && i.getType() != SliceItem.TYPE_COLOR) { i.addHint(Slice.HINT_LIST_ITEM); items.add(i); } }); } /** Loading core/java/android/app/slice/widget/ShortcutView.java +84 −15 Original line number Diff line number Diff line Loading @@ -24,13 +24,20 @@ import android.app.slice.SliceQuery; import android.app.slice.widget.SliceView.SliceModeView; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.net.Uri; import com.android.internal.R; import java.util.List; /** * @hide */ Loading @@ -38,27 +45,26 @@ public class ShortcutView extends SliceModeView { private static final String TAG = "ShortcutView"; private PendingIntent mAction; private Uri mUri; private PendingIntent mAction; private SliceItem mLabel; private SliceItem mIcon; private int mLargeIconSize; private int mSmallIconSize; public ShortcutView(Context context) { super(context); mSmallIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size); final Resources res = getResources(); mSmallIconSize = res.getDimensionPixelSize(R.dimen.slice_icon_size); mLargeIconSize = res.getDimensionPixelSize(R.dimen.slice_shortcut_size); } @Override public void setSlice(Slice slice) { removeAllViews(); SliceItem sliceItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION); SliceItem iconItem = SliceQuery.getPrimaryIcon(slice); SliceItem textItem = sliceItem != null ? SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT) : SliceQuery.find(slice, SliceItem.TYPE_TEXT); SliceItem colorItem = sliceItem != null ? SliceQuery.find(sliceItem, SliceItem.TYPE_COLOR) : SliceQuery.find(slice, SliceItem.TYPE_COLOR); determineShortcutItems(getContext(), slice); SliceItem colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR); if (colorItem == null) { colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR); } Loading @@ -67,13 +73,11 @@ public class ShortcutView extends SliceModeView { ShapeDrawable circle = new ShapeDrawable(new OvalShape()); circle.setTint(color); setBackground(circle); if (iconItem != null) { final boolean isLarge = iconItem.hasHint(Slice.HINT_LARGE); if (mIcon != null) { final boolean isLarge = mIcon.hasHint(Slice.HINT_LARGE); final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize; SliceViewUtil.createCircledIcon(getContext(), color, iconSize, iconItem.getIcon(), SliceViewUtil.createCircledIcon(getContext(), color, iconSize, mIcon.getIcon(), isLarge, this /* parent */); mAction = sliceItem != null ? sliceItem.getAction() : null; mUri = slice.getUri(); setClickable(true); } else { Loading Loading @@ -103,4 +107,69 @@ public class ShortcutView extends SliceModeView { } return true; } /** * Looks at the slice and determines which items are best to use to compose the shortcut. */ private void determineShortcutItems(Context context, Slice slice) { List<String> h = slice.getHints(); SliceItem sliceItem = new SliceItem(slice, SliceItem.TYPE_SLICE, h.toArray(new String[h.size()])); SliceItem titleItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION, Slice.HINT_TITLE, null); if (titleItem != null) { // Preferred case: hinted action containing hinted image and text mAction = titleItem.getAction(); mIcon = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_IMAGE, Slice.HINT_TITLE, null); mLabel = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_TEXT, Slice.HINT_TITLE, null); } else { // No hinted action; just use the first one SliceItem actionItem = SliceQuery.find(sliceItem, SliceItem.TYPE_ACTION, (String) null, null); mAction = (actionItem != null) ? actionItem.getAction() : null; } // First fallback: any hinted image and text if (mIcon == null) { mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, Slice.HINT_TITLE, null); } if (mLabel == null) { mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, Slice.HINT_TITLE, null); } // Second fallback: first image and text if (mIcon == null) { mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, (String) null, null); } if (mLabel == null) { mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, (String) null, null); } // Final fallback: use app info if (mIcon == null || mLabel == null || mAction == null) { PackageManager pm = context.getPackageManager(); ProviderInfo providerInfo = pm.resolveContentProvider( slice.getUri().getAuthority(), 0); ApplicationInfo appInfo = providerInfo.applicationInfo; if (appInfo != null) { if (mIcon == null) { Drawable icon = appInfo.loadDefaultIcon(pm); mIcon = new SliceItem(SliceViewUtil.createIconFromDrawable(icon), SliceItem.TYPE_IMAGE, new String[] {Slice.HINT_LARGE}); } if (mLabel == null) { mLabel = new SliceItem(pm.getApplicationLabel(appInfo), SliceItem.TYPE_TEXT, null); } if (mAction == null) { mAction = PendingIntent.getActivity(context, 0, pm.getLaunchIntentForPackage(appInfo.packageName), 0); } } } } } core/java/android/app/slice/widget/SliceView.java +3 −1 Original line number Diff line number Diff line Loading @@ -115,7 +115,9 @@ public class SliceView extends ViewGroup { */ public static final String MODE_LARGE = "SLICE_LARGE"; /** * Mode indicating this slice should be presented as an icon. * Mode indicating this slice should be presented as an icon. A shortcut requires an intent, * icon, and label. This can be indicated by using {@link Slice#HINT_TITLE} on an action in a * slice. */ public static final String MODE_SHORTCUT = "SLICE_ICON"; Loading Loading
core/java/android/app/slice/Slice.java +14 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.StringDef; import android.app.PendingIntent; import android.app.RemoteInput; import android.app.slice.widget.SliceView; import android.content.ContentResolver; import android.content.IContentProvider; import android.graphics.drawable.Icon; Loading Loading @@ -54,7 +55,12 @@ public final class Slice implements Parcelable { public @interface SliceHint{ } /** * Hint that this content is a title of other content in the slice. * Hint that this content is a title of other content in the slice. This can also indicate that * the content should be used in the shortcut representation of the slice (icon, label, action), * normally this should be indicated by adding the hint on the action containing that content. * * @see SliceView#MODE_SHORTCUT * @see SliceItem#TYPE_ACTION */ public static final String HINT_TITLE = "title"; /** Loading Loading @@ -99,6 +105,13 @@ public final class Slice implements Parcelable { * Hint to indicate that this content should not be tinted. */ public static final String HINT_NO_TINT = "no_tint"; /** * Hint to indicate that this content should not be shown in the {@link SliceView#MODE_SMALL} * and {@link SliceView#MODE_LARGE} modes of SliceView. This content may be used to populate * the {@link SliceView#MODE_SHORTCUT} format of the slice. * @hide */ public static final String HINT_HIDDEN = "hidden"; /** * Hint to indicate that this slice is incomplete and an update will be sent once * loading is complete. Slices which contain HINT_PARTIAL will not be cached by the Loading
core/java/android/app/slice/widget/GridView.java +6 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,9 @@ public class GridView extends LinearLayout implements SliceListView { * Returns true if this item is just an image. */ private boolean addItem(SliceItem item) { if (item.hasHint(Slice.HINT_HIDDEN)) { return false; } if (item.getType() == SliceItem.TYPE_IMAGE) { ImageView v = new ImageView(getContext()); v.setImageIcon(item.getIcon()); Loading @@ -145,6 +148,9 @@ public class GridView extends LinearLayout implements SliceListView { items.addAll(item.getSlice().getItems()); } items.forEach(i -> { if (i.hasHint(Slice.HINT_HIDDEN)) { return; } Context context = getContext(); switch (i.getType()) { case SliceItem.TYPE_TEXT: Loading
core/java/android/app/slice/widget/LargeTemplateView.java +12 −3 Original line number Diff line number Diff line Loading @@ -85,9 +85,14 @@ public class LargeTemplateView extends SliceModeView { addList(slice, items); } else { slice.getItems().forEach(item -> { if (item.hasHint(Slice.HINT_ACTIONS)) { if (item.hasHint(Slice.HINT_HIDDEN)) { // If it's hidden we don't show it return; } else if (item.hasHint(Slice.HINT_ACTIONS)) { // Action groups don't show in lists return; } else if (item.getType() == SliceItem.TYPE_COLOR) { // A color is not a list item return; } else if (item.getType() == SliceItem.TYPE_SLICE && item.hasHint(Slice.HINT_LIST)) { Loading @@ -108,8 +113,12 @@ public class LargeTemplateView extends SliceModeView { private void addList(Slice slice, List<SliceItem> items) { List<SliceItem> sliceItems = slice.getItems(); sliceItems.forEach(i -> i.addHint(Slice.HINT_LIST_ITEM)); items.addAll(sliceItems); sliceItems.forEach(i -> { if (!i.hasHint(Slice.HINT_HIDDEN) && i.getType() != SliceItem.TYPE_COLOR) { i.addHint(Slice.HINT_LIST_ITEM); items.add(i); } }); } /** Loading
core/java/android/app/slice/widget/ShortcutView.java +84 −15 Original line number Diff line number Diff line Loading @@ -24,13 +24,20 @@ import android.app.slice.SliceQuery; import android.app.slice.widget.SliceView.SliceModeView; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.net.Uri; import com.android.internal.R; import java.util.List; /** * @hide */ Loading @@ -38,27 +45,26 @@ public class ShortcutView extends SliceModeView { private static final String TAG = "ShortcutView"; private PendingIntent mAction; private Uri mUri; private PendingIntent mAction; private SliceItem mLabel; private SliceItem mIcon; private int mLargeIconSize; private int mSmallIconSize; public ShortcutView(Context context) { super(context); mSmallIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size); final Resources res = getResources(); mSmallIconSize = res.getDimensionPixelSize(R.dimen.slice_icon_size); mLargeIconSize = res.getDimensionPixelSize(R.dimen.slice_shortcut_size); } @Override public void setSlice(Slice slice) { removeAllViews(); SliceItem sliceItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION); SliceItem iconItem = SliceQuery.getPrimaryIcon(slice); SliceItem textItem = sliceItem != null ? SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT) : SliceQuery.find(slice, SliceItem.TYPE_TEXT); SliceItem colorItem = sliceItem != null ? SliceQuery.find(sliceItem, SliceItem.TYPE_COLOR) : SliceQuery.find(slice, SliceItem.TYPE_COLOR); determineShortcutItems(getContext(), slice); SliceItem colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR); if (colorItem == null) { colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR); } Loading @@ -67,13 +73,11 @@ public class ShortcutView extends SliceModeView { ShapeDrawable circle = new ShapeDrawable(new OvalShape()); circle.setTint(color); setBackground(circle); if (iconItem != null) { final boolean isLarge = iconItem.hasHint(Slice.HINT_LARGE); if (mIcon != null) { final boolean isLarge = mIcon.hasHint(Slice.HINT_LARGE); final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize; SliceViewUtil.createCircledIcon(getContext(), color, iconSize, iconItem.getIcon(), SliceViewUtil.createCircledIcon(getContext(), color, iconSize, mIcon.getIcon(), isLarge, this /* parent */); mAction = sliceItem != null ? sliceItem.getAction() : null; mUri = slice.getUri(); setClickable(true); } else { Loading Loading @@ -103,4 +107,69 @@ public class ShortcutView extends SliceModeView { } return true; } /** * Looks at the slice and determines which items are best to use to compose the shortcut. */ private void determineShortcutItems(Context context, Slice slice) { List<String> h = slice.getHints(); SliceItem sliceItem = new SliceItem(slice, SliceItem.TYPE_SLICE, h.toArray(new String[h.size()])); SliceItem titleItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION, Slice.HINT_TITLE, null); if (titleItem != null) { // Preferred case: hinted action containing hinted image and text mAction = titleItem.getAction(); mIcon = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_IMAGE, Slice.HINT_TITLE, null); mLabel = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_TEXT, Slice.HINT_TITLE, null); } else { // No hinted action; just use the first one SliceItem actionItem = SliceQuery.find(sliceItem, SliceItem.TYPE_ACTION, (String) null, null); mAction = (actionItem != null) ? actionItem.getAction() : null; } // First fallback: any hinted image and text if (mIcon == null) { mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, Slice.HINT_TITLE, null); } if (mLabel == null) { mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, Slice.HINT_TITLE, null); } // Second fallback: first image and text if (mIcon == null) { mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, (String) null, null); } if (mLabel == null) { mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, (String) null, null); } // Final fallback: use app info if (mIcon == null || mLabel == null || mAction == null) { PackageManager pm = context.getPackageManager(); ProviderInfo providerInfo = pm.resolveContentProvider( slice.getUri().getAuthority(), 0); ApplicationInfo appInfo = providerInfo.applicationInfo; if (appInfo != null) { if (mIcon == null) { Drawable icon = appInfo.loadDefaultIcon(pm); mIcon = new SliceItem(SliceViewUtil.createIconFromDrawable(icon), SliceItem.TYPE_IMAGE, new String[] {Slice.HINT_LARGE}); } if (mLabel == null) { mLabel = new SliceItem(pm.getApplicationLabel(appInfo), SliceItem.TYPE_TEXT, null); } if (mAction == null) { mAction = PendingIntent.getActivity(context, 0, pm.getLaunchIntentForPackage(appInfo.packageName), 0); } } } } }
core/java/android/app/slice/widget/SliceView.java +3 −1 Original line number Diff line number Diff line Loading @@ -115,7 +115,9 @@ public class SliceView extends ViewGroup { */ public static final String MODE_LARGE = "SLICE_LARGE"; /** * Mode indicating this slice should be presented as an icon. * Mode indicating this slice should be presented as an icon. A shortcut requires an intent, * icon, and label. This can be indicated by using {@link Slice#HINT_TITLE} on an action in a * slice. */ public static final String MODE_SHORTCUT = "SLICE_ICON"; Loading