• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.app.PendingIntent;
23 import android.graphics.drawable.Icon;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.text.TextUtils;
27 
28 import com.android.internal.util.Preconditions;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 
33 
34 /**
35  * A {@link WalletCard} can represent anything that a user might carry in their wallet -- a credit
36  * card, library card, transit pass, etc. Cards are identified by a String identifier and contain a
37  * card type, card image, card image content description, and a {@link PendingIntent} to be used if
38  * the user clicks on the card. Cards may be displayed with an icon and label, though these are
39  * optional. Non-payment cards will also have a second image that will be displayed when the card is
40  * tapped.
41  */
42 
43 public final class WalletCard implements Parcelable {
44 
45     /**
46      * Unknown cards refer to cards whose types are unspecified.
47      * @hide
48      */
49     public static final int CARD_TYPE_UNKNOWN = 0;
50 
51     /**
52      * Payment cards refer to credit cards, debit cards or any other cards in the wallet used to
53      * make cash-equivalent payments.
54      * @hide
55      */
56     public static final int CARD_TYPE_PAYMENT = 1;
57 
58     /**
59      * Non-payment cards refer to any cards that are not used for cash-equivalent payment, including
60      * event tickets, flights, offers, loyalty cards, gift cards and transit tickets.
61      * @hide
62      */
63     public static final int CARD_TYPE_NON_PAYMENT = 2;
64 
65     private final String mCardId;
66     private final int mCardType;
67     private final Icon mCardImage;
68     private final CharSequence mContentDescription;
69     private final PendingIntent mPendingIntent;
70     private final Icon mCardIcon;
71     private final CharSequence mCardLabel;
72     private final Icon mNonPaymentCardSecondaryImage;
73 
WalletCard(Builder builder)74     private WalletCard(Builder builder) {
75         this.mCardId = builder.mCardId;
76         this.mCardType = builder.mCardType;
77         this.mCardImage = builder.mCardImage;
78         this.mContentDescription = builder.mContentDescription;
79         this.mPendingIntent = builder.mPendingIntent;
80         this.mCardIcon = builder.mCardIcon;
81         this.mCardLabel = builder.mCardLabel;
82         this.mNonPaymentCardSecondaryImage = builder.mNonPaymentCardSecondaryImage;
83     }
84 
85     /**
86      * @hide
87      */
88     @Retention(RetentionPolicy.SOURCE)
89     @IntDef(prefix = {"CARD_TYPE_"}, value = {
90             CARD_TYPE_UNKNOWN,
91             CARD_TYPE_PAYMENT,
92             CARD_TYPE_NON_PAYMENT
93     })
94     public @interface CardType {
95     }
96 
97     @Override
describeContents()98     public int describeContents() {
99         return 0;
100     }
101 
102     @Override
writeToParcel(@onNull Parcel dest, int flags)103     public void writeToParcel(@NonNull Parcel dest, int flags) {
104         dest.writeString(mCardId);
105         dest.writeInt(mCardType);
106         mCardImage.writeToParcel(dest, flags);
107         TextUtils.writeToParcel(mContentDescription, dest, flags);
108         PendingIntent.writePendingIntentOrNullToParcel(mPendingIntent, dest);
109         writeIconIfNonNull(mCardIcon, dest, flags);
110         TextUtils.writeToParcel(mCardLabel, dest, flags);
111         writeIconIfNonNull(mNonPaymentCardSecondaryImage, dest, flags);
112 
113     }
114 
115     /** Utility function called by writeToParcel
116      */
writeIconIfNonNull(Icon icon, Parcel dest, int flags)117     private void writeIconIfNonNull(Icon icon,  Parcel dest, int flags) {
118         if (icon == null) {
119             dest.writeByte((byte) 0);
120         } else {
121             dest.writeByte((byte) 1);
122             icon.writeToParcel(dest, flags);
123         }
124     }
125 
readFromParcel(Parcel source)126     private static WalletCard readFromParcel(Parcel source) {
127         String cardId = source.readString();
128         int cardType = source.readInt();
129         Icon cardImage = Icon.CREATOR.createFromParcel(source);
130         CharSequence contentDesc = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
131         PendingIntent pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(source);
132         Icon cardIcon = source.readByte() == 0 ? null : Icon.CREATOR.createFromParcel(source);
133         CharSequence cardLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
134         Icon nonPaymentCardSecondaryImage = source.readByte() == 0 ? null :
135                 Icon.CREATOR.createFromParcel(source);
136         Builder builder = new Builder(cardId, cardType, cardImage, contentDesc, pendingIntent)
137                 .setCardIcon(cardIcon)
138                 .setCardLabel(cardLabel);
139 
140         return cardType == CARD_TYPE_NON_PAYMENT
141                 ? builder.setNonPaymentCardSecondaryImage(nonPaymentCardSecondaryImage).build() :
142                  builder.build();
143     }
144 
145     @NonNull
146     public static final Creator<WalletCard> CREATOR =
147             new Creator<WalletCard>() {
148                 @Override
149                 public WalletCard createFromParcel(Parcel source) {
150                     return readFromParcel(source);
151                 }
152 
153                 @Override
154                 public WalletCard[] newArray(int size) {
155                     return new WalletCard[size];
156                 }
157             };
158 
159     /**
160      * The card id must be unique within the list of cards returned.
161      */
162     @NonNull
getCardId()163     public String getCardId() {
164         return mCardId;
165     }
166 
167     /**
168      * Returns the card type.
169      * @hide
170      */
171     @NonNull
172     @CardType
getCardType()173     public int getCardType() {
174         return mCardType;
175     }
176 
177     /**
178      * The visual representation of the card. If the card image Icon is a bitmap, it should have a
179      * width of {@link GetWalletCardsRequest#getCardWidthPx()} and a height of {@link
180      * GetWalletCardsRequest#getCardHeightPx()}.
181      */
182     @NonNull
getCardImage()183     public Icon getCardImage() {
184         return mCardImage;
185     }
186 
187     /**
188      * The content description of the card image.
189      */
190     @NonNull
getContentDescription()191     public CharSequence getContentDescription() {
192         return mContentDescription;
193     }
194 
195     /**
196      * If the user performs a click on the card, this PendingIntent will be sent. If the device is
197      * locked, the wallet will first request device unlock before sending the pending intent.
198      */
199     @NonNull
getPendingIntent()200     public PendingIntent getPendingIntent() {
201         return mPendingIntent;
202     }
203 
204     /**
205      * An icon may be shown alongside the card image to convey information about how the card can be
206      * used, or if some other action must be taken before using the card. For example, an NFC logo
207      * could indicate that the card is NFC-enabled and will be provided to an NFC terminal if the
208      * phone is held in close proximity to the NFC reader.
209      *
210      * <p>If the supplied Icon is backed by a bitmap, it should have width and height
211      * {@link GetWalletCardsRequest#getIconSizePx()}.
212      */
213     @Nullable
getCardIcon()214     public Icon getCardIcon() {
215         return mCardIcon;
216     }
217 
218     /**
219      * A card label may be shown alongside the card image to convey information about how the card
220      * can be used, or if some other action must be taken before using the card. For example, an
221      * NFC-enabled card could be labeled "Hold near reader" to inform the user of how to use NFC
222      * cards when interacting with an NFC reader.
223      *
224      * <p>If the provided label is too long to fit on one line, it may be truncated and ellipsized.
225      */
226     @Nullable
getCardLabel()227     public CharSequence getCardLabel() {
228         return mCardLabel;
229     }
230 
231     /**
232      * Visual representation of the card when it is tapped. May include additional information
233      *  unique to the card, such as a barcode or number. Only valid for CARD_TYPE_NON_PAYMENT.
234      * @hide
235      */
236     @Nullable
getNonPaymentCardSecondaryImage()237     public Icon getNonPaymentCardSecondaryImage() {
238         return mNonPaymentCardSecondaryImage;
239     }
240 
241     /**
242      * Builder for {@link WalletCard} objects. You must provide cardId, cardImage,
243      * contentDescription, and pendingIntent. If the card is opaque and should be shown with
244      * elevation, set hasShadow to true. cardIcon and cardLabel are optional.
245      */
246     public static final class Builder {
247         private String mCardId;
248         private int mCardType;
249         private Icon mCardImage;
250         private CharSequence mContentDescription;
251         private PendingIntent mPendingIntent;
252         private Icon mCardIcon;
253         private CharSequence mCardLabel;
254         private Icon mNonPaymentCardSecondaryImage;
255 
256         /**
257          * @param cardId             The card id must be non-null and unique within the list of
258          *                           cards returned. <b>Note:
259          *                           </b> this card ID should <b>not</b> contain PII (Personally
260          *                           Identifiable Information, such as username or email address).
261          * @param cardType           Integer representing the card type. The card type must be
262          *                           non-null.
263          * @param cardImage          The visual representation of the card. If the card image Icon
264          *                           is a bitmap, it should have a width of {@link
265          *                           GetWalletCardsRequest#getCardWidthPx()} and a height of {@link
266          *                           GetWalletCardsRequest#getCardHeightPx()}. If the card image
267          *                           does not have these dimensions, it may appear distorted when it
268          *                           is scaled to fit these dimensions on screen. Bitmaps must be
269          *                           of type {@link android.graphics.Bitmap.Config#HARDWARE} for
270          *                           performance reasons.
271          * @param contentDescription The content description of the card image. This field is
272          *                           required and may not be null or empty.
273          *                           <b>Note: </b> this message should <b>not</b> contain PII
274          *                           (Personally Identifiable Information, such as username or email
275          *                           address).
276          * @param pendingIntent      If the user performs a click on the card, this PendingIntent
277          *                           will be sent. If the device is locked, the wallet will first
278          *                           request device unlock before sending the pending intent. It is
279          *                           recommended that the pending intent be immutable (use {@link
280          *                           PendingIntent#FLAG_IMMUTABLE}).
281          * @hide
282          */
Builder(@onNull String cardId, @NonNull @CardType int cardType, @NonNull Icon cardImage, @NonNull CharSequence contentDescription, @NonNull PendingIntent pendingIntent )283         public Builder(@NonNull String cardId,
284                 @NonNull @CardType int cardType,
285                 @NonNull Icon cardImage,
286                 @NonNull CharSequence contentDescription,
287                 @NonNull PendingIntent pendingIntent
288         ) {
289             mCardId = cardId;
290             mCardType = cardType;
291             mCardImage = cardImage;
292             mContentDescription = contentDescription;
293             mPendingIntent = pendingIntent;
294         }
295 
296         /**
297          * Called when a card type is not provided, in which case it defaults to CARD_TYPE_UNKNOWN.
298          */
Builder(@onNull String cardId, @NonNull Icon cardImage, @NonNull CharSequence contentDescription, @NonNull PendingIntent pendingIntent)299         public Builder(@NonNull String cardId,
300                 @NonNull Icon cardImage,
301                 @NonNull CharSequence contentDescription,
302                 @NonNull PendingIntent pendingIntent) {
303             this(cardId, WalletCard.CARD_TYPE_UNKNOWN, cardImage, contentDescription,
304                     pendingIntent);
305         }
306 
307         /**
308          * An icon may be shown alongside the card image to convey information about how the card
309          * can be used, or if some other action must be taken before using the card. For example, an
310          * NFC logo could indicate that the card is NFC-enabled and will be provided to an NFC
311          * terminal if the phone is held in close proximity to the NFC reader. This field is
312          * optional.
313          *
314          * <p>If the supplied Icon is backed by a bitmap, it should have width and height
315          * {@link GetWalletCardsRequest#getIconSizePx()}.
316          */
317         @NonNull
setCardIcon(@ullable Icon cardIcon)318         public Builder setCardIcon(@Nullable Icon cardIcon) {
319             mCardIcon = cardIcon;
320             return this;
321         }
322 
323         /**
324          * A card label may be shown alongside the card image to convey information about how the
325          * card can be used, or if some other action must be taken before using the card. For
326          * example, an NFC-enabled card could be labeled "Hold near reader" to inform the user of
327          * how to use NFC cards when interacting with an NFC reader. This field is optional.
328          * <b>Note: </b> this card label should <b>not</b> contain PII (Personally Identifiable
329          * Information, such as username or email address). If the provided label is too long to fit
330          * on one line, it may be truncated and ellipsized.
331          */
332         @NonNull
setCardLabel(@ullable CharSequence cardLabel)333         public Builder setCardLabel(@Nullable CharSequence cardLabel) {
334             mCardLabel = cardLabel;
335             return this;
336         }
337 
338         /**
339          * Visual representation of the card when it is tapped. May include additional information
340          *  unique to the card, such as a barcode or number. Only valid for CARD_TYPE_NON_PAYMENT.
341          * @hide
342          */
343         @NonNull
344         public Builder
setNonPaymentCardSecondaryImage(@ullable Icon nonPaymentCardSecondaryImage)345                 setNonPaymentCardSecondaryImage(@Nullable Icon nonPaymentCardSecondaryImage) {
346             Preconditions.checkState(mCardType == CARD_TYPE_NON_PAYMENT,
347                     "This field can only be set on non-payment cards");
348             mNonPaymentCardSecondaryImage = nonPaymentCardSecondaryImage;
349             return this;
350         }
351 
352         /**
353          * Builds a new {@link WalletCard} instance.
354          *
355          * @return A built response.
356          */
357         @NonNull
build()358         public WalletCard build() {
359             return new WalletCard(this);
360         }
361     }
362 }
363