1979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme/* 2979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * Copyright (C) 2017 The Android Open Source Project 3979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 4979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * Licensed under the Apache License, Version 2.0 (the "License"); 5979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * you may not use this file except in compliance with the License. 6979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * You may obtain a copy of the License at 7979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 8979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * http://www.apache.org/licenses/LICENSE-2.0 9979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 10979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * Unless required by applicable law or agreed to in writing, software 11979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * distributed under the License is distributed on an "AS IS" BASIS, 12979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * See the License for the specific language governing permissions and 14979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * limitations under the License. 15979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme */ 16979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 17979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemepackage android.service.autofill; 18979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 19979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport static android.view.autofill.Helper.sDebug; 20979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 21de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmannimport android.annotation.DrawableRes; 22979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport android.annotation.NonNull; 23ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Lemeimport android.annotation.Nullable; 24de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmannimport android.annotation.TestApi; 25979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport android.os.Parcel; 26979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport android.os.Parcelable; 27ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Lemeimport android.text.TextUtils; 28979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport android.util.Log; 29979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport android.view.autofill.AutofillId; 30979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport android.widget.ImageView; 31979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport android.widget.RemoteViews; 32979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 33979013d027d828f404e71f48b88403e562ccbc7bFelipe Lemeimport com.android.internal.util.Preconditions; 34979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 352a9a771c65e086dd8ef5bea648f6447e084ea81cPhilip P. Moltmannimport java.util.ArrayList; 36de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmannimport java.util.regex.Pattern; 37de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann 38979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme/** 39979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * Replaces the content of a child {@link ImageView} of a 40979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * {@link RemoteViews presentation template} with the first image that matches a regular expression 41979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * (regex). 42979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 43979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * <p>Typically used to display credit card logos. Example: 44979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 45979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * <pre class="prettyprint"> 46906b85371766dd696158557987d9b05dc30583e8Felipe Leme * new ImageTransformation.Builder(ccNumberId, Pattern.compile("^4815.*$"), 47ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * R.drawable.ic_credit_card_logo1, "Brand 1") 48ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * .addOption(Pattern.compile("^1623.*$"), R.drawable.ic_credit_card_logo2, "Brand 2") 49ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * .addOption(Pattern.compile("^42.*$"), R.drawable.ic_credit_card_logo3, "Brand 3") 50979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * .build(); 51979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * </pre> 52979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 53979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * <p>There is no imposed limit in the number of options, but keep in mind that regexs are 547fc29dd9311cc36c3eb2a6a05aeed2d39ddcc604Felipe Leme * expensive to evaluate, so use the minimum number of regexs and add the most common first 557fc29dd9311cc36c3eb2a6a05aeed2d39ddcc604Felipe Leme * (for example, if this is a tranformation for a credit card logo and the most common credit card 567fc29dd9311cc36c3eb2a6a05aeed2d39ddcc604Felipe Leme * issuers are banks X and Y, add the regexes that resolves these 2 banks first). 57979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme */ 583858aa67365ad574ee474edc68e2e82d4d8c6081Philip P. Moltmannpublic final class ImageTransformation extends InternalTransformation implements Transformation, 593858aa67365ad574ee474edc68e2e82d4d8c6081Philip P. Moltmann Parcelable { 60979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme private static final String TAG = "ImageTransformation"; 61979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 62979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme private final AutofillId mId; 63ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme private final ArrayList<Option> mOptions; 64979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 65979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme private ImageTransformation(Builder builder) { 66979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme mId = builder.mId; 67979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme mOptions = builder.mOptions; 68979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 69979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 70979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme /** @hide */ 71de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann @TestApi 72979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme @Override 73979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public void apply(@NonNull ValueFinder finder, @NonNull RemoteViews parentTemplate, 7422101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme int childViewId) throws Exception { 75979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme final String value = finder.findByAutofillId(mId); 76979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme if (value == null) { 77979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme Log.w(TAG, "No view for id " + mId); 78979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme return; 79979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 80979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme final int size = mOptions.size(); 81979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme if (sDebug) { 82a5083c40d513184bc84ac39def7303a1424fa4c8Felipe Leme Log.d(TAG, size + " multiple options on id " + childViewId + " to compare against"); 83979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 84979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 85979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme for (int i = 0; i < size; i++) { 86ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme final Option option = mOptions.get(i); 8722101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme try { 88ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme if (option.pattern.matcher(value).matches()) { 8922101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme Log.d(TAG, "Found match at " + i + ": " + option); 90ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme parentTemplate.setImageViewResource(childViewId, option.resId); 91ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme if (option.contentDescription != null) { 92ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme parentTemplate.setContentDescription(childViewId, 93ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme option.contentDescription); 94ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme } 9522101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme return; 9622101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme } 9722101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme } catch (Exception e) { 9822101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme // Do not log full exception to avoid PII leaking 99ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme Log.w(TAG, "Error matching regex #" + i + "(" + option.pattern + ") on id " 100ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme + option.resId + ": " + e.getClass()); 10122101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme throw e; 10222101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme 103979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 104979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 10522101ca5a91e36f56b4d7cab2bb8517f679c6c86Felipe Leme if (sDebug) Log.d(TAG, "No match for " + value); 106979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 107979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 108979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme /** 109979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * Builder for {@link ImageTransformation} objects. 110979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme */ 111979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public static class Builder { 112979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme private final AutofillId mId; 113ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme private final ArrayList<Option> mOptions = new ArrayList<>(); 114979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme private boolean mDestroyed; 115979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 116979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme /** 117ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * Creates a new builder for a autofill id and add a first option. 118979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 119979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * @param id id of the screen field that will be used to evaluate whether the image should 120979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * be used. 121906b85371766dd696158557987d9b05dc30583e8Felipe Leme * @param regex regular expression defining what should be matched to use this image. 122de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann * @param resId resource id of the image (in the autofill service's package). The 123de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. 124ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * 125ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @deprecated use 126ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * {@link #ImageTransformation.Builder(AutofillId, Pattern, int, CharSequence)} instead. 127979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme */ 128ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme @Deprecated 129906b85371766dd696158557987d9b05dc30583e8Felipe Leme public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId) { 130979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme mId = Preconditions.checkNotNull(id); 131de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann addOption(regex, resId); 132979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 133979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 134979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme /** 135ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * Creates a new builder for a autofill id and add a first option. 136ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * 137ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @param id id of the screen field that will be used to evaluate whether the image should 138ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * be used. 139ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @param regex regular expression defining what should be matched to use this image. 140ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @param resId resource id of the image (in the autofill service's package). The 141ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. 142ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @param contentDescription content description to be applied in the child view. 143ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme */ 144ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme public Builder(@NonNull AutofillId id, @NonNull Pattern regex, @DrawableRes int resId, 145ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme @NonNull CharSequence contentDescription) { 146ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme mId = Preconditions.checkNotNull(id); 147ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme addOption(regex, resId, contentDescription); 148ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme } 149ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme 150ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme /** 151979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * Adds an option to replace the child view with a different image when the regex matches. 152979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 153906b85371766dd696158557987d9b05dc30583e8Felipe Leme * @param regex regular expression defining what should be matched to use this image. 154979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * @param resId resource id of the image (in the autofill service's package). The 155979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. 156979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * 157979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * @return this build 158ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * 159ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @deprecated use {@link #addOption(Pattern, int, CharSequence)} instead. 160979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme */ 161ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme @Deprecated 162906b85371766dd696158557987d9b05dc30583e8Felipe Leme public Builder addOption(@NonNull Pattern regex, @DrawableRes int resId) { 163ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme addOptionInternal(regex, resId, null); 164ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme return this; 165ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme } 166ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme 167ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme /** 168ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * Adds an option to replace the child view with a different image and content description 169ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * when the regex matches. 170ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * 171ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @param regex regular expression defining what should be matched to use this image. 172ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @param resId resource id of the image (in the autofill service's package). The 173ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * {@link RemoteViews presentation} must contain a {@link ImageView} child with that id. 174ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @param contentDescription content description to be applied in the child view. 175ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * 176ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme * @return this build 177ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme */ 178ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme public Builder addOption(@NonNull Pattern regex, @DrawableRes int resId, 179ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme @NonNull CharSequence contentDescription) { 180ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme addOptionInternal(regex, resId, Preconditions.checkNotNull(contentDescription)); 181ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme return this; 182ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme } 183ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme 184ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme private void addOptionInternal(@NonNull Pattern regex, @DrawableRes int resId, 185ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme @Nullable CharSequence contentDescription) { 186979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme throwIfDestroyed(); 187de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann 188906b85371766dd696158557987d9b05dc30583e8Felipe Leme Preconditions.checkNotNull(regex); 189de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann Preconditions.checkArgument(resId != 0); 190de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann 191ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme mOptions.add(new Option(regex, resId, contentDescription)); 192979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 193979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 194ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme 195979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme /** 196979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme * Creates a new {@link ImageTransformation} instance. 197979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme */ 198979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public ImageTransformation build() { 199979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme throwIfDestroyed(); 200979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme mDestroyed = true; 201979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme return new ImageTransformation(this); 202979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 203979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 204979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme private void throwIfDestroyed() { 205979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme Preconditions.checkState(!mDestroyed, "Already called build()"); 206979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 207979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 208979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 209979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme ///////////////////////////////////// 210979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme // Object "contract" methods. // 211979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme ///////////////////////////////////// 212979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme @Override 213979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public String toString() { 214979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme if (!sDebug) return super.toString(); 215979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 216979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme return "ImageTransformation: [id=" + mId + ", options=" + mOptions + "]"; 217979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 218979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 219979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme ///////////////////////////////////// 220979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme // Parcelable "contract" methods. // 221979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme ///////////////////////////////////// 222979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme @Override 223979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public int describeContents() { 224979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme return 0; 225979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 226979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme @Override 227979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public void writeToParcel(Parcel parcel, int flags) { 228979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme parcel.writeParcelable(mId, flags); 229de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann 230979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme final int size = mOptions.size(); 231ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme final Pattern[] patterns = new Pattern[size]; 232979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme final int[] resIds = new int[size]; 233ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme final CharSequence[] contentDescriptions = new String[size]; 234979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme for (int i = 0; i < size; i++) { 235ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme final Option option = mOptions.get(i); 236ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme patterns[i] = option.pattern; 237ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme resIds[i] = option.resId; 238ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme contentDescriptions[i] = option.contentDescription; 239979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 240ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme parcel.writeSerializable(patterns); 241979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme parcel.writeIntArray(resIds); 242ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme parcel.writeCharSequenceArray(contentDescriptions); 243979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 244979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 245979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public static final Parcelable.Creator<ImageTransformation> CREATOR = 246979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme new Parcelable.Creator<ImageTransformation>() { 247979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme @Override 248979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public ImageTransformation createFromParcel(Parcel parcel) { 249de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann final AutofillId id = parcel.readParcelable(null); 250de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann 251906b85371766dd696158557987d9b05dc30583e8Felipe Leme final Pattern[] regexs = (Pattern[]) parcel.readSerializable(); 252de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann final int[] resIds = parcel.createIntArray(); 253ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme final CharSequence[] contentDescriptions = parcel.readCharSequenceArray(); 254de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann 255de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann // Always go through the builder to ensure the data ingested by the system obeys the 256de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann // contract of the builder to avoid attacks using specially crafted parcels. 257ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme final CharSequence contentDescription = contentDescriptions[0]; 258ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme final ImageTransformation.Builder builder = (contentDescription != null) 259ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme ? new ImageTransformation.Builder(id, regexs[0], resIds[0], contentDescription) 260ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme : new ImageTransformation.Builder(id, regexs[0], resIds[0]); 261de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann 262de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann final int size = regexs.length; 263de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann for (int i = 1; i < size; i++) { 264ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme if (contentDescriptions[i] != null) { 265ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme builder.addOption(regexs[i], resIds[i], contentDescriptions[i]); 266ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme } else { 267ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme builder.addOption(regexs[i], resIds[i]); 268ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme } 269979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 270de78fabb740063fad2a502c07b6482cba79ce0a6Philip P. Moltmann 271979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme return builder.build(); 272979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 273979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme 274979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme @Override 275979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme public ImageTransformation[] newArray(int size) { 276979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme return new ImageTransformation[size]; 277979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme } 278979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme }; 279ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme 280ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme private static final class Option { 281ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme public final Pattern pattern; 282ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme public final int resId; 283ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme public final CharSequence contentDescription; 284ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme 285ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme Option(Pattern pattern, int resId, CharSequence contentDescription) { 286ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme this.pattern = pattern; 287ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme this.resId = resId; 288ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme this.contentDescription = TextUtils.trimNoCopySpans(contentDescription); 289ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme } 290ce8f7269a01badb5bb037346dfd4d81dd13457d0Felipe Leme } 291979013d027d828f404e71f48b88403e562ccbc7bFelipe Leme} 292