diff --git a/res/xml/input_methods_subtype.xml b/res/xml/input_methods_subtype.xml new file mode 100644 index 00000000000..643e93acb02 --- /dev/null +++ b/res/xml/input_methods_subtype.xml @@ -0,0 +1,25 @@ + + + + diff --git a/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java b/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java index 37f64133915..f3540893649 100644 --- a/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java +++ b/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnabler.java @@ -16,17 +16,18 @@ package com.android.settings.inputmethod; +import android.content.Context; import android.content.Intent; import android.os.Bundle; -import androidx.preference.PreferenceScreen; import android.text.TextUtils; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settingslib.inputmethod.InputMethodAndSubtypeEnablerManager; +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; -public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment { - private InputMethodAndSubtypeEnablerManager mManager; +public class InputMethodAndSubtypeEnabler extends DashboardFragment { + + private static final String TAG = "InputMethodAndSubtypeEnabler"; @Override public int getMetricsCategory() { @@ -34,8 +35,18 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment { } @Override - public void onCreate(final Bundle icicle) { - super.onCreate(icicle); + protected int getPreferenceScreenResId() { + return R.xml.input_methods_subtype; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); // Input method id should be available from an Intent when this preference is launched as a // single Activity (see InputMethodAndSubtypeEnablerActivity). It should be available @@ -44,11 +55,8 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment { final String targetImi = getStringExtraFromIntentOrArguments( android.provider.Settings.EXTRA_INPUT_METHOD_ID); - final PreferenceScreen root = - getPreferenceManager().createPreferenceScreen(getPrefContext()); - mManager = new InputMethodAndSubtypeEnablerManager(this); - mManager.init(this, targetImi, root); - setPreferenceScreen(root); + use(InputMethodAndSubtypePreferenceController.class).initialize(this /* fragment */, + targetImi); } private String getStringExtraFromIntentOrArguments(final String name) { @@ -69,16 +77,4 @@ public class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment { getActivity().setTitle(title); } } - - @Override - public void onResume() { - super.onResume(); - mManager.refresh(getContext(), this); - } - - @Override - public void onPause() { - super.onPause(); - mManager.save(getContext(), this); - } } diff --git a/src/com/android/settings/inputmethod/InputMethodAndSubtypePreferenceController.java b/src/com/android/settings/inputmethod/InputMethodAndSubtypePreferenceController.java new file mode 100644 index 00000000000..625289ccc06 --- /dev/null +++ b/src/com/android/settings/inputmethod/InputMethodAndSubtypePreferenceController.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.inputmethod; + +import android.content.Context; + +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; +import com.android.settingslib.inputmethod.InputMethodAndSubtypeEnablerManager; + +import androidx.preference.PreferenceFragment; +import androidx.preference.PreferenceScreen; + +public class InputMethodAndSubtypePreferenceController extends BasePreferenceController implements + LifecycleObserver, OnStart, OnStop { + + private PreferenceFragment mFragment; + private InputMethodAndSubtypeEnablerManager mManager; + private String mTargetImi; + + public InputMethodAndSubtypePreferenceController(Context context, String key) { + super(context, key); + } + + public void initialize(PreferenceFragment fragment, String imi) { + mFragment = fragment; + mTargetImi = imi; + mManager = new InputMethodAndSubtypeEnablerManager(mFragment); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mManager.init(mFragment, mTargetImi, screen); + } + + @Override + public void onStart() { + mManager.refresh(mContext, mFragment); + } + + @Override + public void onStop() { + mManager.save(mContext, mFragment); + } +} diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider index e6744ded37d..8bd4f823840 100644 --- a/tests/robotests/assets/grandfather_not_implementing_index_provider +++ b/tests/robotests/assets/grandfather_not_implementing_index_provider @@ -27,3 +27,4 @@ com.android.settings.notification.ZenModeEventRuleSettings com.android.settings.notification.ZenModeScheduleRuleSettings com.android.settings.fuelgauge.RestrictedAppDetails com.android.settings.datetime.timezone.TimeZoneSettings +com.android.settings.inputmethod.InputMethodAndSubtypeEnabler diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable index 8523b2f1ab9..a72cd500df6 100644 --- a/tests/robotests/assets/grandfather_not_implementing_indexable +++ b/tests/robotests/assets/grandfather_not_implementing_indexable @@ -28,7 +28,6 @@ com.android.settings.accessibility.ToggleScreenReaderPreferenceFragmentForSetupW com.android.settings.accessibility.ToggleSelectToSpeakPreferenceFragmentForSetupWizard com.android.settings.accounts.AccountSyncSettings com.android.settings.notification.RedactionInterstitial$RedactionInterstitialFragment -com.android.settings.inputmethod.InputMethodAndSubtypeEnabler com.android.settings.applications.appinfo.DrawOverlayDetails com.android.settings.backup.ToggleBackupSettingFragment com.android.settings.users.UserDetailsSettings diff --git a/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnablerTest.java b/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnablerTest.java new file mode 100644 index 00000000000..ffb726ae4c4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypeEnablerTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.inputmethod; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; + +@RunWith(SettingsRobolectricTestRunner.class) +public class InputMethodAndSubtypeEnablerTest { + + private Activity mActivity; + private InputMethodAndSubtypeEnabler mFragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mActivity = Robolectric.setupActivity(Activity.class); + mFragment = spy(new InputMethodAndSubtypeEnabler()); + when(mFragment.getActivity()).thenReturn(mActivity); + } + + @Test + public void onActivityCreated_shouldUpdateTitleFromArgument() { + final String test = "title1"; + final Bundle args = new Bundle(); + args.putString(Intent.EXTRA_TITLE, test); + mFragment.setArguments(args); + + mFragment.onActivityCreated(null); + + assertThat(mFragment.getActivity().getTitle()).isEqualTo(test); + } + + @Test + public void onActivityCreated_shouldUpdateTitleFromIntent() { + final String test = "title1"; + final Intent intent = new Intent(); + intent.putExtra(Intent.EXTRA_TITLE, test); + mActivity.setIntent(intent); + + mFragment.onActivityCreated(null); + + assertThat(mFragment.getActivity().getTitle()).isEqualTo(test); + } + + @Test + public void getPreferenceScreenResId_shouldReturnXml() { + assertThat(mFragment.getPreferenceScreenResId()).isEqualTo(R.xml.input_methods_subtype); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypePreferenceControllerTest.java new file mode 100644 index 00000000000..7e977787cf3 --- /dev/null +++ b/tests/robotests/src/com/android/settings/inputmethod/InputMethodAndSubtypePreferenceControllerTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.inputmethod; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowInputMethodManagerWithMethodList; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.List; + +import androidx.preference.PreferenceFragment; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = ShadowInputMethodManagerWithMethodList.class) +public class InputMethodAndSubtypePreferenceControllerTest { + + @Mock + private PreferenceFragment mFragment; + private Context mContext; + private InputMethodAndSubtypePreferenceController mController; + private PreferenceManager mPreferenceManager; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mPreferenceManager = new PreferenceManager(mContext); + when(mFragment.getContext()).thenReturn(mContext); + when(mFragment.getResources()).thenReturn(mContext.getResources()); + when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager); + mController = new InputMethodAndSubtypePreferenceController(mContext, "pref_key"); + mController.initialize(mFragment, ""); + } + + @Test + public void isAlwaysAvailable() { + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.AVAILABLE); + } + + @Test + public void displayPreference_hasInputMethodSubType_shouldAddPreference() { + final PreferenceManager preferenceManager = new PreferenceManager(mContext); + final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext); + + mController.displayPreference(screen); + + assertThat(screen.getPreferenceCount()).isEqualTo(0); + + final List imis = new ArrayList<>(); + imis.add(createInputMethodInfo("test", mContext)); + ShadowInputMethodManagerWithMethodList.getShadow().setInputMethodList(imis); + + mController.initialize(mFragment, ""); + mController.displayPreference(screen); + + assertThat(screen.getPreferenceCount()).isEqualTo(2); + } + + private InputMethodInfo createInputMethodInfo(final String name, Context targetContext) { + List subtypes = new ArrayList<>(); + + subtypes.add(new InputMethodSubtype.InputMethodSubtypeBuilder() + .build()); + subtypes.add(new InputMethodSubtype.InputMethodSubtypeBuilder() + .build()); + + final ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.serviceInfo = new ServiceInfo(); + resolveInfo.serviceInfo.packageName = "com.android.ime"; + resolveInfo.serviceInfo.name = name; + resolveInfo.serviceInfo.applicationInfo = new ApplicationInfo(); + resolveInfo.serviceInfo.applicationInfo.enabled = true; + + return new InputMethodInfo( + resolveInfo, + false /* isAuxIme */, + "SettingsActivity", + subtypes, + 0 /* isDefaultResId */, + true /* forceDefault */); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputMethodManagerWithMethodList.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputMethodManagerWithMethodList.java index 0e59fec30ce..0b7d69ba3a6 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputMethodManagerWithMethodList.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInputMethodManagerWithMethodList.java @@ -19,8 +19,10 @@ package com.android.settings.testutils.shadow; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowInputMethodManager; import java.util.Collections; @@ -48,4 +50,9 @@ public class ShadowInputMethodManagerWithMethodList extends ShadowInputMethodMan public void setInputMethodList(List inputMethodInfos) { mInputMethodInfos = inputMethodInfos; } + + public static ShadowInputMethodManagerWithMethodList getShadow() { + return (ShadowInputMethodManagerWithMethodList) Shadow.extract( + RuntimeEnvironment.application.getSystemService(InputMethodManager.class)); + } }