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 times 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 TimeKeyListener 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_TIME; 45889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader } 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 474037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 493484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader @NonNull 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected char[] getAcceptedChars() 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 523484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader return mCharacters; 533484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader } 543484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader 553484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader /** 563484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader * @deprecated Use {@link #TimeKeyListener(Locale)} instead. 573484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader */ 583484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader @Deprecated 593484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader public TimeKeyListener() { 603484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader this(null); 613484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader } 623484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader 633484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader private static final String SYMBOLS_TO_IGNORE = "ahHKkms"; 643484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader private static final String SKELETON_12HOUR = "hms"; 653484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader private static final String SKELETON_24HOUR = "Hms"; 663484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader 673484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader public TimeKeyListener(@Nullable Locale locale) { 683484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader final LinkedHashSet<Character> chars = new LinkedHashSet<>(); 693484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader // First add the digits. Then, add all the character in AM and PM markers. Finally, add all 703484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader // the non-pattern characters seen in the patterns for "hms" and "Hms". 719fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader final boolean success = NumberKeyListener.addDigits(chars, locale) 723484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader && NumberKeyListener.addAmPmChars(chars, locale) 733484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader && NumberKeyListener.addFormatCharsFromSkeleton( 743484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader chars, locale, SKELETON_12HOUR, SYMBOLS_TO_IGNORE) 753484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader && NumberKeyListener.addFormatCharsFromSkeleton( 763484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader chars, locale, SKELETON_24HOUR, SYMBOLS_TO_IGNORE); 77889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader if (success) { 78889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader mCharacters = NumberKeyListener.collectionToArray(chars); 799fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader if (locale != null && "en".equals(locale.getLanguage())) { 809fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader // For backward compatibility reasons, assume we don't need advanced input for 819fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader // English locales, although English locales may need uppercase letters for 829fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader // AM and PM. 839fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader mNeedsAdvancedInput = false; 849fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader } else { 859fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters); 869fe1c121272a469f69fb36766dc762e85a2052e1Roozbeh Pournader } 87889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader } else { 88889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader mCharacters = CHARACTERS; 89889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader mNeedsAdvancedInput = false; 90889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader } 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 933484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader /** 943484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader * @deprecated Use {@link #getInstance(Locale)} instead. 953484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader */ 963484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader @Deprecated 973484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader @NonNull 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static TimeKeyListener getInstance() { 993484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader return getInstance(null); 1003484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader } 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1023484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader /** 1033484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader * Returns an instance of TimeKeyListener appropriate for the given locale. 1043484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader */ 1053484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader @NonNull 1063484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader public static TimeKeyListener getInstance(@Nullable Locale locale) { 1073484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader TimeKeyListener instance; 1083484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader synchronized (sLock) { 1093484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader instance = sInstanceCache.get(locale); 1103484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader if (instance == null) { 1113484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader instance = new TimeKeyListener(locale); 1123484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader sInstanceCache.put(locale, instance); 1133484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader } 1143484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader } 1153484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader return instance; 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1193484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader * This field used to list the characters that were used. But is now a fixed data 1203484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader * field that is the list of code units used for the deprecated case where the class 1213484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader * is instantiated with null or no input parameter. 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see KeyEvent#getMatch 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getAcceptedChars 1253484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader * 1263484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader * @deprecated Use {@link #getAcceptedChars()} instead. 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final char[] CHARACTERS = new char[] { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'm', 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 'p', ':' 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1333484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader private final char[] mCharacters; 134889c6503a1764d6dbc1f7f4e23e3b392daab330bRoozbeh Pournader private final boolean mNeedsAdvancedInput; 1353484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader 1363484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader private static final Object sLock = new Object(); 1373484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader @GuardedBy("sLock") 1383484ba8fdc8f5c91937af23e6d59025081c02367Roozbeh Pournader private static final HashMap<Locale, TimeKeyListener> sInstanceCache = new HashMap<>(); 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 140