1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.text.method; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.text.InputType; 22 import android.view.KeyEvent; 23 24 import com.android.internal.annotations.GuardedBy; 25 import com.android.internal.util.ArrayUtils; 26 27 import java.util.HashMap; 28 import java.util.LinkedHashSet; 29 import java.util.Locale; 30 31 /** 32 * For entering times in a text field. 33 * <p></p> 34 * As for all implementations of {@link KeyListener}, this class is only concerned 35 * with hardware keyboards. Software input methods have no obligation to trigger 36 * the methods in this class. 37 */ 38 public class TimeKeyListener extends NumberKeyListener 39 { getInputType()40 public int getInputType() { 41 if (mNeedsAdvancedInput) { 42 return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL; 43 } else { 44 return InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_TIME; 45 } 46 } 47 48 @Override 49 @NonNull getAcceptedChars()50 protected char[] getAcceptedChars() 51 { 52 return mCharacters; 53 } 54 55 /** 56 * @deprecated Use {@link #TimeKeyListener(Locale)} instead. 57 */ 58 @Deprecated TimeKeyListener()59 public TimeKeyListener() { 60 this(null); 61 } 62 63 private static final String SYMBOLS_TO_IGNORE = "ahHKkms"; 64 private static final String SKELETON_12HOUR = "hms"; 65 private static final String SKELETON_24HOUR = "Hms"; 66 TimeKeyListener(@ullable Locale locale)67 public TimeKeyListener(@Nullable Locale locale) { 68 final LinkedHashSet<Character> chars = new LinkedHashSet<>(); 69 // First add the digits. Then, add all the character in AM and PM markers. Finally, add all 70 // the non-pattern characters seen in the patterns for "hms" and "Hms". 71 final boolean success = NumberKeyListener.addDigits(chars, locale) 72 && NumberKeyListener.addAmPmChars(chars, locale) 73 && NumberKeyListener.addFormatCharsFromSkeleton( 74 chars, locale, SKELETON_12HOUR, SYMBOLS_TO_IGNORE) 75 && NumberKeyListener.addFormatCharsFromSkeleton( 76 chars, locale, SKELETON_24HOUR, SYMBOLS_TO_IGNORE); 77 if (success) { 78 mCharacters = NumberKeyListener.collectionToArray(chars); 79 if (locale != null && "en".equals(locale.getLanguage())) { 80 // For backward compatibility reasons, assume we don't need advanced input for 81 // English locales, although English locales may need uppercase letters for 82 // AM and PM. 83 mNeedsAdvancedInput = false; 84 } else { 85 mNeedsAdvancedInput = !ArrayUtils.containsAll(CHARACTERS, mCharacters); 86 } 87 } else { 88 mCharacters = CHARACTERS; 89 mNeedsAdvancedInput = false; 90 } 91 } 92 93 /** 94 * @deprecated Use {@link #getInstance(Locale)} instead. 95 */ 96 @Deprecated 97 @NonNull getInstance()98 public static TimeKeyListener getInstance() { 99 return getInstance(null); 100 } 101 102 /** 103 * Returns an instance of TimeKeyListener appropriate for the given locale. 104 */ 105 @NonNull getInstance(@ullable Locale locale)106 public static TimeKeyListener getInstance(@Nullable Locale locale) { 107 TimeKeyListener instance; 108 synchronized (sLock) { 109 instance = sInstanceCache.get(locale); 110 if (instance == null) { 111 instance = new TimeKeyListener(locale); 112 sInstanceCache.put(locale, instance); 113 } 114 } 115 return instance; 116 } 117 118 /** 119 * This field used to list the characters that were used. But is now a fixed data 120 * field that is the list of code units used for the deprecated case where the class 121 * is instantiated with null or no input parameter. 122 * 123 * @see KeyEvent#getMatch 124 * @see #getAcceptedChars 125 * 126 * @deprecated Use {@link #getAcceptedChars()} instead. 127 */ 128 public static final char[] CHARACTERS = new char[] { 129 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'm', 130 'p', ':' 131 }; 132 133 private final char[] mCharacters; 134 private final boolean mNeedsAdvancedInput; 135 136 private static final Object sLock = new Object(); 137 @GuardedBy("sLock") 138 private static final HashMap<Locale, TimeKeyListener> sInstanceCache = new HashMap<>(); 139 } 140