Open the settings page for a specific physical keyboard

1. Check open from a notification
2. Check open from Bluetooth entry
3. If the inputDeviceIdentifier is not null, open the next page
   directly.
4. Add extra to record the class of sender for the future metrics.

Demo: http://screencast/cast/NDU4MTYxOTIzMTg4MzI2NHxiYTQ0ODE5Ny02YQ

Bug: 269212353
Test: manual, atest
[Pass] atest KeyboardSettingsPreferenceControllerTest
[Pass] atest PhysicalKeyboardPreferenceControllerTest

Change-Id: Ie874003260896bbb949806623913e70486e4731d
This commit is contained in:
danielwbhuang
2023-03-24 19:11:53 +08:00
committed by Daniel Huang
parent 9a40a296cc
commit cc749159df
9 changed files with 99 additions and 42 deletions

View File

@@ -30,8 +30,7 @@
<Preference <Preference
android:key="physical_keyboard_pref" android:key="physical_keyboard_pref"
android:title="@string/physical_keyboard_title" android:title="@string/physical_keyboard_title"
android:summary="@string/summary_placeholder" android:summary="@string/summary_placeholder"/>
android:fragment="com.android.settings.inputmethod.PhysicalKeyboardFragment"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory

View File

@@ -175,7 +175,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
} }
use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice); use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager); use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager);
use(KeyboardSettingsPreferenceController.class).init(mCachedDevice, getActivity()); use(KeyboardSettingsPreferenceController.class).init(mCachedDevice);
final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory( final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
context).getBluetoothFeatureProvider(); context).getBluetoothFeatureProvider();

View File

@@ -16,16 +16,15 @@
package com.android.settings.inputmethod; package com.android.settings.inputmethod;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.provider.Settings; import android.provider.Settings;
import android.util.FeatureFlagUtils; import android.util.FeatureFlagUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference; import androidx.preference.Preference;
import com.android.settings.Settings.PhysicalKeyboardActivity;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo; import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -34,18 +33,14 @@ import java.util.List;
public class KeyboardSettingsPreferenceController extends BasePreferenceController { public class KeyboardSettingsPreferenceController extends BasePreferenceController {
private Context mContext;
private CachedBluetoothDevice mCachedDevice; private CachedBluetoothDevice mCachedDevice;
private Activity mActivity;
public KeyboardSettingsPreferenceController(Context context, String key) { public KeyboardSettingsPreferenceController(Context context, String key) {
super(context, key); super(context, key);
mContext = context;
} }
public void init(@NonNull CachedBluetoothDevice cachedDevice, @NonNull Activity activity) { public void init(@NonNull CachedBluetoothDevice cachedDevice) {
mCachedDevice = cachedDevice; mCachedDevice = cachedDevice;
mActivity = activity;
} }
@Override @Override
@@ -53,18 +48,26 @@ public class KeyboardSettingsPreferenceController extends BasePreferenceControll
if (!getPreferenceKey().equals(preference.getKey())) { if (!getPreferenceKey().equals(preference.getKey())) {
return false; return false;
} }
List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboardList();
final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS); for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
intent.setClass(mContext, PhysicalKeyboardActivity.class); if (mCachedDevice.getAddress().equals(hardKeyboardDeviceInfo.mBluetoothAddress)) {
intent.putExtra(PhysicalKeyboardFragment.EXTRA_BT_ADDRESS, mCachedDevice.getAddress()); Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
mActivity.startActivityForResult(intent, 0); intent.putExtra(
NewKeyboardSettingsUtils.EXTRA_INTENT_FROM,
"com.android.settings.inputmethod.KeyboardSettingsPreferenceController");
intent.putExtra(
Settings.EXTRA_INPUT_DEVICE_IDENTIFIER,
hardKeyboardDeviceInfo.mDeviceIdentifier);
mContext.startActivity(intent);
break;
}
}
return true; return true;
} }
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
final List<HardKeyboardDeviceInfo> newHardKeyboards = List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboardList();
PhysicalKeyboardFragment.getHardKeyboards(mContext);
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI) if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI)
&& !newHardKeyboards.isEmpty()) { && !newHardKeyboards.isEmpty()) {
for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) { for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
@@ -78,4 +81,9 @@ public class KeyboardSettingsPreferenceController extends BasePreferenceControll
} }
return CONDITIONALLY_UNAVAILABLE; return CONDITIONALLY_UNAVAILABLE;
} }
@VisibleForTesting
List<HardKeyboardDeviceInfo> getHardKeyboardList() {
return PhysicalKeyboardFragment.getHardKeyboards(mContext);
}
} }

View File

