1 /** 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.support.v4.content.pm; 17 18 import android.content.ComponentName; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.pm.ShortcutInfo; 22 import android.graphics.Bitmap; 23 import android.support.annotation.DrawableRes; 24 import android.support.annotation.NonNull; 25 import android.support.annotation.Nullable; 26 import android.support.annotation.RequiresApi; 27 import android.support.v4.graphics.drawable.IconCompat; 28 import android.text.TextUtils; 29 30 import java.util.Arrays; 31 32 /** 33 * Helper for accessing features in {@link android.content.pm.ShortcutInfo} 34 * introduced after API level 25 in a backwards compatible fashion. 35 */ 36 public class ShortcutInfoCompat { 37 38 private Context mContext; 39 private String mId; 40 41 private Intent[] mIntents; 42 private ComponentName mActivity; 43 44 private CharSequence mLabel; 45 private CharSequence mLongLabel; 46 private CharSequence mDisabledMessage; 47 48 private IconCompat mIcon; 49 ShortcutInfoCompat()50 private ShortcutInfoCompat() { } 51 52 @RequiresApi(26) toShortcutInfo()53 ShortcutInfo toShortcutInfo() { 54 ShortcutInfo.Builder builder = new ShortcutInfo.Builder(mContext, mId) 55 .setShortLabel(mLabel) 56 .setIntents(mIntents); 57 if (mIcon != null) { 58 builder.setIcon(mIcon.toIcon()); 59 } 60 if (!TextUtils.isEmpty(mLongLabel)) { 61 builder.setLongLabel(mLongLabel); 62 } 63 if (!TextUtils.isEmpty(mDisabledMessage)) { 64 builder.setDisabledMessage(mDisabledMessage); 65 } 66 if (mActivity != null) { 67 builder.setActivity(mActivity); 68 } 69 return builder.build(); 70 } 71 addToIntent(Intent outIntent)72 Intent addToIntent(Intent outIntent) { 73 outIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, mIntents[mIntents.length - 1]) 74 .putExtra(Intent.EXTRA_SHORTCUT_NAME, mLabel.toString()); 75 if (mIcon != null) { 76 mIcon.addToShortcutIntent(outIntent); 77 } 78 return outIntent; 79 } 80 81 /** 82 * Returns the ID of a shortcut. 83 * 84 * <p>Shortcut IDs are unique within each publisher app and must be stable across 85 * devices so that shortcuts will still be valid when restored on a different device. 86 * See {@link android.content.pm.ShortcutManager} for details. 87 */ 88 @NonNull getId()89 public String getId() { 90 return mId; 91 } 92 93 /** 94 * Return the target activity. 95 * 96 * <p>This has nothing to do with the activity that this shortcut will launch. 97 * Launcher apps should show the launcher icon for the returned activity alongside 98 * this shortcut. 99 * 100 * @see Builder#setActivity(ComponentName) 101 */ 102 @Nullable getActivity()103 public ComponentName getActivity() { 104 return mActivity; 105 } 106 107 /** 108 * Return the short description of a shortcut. 109 * 110 * @see Builder#setShortLabel(CharSequence) 111 */ 112 @NonNull getShortLabel()113 public CharSequence getShortLabel() { 114 return mLabel; 115 } 116 117 /** 118 * Return the long description of a shortcut. 119 * 120 * @see Builder#setLongLabel(CharSequence) 121 */ 122 @Nullable getLongLabel()123 public CharSequence getLongLabel() { 124 return mLongLabel; 125 } 126 127 /** 128 * Return the message that should be shown when the user attempts to start a shortcut 129 * that is disabled. 130 * 131 * @see Builder#setDisabledMessage(CharSequence) 132 */ 133 @Nullable getDisabledMessage()134 public CharSequence getDisabledMessage() { 135 return mDisabledMessage; 136 } 137 138 /** 139 * Returns the intent that is executed when the user selects this shortcut. 140 * If setIntents() was used, then return the last intent in the array. 141 * 142 * @see Builder#setIntent(Intent) 143 */ 144 @NonNull getIntent()145 public Intent getIntent() { 146 return mIntents[mIntents.length - 1]; 147 } 148 149 /** 150 * Return the intent set with {@link Builder#setIntents(Intent[])}. 151 * 152 * @see Builder#setIntents(Intent[]) 153 */ 154 @NonNull getIntents()155 public Intent[] getIntents() { 156 return Arrays.copyOf(mIntents, mIntents.length); 157 } 158 159 /** 160 * Builder class for {@link ShortcutInfoCompat} objects. 161 */ 162 public static class Builder { 163 164 private final ShortcutInfoCompat mInfo; 165 Builder(@onNull Context context, @NonNull String id)166 public Builder(@NonNull Context context, @NonNull String id) { 167 mInfo = new ShortcutInfoCompat(); 168 mInfo.mContext = context; 169 mInfo.mId = id; 170 } 171 172 /** 173 * Sets the short title of a shortcut. 174 * 175 * <p>This is a mandatory field when publishing a new shortcut. 176 * 177 * <p>This field is intended to be a concise description of a shortcut. 178 * 179 * <p>The recommended maximum length is 10 characters. 180 */ 181 @NonNull setShortLabel(@onNull CharSequence shortLabel)182 public Builder setShortLabel(@NonNull CharSequence shortLabel) { 183 mInfo.mLabel = shortLabel; 184 return this; 185 } 186 187 /** 188 * Sets the text of a shortcut. 189 * 190 * <p>This field is intended to be more descriptive than the shortcut title. The launcher 191 * shows this instead of the short title when it has enough space. 192 * 193 * <p>The recommend maximum length is 25 characters. 194 */ 195 @NonNull setLongLabel(@onNull CharSequence longLabel)196 public Builder setLongLabel(@NonNull CharSequence longLabel) { 197 mInfo.mLongLabel = longLabel; 198 return this; 199 } 200 201 /** 202 * Sets the message that should be shown when the user attempts to start a shortcut that 203 * is disabled. 204 * 205 * @see ShortcutInfo#getDisabledMessage() 206 */ 207 @NonNull setDisabledMessage(@onNull CharSequence disabledMessage)208 public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) { 209 mInfo.mDisabledMessage = disabledMessage; 210 return this; 211 } 212 213 /** 214 * Sets the intent of a shortcut. Alternatively, {@link #setIntents(Intent[])} can be used 215 * to launch an activity with other activities in the back stack. 216 * 217 * <p>This is a mandatory field when publishing a new shortcut. 218 * 219 * <p>The given {@code intent} can contain extras, but these extras must contain values 220 * of primitive types in order for the system to persist these values. 221 */ 222 @NonNull setIntent(@onNull Intent intent)223 public Builder setIntent(@NonNull Intent intent) { 224 return setIntents(new Intent[]{intent}); 225 } 226 227 /** 228 * Sets multiple intents instead of a single intent, in order to launch an activity with 229 * other activities in back stack. Use {@link android.app.TaskStackBuilder} to build 230 * intents. The last element in the list represents the only intent that doesn't place 231 * an activity on the back stack. 232 */ 233 @NonNull setIntents(@onNull Intent[] intents)234 public Builder setIntents(@NonNull Intent[] intents) { 235 mInfo.mIntents = intents; 236 return this; 237 } 238 239 /** 240 * Sets an icon of a shortcut. 241 * @deprecated use {@link #setIcon(IconCompat)} instead 242 */ 243 @NonNull setIcon(@onNull Bitmap icon)244 public Builder setIcon(@NonNull Bitmap icon) { 245 return setIcon(IconCompat.createWithBitmap(icon)); 246 } 247 248 /** 249 * Sets an icon of a shortcut. 250 * @deprecated use {@link #setIcon(IconCompat)} instead 251 */ 252 @NonNull setIcon(@rawableRes int icon)253 public Builder setIcon(@DrawableRes int icon) { 254 return setIcon(IconCompat.createWithResource(mInfo.mContext, icon)); 255 } 256 257 /** 258 * Sets an icon of a shortcut. 259 */ 260 @NonNull setIcon(IconCompat icon)261 public Builder setIcon(IconCompat icon) { 262 mInfo.mIcon = icon; 263 return this; 264 } 265 266 /** 267 * Sets the target activity. A shortcut will be shown along with this activity's icon 268 * on the launcher. 269 * 270 * @see ShortcutInfo#getActivity() 271 * @see android.content.pm.ShortcutInfo.Builder#setActivity(ComponentName) 272 */ 273 @NonNull setActivity(@onNull ComponentName activity)274 public Builder setActivity(@NonNull ComponentName activity) { 275 mInfo.mActivity = activity; 276 return this; 277 } 278 279 /** 280 * Creates a {@link ShortcutInfoCompat} instance. 281 */ 282 @NonNull build()283 public ShortcutInfoCompat build() { 284 // Verify the arguments 285 if (TextUtils.isEmpty(mInfo.mLabel)) { 286 throw new IllegalArgumentException("Shortcut much have a non-empty label"); 287 } 288 if (mInfo.mIntents == null || mInfo.mIntents.length == 0) { 289 throw new IllegalArgumentException("Shortcut much have an intent"); 290 } 291 return mInfo; 292 } 293 } 294 } 295