1 /* 2 * Copyright 2020 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 17 package android.service.quickaccesswallet; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.PendingIntent; 22 import android.graphics.drawable.Icon; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.text.TextUtils; 26 27 /** 28 * A {@link WalletCard} can represent anything that a user might carry in their wallet -- a credit 29 * card, library card, transit pass, etc. Cards are identified by a String identifier and contain a 30 * card image, card image content description, and a {@link PendingIntent} to be used if the user 31 * clicks on the card. Cards may be displayed with an icon and label, though these are optional. 32 */ 33 public final class WalletCard implements Parcelable { 34 35 private final String mCardId; 36 private final Icon mCardImage; 37 private final CharSequence mContentDescription; 38 private final PendingIntent mPendingIntent; 39 private final Icon mCardIcon; 40 private final CharSequence mCardLabel; 41 WalletCard(Builder builder)42 private WalletCard(Builder builder) { 43 this.mCardId = builder.mCardId; 44 this.mCardImage = builder.mCardImage; 45 this.mContentDescription = builder.mContentDescription; 46 this.mPendingIntent = builder.mPendingIntent; 47 this.mCardIcon = builder.mCardIcon; 48 this.mCardLabel = builder.mCardLabel; 49 } 50 51 @Override describeContents()52 public int describeContents() { 53 return 0; 54 } 55 56 @Override writeToParcel(@onNull Parcel dest, int flags)57 public void writeToParcel(@NonNull Parcel dest, int flags) { 58 dest.writeString(mCardId); 59 mCardImage.writeToParcel(dest, flags); 60 TextUtils.writeToParcel(mContentDescription, dest, flags); 61 PendingIntent.writePendingIntentOrNullToParcel(mPendingIntent, dest); 62 if (mCardIcon == null) { 63 dest.writeByte((byte) 0); 64 } else { 65 dest.writeByte((byte) 1); 66 mCardIcon.writeToParcel(dest, flags); 67 } 68 TextUtils.writeToParcel(mCardLabel, dest, flags); 69 } 70 readFromParcel(Parcel source)71 private static WalletCard readFromParcel(Parcel source) { 72 String cardId = source.readString(); 73 Icon cardImage = Icon.CREATOR.createFromParcel(source); 74 CharSequence contentDesc = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 75 PendingIntent pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(source); 76 Icon cardIcon = source.readByte() == 0 ? null : Icon.CREATOR.createFromParcel(source); 77 CharSequence cardLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 78 return new Builder(cardId, cardImage, contentDesc, pendingIntent) 79 .setCardIcon(cardIcon) 80 .setCardLabel(cardLabel) 81 .build(); 82 } 83 84 @NonNull 85 public static final Creator<WalletCard> CREATOR = 86 new Creator<WalletCard>() { 87 @Override 88 public WalletCard createFromParcel(Parcel source) { 89 return readFromParcel(source); 90 } 91 92 @Override 93 public WalletCard[] newArray(int size) { 94 return new WalletCard[size]; 95 } 96 }; 97 98 /** 99 * The card id must be unique within the list of cards returned. 100 */ 101 @NonNull getCardId()102 public String getCardId() { 103 return mCardId; 104 } 105 106 /** 107 * The visual representation of the card. If the card image Icon is a bitmap, it should have a 108 * width of {@link GetWalletCardsRequest#getCardWidthPx()} and a height of {@link 109 * GetWalletCardsRequest#getCardHeightPx()}. 110 */ 111 @NonNull getCardImage()112 public Icon getCardImage() { 113 return mCardImage; 114 } 115 116 /** 117 * The content description of the card image. 118 */ 119 @NonNull getContentDescription()120 public CharSequence getContentDescription() { 121 return mContentDescription; 122 } 123 124 /** 125 * If the user performs a click on the card, this PendingIntent will be sent. If the device is 126 * locked, the wallet will first request device unlock before sending the pending intent. 127 */ 128 @NonNull getPendingIntent()129 public PendingIntent getPendingIntent() { 130 return mPendingIntent; 131 } 132 133 /** 134 * An icon may be shown alongside the card image to convey information about how the card can be 135 * used, or if some other action must be taken before using the card. For example, an NFC logo 136 * could indicate that the card is NFC-enabled and will be provided to an NFC terminal if the 137 * phone is held in close proximity to the NFC reader. 138 * 139 * <p>If the supplied Icon is backed by a bitmap, it should have width and height 140 * {@link GetWalletCardsRequest#getIconSizePx()}. 141 */ 142 @Nullable getCardIcon()143 public Icon getCardIcon() { 144 return mCardIcon; 145 } 146 147 /** 148 * A card label may be shown alongside the card image to convey information about how the card 149 * can be used, or if some other action must be taken before using the card. For example, an 150 * NFC-enabled card could be labeled "Hold near reader" to inform the user of how to use NFC 151 * cards when interacting with an NFC reader. 152 * 153 * <p>If the provided label is too long to fit on one line, it may be truncated and ellipsized. 154 */ 155 @Nullable getCardLabel()156 public CharSequence getCardLabel() { 157 return mCardLabel; 158 } 159 160 /** 161 * Builder for {@link WalletCard} objects. You must to provide cardId, cardImage, 162 * contentDescription, and pendingIntent. If the card is opaque and should be shown with 163 * elevation, set hasShadow to true. cardIcon and cardLabel are optional. 164 */ 165 public static final class Builder { 166 private String mCardId; 167 private Icon mCardImage; 168 private CharSequence mContentDescription; 169 private PendingIntent mPendingIntent; 170 private Icon mCardIcon; 171 private CharSequence mCardLabel; 172 173 /** 174 * @param cardId The card id must be non-null and unique within the list of 175 * cards returned. <b>Note: 176 * </b> this card ID should <b>not</b> contain PII (Personally 177 * Identifiable Information, such as username or email address). 178 * @param cardImage The visual representation of the card. If the card image Icon 179 * is a bitmap, it should have a width of {@link 180 * GetWalletCardsRequest#getCardWidthPx()} and a height of {@link 181 * GetWalletCardsRequest#getCardHeightPx()}. If the card image 182 * does not have these dimensions, it may appear distorted when it 183 * is scaled to fit these dimensions on screen. Bitmaps must be 184 * of type {@link android.graphics.Bitmap.Config#HARDWARE} for 185 * performance reasons. 186 * @param contentDescription The content description of the card image. This field is 187 * required and may not be null or empty. 188 * <b>Note: </b> this message should <b>not</b> contain PII 189 * (Personally Identifiable Information, such as username or email 190 * address). 191 * @param pendingIntent If the user performs a click on the card, this PendingIntent 192 * will be sent. If the device is locked, the wallet will first 193 * request device unlock before sending the pending intent. It is 194 * recommended that the pending intent be immutable (use {@link 195 * PendingIntent#FLAG_IMMUTABLE}). 196 */ Builder(@onNull String cardId, @NonNull Icon cardImage, @NonNull CharSequence contentDescription, @NonNull PendingIntent pendingIntent)197 public Builder(@NonNull String cardId, 198 @NonNull Icon cardImage, 199 @NonNull CharSequence contentDescription, 200 @NonNull PendingIntent pendingIntent) { 201 mCardId = cardId; 202 mCardImage = cardImage; 203 mContentDescription = contentDescription; 204 mPendingIntent = pendingIntent; 205 } 206 207 /** 208 * An icon may be shown alongside the card image to convey information about how the card 209 * can be used, or if some other action must be taken before using the card. For example, an 210 * NFC logo could indicate that the card is NFC-enabled and will be provided to an NFC 211 * terminal if the phone is held in close proximity to the NFC reader. This field is 212 * optional. 213 * 214 * <p>If the supplied Icon is backed by a bitmap, it should have width and height 215 * {@link GetWalletCardsRequest#getIconSizePx()}. 216 */ 217 @NonNull setCardIcon(@ullable Icon cardIcon)218 public Builder setCardIcon(@Nullable Icon cardIcon) { 219 mCardIcon = cardIcon; 220 return this; 221 } 222 223 /** 224 * A card label may be shown alongside the card image to convey information about how the 225 * card can be used, or if some other action must be taken before using the card. For 226 * example, an NFC-enabled card could be labeled "Hold near reader" to inform the user of 227 * how to use NFC cards when interacting with an NFC reader. This field is optional. 228 * <b>Note: </b> this card label should <b>not</b> contain PII (Personally Identifiable 229 * Information, such as username or email address). If the provided label is too long to fit 230 * on one line, it may be truncated and ellipsized. 231 */ 232 @NonNull setCardLabel(@ullable CharSequence cardLabel)233 public Builder setCardLabel(@Nullable CharSequence cardLabel) { 234 mCardLabel = cardLabel; 235 return this; 236 } 237 238 /** 239 * Builds a new {@link WalletCard} instance. 240 * 241 * @return A built response. 242 */ 243 @NonNull build()244 public WalletCard build() { 245 return new WalletCard(this); 246 } 247 } 248 } 249