@@ -23,6 +23,7 @@ import android.hardware.input.InputManager;
import android.hardware.input.KeyboardLayout; import android.hardware.input.KeyboardLayout;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle; import android.os.UserHandle;
import android.util.Log;
import android.view.InputDevice; import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
@@ -59,10 +60,19 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment
public void onActivityCreated(final Bundle icicle) { public void onActivityCreated(final Bundle icicle) {
super.onActivityCreated(icicle); super.onActivityCreated(icicle);
Bundle arguments = getArguments(); Bundle arguments = getArguments();
final String title =
arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_DEVICE_NAME);
mInputDeviceIdentifier = mInputDeviceIdentifier =
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER); arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER);
if (mInputDeviceIdentifier == null) {
Log.e(TAG, "The inputDeviceIdentifier should not be null");
return;
}
InputDevice inputDevice =
NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier);
if (inputDevice == null) {
Log.e(TAG, "inputDevice is null");
return;
}
final String title = inputDevice.getName();
getActivity().setTitle(title); getActivity().setTitle(title);
updateCheckedState(); updateCheckedState();
} }

View File

@@ -47,6 +47,7 @@ public class NewKeyboardLayoutPickerContent extends DashboardFragment {
arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE); arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE);
if (identifier == null if (identifier == null
|| NewKeyboardSettingsUtils.getInputDevice(inputManager, identifier) == null) { || NewKeyboardSettingsUtils.getInputDevice(inputManager, identifier) == null) {
getActivity().finish();
return; return;
} }
getActivity().setTitle(title); getActivity().setTitle(title);

View File

@@ -32,7 +32,12 @@ import java.util.List;
*/ */
public class NewKeyboardSettingsUtils { public class NewKeyboardSettingsUtils {
static final String EXTRA_KEYBOARD_DEVICE_NAME = "extra_keyboard_device_name"; /**
* Record the class name of the intent sender for metrics.
*/
public static final String EXTRA_INTENT_FROM =
"com.android.settings.inputmethod.EXTRA_INTENT_FROM";
static final String EXTRA_TITLE = "keyboard_layout_picker_title"; static final String EXTRA_TITLE = "keyboard_layout_picker_title";
static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout"; static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout";
static final String EXTRA_USER_ID = "user_id"; static final String EXTRA_USER_ID = "user_id";

View File

@@ -87,7 +87,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
@Override @Override
public void onCreatePreferences(Bundle bundle, String s) { public void onCreatePreferences(Bundle bundle, String s) {
Activity activity = Preconditions.checkNotNull(getActivity()); Activity activity = Preconditions.checkNotNull(getActivity());
mBluetoothAddress = activity.getIntent().getStringExtra(EXTRA_BT_ADDRESS);
addPreferencesFromResource(R.xml.physical_keyboard_settings); addPreferencesFromResource(R.xml.physical_keyboard_settings);
mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class)); mIm = Preconditions.checkNotNull(activity.getSystemService(InputManager.class));
mImm = Preconditions.checkNotNull(activity.getSystemService(InputMethodManager.class)); mImm = Preconditions.checkNotNull(activity.getSystemService(InputMethodManager.class));
@@ -104,6 +103,19 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
if (!isModifierKeySettingsEnabled) { if (!isModifierKeySettingsEnabled) {
mKeyboardAssistanceCategory.removePreference(findPreference(MODIFIER_KEYS_SETTINGS)); mKeyboardAssistanceCategory.removePreference(findPreference(MODIFIER_KEYS_SETTINGS));
} }
InputDeviceIdentifier inputDeviceIdentifier = activity.getIntent().getParcelableExtra(
KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER);
// TODO (b/271391879): The EXTRA_INTENT_FROM is used for the future metrics.
if (inputDeviceIdentifier != null) {
Bundle arguments = new Bundle();
arguments.putParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER,
inputDeviceIdentifier);
new SubSettingLauncher(getContext())
.setSourceMetricsCategory(getMetricsCategory())
.setDestination(NewKeyboardLayoutEnabledLocalesFragment.class.getName())
.setArguments(arguments)
.launch();
}
} }
@Override @Override
@@ -187,14 +199,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
preferenceScreen.addPreference(category); preferenceScreen.addPreference(category);
for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) { for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
// if user go into this page from Connected devices entry, we should distinguish the
// user-selected keyboard from all enabled keyboards.
if (mBluetoothAddress != null
&& !mBluetoothAddress.equals(hardKeyboardDeviceInfo.mBluetoothAddress)) {
continue;
}
// TODO(yukawa): Consider using com.android.settings.widget.GearPreference // TODO(yukawa): Consider using com.android.settings.widget.GearPreference
final Preference pref = new Preference(getPrefContext()); final Preference pref = new Preference(getPrefContext());
pref.setTitle(hardKeyboardDeviceInfo.mDeviceName); pref.setTitle(hardKeyboardDeviceInfo.mDeviceName);
@@ -247,7 +251,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
Bundle arguments = new Bundle(); Bundle arguments = new Bundle();
arguments.putParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER, arguments.putParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER,
inputDeviceIdentifier); inputDeviceIdentifier);
arguments.putString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_DEVICE_NAME, keyboardName);
new SubSettingLauncher(getContext()) new SubSettingLauncher(getContext())
.setSourceMetricsCategory(getMetricsCategory()) .setSourceMetricsCategory(getMetricsCategory())
.setDestination(NewKeyboardLayoutEnabledLocalesFragment.class.getName()) .setDestination(NewKeyboardLayoutEnabledLocalesFragment.class.getName())

