1 /* 2 * Copyright (C) 2023 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.hardware.biometrics; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.util.Log; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 27 import java.util.ArrayList; 28 import java.util.List; 29 30 31 /** 32 * Contains the information of the template of vertical list content view for Biometric Prompt. 33 * <p> 34 * Here's how you'd set a <code>PromptVerticalListContentView</code> on a Biometric Prompt: 35 * <pre class="prettyprint"> 36 * BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(...) 37 * .setTitle(...) 38 * .setSubTitle(...) 39 * .setContentView(new PromptVerticalListContentView.Builder() 40 * .setDescription("test description") 41 * .addListItem(new PromptContentItemPlainText("test item 1")) 42 * .addListItem(new PromptContentItemPlainText("test item 2")) 43 * .addListItem(new PromptContentItemBulletedText("test item 3")) 44 * .build()) 45 * .build(); 46 * </pre> 47 */ 48 public final class PromptVerticalListContentView implements PromptContentViewParcelable { 49 private static final String TAG = "PromptVerticalListContentView"; 50 @VisibleForTesting 51 static final int MAX_ITEM_NUMBER = 20; 52 @VisibleForTesting 53 static final int MAX_EACH_ITEM_CHARACTER_NUMBER = 640; 54 @VisibleForTesting 55 static final int MAX_DESCRIPTION_CHARACTER_NUMBER = 225; 56 57 private final List<PromptContentItemParcelable> mContentList; 58 private final String mDescription; 59 PromptVerticalListContentView( @onNull List<PromptContentItemParcelable> contentList, @NonNull String description)60 private PromptVerticalListContentView( 61 @NonNull List<PromptContentItemParcelable> contentList, 62 @NonNull String description) { 63 mContentList = contentList; 64 mDescription = description; 65 } 66 PromptVerticalListContentView(Parcel in)67 private PromptVerticalListContentView(Parcel in) { 68 mContentList = in.readArrayList( 69 PromptContentItemParcelable.class.getClassLoader(), 70 PromptContentItemParcelable.class); 71 mDescription = in.readString(); 72 } 73 74 /** 75 * Returns the maximum count of the list items. 76 */ getMaxItemCount()77 public static int getMaxItemCount() { 78 return MAX_ITEM_NUMBER; 79 } 80 81 /** 82 * Returns the maximum number of characters allowed for each item's text. 83 */ getMaxEachItemCharacterNumber()84 public static int getMaxEachItemCharacterNumber() { 85 return MAX_EACH_ITEM_CHARACTER_NUMBER; 86 } 87 88 /** 89 * Gets the description for the content view, as set by 90 * {@link PromptVerticalListContentView.Builder#setDescription(String)}. 91 * 92 * @return The description for the content view, or null if the content view has no description. 93 */ 94 @Nullable getDescription()95 public String getDescription() { 96 return mDescription; 97 } 98 99 /** 100 * Gets the list of items on the content view, as set by 101 * {@link PromptVerticalListContentView.Builder#addListItem(PromptContentItem)}. 102 * 103 * @return The item list on the content view. 104 */ 105 @NonNull getListItems()106 public List<PromptContentItem> getListItems() { 107 return new ArrayList<>(mContentList); 108 } 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override describeContents()114 public int describeContents() { 115 return 0; 116 } 117 118 /** 119 * {@inheritDoc} 120 */ 121 @Override writeToParcel(@ndroidx.annotation.NonNull Parcel dest, int flags)122 public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) { 123 dest.writeList(mContentList); 124 dest.writeString(mDescription); 125 } 126 127 /** 128 * @see Parcelable.Creator 129 */ 130 @NonNull 131 public static final Creator<PromptVerticalListContentView> CREATOR = new Creator<>() { 132 @Override 133 public PromptVerticalListContentView createFromParcel(Parcel in) { 134 return new PromptVerticalListContentView(in); 135 } 136 137 @Override 138 public PromptVerticalListContentView[] newArray(int size) { 139 return new PromptVerticalListContentView[size]; 140 } 141 }; 142 143 144 /** 145 * A builder that collects arguments to be shown on the vertical list view. 146 */ 147 public static final class Builder { 148 private final List<PromptContentItemParcelable> mContentList = new ArrayList<>(); 149 private String mDescription; 150 151 /** 152 * Optional: Sets a description that will be shown on the content view. 153 * 154 * @param description The description to display. 155 * @return This builder. 156 */ 157 @NonNull setDescription(@onNull String description)158 public Builder setDescription(@NonNull String description) { 159 if (description.length() > MAX_DESCRIPTION_CHARACTER_NUMBER) { 160 Log.w(TAG, "The character number of description exceeds " 161 + MAX_DESCRIPTION_CHARACTER_NUMBER); 162 } 163 mDescription = description; 164 return this; 165 } 166 167 /** 168 * Optional: Adds a list item in the current row. 169 * 170 * @param listItem The list item view to display 171 * @return This builder. 172 * @throws IllegalArgumentException If the number of list items exceeds certain limit. 173 */ 174 @NonNull addListItem(@onNull PromptContentItem listItem)175 public Builder addListItem(@NonNull PromptContentItem listItem) { 176 mContentList.add((PromptContentItemParcelable) listItem); 177 checkItemLimits(listItem); 178 return this; 179 } 180 181 /** 182 * Optional: Adds a list item in the current row. 183 * 184 * @param listItem The list item view to display 185 * @param index The position at which to add the item 186 * @return This builder. 187 * @throws IllegalArgumentException If the number of list items exceeds certain limit. 188 */ 189 @NonNull addListItem(@onNull PromptContentItem listItem, int index)190 public Builder addListItem(@NonNull PromptContentItem listItem, int index) { 191 mContentList.add(index, (PromptContentItemParcelable) listItem); 192 checkItemLimits(listItem); 193 return this; 194 } 195 checkItemLimits(@onNull PromptContentItem listItem)196 private void checkItemLimits(@NonNull PromptContentItem listItem) { 197 if (doesListItemExceedsCharLimit(listItem)) { 198 Log.w(TAG, "The character number of list item exceeds " 199 + MAX_EACH_ITEM_CHARACTER_NUMBER); 200 } 201 if (mContentList.size() > MAX_ITEM_NUMBER) { 202 throw new IllegalArgumentException( 203 "The number of list items exceeds " + MAX_ITEM_NUMBER); 204 } 205 } 206 doesListItemExceedsCharLimit(PromptContentItem listItem)207 private boolean doesListItemExceedsCharLimit(PromptContentItem listItem) { 208 if (listItem instanceof PromptContentItemPlainText) { 209 return ((PromptContentItemPlainText) listItem).getText().length() 210 > MAX_EACH_ITEM_CHARACTER_NUMBER; 211 } else if (listItem instanceof PromptContentItemBulletedText) { 212 return ((PromptContentItemBulletedText) listItem).getText().length() 213 > MAX_EACH_ITEM_CHARACTER_NUMBER; 214 } else { 215 return false; 216 } 217 } 218 219 220 /** 221 * Creates a {@link PromptVerticalListContentView}. 222 * 223 * @return An instance of {@link PromptVerticalListContentView}. 224 */ 225 @NonNull build()226 public PromptVerticalListContentView build() { 227 return new PromptVerticalListContentView(mContentList, mDescription); 228 } 229 } 230 } 231