Loading res/layout/preference_radio_with_extra_widget.xml 0 → 100644 +106 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2019 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 --> <!-- This file is copied from preference_radio.xml with modification to support an extra clickable icon on the opposite side horizontally --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:gravity="center_vertical" android:minHeight="?android:attr/listPreferredItemHeightSmall" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> <LinearLayout android:id="@android:id/widget_frame" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:minWidth="56dp" android:layout_marginEnd="16dp" android:orientation="vertical" /> <LinearLayout android:id="@+id/icon_frame" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:minWidth="32dp" android:orientation="horizontal" android:layout_marginEnd="16dp" android:paddingTop="4dp" android:paddingBottom="4dp"> <androidx.preference.internal.PreferenceImageView android:id="@android:id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" settings:maxWidth="@dimen/secondary_app_icon_size" settings:maxHeight="@dimen/secondary_app_icon_size" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:paddingTop="16dp" android:paddingBottom="16dp"> <TextView android:id="@android:id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:textAppearance="@style/TextAppearance.TileTitle" android:ellipsize="marquee" android:fadingEdge="horizontal" /> <TextView android:id="@android:id/summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:textAppearance="@style/TextAppearance.Small" android:textAlignment="viewStart" android:textColor="?android:attr/textColorSecondary" /> </LinearLayout> <LinearLayout android:id="@+id/radio_extra_widget_container" android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" android:gravity="center_vertical"> <View android:id="@+id/radio_extra_widget_divider" android:layout_width="@dimen/vertical_divider_width" android:layout_height="match_parent" android:layout_marginTop="36dp" android:layout_marginBottom="36dp" android:layout_marginStart="8dp" android:background="?android:attr/dividerVertical" /> <ImageView android:id="@+id/radio_extra_widget" android:layout_width="wrap_content" android:layout_height="fill_parent" android:paddingStart="16dp" android:paddingEnd="16dp" android:src="@drawable/ic_settings_about" android:contentDescription="@string/information_label" android:layout_gravity="center" android:background="?android:attr/selectableItemBackground" /> </LinearLayout> </LinearLayout> src/com/android/settings/gestures/SystemNavigationGestureSettings.java +59 −5 Original line number Diff line number Diff line Loading @@ -21,6 +21,10 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVE import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_GONE; import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_INFO; import android.app.AlertDialog; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.SharedPreferences; Loading @@ -29,7 +33,6 @@ import android.graphics.drawable.Drawable; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.SearchIndexableResource; import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.preference.PreferenceScreen; Loading @@ -41,6 +44,7 @@ import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.widget.RadioButtonPickerFragment; import com.android.settings.widget.RadioButtonPreference; import com.android.settings.widget.RadioButtonPreferenceWithExtraWidget; import com.android.settings.widget.VideoPreference; import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.widget.CandidateInfo; Loading Loading @@ -94,8 +98,25 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment { } @Override protected void addStaticPreferences(PreferenceScreen screen) { public void updateCandidates() { final String defaultKey = getDefaultKey(); final String systemDefaultKey = getSystemDefaultKey(); final PreferenceScreen screen = getPreferenceScreen(); screen.removeAll(); screen.addPreference(mVideoPreference); final List<? extends CandidateInfo> candidateList = getCandidates(); if (candidateList == null) { return; } for (CandidateInfo info : candidateList) { RadioButtonPreferenceWithExtraWidget pref = new RadioButtonPreferenceWithExtraWidget(getPrefContext()); bindPreference(pref, info.getKey(), info, defaultKey); bindPreferenceExtra(pref, info.getKey(), info, defaultKey, systemDefaultKey); screen.addPreference(pref); } mayCheckOnlyRadioButton(); } @Override Loading Loading @@ -135,6 +156,13 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment { @Override protected boolean setDefaultKey(String key) { final Context c = getContext(); if (key == KEY_SYSTEM_NAV_GESTURAL && !SystemNavigationPreferenceController.isGestureNavSupportedByDefaultLauncher(c)) { // This should not happen since the preference is disabled. Return to be safe. return false; } setCurrentSystemNavigationMode(mOverlayManager, key); setIllustrationVideo(mVideoPreference, key); return true; Loading Loading @@ -196,10 +224,36 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment { @Override public void bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey) { if (info instanceof NavModeCandidateInfo) { if (!(info instanceof NavModeCandidateInfo) || !(pref instanceof RadioButtonPreferenceWithExtraWidget)) { return; } pref.setSummary(((NavModeCandidateInfo) info).loadSummary()); pref.setAppendixVisibility(View.GONE); RadioButtonPreferenceWithExtraWidget p = (RadioButtonPreferenceWithExtraWidget) pref; if (info.getKey() == KEY_SYSTEM_NAV_GESTURAL && !SystemNavigationPreferenceController.isGestureNavSupportedByDefaultLauncher( getContext())) { p.setEnabled(false); p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_INFO); p.setExtraWidgetOnClickListener((v) -> { showGestureNavDisabledDialog(); }); } else { p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_GONE); } } private void showGestureNavDisabledDialog() { final String defaultHomeAppName = SystemNavigationPreferenceController .getDefaultHomeAppName(getContext()); final String message = getString(R.string.gesture_not_supported_dialog_message, defaultHomeAppName); AlertDialog d = new AlertDialog.Builder(getContext()) .setMessage(message) .setPositiveButton(R.string.okay, null) .show(); } static class NavModeCandidateInfo extends CandidateInfo { Loading src/com/android/settings/gestures/SystemNavigationPreferenceController.java +30 −0 Original line number Diff line number Diff line Loading @@ -22,11 +22,14 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import java.util.ArrayList; public class SystemNavigationPreferenceController extends BasePreferenceController { static final String PREF_KEY_SYSTEM_NAVIGATION = "gesture_system_navigation"; Loading Loading @@ -98,4 +101,31 @@ public class SystemNavigationPreferenceController extends BasePreferenceControll return NAV_BAR_MODE_GESTURAL == context.getResources().getInteger( com.android.internal.R.integer.config_navBarInteractionMode); } static boolean isGestureNavSupportedByDefaultLauncher(Context context) { final ComponentName cn = context.getPackageManager().getHomeActivities(new ArrayList<>()); if (cn == null) { // There is no default home app set for the current user, don't make any changes yet. return true; } ComponentName recentsComponentName = ComponentName.unflattenFromString(context.getString( com.android.internal.R.string.config_recentsComponentName)); return recentsComponentName.getPackageName().equals(cn.getPackageName()); } static String getDefaultHomeAppName(Context context) { final PackageManager pm = context.getPackageManager(); final ComponentName cn = pm.getHomeActivities(new ArrayList<>()); if (cn != null) { try { ApplicationInfo ai = pm.getApplicationInfo(cn.getPackageName(), 0); if (ai != null) { return pm.getApplicationLabel(ai).toString(); } } catch (final PackageManager.NameNotFoundException e) { // Do nothing } } return ""; } } src/com/android/settings/widget/RadioButtonPreferenceWithExtraWidget.java 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.widget; import android.content.Context; import android.view.View; import android.widget.ImageView; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; public class RadioButtonPreferenceWithExtraWidget extends RadioButtonPreference { public static final int EXTRA_WIDGET_VISIBILITY_GONE = 0; public static final int EXTRA_WIDGET_VISIBILITY_INFO = 1; private View mExtraWidgetDivider; private ImageView mExtraWidget; private int mExtraWidgetVisibility = EXTRA_WIDGET_VISIBILITY_GONE; private View.OnClickListener mExtraWidgetOnClickListener; public RadioButtonPreferenceWithExtraWidget(Context context) { super(context, null); setLayoutResource(R.layout.preference_radio_with_extra_widget); } @Override public void onBindViewHolder(PreferenceViewHolder view) { super.onBindViewHolder(view); mExtraWidget = (ImageView) view.findViewById(R.id.radio_extra_widget); mExtraWidgetDivider = view.findViewById(R.id.radio_extra_widget_divider); setExtraWidgetVisibility(mExtraWidgetVisibility); if (mExtraWidgetOnClickListener != null) { setExtraWidgetOnClickListener(mExtraWidgetOnClickListener); } } public void setExtraWidgetVisibility(int visibility) { mExtraWidgetVisibility = visibility; if (mExtraWidget == null || mExtraWidgetDivider == null) { return; } if (visibility == EXTRA_WIDGET_VISIBILITY_GONE) { mExtraWidget.setClickable(false); mExtraWidget.setVisibility(View.GONE); mExtraWidgetDivider.setVisibility(View.GONE); } else { mExtraWidget.setClickable(true); mExtraWidget.setVisibility(View.VISIBLE); mExtraWidgetDivider.setVisibility(View.VISIBLE); } } public void setExtraWidgetOnClickListener(View.OnClickListener listener) { mExtraWidgetOnClickListener = listener; if (mExtraWidget != null) { mExtraWidget.setEnabled(true); mExtraWidget.setOnClickListener(listener); } } } No newline at end of file tests/robotests/src/com/android/settings/gestures/SystemNavigationPreferenceControllerTest.java +57 −0 Original line number Diff line number Diff line Loading @@ -24,10 +24,14 @@ import static com.android.settings.gestures.SystemNavigationPreferenceController import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.text.TextUtils; Loading @@ -39,6 +43,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; Loading @@ -53,9 +58,15 @@ public class SystemNavigationPreferenceControllerTest { private Context mContext; private ShadowPackageManager mPackageManager; @Mock private Context mMockContext; @Mock private PackageManager mMockPackageManager; private SystemNavigationPreferenceController mController; private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE"; private static final String TEST_RECENTS_COMPONENT_NAME = "test.component.name/.testActivity"; @Before public void setUp() { Loading @@ -69,6 +80,10 @@ public class SystemNavigationPreferenceControllerTest { mController = new SystemNavigationPreferenceController(mContext, PREF_KEY_SYSTEM_NAVIGATION); when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); when(mMockContext.getString(com.android.internal.R.string.config_recentsComponentName)) .thenReturn(TEST_RECENTS_COMPONENT_NAME); } @After Loading Loading @@ -166,4 +181,46 @@ public class SystemNavigationPreferenceControllerTest { assertThat(TextUtils.equals(mController.getSummary(), mContext.getText( com.android.settings.R.string.swipe_up_to_switch_apps_title))).isTrue(); } @Test public void testIsGestureNavSupportedByDefaultLauncher_noDefaultLauncher() { when(mMockPackageManager.getHomeActivities(any())).thenReturn(null); assertThat(SystemNavigationPreferenceController .isGestureNavSupportedByDefaultLauncher(mMockContext)).isTrue(); } @Test public void testIsGestureNavSupportedByDefaultLauncher_supported() { when(mMockPackageManager.getHomeActivities(any())).thenReturn( ComponentName.unflattenFromString(TEST_RECENTS_COMPONENT_NAME)); assertThat(SystemNavigationPreferenceController .isGestureNavSupportedByDefaultLauncher(mMockContext)).isTrue(); } @Test public void testIsGestureNavSupportedByDefaultLauncher_notSupported() { when(mMockPackageManager.getHomeActivities(any())).thenReturn( new ComponentName("unsupported", "launcher")); assertThat(SystemNavigationPreferenceController .isGestureNavSupportedByDefaultLauncher(mMockContext)).isFalse(); } @Test public void testGetDefaultHomeAppName_noDefaultLauncher() { when(mMockPackageManager.getHomeActivities(any())).thenReturn(null); assertThat(SystemNavigationPreferenceController .getDefaultHomeAppName(mMockContext)).isEqualTo(""); } @Test public void testGetDefaultHomeAppName_defaultLauncherExists() throws Exception { when(mMockPackageManager.getHomeActivities(any())).thenReturn( new ComponentName("supported", "launcher")); ApplicationInfo info = new ApplicationInfo(); when(mMockPackageManager.getApplicationInfo("supported", 0)).thenReturn(info); when(mMockPackageManager.getApplicationLabel(info)).thenReturn("Test Home App"); assertThat(SystemNavigationPreferenceController .getDefaultHomeAppName(mMockContext)).isEqualTo("Test Home App"); } } No newline at end of file Loading
res/layout/preference_radio_with_extra_widget.xml 0 → 100644 +106 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2019 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 --> <!-- This file is copied from preference_radio.xml with modification to support an extra clickable icon on the opposite side horizontally --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:gravity="center_vertical" android:minHeight="?android:attr/listPreferredItemHeightSmall" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"> <LinearLayout android:id="@android:id/widget_frame" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center" android:minWidth="56dp" android:layout_marginEnd="16dp" android:orientation="vertical" /> <LinearLayout android:id="@+id/icon_frame" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:minWidth="32dp" android:orientation="horizontal" android:layout_marginEnd="16dp" android:paddingTop="4dp" android:paddingBottom="4dp"> <androidx.preference.internal.PreferenceImageView android:id="@android:id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" settings:maxWidth="@dimen/secondary_app_icon_size" settings:maxHeight="@dimen/secondary_app_icon_size" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:paddingTop="16dp" android:paddingBottom="16dp"> <TextView android:id="@android:id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:textAppearance="@style/TextAppearance.TileTitle" android:ellipsize="marquee" android:fadingEdge="horizontal" /> <TextView android:id="@android:id/summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:textAppearance="@style/TextAppearance.Small" android:textAlignment="viewStart" android:textColor="?android:attr/textColorSecondary" /> </LinearLayout> <LinearLayout android:id="@+id/radio_extra_widget_container" android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" android:gravity="center_vertical"> <View android:id="@+id/radio_extra_widget_divider" android:layout_width="@dimen/vertical_divider_width" android:layout_height="match_parent" android:layout_marginTop="36dp" android:layout_marginBottom="36dp" android:layout_marginStart="8dp" android:background="?android:attr/dividerVertical" /> <ImageView android:id="@+id/radio_extra_widget" android:layout_width="wrap_content" android:layout_height="fill_parent" android:paddingStart="16dp" android:paddingEnd="16dp" android:src="@drawable/ic_settings_about" android:contentDescription="@string/information_label" android:layout_gravity="center" android:background="?android:attr/selectableItemBackground" /> </LinearLayout> </LinearLayout>
src/com/android/settings/gestures/SystemNavigationGestureSettings.java +59 −5 Original line number Diff line number Diff line Loading @@ -21,6 +21,10 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVE import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_GONE; import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_INFO; import android.app.AlertDialog; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.SharedPreferences; Loading @@ -29,7 +33,6 @@ import android.graphics.drawable.Drawable; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.SearchIndexableResource; import android.view.View; import androidx.annotation.VisibleForTesting; import androidx.preference.PreferenceScreen; Loading @@ -41,6 +44,7 @@ import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.widget.RadioButtonPickerFragment; import com.android.settings.widget.RadioButtonPreference; import com.android.settings.widget.RadioButtonPreferenceWithExtraWidget; import com.android.settings.widget.VideoPreference; import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.widget.CandidateInfo; Loading Loading @@ -94,8 +98,25 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment { } @Override protected void addStaticPreferences(PreferenceScreen screen) { public void updateCandidates() { final String defaultKey = getDefaultKey(); final String systemDefaultKey = getSystemDefaultKey(); final PreferenceScreen screen = getPreferenceScreen(); screen.removeAll(); screen.addPreference(mVideoPreference); final List<? extends CandidateInfo> candidateList = getCandidates(); if (candidateList == null) { return; } for (CandidateInfo info : candidateList) { RadioButtonPreferenceWithExtraWidget pref = new RadioButtonPreferenceWithExtraWidget(getPrefContext()); bindPreference(pref, info.getKey(), info, defaultKey); bindPreferenceExtra(pref, info.getKey(), info, defaultKey, systemDefaultKey); screen.addPreference(pref); } mayCheckOnlyRadioButton(); } @Override Loading Loading @@ -135,6 +156,13 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment { @Override protected boolean setDefaultKey(String key) { final Context c = getContext(); if (key == KEY_SYSTEM_NAV_GESTURAL && !SystemNavigationPreferenceController.isGestureNavSupportedByDefaultLauncher(c)) { // This should not happen since the preference is disabled. Return to be safe. return false; } setCurrentSystemNavigationMode(mOverlayManager, key); setIllustrationVideo(mVideoPreference, key); return true; Loading Loading @@ -196,10 +224,36 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment { @Override public void bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey) { if (info instanceof NavModeCandidateInfo) { if (!(info instanceof NavModeCandidateInfo) || !(pref instanceof RadioButtonPreferenceWithExtraWidget)) { return; } pref.setSummary(((NavModeCandidateInfo) info).loadSummary()); pref.setAppendixVisibility(View.GONE); RadioButtonPreferenceWithExtraWidget p = (RadioButtonPreferenceWithExtraWidget) pref; if (info.getKey() == KEY_SYSTEM_NAV_GESTURAL && !SystemNavigationPreferenceController.isGestureNavSupportedByDefaultLauncher( getContext())) { p.setEnabled(false); p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_INFO); p.setExtraWidgetOnClickListener((v) -> { showGestureNavDisabledDialog(); }); } else { p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_GONE); } } private void showGestureNavDisabledDialog() { final String defaultHomeAppName = SystemNavigationPreferenceController .getDefaultHomeAppName(getContext()); final String message = getString(R.string.gesture_not_supported_dialog_message, defaultHomeAppName); AlertDialog d = new AlertDialog.Builder(getContext()) .setMessage(message) .setPositiveButton(R.string.okay, null) .show(); } static class NavModeCandidateInfo extends CandidateInfo { Loading
src/com/android/settings/gestures/SystemNavigationPreferenceController.java +30 −0 Original line number Diff line number Diff line Loading @@ -22,11 +22,14 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import java.util.ArrayList; public class SystemNavigationPreferenceController extends BasePreferenceController { static final String PREF_KEY_SYSTEM_NAVIGATION = "gesture_system_navigation"; Loading Loading @@ -98,4 +101,31 @@ public class SystemNavigationPreferenceController extends BasePreferenceControll return NAV_BAR_MODE_GESTURAL == context.getResources().getInteger( com.android.internal.R.integer.config_navBarInteractionMode); } static boolean isGestureNavSupportedByDefaultLauncher(Context context) { final ComponentName cn = context.getPackageManager().getHomeActivities(new ArrayList<>()); if (cn == null) { // There is no default home app set for the current user, don't make any changes yet. return true; } ComponentName recentsComponentName = ComponentName.unflattenFromString(context.getString( com.android.internal.R.string.config_recentsComponentName)); return recentsComponentName.getPackageName().equals(cn.getPackageName()); } static String getDefaultHomeAppName(Context context) { final PackageManager pm = context.getPackageManager(); final ComponentName cn = pm.getHomeActivities(new ArrayList<>()); if (cn != null) { try { ApplicationInfo ai = pm.getApplicationInfo(cn.getPackageName(), 0); if (ai != null) { return pm.getApplicationLabel(ai).toString(); } } catch (final PackageManager.NameNotFoundException e) { // Do nothing } } return ""; } }
src/com/android/settings/widget/RadioButtonPreferenceWithExtraWidget.java 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.widget; import android.content.Context; import android.view.View; import android.widget.ImageView; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; public class RadioButtonPreferenceWithExtraWidget extends RadioButtonPreference { public static final int EXTRA_WIDGET_VISIBILITY_GONE = 0; public static final int EXTRA_WIDGET_VISIBILITY_INFO = 1; private View mExtraWidgetDivider; private ImageView mExtraWidget; private int mExtraWidgetVisibility = EXTRA_WIDGET_VISIBILITY_GONE; private View.OnClickListener mExtraWidgetOnClickListener; public RadioButtonPreferenceWithExtraWidget(Context context) { super(context, null); setLayoutResource(R.layout.preference_radio_with_extra_widget); } @Override public void onBindViewHolder(PreferenceViewHolder view) { super.onBindViewHolder(view); mExtraWidget = (ImageView) view.findViewById(R.id.radio_extra_widget); mExtraWidgetDivider = view.findViewById(R.id.radio_extra_widget_divider); setExtraWidgetVisibility(mExtraWidgetVisibility); if (mExtraWidgetOnClickListener != null) { setExtraWidgetOnClickListener(mExtraWidgetOnClickListener); } } public void setExtraWidgetVisibility(int visibility) { mExtraWidgetVisibility = visibility; if (mExtraWidget == null || mExtraWidgetDivider == null) { return; } if (visibility == EXTRA_WIDGET_VISIBILITY_GONE) { mExtraWidget.setClickable(false); mExtraWidget.setVisibility(View.GONE); mExtraWidgetDivider.setVisibility(View.GONE); } else { mExtraWidget.setClickable(true); mExtraWidget.setVisibility(View.VISIBLE); mExtraWidgetDivider.setVisibility(View.VISIBLE); } } public void setExtraWidgetOnClickListener(View.OnClickListener listener) { mExtraWidgetOnClickListener = listener; if (mExtraWidget != null) { mExtraWidget.setEnabled(true); mExtraWidget.setOnClickListener(listener); } } } No newline at end of file
tests/robotests/src/com/android/settings/gestures/SystemNavigationPreferenceControllerTest.java +57 −0 Original line number Diff line number Diff line Loading @@ -24,10 +24,14 @@ import static com.android.settings.gestures.SystemNavigationPreferenceController import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.text.TextUtils; Loading @@ -39,6 +43,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; Loading @@ -53,9 +58,15 @@ public class SystemNavigationPreferenceControllerTest { private Context mContext; private ShadowPackageManager mPackageManager; @Mock private Context mMockContext; @Mock private PackageManager mMockPackageManager; private SystemNavigationPreferenceController mController; private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE"; private static final String TEST_RECENTS_COMPONENT_NAME = "test.component.name/.testActivity"; @Before public void setUp() { Loading @@ -69,6 +80,10 @@ public class SystemNavigationPreferenceControllerTest { mController = new SystemNavigationPreferenceController(mContext, PREF_KEY_SYSTEM_NAVIGATION); when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); when(mMockContext.getString(com.android.internal.R.string.config_recentsComponentName)) .thenReturn(TEST_RECENTS_COMPONENT_NAME); } @After Loading Loading @@ -166,4 +181,46 @@ public class SystemNavigationPreferenceControllerTest { assertThat(TextUtils.equals(mController.getSummary(), mContext.getText( com.android.settings.R.string.swipe_up_to_switch_apps_title))).isTrue(); } @Test public void testIsGestureNavSupportedByDefaultLauncher_noDefaultLauncher() { when(mMockPackageManager.getHomeActivities(any())).thenReturn(null); assertThat(SystemNavigationPreferenceController .isGestureNavSupportedByDefaultLauncher(mMockContext)).isTrue(); } @Test public void testIsGestureNavSupportedByDefaultLauncher_supported() { when(mMockPackageManager.getHomeActivities(any())).thenReturn( ComponentName.unflattenFromString(TEST_RECENTS_COMPONENT_NAME)); assertThat(SystemNavigationPreferenceController .isGestureNavSupportedByDefaultLauncher(mMockContext)).isTrue(); } @Test public void testIsGestureNavSupportedByDefaultLauncher_notSupported() { when(mMockPackageManager.getHomeActivities(any())).thenReturn( new ComponentName("unsupported", "launcher")); assertThat(SystemNavigationPreferenceController .isGestureNavSupportedByDefaultLauncher(mMockContext)).isFalse(); } @Test public void testGetDefaultHomeAppName_noDefaultLauncher() { when(mMockPackageManager.getHomeActivities(any())).thenReturn(null); assertThat(SystemNavigationPreferenceController .getDefaultHomeAppName(mMockContext)).isEqualTo(""); } @Test public void testGetDefaultHomeAppName_defaultLauncherExists() throws Exception { when(mMockPackageManager.getHomeActivities(any())).thenReturn( new ComponentName("supported", "launcher")); ApplicationInfo info = new ApplicationInfo(); when(mMockPackageManager.getApplicationInfo("supported", 0)).thenReturn(info); when(mMockPackageManager.getApplicationLabel(info)).thenReturn("Test Home App"); assertThat(SystemNavigationPreferenceController .getDefaultHomeAppName(mMockContext)).isEqualTo("Test Home App"); } } No newline at end of file