1c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme/*
2c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * Copyright (C) 2018 The Android Open Source Project
3c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme *
4c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * Licensed under the Apache License, Version 2.0 (the "License");
5c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * you may not use this file except in compliance with the License.
6c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * You may obtain a copy of the License at
7c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme *
8c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme *      http://www.apache.org/licenses/LICENSE-2.0
9c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme *
10c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * Unless required by applicable law or agreed to in writing, software
11c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * distributed under the License is distributed on an "AS IS" BASIS,
12c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * See the License for the specific language governing permissions and
14c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * limitations under the License.
15c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme */
16c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
17c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemepackage android.service.autofill;
18c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
19c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport static android.view.autofill.Helper.sDebug;
20c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
21c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.annotation.NonNull;
22c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.annotation.TestApi;
2327206d7940540b3eb961700ff07702ca14704742Felipe Lemeimport android.icu.text.DateFormat;
24c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.os.Parcel;
25c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.os.Parcelable;
26c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.util.Log;
27c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.view.autofill.AutofillId;
28c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.view.autofill.AutofillValue;
29c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.widget.RemoteViews;
30c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport android.widget.TextView;
31c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
32c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport com.android.internal.util.Preconditions;
33c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
34c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemeimport java.util.Date;
35c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
36c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme/**
37c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * Replaces a {@link TextView} child of a {@link CustomDescription} with the contents of a field
38c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * that is expected to have a {@link AutofillValue#forDate(long) date value}.
39c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme *
40c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * <p>For example, a transformation to display a credit card expiration date as month/year would be:
41c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme *
42c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * <pre class="prettyprint">
43c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * new DateTransformation(ccExpDate, new java.text.SimpleDateFormat("MM/yyyy")
44c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme * </pre>
45c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme */
46c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Lemepublic final class DateTransformation extends InternalTransformation implements
47c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        Transformation, Parcelable {
48c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    private static final String TAG = "DateTransformation";
49c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
50c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    private final AutofillId mFieldId;
51c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    private final DateFormat mDateFormat;
52c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
53c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    /**
54c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme     * Creates a new transformation.
55c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme     *
56c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme     * @param id id of the screen field.
57c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme     * @param dateFormat object used to transform the date value of the field to a String.
58c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme     */
59c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    public DateTransformation(@NonNull AutofillId id, @NonNull DateFormat dateFormat) {
60c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        mFieldId = Preconditions.checkNotNull(id);
61c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        mDateFormat = Preconditions.checkNotNull(dateFormat);
62c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    }
63c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
64c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    /** @hide */
65c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    @Override
66c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    @TestApi
67c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    public void apply(@NonNull ValueFinder finder, @NonNull RemoteViews parentTemplate,
68c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            int childViewId) throws Exception {
69c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        final AutofillValue value = finder.findRawValueByAutofillId(mFieldId);
70c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        if (value == null) {
71c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            Log.w(TAG, "No value for id " + mFieldId);
72c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            return;
73c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        }
74c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        if (!value.isDate()) {
75c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            Log.w(TAG, "Value for " + mFieldId + " is not date: " + value);
76c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            return;
77c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        }
78c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
79c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        try {
80c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            final Date date = new Date(value.getDateValue());
81c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            final String transformed = mDateFormat.format(date);
82c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            if (sDebug) Log.d(TAG, "Transformed " + date + " to " + transformed);
83c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
84c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            parentTemplate.setCharSequence(childViewId, "setText", transformed);
85c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        } catch (Exception e) {
86c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            Log.w(TAG, "Could not apply " + mDateFormat + " to " + value + ": " + e);
87c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        }
88c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    }
89c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
90c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    /////////////////////////////////////
91c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    // Object "contract" methods. //
92c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    /////////////////////////////////////
93c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    @Override
94c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    public String toString() {
95c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        if (!sDebug) return super.toString();
96c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
97c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        return "DateTransformation: [id=" + mFieldId + ", format=" + mDateFormat + "]";
98c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    }
99c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
100c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    /////////////////////////////////////
101c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    // Parcelable "contract" methods. //
102c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    /////////////////////////////////////
103c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    @Override
104c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    public int describeContents() {
105c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        return 0;
106c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    }
107c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
108c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    @Override
109c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    public void writeToParcel(Parcel parcel, int flags) {
110c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        parcel.writeParcelable(mFieldId, flags);
111c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        parcel.writeSerializable(mDateFormat);
112c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    }
113c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
114c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    public static final Parcelable.Creator<DateTransformation> CREATOR =
115c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            new Parcelable.Creator<DateTransformation>() {
116c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        @Override
117c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        public DateTransformation createFromParcel(Parcel parcel) {
118c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            return new DateTransformation(parcel.readParcelable(null),
119c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme                    (DateFormat) parcel.readSerializable());
120c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        }
121c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme
122c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        @Override
123c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        public DateTransformation[] newArray(int size) {
124c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme            return new DateTransformation[size];
125c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme        }
126c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme    };
127c8c0a82f56a5ef0cb3c8f749006d3a3b3e501849Felipe Leme}
128