1 /* 2 * Copyright (C) 2018 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 com.android.settings.inputmethod; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyString; 23 import static org.mockito.Mockito.never; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.content.Context; 28 import android.hardware.input.InputDeviceIdentifier; 29 import android.hardware.input.InputManager; 30 import android.hardware.input.KeyboardLayout; 31 import android.view.InputDevice; 32 33 import androidx.fragment.app.Fragment; 34 import androidx.fragment.app.FragmentActivity; 35 import androidx.preference.PreferenceManager; 36 import androidx.preference.PreferenceScreen; 37 38 import com.android.settings.core.BasePreferenceController; 39 import com.android.settings.testutils.shadow.ShadowInputDevice; 40 41 import org.junit.Before; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 import org.mockito.Mock; 45 import org.mockito.MockitoAnnotations; 46 import org.robolectric.Robolectric; 47 import org.robolectric.RobolectricTestRunner; 48 import org.robolectric.RuntimeEnvironment; 49 import org.robolectric.annotation.Config; 50 import org.robolectric.shadows.ShadowApplication; 51 52 @RunWith(RobolectricTestRunner.class) 53 @Config(shadows = { 54 com.android.settings.testutils.shadow.ShadowFragment.class, 55 }) 56 public class KeyboardLayoutPickerControllerTest { 57 58 @Mock 59 private Fragment mFragment; 60 @Mock 61 private InputManager mInputManager; 62 63 private Context mContext; 64 private InputDeviceIdentifier mInputDeviceIdentifier; 65 private KeyboardLayoutPickerController mController; 66 67 @Before setUp()68 public void setUp() { 69 MockitoAnnotations.initMocks(this); 70 final ShadowApplication shadowContext = ShadowApplication.getInstance(); 71 shadowContext.setSystemService(Context.INPUT_SERVICE, mInputManager); 72 73 mContext = RuntimeEnvironment.application; 74 mInputDeviceIdentifier = new InputDeviceIdentifier("descriptor", 1, 1); 75 mController = new KeyboardLayoutPickerController(mContext, "pref_key"); 76 77 initializeOneLayout(); 78 } 79 80 @Test isAlwaysAvailable()81 public void isAlwaysAvailable() { 82 assertThat(mController.getAvailabilityStatus()) 83 .isEqualTo(BasePreferenceController.AVAILABLE); 84 } 85 86 @Test testLifecycle_onStart_shouldRegisterInputManager()87 public void testLifecycle_onStart_shouldRegisterInputManager() { 88 final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class); 89 when(mFragment.getActivity()).thenReturn(activity); 90 91 mController.onStart(); 92 93 // Register is called, but unregister should not be called. 94 verify(mInputManager).registerInputDeviceListener(mController, null); 95 verify(mInputManager, never()).unregisterInputDeviceListener(mController); 96 } 97 98 @Test testLifecycle_onStart_NoInputDevice_shouldReturn()99 public void testLifecycle_onStart_NoInputDevice_shouldReturn() { 100 final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class); 101 when(mInputManager.getInputDeviceByDescriptor(anyString())).thenReturn(null); 102 when(mFragment.getActivity()).thenReturn(activity); 103 104 mController.onStart(); 105 verify(mInputManager, never()).getEnabledKeyboardLayoutsForInputDevice(any()); 106 } 107 108 @Test testLifecycle_onStop_shouldCancelRegisterInputManager()109 public void testLifecycle_onStop_shouldCancelRegisterInputManager() { 110 mController.onStop(); 111 112 // Unregister is called, but register should not be called. 113 verify(mInputManager).unregisterInputDeviceListener(mController); 114 verify(mInputManager, never()).registerInputDeviceListener(mController, null); 115 } 116 117 @Test test_createPreferenceHierarchy_shouldAddOnePreference()118 public void test_createPreferenceHierarchy_shouldAddOnePreference() { 119 final PreferenceManager preferenceManager = new PreferenceManager(mContext); 120 final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext); 121 122 mController.displayPreference(screen); 123 124 // We create a keyboard layouts in initializeOneLayout() 125 assertThat(screen.getPreferenceCount()).isEqualTo(1); 126 } 127 128 @Test test_createPreferenceHierarchy_shouldAddTwoPreference()129 public void test_createPreferenceHierarchy_shouldAddTwoPreference() { 130 initializeTwoLayouts(); 131 final PreferenceManager preferenceManager = new PreferenceManager(mContext); 132 final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext); 133 134 mController.displayPreference(screen); 135 136 // We create two keyboard layouts in initializeOneLayout() 137 assertThat(screen.getPreferenceCount()).isEqualTo(2); 138 } 139 140 @Test 141 @Config(shadows = ShadowInputDevice.class) testOnDeviceRemove_getSameDevice_shouldFinish()142 public void testOnDeviceRemove_getSameDevice_shouldFinish() { 143 final int TARGET_DEVICE_ID = 1; 144 final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class); 145 final String[] enableKeyboardLayouts = {"layout1"}; 146 final InputDevice device = ShadowInputDevice.makeInputDevicebyId(TARGET_DEVICE_ID); 147 148 when(mFragment.getActivity()).thenReturn(activity); 149 when(mInputManager.getInputDeviceByDescriptor(anyString())).thenReturn(device); 150 when(mInputManager.getEnabledKeyboardLayoutsForInputDevice( 151 any(InputDeviceIdentifier.class))).thenReturn(enableKeyboardLayouts); 152 153 mController.onStart(); 154 mController.onInputDeviceRemoved(TARGET_DEVICE_ID); 155 156 assertThat(activity.isFinishing()).isTrue(); 157 } 158 159 @Test 160 @Config(shadows = ShadowInputDevice.class) testOnDeviceRemove_getDifferentDevice_shouldNotFinish()161 public void testOnDeviceRemove_getDifferentDevice_shouldNotFinish() { 162 final int TARGET_DEVICE_ID = 1; 163 final int ANOTHER_DEVICE_ID = 2; 164 final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class); 165 final String[] enableKeyboardLayouts = {"layout1"}; 166 final InputDevice device = ShadowInputDevice.makeInputDevicebyId(TARGET_DEVICE_ID); 167 168 when(mFragment.getActivity()).thenReturn(activity); 169 when(mInputManager.getInputDeviceByDescriptor(anyString())).thenReturn(device); 170 when(mInputManager.getEnabledKeyboardLayoutsForInputDevice( 171 any(InputDeviceIdentifier.class))).thenReturn(enableKeyboardLayouts); 172 173 mController.onStart(); 174 mController.onInputDeviceRemoved(ANOTHER_DEVICE_ID); 175 176 assertThat(activity.isFinishing()).isFalse(); 177 } 178 initializeOneLayout()179 private void initializeOneLayout() { 180 final KeyboardLayout[] keyboardLayouts = {new KeyboardLayout("", "", "", 1, null, 0, 1, 1)}; 181 when(mInputManager.getKeyboardLayoutsForInputDevice( 182 any(InputDeviceIdentifier.class))).thenReturn( 183 keyboardLayouts); 184 185 mController.initialize(mFragment, mInputDeviceIdentifier); 186 } 187 initializeTwoLayouts()188 private void initializeTwoLayouts() { 189 final KeyboardLayout[] keyboardLayouts = {new KeyboardLayout("", "", "", 1, null, 0, 1, 1), 190 new KeyboardLayout("", "", "", 2, null, 0, 2, 2)}; 191 when(mInputManager.getKeyboardLayoutsForInputDevice(any(InputDeviceIdentifier.class))). 192 thenReturn(keyboardLayouts); 193 194 mController.initialize(mFragment, mInputDeviceIdentifier); 195 } 196 } 197