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