View File

@@ -17,8 +17,10 @@
package com.android.settings.inputmethod; package com.android.settings.inputmethod;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.icu.text.ListFormatter; import android.icu.text.ListFormatter;
import android.provider.Settings;
import androidx.preference.Preference; import androidx.preference.Preference;
@@ -58,6 +60,19 @@ public class PhysicalKeyboardPreferenceController extends AbstractPreferenceCont
&& mContext.getResources().getBoolean(R.bool.config_show_physical_keyboard_pref); && mContext.getResources().getBoolean(R.bool.config_show_physical_keyboard_pref);
} }
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (!getPreferenceKey().equals(preference.getKey())) {
return false;
}
Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
intent.putExtra(
NewKeyboardSettingsUtils.EXTRA_INTENT_FROM,
"com.android.settings.inputmethod.PhysicalKeyboardPreferenceController");
mContext.startActivity(intent);
return true;
}
@Override @Override
public void updateState(Preference preference) { public void updateState(Preference preference) {
mPreference = preference; mPreference = preference;

View File

@@ -18,18 +18,21 @@ package com.android.settings.inputmethod;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.hardware.input.InputDeviceIdentifier;
import android.provider.Settings; import android.provider.Settings;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.settings.inputmethod.PhysicalKeyboardFragment.HardKeyboardDeviceInfo;
import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import org.junit.Before; import org.junit.Before;
@@ -37,12 +40,14 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule; import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList;
import java.util.List;
/** Tests for {@link KeyboardSettingsPreferenceController} */ /** Tests for {@link KeyboardSettingsPreferenceController} */
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class KeyboardSettingsPreferenceControllerTest { public class KeyboardSettingsPreferenceControllerTest {
@@ -52,32 +57,43 @@ public class KeyboardSettingsPreferenceControllerTest {
private static final String PREFERENCE_KEY = "keyboard_settings"; private static final String PREFERENCE_KEY = "keyboard_settings";
@Mock
private Activity mActivity;
@Mock @Mock
private CachedBluetoothDevice mCachedBluetoothDevice; private CachedBluetoothDevice mCachedBluetoothDevice;
@Captor @Mock
private ArgumentCaptor<Intent> mIntentArgumentCaptor; private InputDeviceIdentifier mInputDeviceIdentifier;
private Context mContext; private Context mContext;
private KeyboardSettingsPreferenceController mController; private KeyboardSettingsPreferenceController mController;
@Before @Before
public void setUp() { public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext()); mContext = spy(ApplicationProvider.getApplicationContext());
mController = new KeyboardSettingsPreferenceController(mContext, PREFERENCE_KEY); doNothing().when(mContext).startActivity(any());
mController.init(mCachedBluetoothDevice, mActivity); mController = spy(new KeyboardSettingsPreferenceController(mContext, PREFERENCE_KEY));
mController.init(mCachedBluetoothDevice);
} }
@Test @Test
public void handlePreferenceTreeClick_expected() { public void handlePreferenceTreeClick_expected() {
Preference mKeyboardPreference = new Preference(mContext); Preference mKeyboardPreference = new Preference(mContext);
mKeyboardPreference.setKey(PREFERENCE_KEY); mKeyboardPreference.setKey(PREFERENCE_KEY);
final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
String address = "BT_ADDRESS";
HardKeyboardDeviceInfo deviceInfo =
new HardKeyboardDeviceInfo(
"TEST_DEVICE",
mInputDeviceIdentifier,
"TEST_DEVICE_LABEL",
address);
List<HardKeyboardDeviceInfo> keyboards = new ArrayList<>();
keyboards.add(deviceInfo);
when(mController.getHardKeyboardList()).thenReturn(keyboards);
when(mCachedBluetoothDevice.getAddress()).thenReturn(address);
mController.handlePreferenceTreeClick(mKeyboardPreference); mController.handlePreferenceTreeClick(mKeyboardPreference);
verify(mActivity).startActivityForResult(mIntentArgumentCaptor.capture(), eq(0)); verify(mContext).startActivity(captor.capture());
Intent expectedIntent = mIntentArgumentCaptor.getValue(); assertThat(captor.getValue().getAction()).isEqualTo(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
assertThat(expectedIntent.getAction()).isEqualTo(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
} }
@Test @Test