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