1 /* 2 * Copyright (C) 2008 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.cts; 18 19 20 import android.cts.util.PollingCheck; 21 import android.graphics.Rect; 22 import android.provider.Settings.SettingNotFoundException; 23 import android.provider.Settings.System; 24 import android.test.ActivityInstrumentationTestCase2; 25 import android.text.Editable; 26 import android.text.method.PasswordTransformationMethod; 27 import android.view.KeyCharacterMap; 28 import android.view.View; 29 import android.widget.Button; 30 import android.widget.EditText; 31 import android.widget.LinearLayout; 32 import android.widget.LinearLayout.LayoutParams; 33 34 /** 35 * Test {@link PasswordTransformationMethod}. 36 */ 37 public class PasswordTransformationMethodTest extends 38 ActivityInstrumentationTestCase2<StubActivity> { 39 private static final int EDIT_TXT_ID = 1; 40 41 /** original text */ 42 private static final String TEST_CONTENT = "test content"; 43 44 /** text after transformation: ************(12 dots) */ 45 private static final String TEST_CONTENT_TRANSFORMED = 46 "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"; 47 48 private int mPasswordPrefBackUp; 49 50 private boolean isPasswordPrefSaved; 51 52 private StubActivity mActicity; 53 54 private MockPasswordTransformationMethod mMethod; 55 56 private EditText mEditText; 57 58 private CharSequence mTransformedText; 59 PasswordTransformationMethodTest()60 public PasswordTransformationMethodTest() { 61 super("com.android.cts.stub", StubActivity.class); 62 } 63 64 @Override setUp()65 protected void setUp() throws Exception { 66 super.setUp(); 67 mActicity = getActivity(); 68 mMethod = new MockPasswordTransformationMethod(); 69 try { 70 runTestOnUiThread(new Runnable() { 71 public void run() { 72 EditText editText = new EditText(mActicity); 73 editText.setId(EDIT_TXT_ID); 74 editText.setTransformationMethod(mMethod); 75 Button button = new Button(mActicity); 76 LinearLayout layout = new LinearLayout(mActicity); 77 layout.setOrientation(LinearLayout.VERTICAL); 78 layout.addView(editText, new LayoutParams(LayoutParams.MATCH_PARENT, 79 LayoutParams.WRAP_CONTENT)); 80 layout.addView(button, new LayoutParams(LayoutParams.MATCH_PARENT, 81 LayoutParams.WRAP_CONTENT)); 82 mActicity.setContentView(layout); 83 editText.requestFocus(); 84 } 85 }); 86 } catch (Throwable e) { 87 fail("Exception thrown is UI thread:" + e.getMessage()); 88 } 89 getInstrumentation().waitForIdleSync(); 90 91 mEditText = (EditText) getActivity().findViewById(EDIT_TXT_ID); 92 assertTrue(mEditText.isFocused()); 93 94 savePasswordPref(); 95 switchShowPassword(true); 96 } 97 98 @Override tearDown()99 protected void tearDown() throws Exception { 100 resumePasswordPref(); 101 super.tearDown(); 102 } 103 testConstructor()104 public void testConstructor() { 105 new PasswordTransformationMethod(); 106 } 107 testTextChangedCallBacks()108 public void testTextChangedCallBacks() throws Throwable { 109 runTestOnUiThread(new Runnable() { 110 public void run() { 111 mTransformedText = mMethod.getTransformation(mEditText.getText(), mEditText); 112 } 113 }); 114 115 mMethod.reset(); 116 // 12-key support 117 KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); 118 if (keymap.getKeyboardType() == KeyCharacterMap.NUMERIC) { 119 // "HELLO" in case of 12-key(NUMERIC) keyboard 120 sendKeys("6*4 6*3 7*5 DPAD_RIGHT 7*5 7*6 DPAD_RIGHT"); 121 } 122 else { 123 sendKeys("H E 2*L O"); 124 } 125 assertTrue(mMethod.hasCalledBeforeTextChanged()); 126 assertTrue(mMethod.hasCalledOnTextChanged()); 127 assertTrue(mMethod.hasCalledAfterTextChanged()); 128 129 mMethod.reset(); 130 131 runTestOnUiThread(new Runnable() { 132 public void run() { 133 mEditText.append(" "); 134 } 135 }); 136 137 // the appended string will not get transformed immediately 138 // "***** " 139 assertEquals("\u2022\u2022\u2022\u2022\u2022 ", mTransformedText.toString()); 140 assertTrue(mMethod.hasCalledBeforeTextChanged()); 141 assertTrue(mMethod.hasCalledOnTextChanged()); 142 assertTrue(mMethod.hasCalledAfterTextChanged()); 143 144 // it will get transformed after a while 145 new PollingCheck() { 146 @Override 147 protected boolean check() { 148 // "******" 149 return mTransformedText.toString() 150 .equals("\u2022\u2022\u2022\u2022\u2022\u2022"); 151 } 152 }.run(); 153 } 154 testGetTransformation()155 public void testGetTransformation() { 156 PasswordTransformationMethod method = new PasswordTransformationMethod(); 157 158 assertEquals(TEST_CONTENT_TRANSFORMED, 159 method.getTransformation(TEST_CONTENT, null).toString()); 160 161 CharSequence transformed = method.getTransformation(null, mEditText); 162 assertNotNull(transformed); 163 try { 164 transformed.toString(); 165 fail("Should throw NullPointerException if the source is null."); 166 } catch (NullPointerException e) { 167 // expected 168 } 169 } 170 testGetInstance()171 public void testGetInstance() { 172 PasswordTransformationMethod method0 = PasswordTransformationMethod.getInstance(); 173 assertNotNull(method0); 174 175 PasswordTransformationMethod method1 = PasswordTransformationMethod.getInstance(); 176 assertNotNull(method1); 177 assertSame(method0, method1); 178 } 179 testOnFocusChanged()180 public void testOnFocusChanged() { 181 // lose focus 182 mMethod.reset(); 183 assertTrue(mEditText.isFocused()); 184 sendKeys("DPAD_DOWN"); 185 assertFalse(mEditText.isFocused()); 186 assertTrue(mMethod.hasCalledOnFocusChanged()); 187 188 // gain focus 189 mMethod.reset(); 190 assertFalse(mEditText.isFocused()); 191 sendKeys("DPAD_UP"); 192 assertTrue(mEditText.isFocused()); 193 assertTrue(mMethod.hasCalledOnFocusChanged()); 194 } 195 savePasswordPref()196 private void savePasswordPref() { 197 try { 198 mPasswordPrefBackUp = System.getInt(mActicity.getContentResolver(), 199 System.TEXT_SHOW_PASSWORD); 200 isPasswordPrefSaved = true; 201 } catch (SettingNotFoundException e) { 202 isPasswordPrefSaved = false; 203 } 204 } 205 resumePasswordPref()206 private void resumePasswordPref() { 207 if (isPasswordPrefSaved) { 208 System.putInt(mActicity.getContentResolver(), System.TEXT_SHOW_PASSWORD, 209 mPasswordPrefBackUp); 210 } 211 } 212 switchShowPassword(boolean on)213 private void switchShowPassword(boolean on) { 214 System.putInt(mActicity.getContentResolver(), System.TEXT_SHOW_PASSWORD, 215 on ? 1 : 0); 216 } 217 218 private static class MockPasswordTransformationMethod extends PasswordTransformationMethod { 219 private boolean mHasCalledBeforeTextChanged; 220 221 private boolean mHasCalledOnTextChanged; 222 223 private boolean mHasCalledAfterTextChanged; 224 225 private boolean mHasCalledOnFocusChanged; 226 227 @Override afterTextChanged(Editable s)228 public void afterTextChanged(Editable s) { 229 super.afterTextChanged(s); 230 mHasCalledAfterTextChanged = true; 231 } 232 233 @Override beforeTextChanged(CharSequence s, int start, int count, int after)234 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 235 super.beforeTextChanged(s, start, count, after); 236 mHasCalledBeforeTextChanged = true; 237 } 238 239 @Override onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction, Rect previouslyFocusedRect)240 public void onFocusChanged(View view, CharSequence sourceText, boolean focused, 241 int direction, Rect previouslyFocusedRect) { 242 super.onFocusChanged(view, sourceText, focused, direction, previouslyFocusedRect); 243 mHasCalledOnFocusChanged = true; 244 } 245 246 @Override onTextChanged(CharSequence s, int start, int before, int count)247 public void onTextChanged(CharSequence s, int start, int before, int count) { 248 super.onTextChanged(s, start, before, count); 249 mHasCalledOnTextChanged = true; 250 } 251 hasCalledBeforeTextChanged()252 public boolean hasCalledBeforeTextChanged() { 253 return mHasCalledBeforeTextChanged; 254 } 255 hasCalledOnTextChanged()256 public boolean hasCalledOnTextChanged() { 257 return mHasCalledOnTextChanged; 258 } 259 hasCalledAfterTextChanged()260 public boolean hasCalledAfterTextChanged() { 261 return mHasCalledAfterTextChanged; 262 } 263 hasCalledOnFocusChanged()264 public boolean hasCalledOnFocusChanged() { 265 return mHasCalledOnFocusChanged; 266 } 267 reset()268 public void reset() { 269 mHasCalledBeforeTextChanged = false; 270 mHasCalledOnTextChanged = false; 271 mHasCalledAfterTextChanged = false; 272 mHasCalledOnFocusChanged = false; 273 } 274 } 275 } 276