From 7129b374bb57e39ac94ffd5b27dc3acc79fb1fb9 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Thu, 8 Mar 2018 13:47:56 -0800 Subject: [PATCH 1/2] Reenable pre-N style hard keyboard layout settings This CL logically reverts Settings app changes for Bug 25752812, which aimed to improve UX by tightly integrating physical keyboard layout with input method subtype. What went wrong is that the concept of input method subtype is not widely accepted by the ecosystem actually. Until we figoure out any other better way here, let's revert back to the good old way that enables users to specify multiple keyboard layouts per physical keyboard device, not one layout per one input method subtype. Note that we cannot simply revert the CL that originally introduced the new flow [1] because it was indeed a huge CL that also touched IME settings, which we want to continue using. In that sense, this CL is a kind of re-implementation of the previous style on top of the recent language settings flow. Note also that a fix [2] fox Bug 25062009 was also ported from previous InputMethodAndLanguageSetting to KeyboardLayoutPickerFragment. [1]: I728d7ee185827ed328c16cb7abce244557a26518 976bb3f45915bdd5165d9a50402d4c1163dae809 [2]: I4483dfc89afc8d148b2cfa7c6a5f66d2a02f712a 17b631988451613393c4656900c1821e23d8434a Fix: 66498367 Test: make -j RunSettingsRoboTests Test: Manually done with two Bluetooth keyboards Change-Id: I7a2ed6dd39dcd8207d3d94e12cd01d5d67ba4bb5 --- res/values/strings.xml | 4 - .../KeyboardLayoutPickerFragment.java | 88 ++-- .../inputmethod/PhysicalKeyboardFragment.java | 434 +++++------------- .../PhysicalKeyboardPreferenceController.java | 2 +- ...sicalKeyboardPreferenceControllerTest.java | 2 +- 5 files changed, 167 insertions(+), 363 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 39f641c4e47..0919d1af57c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4177,10 +4177,6 @@ Keyboard shortcuts helper Display available shortcuts - - %1$s - %2$s Default diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java index 80d353181ba..4c9715ca467 100644 --- a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java +++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment.java @@ -16,43 +16,31 @@ package com.android.settings.inputmethod; -import android.annotation.Nullable; -import android.app.Activity; +import android.content.Context; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; import android.hardware.input.InputManager.InputDeviceListener; import android.hardware.input.KeyboardLayout; import android.os.Bundle; +import android.support.v7.preference.CheckBoxPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.view.InputDevice; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodSubtype; -import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.util.Preconditions; -import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.inputmethod.PhysicalKeyboardFragment.KeyboardInfoPreference; import java.util.Arrays; import java.util.HashMap; import java.util.Map; -public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragment +public class KeyboardLayoutPickerFragment extends SettingsPreferenceFragment implements InputDeviceListener { - private InputDeviceIdentifier mInputDeviceIdentifier; private int mInputDeviceId = -1; private InputManager mIm; - private InputMethodInfo mImi; - @Nullable - private InputMethodSubtype mSubtype; private KeyboardLayout[] mKeyboardLayouts; - private Map mPreferenceMap = new HashMap<>(); - - // TODO: Make these constants public API for b/25752827 + private HashMap mPreferenceMap = new HashMap<>(); /** * Intent extra: The input device descriptor of the keyboard whose keyboard @@ -60,16 +48,6 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme */ public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier"; - /** - * Intent extra: The associated {@link InputMethodInfo}. - */ - public static final String EXTRA_INPUT_METHOD_INFO = "input_method_info"; - - /** - * Intent extra: The associated {@link InputMethodSubtype}. - */ - public static final String EXTRA_INPUT_METHOD_SUBTYPE = "input_method_subtype"; - @Override public int getMetricsCategory() { return MetricsEvent.INPUTMETHOD_KEYBOARD; @@ -78,18 +56,14 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - Activity activity = Preconditions.checkNotNull(getActivity()); - mInputDeviceIdentifier = activity.getIntent().getParcelableExtra( + mInputDeviceIdentifier = getActivity().getIntent().getParcelableExtra( EXTRA_INPUT_DEVICE_IDENTIFIER); - mImi = activity.getIntent().getParcelableExtra(EXTRA_INPUT_METHOD_INFO); - mSubtype = activity.getIntent().getParcelableExtra(EXTRA_INPUT_METHOD_SUBTYPE); - - if (mInputDeviceIdentifier == null || mImi == null) { - activity.finish(); + if (mInputDeviceIdentifier == null) { + getActivity().finish(); } - mIm = activity.getSystemService(InputManager.class); + mIm = (InputManager) getSystemService(Context.INPUT_SERVICE); mKeyboardLayouts = mIm.getKeyboardLayoutsForInputDevice(mInputDeviceIdentifier); Arrays.sort(mKeyboardLayouts); setPreferenceScreen(createPreferenceHierarchy()); @@ -108,6 +82,8 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme return; } mInputDeviceId = inputDevice.getId(); + + updateCheckedState(); } @Override @@ -120,21 +96,34 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme @Override public boolean onPreferenceTreeClick(Preference preference) { - KeyboardLayout layout = mPreferenceMap.get(preference); - if (layout != null) { - mIm.setKeyboardLayoutForInputDevice(mInputDeviceIdentifier, mImi, mSubtype, - layout.getDescriptor()); - getActivity().finish(); - return true; + if (preference instanceof CheckBoxPreference) { + CheckBoxPreference checkboxPref = (CheckBoxPreference)preference; + KeyboardLayout layout = mPreferenceMap.get(checkboxPref); + if (layout != null) { + boolean checked = checkboxPref.isChecked(); + if (checked) { + mIm.addKeyboardLayoutForInputDevice(mInputDeviceIdentifier, + layout.getDescriptor()); + } else { + mIm.removeKeyboardLayoutForInputDevice(mInputDeviceIdentifier, + layout.getDescriptor()); + } + return true; + } } return super.onPreferenceTreeClick(preference); } @Override - public void onInputDeviceAdded(int deviceId) {} + public void onInputDeviceAdded(int deviceId) { + } @Override - public void onInputDeviceChanged(int deviceId) {} + public void onInputDeviceChanged(int deviceId) { + if (mInputDeviceId >= 0 && deviceId == mInputDeviceId) { + updateCheckedState(); + } + } @Override public void onInputDeviceRemoved(int deviceId) { @@ -147,14 +136,23 @@ public final class KeyboardLayoutPickerFragment extends SettingsPreferenceFragme PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity()); for (KeyboardLayout layout : mKeyboardLayouts) { - Preference pref = new Preference(getPrefContext()); + CheckBoxPreference pref = new CheckBoxPreference(getPrefContext()); pref.setTitle(layout.getLabel()); pref.setSummary(layout.getCollection()); root.addPreference(pref); mPreferenceMap.put(pref, layout); } - - root.setTitle(KeyboardInfoPreference.getDisplayName(getContext(), mImi, mSubtype)); return root; } + + private void updateCheckedState() { + String[] enabledKeyboardLayouts = mIm.getEnabledKeyboardLayoutsForInputDevice( + mInputDeviceIdentifier); + Arrays.sort(enabledKeyboardLayouts); + + for (Map.Entry entry : mPreferenceMap.entrySet()) { + entry.getKey().setChecked(Arrays.binarySearch(enabledKeyboardLayouts, + entry.getValue().getDescriptor()) >= 0); + } + } } diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java index 83d501d0a35..a02a6d035c3 100644 --- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java @@ -19,11 +19,8 @@ package com.android.settings.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; -import android.app.LoaderManager; -import android.content.AsyncTaskLoader; import android.content.Context; import android.content.Intent; -import android.content.Loader; import android.database.ContentObserver; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; @@ -40,9 +37,6 @@ import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceScreen; import android.text.TextUtils; import android.view.InputDevice; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; import com.android.internal.inputmethod.InputMethodUtils; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -52,33 +46,25 @@ import com.android.settings.Settings; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; -import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; +import com.android.settingslib.utils.ThreadUtils; import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Objects; public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment - implements InputManager.InputDeviceListener, Indexable { + implements InputManager.InputDeviceListener, + KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener, Indexable { private static final String KEYBOARD_ASSISTANCE_CATEGORY = "keyboard_assistance_category"; private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch"; private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper"; - private static final String IM_SUBTYPE_MODE_KEYBOARD = "keyboard"; @NonNull - private final List mLastHardKeyboards = new ArrayList<>(); - @NonNull - private final List mTempKeyboardInfoList = new ArrayList<>(); - - @NonNull - private final HashSet mLoaderIDs = new HashSet<>(); - private int mNextLoaderId = 0; + private final ArrayList mLastHardKeyboards = new ArrayList<>(); private InputManager mIm; @NonNull @@ -88,6 +74,8 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment @NonNull private InputMethodUtils.InputMethodSettings mSettings; + private Intent mIntentWaitingForResult; + @Override public void onCreatePreferences(Bundle bundle, String s) { Activity activity = Preconditions.checkNotNull(getActivity()); @@ -118,9 +106,8 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment @Override public void onResume() { super.onResume(); - clearLoader(); mLastHardKeyboards.clear(); - updateHardKeyboards(); + scheduleUpdateHardKeyboards(); mIm.registerInputDeviceListener(this, null); mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener( mShowVirtualKeyboardSwitchPreferenceChangeListener); @@ -130,67 +117,25 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment @Override public void onPause() { super.onPause(); - clearLoader(); mLastHardKeyboards.clear(); mIm.unregisterInputDeviceListener(this); mShowVirtualKeyboardSwitch.setOnPreferenceChangeListener(null); unregisterShowVirtualKeyboardSettingsObserver(); } - private void onLoadFinishedInternal( - final int loaderId, @NonNull final List keyboardsList) { - if (!mLoaderIDs.remove(loaderId)) { - // Already destroyed loader. Ignore. - return; - } - - Collections.sort(keyboardsList); - final PreferenceScreen preferenceScreen = getPreferenceScreen(); - preferenceScreen.removeAll(); - for (Keyboards keyboards : keyboardsList) { - final PreferenceCategory category = new PreferenceCategory(getPrefContext(), null); - category.setTitle(keyboards.mDeviceInfo.mDeviceName); - category.setOrder(0); - preferenceScreen.addPreference(category); - for (Keyboards.KeyboardInfo info : keyboards.mKeyboardInfoList) { - mTempKeyboardInfoList.clear(); - final InputMethodInfo imi = info.mImi; - final InputMethodSubtype imSubtype = info.mImSubtype; - if (imi != null) { - KeyboardInfoPreference pref = - new KeyboardInfoPreference(getPrefContext(), info); - pref.setOnPreferenceClickListener(preference -> { - showKeyboardLayoutScreen( - keyboards.mDeviceInfo.mDeviceIdentifier, imi, imSubtype); - return true; - }); - mTempKeyboardInfoList.add(pref); - Collections.sort(mTempKeyboardInfoList); - } - for (KeyboardInfoPreference pref : mTempKeyboardInfoList) { - category.addPreference(pref); - } - } - } - mTempKeyboardInfoList.clear(); - mKeyboardAssistanceCategory.setOrder(1); - preferenceScreen.addPreference(mKeyboardAssistanceCategory); - updateShowVirtualKeyboardSwitch(); - } - @Override public void onInputDeviceAdded(int deviceId) { - updateHardKeyboards(); + scheduleUpdateHardKeyboards(); } @Override public void onInputDeviceRemoved(int deviceId) { - updateHardKeyboards(); + scheduleUpdateHardKeyboards(); } @Override public void onInputDeviceChanged(int deviceId) { - updateHardKeyboards(); + scheduleUpdateHardKeyboards(); } @Override @@ -198,50 +143,57 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment return MetricsEvent.PHYSICAL_KEYBOARDS; } - @NonNull - public static List getHardKeyboards() { - final List keyboards = new ArrayList<>(); - final int[] devicesIds = InputDevice.getDeviceIds(); - for (int deviceId : devicesIds) { - final InputDevice device = InputDevice.getDevice(deviceId); - if (device != null && !device.isVirtual() && device.isFullKeyboard()) { - keyboards.add(new HardKeyboardDeviceInfo(device.getName(), device.getIdentifier())); - } - } - return keyboards; + private void scheduleUpdateHardKeyboards() { + final Context context = getContext(); + ThreadUtils.postOnBackgroundThread(() -> { + final List newHardKeyboards = getHardKeyboards(context); + ThreadUtils.postOnMainThread(() -> updateHardKeyboards(newHardKeyboards)); + }); } - private void updateHardKeyboards() { - final List newHardKeyboards = getHardKeyboards(); - if (!Objects.equals(newHardKeyboards, mLastHardKeyboards)) { - clearLoader(); - mLastHardKeyboards.clear(); - mLastHardKeyboards.addAll(newHardKeyboards); - mLoaderIDs.add(mNextLoaderId); - getLoaderManager().initLoader(mNextLoaderId, null, - new Callbacks(getContext(), this, mLastHardKeyboards)); - ++mNextLoaderId; + private void updateHardKeyboards(@NonNull List newHardKeyboards) { + if (Objects.equals(mLastHardKeyboards, newHardKeyboards)) { + // Nothing has changed. Ignore. + return; } + + // TODO(yukawa): Maybe we should follow the style used in ConnectedDeviceDashboardFragment. + + mLastHardKeyboards.clear(); + mLastHardKeyboards.addAll(newHardKeyboards); + + final PreferenceScreen preferenceScreen = getPreferenceScreen(); + preferenceScreen.removeAll(); + final PreferenceCategory category = new PreferenceCategory(getPrefContext()); + category.setTitle(R.string.builtin_keyboard_settings_title); + category.setOrder(0); + preferenceScreen.addPreference(category); + + for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) { + // TODO(yukawa): Consider using com.android.settings.widget.GearPreference + final Preference pref = new Preference(getPrefContext()); + pref.setTitle(hardKeyboardDeviceInfo.mDeviceName); + pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel); + pref.setOnPreferenceClickListener(preference -> { + showKeyboardLayoutDialog(hardKeyboardDeviceInfo.mDeviceIdentifier); + return true; + }); + category.addPreference(pref); + } + + mKeyboardAssistanceCategory.setOrder(1); + preferenceScreen.addPreference(mKeyboardAssistanceCategory); + updateShowVirtualKeyboardSwitch(); } - private void showKeyboardLayoutScreen( - @NonNull InputDeviceIdentifier inputDeviceIdentifier, - @NonNull InputMethodInfo imi, - @Nullable InputMethodSubtype imSubtype) { - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class); - intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER, - inputDeviceIdentifier); - intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_METHOD_INFO, imi); - intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_METHOD_SUBTYPE, imSubtype); - startActivity(intent); - } - - private void clearLoader() { - for (final int loaderId : mLoaderIDs) { - getLoaderManager().destroyLoader(loaderId); + private void showKeyboardLayoutDialog(InputDeviceIdentifier inputDeviceIdentifier) { + KeyboardLayoutDialogFragment fragment = (KeyboardLayoutDialogFragment) + getFragmentManager().findFragmentByTag("keyboardLayout"); + if (fragment == null) { + fragment = new KeyboardLayoutDialogFragment(inputDeviceIdentifier); + fragment.setTargetFragment(this, 0); + fragment.show(getActivity().getFragmentManager(), "keyboardLayout"); } - mLoaderIDs.clear(); } private void registerShowVirtualKeyboardSettingsObserver() { @@ -282,102 +234,75 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment } }; - private static final class Callbacks implements LoaderManager.LoaderCallbacks> { - @NonNull - final Context mContext; - @NonNull - final PhysicalKeyboardFragment mPhysicalKeyboardFragment; - @NonNull - final List mHardKeyboards; + @Override + public void onSetupKeyboardLayouts(InputDeviceIdentifier inputDeviceIdentifier) { + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class); + intent.putExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER, + inputDeviceIdentifier); + mIntentWaitingForResult = intent; + startActivityForResult(intent, 0); + } - public Callbacks( - @NonNull Context context, - @NonNull PhysicalKeyboardFragment physicalKeyboardFragment, - @NonNull List hardKeyboards) { - mContext = context; - mPhysicalKeyboardFragment = physicalKeyboardFragment; - mHardKeyboards = hardKeyboards; - } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); - @Override - public Loader> onCreateLoader(int id, Bundle args) { - return new KeyboardLayoutLoader(mContext, mHardKeyboards); - } - - @Override - public void onLoadFinished(Loader> loader, List data) { - mPhysicalKeyboardFragment.onLoadFinishedInternal(loader.getId(), data); - } - - @Override - public void onLoaderReset(Loader> loader) { + if (mIntentWaitingForResult != null) { + InputDeviceIdentifier inputDeviceIdentifier = mIntentWaitingForResult + .getParcelableExtra(KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER); + mIntentWaitingForResult = null; + showKeyboardLayoutDialog(inputDeviceIdentifier); } } - private static final class KeyboardLayoutLoader extends AsyncTaskLoader> { - @NonNull - private final List mHardKeyboards; - - public KeyboardLayoutLoader( - @NonNull Context context, - @NonNull List hardKeyboards) { - super(context); - mHardKeyboards = Preconditions.checkNotNull(hardKeyboards); + private static String getLayoutLabel(@NonNull InputDevice device, + @NonNull Context context, @NonNull InputManager im) { + final String currentLayoutDesc = + im.getCurrentKeyboardLayoutForInputDevice(device.getIdentifier()); + if (currentLayoutDesc == null) { + return context.getString(R.string.keyboard_layout_default_label); } + final KeyboardLayout currentLayout = im.getKeyboardLayout(currentLayoutDesc); + if (currentLayout == null) { + return context.getString(R.string.keyboard_layout_default_label); + } + // If current layout is specified but the layout is null, just return an empty string + // instead of falling back to R.string.keyboard_layout_default_label. + return TextUtils.emptyIfNull(currentLayout.getLabel()); + } - private Keyboards loadInBackground(HardKeyboardDeviceInfo deviceInfo) { - final ArrayList keyboardInfoList = new ArrayList<>(); - final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); - final InputManager im = getContext().getSystemService(InputManager.class); - if (imm != null && im != null) { - for (InputMethodInfo imi : imm.getEnabledInputMethodList()) { - final List subtypes = imm.getEnabledInputMethodSubtypeList( - imi, true /* allowsImplicitlySelectedSubtypes */); - if (subtypes.isEmpty()) { - // Here we use null to indicate that this IME has no subtype. - final InputMethodSubtype nullSubtype = null; - final KeyboardLayout layout = im.getKeyboardLayoutForInputDevice( - deviceInfo.mDeviceIdentifier, imi, nullSubtype); - keyboardInfoList.add(new Keyboards.KeyboardInfo(imi, nullSubtype, layout)); - continue; - } - - // If the IME supports subtypes, we pick up "keyboard" subtypes only. - final int N = subtypes.size(); - for (int i = 0; i < N; ++i) { - final InputMethodSubtype subtype = subtypes.get(i); - if (!IM_SUBTYPE_MODE_KEYBOARD.equalsIgnoreCase(subtype.getMode())) { - continue; - } - final KeyboardLayout layout = im.getKeyboardLayoutForInputDevice( - deviceInfo.mDeviceIdentifier, imi, subtype); - keyboardInfoList.add(new Keyboards.KeyboardInfo(imi, subtype, layout)); - } - } + @NonNull + static List getHardKeyboards(@NonNull Context context) { + final List keyboards = new ArrayList<>(); + final InputManager im = context.getSystemService(InputManager.class); + if (im == null) { + return new ArrayList<>(); + } + for (int deviceId : InputDevice.getDeviceIds()) { + final InputDevice device = InputDevice.getDevice(deviceId); + if (device == null || device.isVirtual() || !device.isFullKeyboard()) { + continue; } - return new Keyboards(deviceInfo, keyboardInfoList); + keyboards.add(new HardKeyboardDeviceInfo( + device.getName(), device.getIdentifier(), getLayoutLabel(device, context, im))); } - @Override - public List loadInBackground() { - List keyboardsList = new ArrayList<>(mHardKeyboards.size()); - for (HardKeyboardDeviceInfo deviceInfo : mHardKeyboards) { - keyboardsList.add(loadInBackground(deviceInfo)); + // We intentionally don't reuse Comparator because Collator may not be thread-safe. + final Collator collator = Collator.getInstance(); + keyboards.sort((a, b) -> { + int result = collator.compare(a.mDeviceName, b.mDeviceName); + if (result != 0) { + return result; } - return keyboardsList; - } - - @Override - protected void onStartLoading() { - super.onStartLoading(); - forceLoad(); - } - - @Override - protected void onStopLoading() { - super.onStopLoading(); - cancelLoad(); - } + result = a.mDeviceIdentifier.getDescriptor().compareTo( + b.mDeviceIdentifier.getDescriptor()); + if (result != 0) { + return result; + } + return collator.compare(a.mLayoutLabel, b.mLayoutLabel); + }); + return keyboards; } public static final class HardKeyboardDeviceInfo { @@ -385,12 +310,16 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment public final String mDeviceName; @NonNull public final InputDeviceIdentifier mDeviceIdentifier; + @NonNull + public final String mLayoutLabel; public HardKeyboardDeviceInfo( - @Nullable final String deviceName, - @NonNull final InputDeviceIdentifier deviceIdentifier) { - mDeviceName = deviceName != null ? deviceName : ""; + @Nullable String deviceName, + @NonNull InputDeviceIdentifier deviceIdentifier, + @NonNull String layoutLabel) { + mDeviceName = TextUtils.emptyIfNull(deviceName); mDeviceIdentifier = deviceIdentifier; + mLayoutLabel = layoutLabel; } @Override @@ -404,14 +333,10 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment if (!TextUtils.equals(mDeviceName, that.mDeviceName)) { return false; } - if (mDeviceIdentifier.getVendorId() != that.mDeviceIdentifier.getVendorId()) { + if (!Objects.equals(mDeviceIdentifier, that.mDeviceIdentifier)) { return false; } - if (mDeviceIdentifier.getProductId() != that.mDeviceIdentifier.getProductId()) { - return false; - } - if (!TextUtils.equals(mDeviceIdentifier.getDescriptor(), - that.mDeviceIdentifier.getDescriptor())) { + if (!TextUtils.equals(mLayoutLabel, that.mLayoutLabel)) { return false; } @@ -419,121 +344,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment } } - public static final class Keyboards implements Comparable { - @NonNull - public final HardKeyboardDeviceInfo mDeviceInfo; - @NonNull - public final ArrayList mKeyboardInfoList; - @NonNull - public final Collator mCollator = Collator.getInstance(); - - public Keyboards( - @NonNull final HardKeyboardDeviceInfo deviceInfo, - @NonNull final ArrayList keyboardInfoList) { - mDeviceInfo = deviceInfo; - mKeyboardInfoList = keyboardInfoList; - } - - @Override - public int compareTo(@NonNull Keyboards another) { - return mCollator.compare(mDeviceInfo.mDeviceName, another.mDeviceInfo.mDeviceName); - } - - public static final class KeyboardInfo { - @NonNull - public final InputMethodInfo mImi; - @Nullable - public final InputMethodSubtype mImSubtype; - @NonNull - public final KeyboardLayout mLayout; - - public KeyboardInfo( - @NonNull final InputMethodInfo imi, - @Nullable final InputMethodSubtype imSubtype, - @NonNull final KeyboardLayout layout) { - mImi = imi; - mImSubtype = imSubtype; - mLayout = layout; - } - } - } - - static final class KeyboardInfoPreference extends Preference { - - @NonNull - private final CharSequence mImeName; - @Nullable - private final CharSequence mImSubtypeName; - @NonNull - private final Collator collator = Collator.getInstance(); - - private KeyboardInfoPreference( - @NonNull Context context, @NonNull Keyboards.KeyboardInfo info) { - super(context); - mImeName = info.mImi.loadLabel(context.getPackageManager()); - mImSubtypeName = getImSubtypeName(context, info.mImi, info.mImSubtype); - setTitle(formatDisplayName(context, mImeName, mImSubtypeName)); - if (info.mLayout != null) { - setSummary(info.mLayout.getLabel()); - } - } - - @NonNull - static CharSequence getDisplayName( - @NonNull Context context, @NonNull InputMethodInfo imi, - @Nullable InputMethodSubtype imSubtype) { - final CharSequence imeName = imi.loadLabel(context.getPackageManager()); - final CharSequence imSubtypeName = getImSubtypeName(context, imi, imSubtype); - return formatDisplayName(context, imeName, imSubtypeName); - } - - private static CharSequence formatDisplayName( - @NonNull Context context, - @NonNull CharSequence imeName, @Nullable CharSequence imSubtypeName) { - if (imSubtypeName == null) { - return imeName; - } - return String.format( - context.getString(R.string.physical_device_title), imeName, imSubtypeName); - } - - @Nullable - private static CharSequence getImSubtypeName( - @NonNull Context context, @NonNull InputMethodInfo imi, - @Nullable InputMethodSubtype imSubtype) { - if (imSubtype != null) { - return InputMethodAndSubtypeUtil.getSubtypeLocaleNameAsSentence( - imSubtype, context, imi); - } - return null; - } - - @Override - public int compareTo(@NonNull Preference object) { - if (!(object instanceof KeyboardInfoPreference)) { - return super.compareTo(object); - } - KeyboardInfoPreference another = (KeyboardInfoPreference) object; - int result = compare(mImeName, another.mImeName); - if (result == 0) { - result = compare(mImSubtypeName, another.mImSubtypeName); - } - return result; - } - - private int compare(@Nullable CharSequence lhs, @Nullable CharSequence rhs) { - if (!TextUtils.isEmpty(lhs) && !TextUtils.isEmpty(rhs)) { - return collator.compare(lhs.toString(), rhs.toString()); - } else if (TextUtils.isEmpty(lhs) && TextUtils.isEmpty(rhs)) { - return 0; - } else if (!TextUtils.isEmpty(lhs)) { - return -1; - } else { - return 1; - } - } - } - public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { @Override diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java b/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java index f80b68f3237..b9e95bee194 100644 --- a/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java +++ b/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceController.java @@ -94,7 +94,7 @@ public class PhysicalKeyboardPreferenceController extends AbstractPreferenceCont return; } final List keyboards = - PhysicalKeyboardFragment.getHardKeyboards(); + PhysicalKeyboardFragment.getHardKeyboards(mContext); if (keyboards.isEmpty()) { mPreference.setSummary(R.string.disconnected); return; diff --git a/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java index 13c99a63730..3c8f3c48851 100644 --- a/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/inputmethod/PhysicalKeyboardPreferenceControllerTest.java @@ -55,7 +55,7 @@ public class PhysicalKeyboardPreferenceControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - when(mContext.getSystemService(Context.INPUT_SERVICE)).thenReturn(mIm); + when(mContext.getSystemService(InputManager.class)).thenReturn(mIm); mController = new PhysicalKeyboardPreferenceController(mContext, null /* lifecycle */); } From a4a3dfffa20e317f4236349e4717f9da312b8ee1 Mon Sep 17 00:00:00 2001 From: Matthew Fritze Date: Wed, 28 Feb 2018 08:15:55 -0800 Subject: [PATCH 2/2] Declare official platform slice Create the notion of an official platform slice. This includes: - Adding a second authority to the provider - tagging slices in xml with a platform slice flag - Including authority in the getUri method Bug:73359139 Test: robotests Change-Id: I5382be138a262dbc5a8324c34aab131c5d0d5516 Merged-In: I581ee6dfcdf935f452a15e89e5d055e375ff1877 --- AndroidManifest.xml | 2 +- res/values/attrs.xml | 4 + res/xml/connected_devices_advanced.xml | 3 +- .../core/PreferenceXmlParserUtils.java | 90 ++++++++++++++++--- .../slices/SettingsSliceProvider.java | 15 ++-- .../slices/SliceBroadcastReceiver.java | 3 +- .../settings/slices/SliceBuilderUtils.java | 14 +++ .../android/settings/slices/SliceData.java | 14 +++ .../settings/slices/SliceDataConverter.java | 6 +- .../res/xml-mcc999/location_settings.xml | 3 +- .../slices/SettingsSliceProviderTest.java | 31 ++----- .../slices/SliceBuilderUtilsTest.java | 57 ++++++++++++ .../slices/SliceDataConverterTest.java | 3 +- .../settings/slices/SliceDataTest.java | 5 +- .../slices/SlicesDatabaseAccessorTest.java | 4 +- 15 files changed, 201 insertions(+), 53 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index dbe231b5255..f1bb5954ef5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3218,7 +3218,7 @@ diff --git a/res/values/attrs.xml b/res/values/attrs.xml index d37091c5948..d0ddab6ffe2 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -96,8 +96,12 @@ + + + + diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml index 36eab229754..dda5655f083 100644 --- a/res/xml/connected_devices_advanced.xml +++ b/res/xml/connected_devices_advanced.xml @@ -26,7 +26,8 @@ android:icon="@drawable/ic_settings_bluetooth" android:summary="@string/bluetooth_pref_summary" android:order="-7" - settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"/> + settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController" + settings:platform_slice="true"/> outerDepth)); parser.close(); @@ -205,12 +239,16 @@ public class PreferenceXmlParserUtils { * Returns the fragment name if this preference launches a child fragment. */ public static String getDataChildFragment(Context context, AttributeSet attrs) { - return getData(context, attrs, R.styleable.Preference, + return getStringData(context, attrs, R.styleable.Preference, R.styleable.Preference_android_fragment); } + /** + * Call {@link #extractMetadata(Context, int, int)} with a {@link MetadataFlag} instead. + */ + @Deprecated @Nullable - private static String getData(Context context, AttributeSet set, int[] attrs, int resId) { + private static String getStringData(Context context, AttributeSet set, int[] attrs, int resId) { final TypedArray ta = context.obtainStyledAttributes(set, attrs); String data = ta.getString(resId); ta.recycle(); @@ -243,4 +281,28 @@ public class PreferenceXmlParserUtils { } return result.toString(); } + + private static String getKey(TypedArray styledAttributes) { + return styledAttributes.getString(com.android.internal.R.styleable.Preference_key); + } + + private static String getTitle(TypedArray styledAttributes) { + return styledAttributes.getString(com.android.internal.R.styleable.Preference_title); + } + + private static String getSummary(TypedArray styledAttributes) { + return styledAttributes.getString(com.android.internal.R.styleable.Preference_summary); + } + + private static String getController(TypedArray styledAttributes) { + return styledAttributes.getString(R.styleable.Preference_controller); + } + + private static int getIcon(TypedArray styledAttributes) { + return styledAttributes.getResourceId(com.android.internal.R.styleable.Icon_icon, 0); + } + + private static boolean getPlatformSlice(TypedArray styledAttributes) { + return styledAttributes.getBoolean(R.styleable.Preference_platform_slice, false /* def */); + } } diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index d8ba991a145..68c9731d8cb 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.graphics.drawable.Icon; import android.net.Uri; import android.net.wifi.WifiManager; +import android.provider.SettingsSlicesContract; import android.support.annotation.VisibleForTesting; import android.util.Log; @@ -63,6 +64,10 @@ public class SettingsSliceProvider extends SliceProvider { private static final String TAG = "SettingsSliceProvider"; + /** + * Authority for Settings slices not officially supported by the platform, but extensible for + * OEMs. + */ public static final String SLICE_AUTHORITY = "com.android.settings.slices"; public static final String PATH_WIFI = "wifi"; @@ -82,13 +87,6 @@ public class SettingsSliceProvider extends SliceProvider { @VisibleForTesting Map mSliceDataCache; - public static Uri getUri(String path) { - return new Uri.Builder() - .scheme(ContentResolver.SCHEME_CONTENT) - .authority(SLICE_AUTHORITY) - .appendPath(path).build(); - } - @Override public boolean onCreateSliceProvider() { mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext()); @@ -176,7 +174,8 @@ public class SettingsSliceProvider extends SliceProvider { .setSubtitle(state) .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED), null, finalWifiEnabled)) - .setPrimaryAction(new SliceAction(getIntent(Intent.ACTION_MAIN), null, null))) + .setPrimaryAction( + new SliceAction(getIntent(Intent.ACTION_MAIN), null, null))) .build(); } diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index a68ed19db1d..4124df7718c 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -59,7 +59,8 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { // Wait a bit for wifi to update (TODO: is there a better way to do this?) Handler h = new Handler(); h.postDelayed(() -> { - Uri uri = SettingsSliceProvider.getUri(SettingsSliceProvider.PATH_WIFI); + Uri uri = SliceBuilderUtils.getUri(SettingsSliceProvider.PATH_WIFI, + false /* isPlatformSlice */); context.getContentResolver().notifyChange(uri, null); }, 1000); break; diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java index e94ee56ddc6..e90ea8e9f68 100644 --- a/src/com/android/settings/slices/SliceBuilderUtils.java +++ b/src/com/android/settings/slices/SliceBuilderUtils.java @@ -19,9 +19,12 @@ package com.android.settings.slices; import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY; import android.app.PendingIntent; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Icon; +import android.net.Uri; +import android.provider.SettingsSlicesContract; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; @@ -98,6 +101,17 @@ public class SliceBuilderUtils { sliceData.getKey()); } + public static Uri getUri(String path, boolean isPlatformSlice) { + final String authority = isPlatformSlice + ? SettingsSlicesContract.AUTHORITY + : SettingsSliceProvider.SLICE_AUTHORITY; + return new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(authority) + .appendPath(path) + .build(); + } + private static BasePreferenceController getPreferenceController(Context context, String controllerClassName, String controllerKey) { try { diff --git a/src/com/android/settings/slices/SliceData.java b/src/com/android/settings/slices/SliceData.java index a7c9a116dad..c02b1135699 100644 --- a/src/com/android/settings/slices/SliceData.java +++ b/src/com/android/settings/slices/SliceData.java @@ -70,6 +70,8 @@ public class SliceData { @SliceType private final int mSliceType; + private final boolean mIsPlatformDefined; + public String getKey() { return mKey; } @@ -106,6 +108,10 @@ public class SliceData { return mSliceType; } + public boolean isPlatformDefined() { + return mIsPlatformDefined; + } + private SliceData(Builder builder) { mKey = builder.mKey; mTitle = builder.mTitle; @@ -116,6 +122,7 @@ public class SliceData { mUri = builder.mUri; mPreferenceController = builder.mPrefControllerClassName; mSliceType = builder.mSliceType; + mIsPlatformDefined = builder.mIsPlatformDefined; } @Override @@ -151,6 +158,8 @@ public class SliceData { private int mSliceType; + private boolean mIsPlatformDefined; + public Builder setKey(String key) { mKey = key; return this; @@ -196,6 +205,11 @@ public class SliceData { return this; } + public Builder setPlatformDefined(boolean isPlatformDefined) { + mIsPlatformDefined = isPlatformDefined; + return this; + } + public SliceData build() { if (TextUtils.isEmpty(mKey)) { throw new IllegalStateException("Key cannot be empty"); diff --git a/src/com/android/settings/slices/SliceDataConverter.java b/src/com/android/settings/slices/SliceDataConverter.java index e7b53d03940..7cf1994f9ed 100644 --- a/src/com/android/settings/slices/SliceDataConverter.java +++ b/src/com/android/settings/slices/SliceDataConverter.java @@ -19,6 +19,7 @@ package com.android.settings.slices; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_CONTROLLER; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_ICON; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; +import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_PLATFORM_SLICE_FLAG; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE; @@ -164,7 +165,8 @@ class SliceDataConverter { | MetadataFlag.FLAG_NEED_PREF_TYPE | MetadataFlag.FLAG_NEED_PREF_TITLE | MetadataFlag.FLAG_NEED_PREF_ICON - | MetadataFlag.FLAG_NEED_PREF_SUMMARY); + | MetadataFlag.FLAG_NEED_PREF_SUMMARY + | MetadataFlag.FLAG_NEED_PLATFORM_SLICE_FLAG); for (Bundle bundle : metadata) { // TODO (b/67996923) Non-controller Slices should become intent-only slices. @@ -179,6 +181,7 @@ class SliceDataConverter { final int iconResId = bundle.getInt(METADATA_ICON); final int sliceType = SliceBuilderUtils.getSliceType(mContext, controllerClassName, key); + final boolean isPlatformSlice = bundle.getBoolean(METADATA_PLATFORM_SLICE_FLAG); final SliceData xmlSlice = new SliceData.Builder() .setKey(key) @@ -189,6 +192,7 @@ class SliceDataConverter { .setPreferenceControllerClassName(controllerClassName) .setFragmentName(fragmentName) .setSliceType(sliceType) + .setPlatformDefined(isPlatformSlice) .build(); xmlSliceData.add(xmlSlice); diff --git a/tests/robotests/res/xml-mcc999/location_settings.xml b/tests/robotests/res/xml-mcc999/location_settings.xml index 5619c774a6d..08cd8ad65d2 100644 --- a/tests/robotests/res/xml-mcc999/location_settings.xml +++ b/tests/robotests/res/xml-mcc999/location_settings.xml @@ -25,6 +25,7 @@ android:title="title" android:icon="@drawable/ic_android" android:summary="summary" - settings:controller="com.android.settings.slices.FakePreferenceController"/> + settings:controller="com.android.settings.slices.FakePreferenceController" + settings:platform_slice="true"/> \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java index 50f47ff7801..9edae7e39cb 100644 --- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java +++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java @@ -18,8 +18,7 @@ package com.android.settings.slices; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; + import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -28,6 +27,7 @@ import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; +import android.provider.SettingsSlicesContract; import com.android.settings.testutils.DatabaseTestUtils; import com.android.settings.testutils.FakeToggleController; @@ -50,6 +50,8 @@ import java.util.HashMap; public class SettingsSliceProviderTest { private final String KEY = "KEY"; + private final String INTENT_PATH = SettingsSlicesContract.PATH_SETTING_INTENT + "/" + KEY; + private final String ACTION_PATH = SettingsSlicesContract.PATH_SETTING_ACTION + "/" + KEY; private final String TITLE = "title"; private final String SUMMARY = "summary"; private final String SCREEN_TITLE = "screen title"; @@ -67,6 +69,8 @@ public class SettingsSliceProviderTest { mProvider = spy(new SettingsSliceProvider()); mProvider.mSliceDataCache = new HashMap<>(); mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext); + when(mProvider.getContext()).thenReturn(mContext); + mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase(); SlicesDatabaseHelper.getInstance(mContext).setIndexedState(); } @@ -78,34 +82,18 @@ public class SettingsSliceProviderTest { @Test public void testInitialSliceReturned_emptySlice() { - insertSpecialCase(KEY); - ContentResolver mockResolver = mock(ContentResolver.class); - doReturn(mockResolver).when(mContext).getContentResolver(); - when(mProvider.getContext()).thenReturn(mContext); - - Uri uri = SettingsSliceProvider.getUri(KEY); + insertSpecialCase(INTENT_PATH); + Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false); Slice slice = mProvider.onBindSlice(uri); assertThat(slice.getUri()).isEqualTo(uri); assertThat(slice.getItems()).isEmpty(); } - @Test - public void testUriBuilder_returnsValidSliceUri() { - Uri uri = SettingsSliceProvider.getUri(KEY); - - assertThat(uri.getScheme()).isEqualTo(ContentResolver.SCHEME_CONTENT); - assertThat(uri.getAuthority()).isEqualTo(SettingsSliceProvider.SLICE_AUTHORITY); - assertThat(uri.getLastPathSegment()).isEqualTo(KEY); - } - @Test public void testLoadSlice_returnsSliceFromAccessor() { - ContentResolver mockResolver = mock(ContentResolver.class); - doReturn(mockResolver).when(mContext).getContentResolver(); - when(mProvider.getContext()).thenReturn(mContext); insertSpecialCase(KEY); - Uri uri = SettingsSliceProvider.getUri(KEY); + Uri uri = SliceBuilderUtils.getUri(KEY, false); mProvider.loadSlice(uri); SliceData data = mProvider.mSliceDataCache.get(uri); @@ -116,7 +104,6 @@ public class SettingsSliceProviderTest { @Test public void testLoadSlice_cachedEntryRemovedOnBuild() { - when(mProvider.getContext()).thenReturn(mContext); SliceData data = getDummyData(); mProvider.mSliceDataCache.put(data.getUri(), data); mProvider.onBindSlice(data.getUri()); diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java index 5a2271aadd2..0fcce5fb19a 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java @@ -20,8 +20,10 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import android.content.ContentResolver; import android.content.Context; import android.net.Uri; +import android.provider.SettingsSlicesContract; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -48,6 +50,9 @@ public class SliceBuilderUtilsTest { private final Class PREF_CONTROLLER = FakeToggleController.class; private final Class PREF_CONTROLLER2 = FakeContextOnlyPreferenceController.class; + private final String INTENT_PATH = SettingsSlicesContract.PATH_SETTING_INTENT + "/" + KEY; + private final String ACTION_PATH = SettingsSlicesContract.PATH_SETTING_ACTION + "/" + KEY; + private Context mContext; @Before @@ -62,6 +67,58 @@ public class SliceBuilderUtilsTest { assertThat(slice).isNotNull(); // TODO improve test for Slice content } + @Test + public void testUriBuilder_oemAuthority_intentPath_returnsValidSliceUri() { + Uri expectedUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(INTENT_PATH) + .build(); + + Uri actualUri = SliceBuilderUtils.getUri(INTENT_PATH, false); + + assertThat(actualUri).isEqualTo(expectedUri); + } + + @Test + public void testUriBuilder_oemAuthority_actionPath_returnsValidSliceUri() { + Uri expectedUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(ACTION_PATH) + .build(); + + Uri actualUri = SliceBuilderUtils.getUri(ACTION_PATH, false); + + assertThat(actualUri).isEqualTo(expectedUri); + } + + @Test + public void testUriBuilder_platformAuthority_intentPath_returnsValidSliceUri() { + Uri expectedUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSlicesContract.AUTHORITY) + .appendPath(ACTION_PATH) + .build(); + + Uri actualUri = SliceBuilderUtils.getUri(ACTION_PATH, true); + + assertThat(actualUri).isEqualTo(expectedUri); + } + + @Test + public void testUriBuilder_platformAuthority_actionPath_returnsValidSliceUri() { + Uri expectedUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSlicesContract.AUTHORITY) + .appendPath(ACTION_PATH) + .build(); + + Uri actualUri = SliceBuilderUtils.getUri(ACTION_PATH, true); + + assertThat(actualUri).isEqualTo(expectedUri); + } + @Test public void testGetPreferenceController_buildsMatchingController() { BasePreferenceController controller = diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java index 4d6c08dda8b..36c27548c13 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java @@ -81,6 +81,7 @@ public class SliceDataConverterTest { assertThat(fakeSlice.getUri()).isNull(); assertThat(fakeSlice.getFragmentClassName()).isEqualTo(fakeFragmentClassName); assertThat(fakeSlice.getPreferenceController()).isEqualTo(fakeControllerName); - assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); + assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); // from XML + assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java index 7cd19b5bcf7..c2ab0afb183 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceDataTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java @@ -37,6 +37,7 @@ public class SliceDataTest { private final Uri URI = Uri.parse("content://com.android.settings.slices/test"); private final String PREF_CONTROLLER = "com.android.settings.slices.tester"; private final int SLICE_TYPE = SliceData.SliceType.SWITCH; + private final boolean IS_PLATFORM_DEFINED = true; @Test public void testBuilder_buildsMatchingObject() { @@ -49,7 +50,8 @@ public class SliceDataTest { .setFragmentName(FRAGMENT_NAME) .setUri(URI) .setPreferenceControllerClassName(PREF_CONTROLLER) - .setSliceType(SLICE_TYPE); + .setSliceType(SLICE_TYPE) + .setPlatformDefined(IS_PLATFORM_DEFINED); SliceData data = builder.build(); @@ -62,6 +64,7 @@ public class SliceDataTest { assertThat(data.getUri()).isEqualTo(URI); assertThat(data.getPreferenceController()).isEqualTo(PREF_CONTROLLER); assertThat(data.getSliceType()).isEqualTo(SLICE_TYPE); + assertThat(data.isPlatformDefined()).isEqualTo(IS_PLATFORM_DEFINED); } @Test(expected = IllegalStateException.class) diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java index 8989de9ef7f..331058c96c5 100644 --- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java +++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java @@ -90,7 +90,7 @@ public class SlicesDatabaseAccessorTest { public void testGetSliceFromUri_validUri_validSliceReturned() { String key = "key"; insertSpecialCase(key); - Uri uri = SettingsSliceProvider.getUri(key); + Uri uri = SliceBuilderUtils.getUri(key, false); SliceData data = mAccessor.getSliceDataFromUri(uri); @@ -106,7 +106,7 @@ public class SlicesDatabaseAccessorTest { @Test(expected = IllegalStateException.class) public void testGetSliceFromUri_invalidUri_errorThrown() { - Uri uri = SettingsSliceProvider.getUri("durr"); + Uri uri = SliceBuilderUtils.getUri("durr", false); mAccessor.getSliceDataFromUri(uri); }