19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text.method;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
193484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournaderimport android.annotation.NonNull;
203484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournaderimport android.annotation.Nullable;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType;
224037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport android.view.KeyEvent;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
243484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournaderimport com.android.internal.annotations.GuardedBy;
25889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournaderimport com.android.internal.util.ArrayUtils;
263484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader
273484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournaderimport java.util.HashMap;
283484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournaderimport java.util.LinkedHashSet;
293484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournaderimport java.util.Locale;
303484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For entering dates in a text field.
33405bc51c5dc73846a4abdc325cd234eb2d37469fJean Chalard * <p></p>
34405bc51c5dc73846a4abdc325cd234eb2d37469fJean Chalard * As for all implementations of {@link KeyListener}, this class is only concerned
35405bc51c5dc73846a4abdc325cd234eb2d37469fJean Chalard * with hardware keyboards.  Software input methods have no obligation to trigger
36405bc51c5dc73846a4abdc325cd234eb2d37469fJean Chalard * the methods in this class.
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class DateKeyListener extends NumberKeyListener
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getInputType() {
41889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader        if (mNeedsAdvancedInput) {
42889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader            return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
43889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader        } else {
44889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader            return InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
45889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader        }
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
474037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
493484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    @NonNull
503484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    protected char[] getAcceptedChars() {
513484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        return mCharacters;
523484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    }
533484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader
543484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    /**
553484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     * @deprecated Use {@link #DateKeyListener(Locale)} instead.
563484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     */
573484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    @Deprecated
583484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    public DateKeyListener() {
593484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        this(null);
603484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    }
613484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader
623484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    private static final String SYMBOLS_TO_IGNORE = "yMLd";
633484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    private static final String[] SKELETONS = {"yMd", "yM", "Md"};
643484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader
653484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    public DateKeyListener(@Nullable Locale locale) {
663484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        final LinkedHashSet<Character> chars = new LinkedHashSet<>();
673484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        // First add the digits, then add all the non-pattern characters seen in the pattern for
683484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        // "yMd", which is supposed to only have numerical fields.
693484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        final boolean success = NumberKeyListener.addDigits(chars, locale)
703484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader                                && NumberKeyListener.addFormatCharsFromSkeletons(
713484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader                                        chars, locale, SKELETONS, SYMBOLS_TO_IGNORE);
72889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader        if (success) {
73889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader            mCharacters = NumberKeyListener.collectionToArray(chars);
74889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader            mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters);
75889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader        } else {
76889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader            mCharacters = CHARACTERS;
77889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader            mNeedsAdvancedInput = false;
78889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader        }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
813484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    /**
823484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     * @deprecated Use {@link #getInstance(Locale)} instead.
833484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     */
843484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    @Deprecated
853484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    @NonNull
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static DateKeyListener getInstance() {
873484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        return getInstance(null);
883484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    }
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
903484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    /**
913484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     * Returns an instance of DateKeyListener appropriate for the given locale.
923484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     */
933484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    @NonNull
943484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    public static DateKeyListener getInstance(@Nullable Locale locale) {
953484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        DateKeyListener instance;
963484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        synchronized (sLock) {
973484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader            instance = sInstanceCache.get(locale);
983484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader            if (instance == null) {
993484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader                instance = new DateKeyListener(locale);
1003484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader                sInstanceCache.put(locale, instance);
1013484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader            }
1023484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        }
1033484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader        return instance;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1073484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     * This field used to list the characters that were used. But is now a fixed data
1083484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     * field that is the list of code units used for the deprecated case where the class
1093484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     * is instantiated with null or no input parameter.
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see KeyEvent#getMatch
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getAcceptedChars
1133484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     *
1143484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader     * @deprecated Use {@link #getAcceptedChars()} instead.
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1163484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    @Deprecated
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final char[] CHARACTERS = new char[] {
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            '/', '-', '.'
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        };
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1223484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    private final char[] mCharacters;
123889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader    private final boolean mNeedsAdvancedInput;
1243484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader
1253484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    private static final Object sLock = new Object();
1263484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    @GuardedBy("sLock")
1273484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader    private static final HashMap<Locale, DateKeyListener> sInstanceCache = new HashMap<>();
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
129