Merge Android 24Q2 Release (ab/11526283) to aosp-main-future

Bug: 337098550
Merged-In: I96574a79eba581db95d387f0d9c9fde2e004c41c
Change-Id: Ib9f2c742f8aa72651ef9eca80a716dd94b9041ea
This commit is contained in:
Xin Li
2024-05-23 14:12:07 -07:00
1413 changed files with 69959 additions and 31812 deletions

View File

@@ -4,15 +4,14 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.ShadowPowerManager;
import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
@@ -21,9 +20,8 @@ import java.util.List;
public class DisplaySettingsTest {
@Test
@Config(shadows = ShadowPowerManager.class)
public void testPreferenceControllers_getPreferenceKeys_existInPreferenceScreen() {
final Context context = RuntimeEnvironment.application;
final Context context = ApplicationProvider.getApplicationContext();
final DisplaySettings fragment = new DisplaySettings();
final List<String> preferenceScreenKeys = XmlTestUtils.getKeysFromPreferenceXml(context,
fragment.getPreferenceScreenResId());

View File

@@ -29,10 +29,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import com.android.settings.fuelgauge.batterytip.AnomalyConfigJobService;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -83,22 +79,6 @@ public class SettingsDumpServiceTest {
assertThat(mTestService.dumpDefaultBrowser()).isEqualTo(null);
}
@Test
public void testDumpAnomalyDetection_returnAnomalyInfo() throws JSONException {
final SharedPreferences sharedPreferences =
RuntimeEnvironment.application.getSharedPreferences(AnomalyConfigJobService.PREF_DB,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt(AnomalyConfigJobService.KEY_ANOMALY_CONFIG_VERSION, ANOMALY_VERSION);
editor.commit();
doReturn(sharedPreferences).when(mTestService).getSharedPreferences(anyString(), anyInt());
final JSONObject jsonObject = mTestService.dumpAnomalyDetection();
assertThat(jsonObject.getInt(AnomalyConfigJobService.KEY_ANOMALY_CONFIG_VERSION)).isEqualTo(
ANOMALY_VERSION);
}
@Test
public void testDump_printServiceAsKey() {
mResolveInfo.activityInfo = new ActivityInfo();

View File

@@ -31,6 +31,7 @@ import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settingslib.search.SearchIndexableRaw;
import org.junit.Before;
import org.junit.Rule;
@@ -42,6 +43,9 @@ import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import java.util.ArrayList;
import java.util.List;
/** Tests for {@link AccessibilityButtonPreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class AccessibilityButtonPreferenceControllerTest {
@@ -88,4 +92,36 @@ public class AccessibilityButtonPreferenceControllerTest {
assertThat(mPreference.getTitle()).isEqualTo(
mContext.getText(R.string.accessibility_button_title));
}
@Test
public void updateDynamicRawDataToIndex_navigationGestureEnabled_setCorrectIndex() {
when(mResources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode))
.thenReturn(NAV_BAR_MODE_GESTURAL);
List<SearchIndexableRaw> rawDataList = new ArrayList<>();
mController.updateDynamicRawDataToIndex(rawDataList);
assertThat(rawDataList).hasSize(1);
SearchIndexableRaw raw = rawDataList.get(0);
assertThat(raw.title).isEqualTo(
mResources.getString(R.string.accessibility_button_gesture_title));
assertThat(raw.screenTitle).isEqualTo(
mResources.getString(R.string.accessibility_shortcuts_settings_title));
}
@Test
public void updateDynamicRawDataToIndex_navigationGestureDisabled_setCorrectIndex() {
when(mResources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode))
.thenReturn(NAV_BAR_MODE_2BUTTON);
List<SearchIndexableRaw> rawDataList = new ArrayList<>();
mController.updateDynamicRawDataToIndex(rawDataList);
assertThat(rawDataList).hasSize(1);
SearchIndexableRaw raw = rawDataList.get(0);
assertThat(raw.title).isEqualTo(
mResources.getString(R.string.accessibility_button_title));
assertThat(raw.screenTitle).isEqualTo(
mResources.getString(R.string.accessibility_shortcuts_settings_title));
}
}

View File

@@ -38,6 +38,7 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.settings.SettingsActivity;
import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import com.google.common.collect.ImmutableList;
@@ -57,7 +58,10 @@ import java.util.ArrayList;
import java.util.List;
/** Tests for {@link AccessibilityDetailsSettingsFragment}. */
@Config(shadows = ShadowDevicePolicyManager.class)
@Config(shadows = {
ShadowDevicePolicyManager.class,
ShadowRestrictedLockUtilsInternal.class
})
@RunWith(RobolectricTestRunner.class)
public class AccessibilityDetailsSettingsFragmentTest {
private static final String PACKAGE_NAME = "com.foo.bar";

View File

@@ -52,6 +52,7 @@ import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.ShadowApplicationPackageManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -87,6 +88,7 @@ import java.util.List;
ShadowUserManager.class,
ShadowColorDisplayManager.class,
ShadowApplicationPackageManager.class,
ShadowRestrictedLockUtilsInternal.class,
})
public class AccessibilitySettingsTest {
private static final String PACKAGE_NAME = "com.android.test";

View File

@@ -15,7 +15,9 @@
*/
package com.android.settings.accessibility;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -50,4 +52,14 @@ public class AccessibilitySetupWizardUtilsTest {
verify(layout).setIcon(icon);
verify(layout).setHeaderText(title);
}
@Test
public void setupGlifPreferenceLayout_descriptionIsNull_doesNotCallSetDescriptionText() {
GlifPreferenceLayout layout = mock(GlifPreferenceLayout.class);
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(mContext, layout, "title",
/* description= */ null, /* icon= */ null);
verify(layout, times(0)).setDescriptionText(any());
}
}

View File

@@ -110,7 +110,7 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.getComponentName().flattenToString(), UserShortcutType.SOFTWARE);
mFragment.getComponentName().flattenToString());
// Compare to default UserShortcutType
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE);
}
@@ -123,7 +123,7 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.getComponentName().flattenToString(), UserShortcutType.SOFTWARE);
mFragment.getComponentName().flattenToString());
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
}
@@ -136,7 +136,7 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.getComponentName().flattenToString(), UserShortcutType.SOFTWARE);
mFragment.getComponentName().flattenToString());
assertThat(expectedType).isEqualTo(UserShortcutType.HARDWARE);
}
@@ -201,7 +201,7 @@ public class AccessibilityShortcutPreferenceFragmentTest {
mFragment.saveNonEmptyUserShortcutType(value);
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.getComponentName().flattenToString(), UserShortcutType.SOFTWARE);
mFragment.getComponentName().flattenToString());
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2024 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.accessibility;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link ArrowPreference} */
@RunWith(RobolectricTestRunner.class)
public class ArrowPreferenceTest {
private final Context mContext = ApplicationProvider.getApplicationContext();
private ArrowPreference mPreference;
@Before
public void setUp() {
mPreference = new ArrowPreference(mContext);
}
@Test
public void construct_withArrow() {
assertThat(mPreference.getWidgetLayoutResource()).isEqualTo(
R.layout.preference_widget_arrow);
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2024 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.accessibility;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;
import androidx.preference.PreferenceViewHolder;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link BackgroundPreference} */
@RunWith(RobolectricTestRunner.class)
public class BackgroundPreferenceTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private final Context mContext = ApplicationProvider.getApplicationContext();
private View mRootView = new View(mContext);
@Spy
private PreferenceViewHolder mViewHolder = PreferenceViewHolder.createInstanceForTests(
mRootView);
@Spy
private LinearLayout mLinearLayout = new LinearLayout(mContext);
private BackgroundPreference mPreference;
@Before
public void setUp() {
mPreference = new BackgroundPreference(mContext);
}
@Test
public void setBackground_success() {
doReturn(mLinearLayout).when(mViewHolder).findViewById(R.id.background);
mPreference.setBackground(android.R.drawable.screen_background_dark);
mPreference.onBindViewHolder(mViewHolder);
verify(mLinearLayout).setBackground(any());
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2024 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.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.UiModeManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.XmlTestUtils;
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 java.util.List;
/** Tests for {@link ColorContrastFragment}. */
@RunWith(RobolectricTestRunner.class)
public class ColorContrastFragmentTest {
private ColorContrastFragment mFragment;
private Context mContext;
@Mock
private UiModeManager mUiService;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new ColorContrastFragment());
mContext = spy(ApplicationProvider.getApplicationContext());
when(mFragment.getContext()).thenReturn(mContext);
when(mContext.getSystemService(UiModeManager.class)).thenReturn(mUiService);
}
@Test
public void getMetricsCategory_returnsCorrectCategory() {
assertThat(mFragment.getMetricsCategory()).isEqualTo(
SettingsEnums.ACCESSIBILITY_COLOR_CONTRAST);
}
@Test
public void getPreferenceScreenResId_returnsCorrectXml() {
assertThat(mFragment.getPreferenceScreenResId()).isEqualTo(
R.xml.accessibility_color_contrast);
}
@Test
public void getLogTag_returnsCorrectTag() {
assertThat(mFragment.getLogTag()).isEqualTo("ColorContrastFragment");
}
@Test
public void getNonIndexableKeys_existInXmlLayout() {
final List<String> niks =
ShortcutsSettingsFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(mContext);
final List<String> keys =
XmlTestUtils.getKeysFromPreferenceXml(mContext,
R.xml.accessibility_color_contrast);
assertThat(keys).containsAtLeastElementsIn(niks);
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2024 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.accessibility;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link ContrastPreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class ContrastPreferenceControllerTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PREFERENCE_KEY = "preference_key";
private Context mContext;
private ContrastPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new ContrastPreferenceController(mContext, PREFERENCE_KEY);
}
@Test
public void getAvailabilityStatus_flagsEnabled_shouldReturnAvailable() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_COLOR_CONTRAST_CONTROL);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_flagsDisabled_shouldReturnUnsupported() {
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_COLOR_CONTRAST_CONTROL);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2024 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.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.UiModeManager;
import android.content.Context;
import android.widget.FrameLayout;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.widget.LayoutPreference;
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 java.util.concurrent.Executor;
/** Tests for {@link ContrastSelectorPreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class ContrastSelectorPreferenceControllerTest {
private static final String PREFERENCE_KEY = "color_contrast_selector";
@Mock
private UiModeManager mUiService;
@Mock
private Executor mExecutor;
@Mock
private PreferenceScreen mScreen;
@Mock
private FrameLayout mFrameLayout;
@Mock
private LayoutPreference mLayoutPreference;
private Context mContext;
private ContrastSelectorPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getMainExecutor()).thenReturn(mExecutor);
when(mContext.getSystemService(UiModeManager.class)).thenReturn(mUiService);
mController = new ContrastSelectorPreferenceController(mContext, PREFERENCE_KEY);
when(mScreen.findPreference(PREFERENCE_KEY)).thenReturn(mLayoutPreference);
when(mLayoutPreference.findViewById(anyInt())).thenReturn(mFrameLayout);
}
@Test
public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void onStart_shouldAddContrastListener() {
mController.displayPreference(mScreen);
mController.onStart();
verify(mUiService).addContrastChangeListener(mExecutor, mController);
}
@Test
public void onStop_shouldRemoveContrastListener() {
mController.displayPreference(mScreen);
mController.onStart();
mController.onStop();
verify(mUiService).removeContrastChangeListener(mController);
}
@Test
public void displayPreference_shouldAddClickListener() {
mController.displayPreference(mScreen);
verify(mFrameLayout, times(3)).setOnClickListener(any());
}
@Test
public void onContrastChanged_buttonShouldBeSelected() {
mController.displayPreference(mScreen);
mController.onContrastChanged(1);
verify(mFrameLayout, times(2)).setSelected(true);
}
}

View File

@@ -138,7 +138,7 @@ public class HearingAidPairingDialogFragmentTest {
final Intent intent = shadowOf(mActivity).getNextStartedActivity();
assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(HearingDevicePairingDetail.class.getName());
.isEqualTo(HearingDevicePairingFragment.class.getName());
}
@Test

View File

@@ -1,115 +0,0 @@
/*
* Copyright (C) 2023 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.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.bluetooth.BluetoothProgressCategory;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
/** Tests for {@link HearingDevicePairingDetail}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
public class HearingDevicePairingDetailTest {
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
private final Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private CachedBluetoothDevice mCachedBluetoothDevice;
private BluetoothProgressCategory mProgressCategory;
private TestHearingDevicePairingDetail mFragment;
@Before
public void setUp() {
final BluetoothAdapter bluetoothAdapter = spy(BluetoothAdapter.getDefaultAdapter());
final ShadowBluetoothAdapter shadowBluetoothAdapter = Shadow.extract(
BluetoothAdapter.getDefaultAdapter());
shadowBluetoothAdapter.setEnabled(true);
mProgressCategory = spy(new BluetoothProgressCategory(mContext));
mFragment = spy(new TestHearingDevicePairingDetail());
when(mFragment.getContext()).thenReturn(mContext);
when(mFragment.findPreference(
HearingDevicePairingDetail.KEY_AVAILABLE_HEARING_DEVICES)).thenReturn(
mProgressCategory);
mFragment.setBluetoothAdapter(bluetoothAdapter);
}
@Test
public void getDeviceListKey_expectedKey() {
assertThat(mFragment.getDeviceListKey()).isEqualTo(
HearingDevicePairingDetail.KEY_AVAILABLE_HEARING_DEVICES);
}
@Test
public void onDeviceBondStateChanged_bondNone_setProgressFalse() {
mFragment.initPreferencesFromPreferenceScreen();
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
verify(mProgressCategory).setProgress(true);
}
@Test
public void onDeviceBondStateChanged_bonding_setProgressTrue() {
mFragment.initPreferencesFromPreferenceScreen();
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
verify(mProgressCategory).setProgress(false);
}
private static class TestHearingDevicePairingDetail extends HearingDevicePairingDetail {
TestHearingDevicePairingDetail() {
super();
}
public void setBluetoothAdapter(BluetoothAdapter bluetoothAdapter) {
this.mBluetoothAdapter = bluetoothAdapter;
}
public void enableScanning() {
super.enableScanning();
}
}
}

View File

@@ -0,0 +1,318 @@
/*
* Copyright (C) 2023 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.accessibility;
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.never;
import static org.mockito.Mockito.verify;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.Pair;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.bluetooth.BluetoothDevicePreference;
import com.android.settings.bluetooth.BluetoothProgressCategory;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.List;
/** Tests for {@link HearingDevicePairingFragment}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
public class HearingDevicePairingFragmentTest {
private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Spy
private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
@Spy
private final HearingDevicePairingFragment mFragment = new TestHearingDevicePairingFragment();
@Mock
private LocalBluetoothManager mLocalManager;
@Mock
private CachedBluetoothDeviceManager mCachedDeviceManager;
@Mock
private CachedBluetoothDevice mCachedDevice;
@Mock
private BluetoothProgressCategory mAvailableHearingDeviceGroup;
private final Context mContext = ApplicationProvider.getApplicationContext();
private BluetoothDevice mDevice;
private BluetoothDevicePreference mDevicePreference;
@Before
public void setUp() {
mFragment.mLocalManager = mLocalManager;
mFragment.mCachedDeviceManager = mCachedDeviceManager;
mFragment.mBluetoothAdapter = mBluetoothAdapter;
doReturn(mContext).when(mFragment).getContext();
doReturn(mAvailableHearingDeviceGroup).when(mFragment).findPreference(
"available_hearing_devices");
mFragment.initPreferencesFromPreferenceScreen();
mDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
doReturn(mDevice).when(mCachedDevice).getDevice();
final Pair<Drawable, String> pair = new Pair<>(mock(Drawable.class), "test_device");
doReturn(pair).when(mCachedDevice).getDrawableWithDescription();
mDevicePreference = new BluetoothDevicePreference(mContext, mCachedDevice, true,
BluetoothDevicePreference.SortType.TYPE_DEFAULT);
}
@Test
public void startAndStopScanning_stateIsCorrect() {
mFragment.startScanning();
verify(mFragment).startLeScanning();
mFragment.stopScanning();
verify(mFragment).stopLeScanning();
}
@Test
public void onDeviceDeleted_stateIsCorrect() {
mFragment.mDevicePreferenceMap.put(mCachedDevice, mDevicePreference);
assertThat(mFragment.mDevicePreferenceMap).isNotEmpty();
mFragment.onDeviceDeleted(mCachedDevice);
assertThat(mFragment.mDevicePreferenceMap).isEmpty();
verify(mAvailableHearingDeviceGroup).removePreference(mDevicePreference);
}
@Test
public void addDevice_bluetoothOff_doNothing() {
doReturn(BluetoothAdapter.STATE_OFF).when(mBluetoothAdapter).getState();
assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(0);
mFragment.addDevice(mCachedDevice);
verify(mAvailableHearingDeviceGroup, never()).addPreference(mDevicePreference);
assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(0);
}
@Test
public void addDevice_addToAvailableHearingDeviceGroup() {
doReturn(BluetoothAdapter.STATE_ON).when(mBluetoothAdapter).getState();
assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(0);
mFragment.addDevice(mCachedDevice);
verify(mAvailableHearingDeviceGroup).addPreference(mDevicePreference);
assertThat(mFragment.mDevicePreferenceMap.size()).isEqualTo(1);
}
@Test
public void handleLeScanResult_markDeviceAsHearingAid() {
ScanResult scanResult = mock(ScanResult.class);
doReturn(mDevice).when(scanResult).getDevice();
doReturn(mCachedDevice).when(mCachedDeviceManager).findDevice(mDevice);
mFragment.handleLeScanResult(scanResult);
verify(mCachedDevice).setHearingAidInfo(new HearingAidInfo.Builder().build());
}
@Test
public void handleLeScanResult_isAndroidCompatible_addDevice() {
ScanResult scanResult = mock(ScanResult.class);
doReturn(mDevice).when(scanResult).getDevice();
doReturn(mCachedDevice).when(mCachedDeviceManager).findDevice(mDevice);
doReturn(true).when(mFragment).isAndroidCompatibleHearingAid(scanResult);
mFragment.handleLeScanResult(scanResult);
verify(mFragment).addDevice(mCachedDevice);
}
@Test
public void handleLeScanResult_isNotAndroidCompatible_() {
ScanResult scanResult = mock(ScanResult.class);
doReturn(mDevice).when(scanResult).getDevice();
doReturn(mCachedDevice).when(mCachedDeviceManager).findDevice(mDevice);
doReturn(false).when(mFragment).isAndroidCompatibleHearingAid(scanResult);
mFragment.handleLeScanResult(scanResult);
verify(mFragment).discoverServices(mCachedDevice);
}
@Test
public void onProfileConnectionStateChanged_deviceConnected_inSelectedList_finish() {
doReturn(true).when(mCachedDevice).isConnected();
mFragment.mSelectedDeviceList.add(mDevice);
mFragment.onProfileConnectionStateChanged(mCachedDevice, BluetoothAdapter.STATE_CONNECTED,
BluetoothProfile.A2DP);
verify(mFragment).finish();
}
@Test
public void onProfileConnectionStateChanged_deviceConnected_notInSelectedList_deleteDevice() {
doReturn(true).when(mCachedDevice).isConnected();
mFragment.onProfileConnectionStateChanged(mCachedDevice, BluetoothAdapter.STATE_CONNECTED,
BluetoothProfile.A2DP);
verify(mFragment).removeDevice(mCachedDevice);
}
@Test
public void onProfileConnectionStateChanged_deviceNotConnected_doNothing() {
doReturn(false).when(mCachedDevice).isConnected();
mFragment.onProfileConnectionStateChanged(mCachedDevice, BluetoothAdapter.STATE_CONNECTED,
BluetoothProfile.A2DP);
verify(mFragment, never()).finish();
verify(mFragment, never()).removeDevice(mCachedDevice);
}
@Test
public void onBluetoothStateChanged_stateOn_startScanningAndShowToast() {
mFragment.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
verify(mFragment).startScanning();
verify(mFragment).showBluetoothTurnedOnToast();
}
@Test
public void onBluetoothStateChanged_stateOff_finish() {
mFragment.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
verify(mFragment).finish();
}
@Test
public void onDeviceBondStateChanged_bonded_finish() {
mFragment.onDeviceBondStateChanged(mCachedDevice, BluetoothDevice.BOND_BONDED);
verify(mFragment).finish();
}
@Test
public void onDeviceBondStateChanged_selectedDeviceNotBonded_startScanning() {
mFragment.mSelectedDevice = mDevice;
mFragment.onDeviceBondStateChanged(mCachedDevice, BluetoothDevice.BOND_NONE);
verify(mFragment).startScanning();
}
@Test
public void isAndroidCompatibleHearingAid_asha_returnTrue() {
ScanResult scanResult = createAshaScanResult();
boolean isCompatible = mFragment.isAndroidCompatibleHearingAid(scanResult);
assertThat(isCompatible).isTrue();
}
@Test
public void isAndroidCompatibleHearingAid_has_returnTrue() {
ScanResult scanResult = createHasScanResult();
boolean isCompatible = mFragment.isAndroidCompatibleHearingAid(scanResult);
assertThat(isCompatible).isTrue();
}
@Test
public void isAndroidCompatibleHearingAid_mfiHas_returnFalse() {
ScanResult scanResult = createMfiHasScanResult();
boolean isCompatible = mFragment.isAndroidCompatibleHearingAid(scanResult);
assertThat(isCompatible).isFalse();
}
private ScanResult createAshaScanResult() {
ScanResult scanResult = mock(ScanResult.class);
ScanRecord scanRecord = mock(ScanRecord.class);
byte[] fakeAshaServiceData = new byte[] {
0x09, 0x16, (byte) 0xf0, (byte) 0xfd, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04};
doReturn(scanRecord).when(scanResult).getScanRecord();
doReturn(fakeAshaServiceData).when(scanRecord).getServiceData(BluetoothUuid.HEARING_AID);
return scanResult;
}
private ScanResult createHasScanResult() {
ScanResult scanResult = mock(ScanResult.class);
ScanRecord scanRecord = mock(ScanRecord.class);
doReturn(scanRecord).when(scanResult).getScanRecord();
doReturn(List.of(BluetoothUuid.HAS)).when(scanRecord).getServiceUuids();
return scanResult;
}
private ScanResult createMfiHasScanResult() {
ScanResult scanResult = mock(ScanResult.class);
ScanRecord scanRecord = mock(ScanRecord.class);
byte[] fakeMfiServiceData = new byte[] {0x00, 0x00, 0x00, 0x00};
doReturn(scanRecord).when(scanResult).getScanRecord();
doReturn(fakeMfiServiceData).when(scanRecord).getServiceData(BluetoothUuid.MFI_HAS);
return scanResult;
}
private class TestHearingDevicePairingFragment extends HearingDevicePairingFragment {
@Override
protected Preference getCachedPreference(String key) {
if (key.equals(TEST_DEVICE_ADDRESS)) {
return mDevicePreference;
}
return super.getCachedPreference(key);
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2024 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.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class KeyboardBounceKeyPreferenceControllerTest {
private static final String KEY_ACCESSIBILITY_BOUNCE_KEYS =
Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS;
private static final int UNKNOWN = -1;
private final Context mContext = ApplicationProvider.getApplicationContext();
private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
private final KeyboardBounceKeyPreferenceController mController =
new KeyboardBounceKeyPreferenceController(mContext,
KeyboardBounceKeyPreferenceController.PREF_KEY);
@Before
public void setUp() {
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
mSwitchPreference.setKey(KeyboardBounceKeyPreferenceController.PREF_KEY);
screen.addPreference(mSwitchPreference);
mController.displayPreference(screen);
}
@Test
public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void isChecked_disableBounceKey_onResumeShouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, OFF);
mController.updateState(mSwitchPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mSwitchPreference.isChecked()).isFalse();
}
@Test
public void isChecked_enableBounceKey_onResumeShouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, ON);
mController.updateState(mSwitchPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mSwitchPreference.isChecked()).isTrue();
}
@Test
public void performClick_enableBounceKey_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, OFF);
mController.updateState(mSwitchPreference);
mSwitchPreference.performClick();
verify(mSwitchPreference).setChecked(true);
assertThat(mController.isChecked()).isTrue();
assertThat(mSwitchPreference.isChecked()).isTrue();
}
@Test
public void performClick_disableBounceKey_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, ON);
mController.updateState(mSwitchPreference);
mSwitchPreference.performClick();
verify(mSwitchPreference).setChecked(false);
assertThat(mController.isChecked()).isFalse();
assertThat(mSwitchPreference.isChecked()).isFalse();
}
@Test
public void setChecked_setFalse_shouldDisableBounceKey() {
mController.setChecked(false);
assertThat(Settings.Secure.getInt(
mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS, UNKNOWN)).isEqualTo(
OFF);
}
@Test
public void setChecked_setTrue_shouldEnableBounceKey() {
mController.setChecked(true);
assertThat(Settings.Secure.getInt(
mContext.getContentResolver(), KEY_ACCESSIBILITY_BOUNCE_KEYS,
UNKNOWN)).isNotEqualTo(OFF);
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2024 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.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class KeyboardSlowKeyPreferenceControllerTest {
private static final String KEY_ACCESSIBILITY_SLOW_KEYS =
Settings.Secure.ACCESSIBILITY_SLOW_KEYS;
private static final int UNKNOWN = -1;
private final Context mContext = ApplicationProvider.getApplicationContext();
private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
private final KeyboardSlowKeyPreferenceController mController =
new KeyboardSlowKeyPreferenceController(mContext,
KeyboardSlowKeyPreferenceController.PREF_KEY);
@Before
public void setUp() {
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
mSwitchPreference.setKey(KeyboardSlowKeyPreferenceController.PREF_KEY);
screen.addPreference(mSwitchPreference);
mController.displayPreference(screen);
}
@Test
public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void isChecked_disableSlowKey_onResumeShouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, OFF);
mController.updateState(mSwitchPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mSwitchPreference.isChecked()).isFalse();
}
@Test
public void isChecked_enableSlowKey_onResumeShouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, ON);
mController.updateState(mSwitchPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mSwitchPreference.isChecked()).isTrue();
}
@Test
public void performClick_enableSlowKey_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, OFF);
mController.updateState(mSwitchPreference);
mSwitchPreference.performClick();
verify(mSwitchPreference).setChecked(true);
assertThat(mController.isChecked()).isTrue();
assertThat(mSwitchPreference.isChecked()).isTrue();
}
@Test
public void performClick_disableSlowKey_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, ON);
mController.updateState(mSwitchPreference);
mSwitchPreference.performClick();
verify(mSwitchPreference).setChecked(false);
assertThat(mController.isChecked()).isFalse();
assertThat(mSwitchPreference.isChecked()).isFalse();
}
@Test
public void setChecked_setFalse_shouldDisableSlowKey() {
mController.setChecked(false);
assertThat(Settings.Secure.getInt(
mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, UNKNOWN)).isEqualTo(
OFF);
}
@Test
public void setChecked_setTrue_shouldEnableSlowKey() {
mController.setChecked(true);
assertThat(Settings.Secure.getInt(
mContext.getContentResolver(), KEY_ACCESSIBILITY_SLOW_KEYS, UNKNOWN)).isNotEqualTo(
OFF);
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2024 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.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class KeyboardStickyKeyPreferenceControllerTest {
private static final String KEY_ACCESSIBILITY_STICKY_KEYS =
Settings.Secure.ACCESSIBILITY_STICKY_KEYS;
private static final int UNKNOWN = -1;
private final Context mContext = ApplicationProvider.getApplicationContext();
private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
private final KeyboardStickyKeyPreferenceController mController =
new KeyboardStickyKeyPreferenceController(mContext,
KeyboardStickyKeyPreferenceController.PREF_KEY);
@Before
public void setUp() {
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
mSwitchPreference.setKey(KeyboardStickyKeyPreferenceController.PREF_KEY);
screen.addPreference(mSwitchPreference);
mController.displayPreference(screen);
}
@Test
public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void isChecked_disableStickyKey_onResumeShouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, OFF);
mController.updateState(mSwitchPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mSwitchPreference.isChecked()).isFalse();
}
@Test
public void isChecked_enableStickyKey_onResumeShouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, ON);
mController.updateState(mSwitchPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mSwitchPreference.isChecked()).isTrue();
}
@Test
public void performClick_enableStickyKey_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, OFF);
mController.updateState(mSwitchPreference);
mSwitchPreference.performClick();
verify(mSwitchPreference).setChecked(true);
assertThat(mController.isChecked()).isTrue();
assertThat(mSwitchPreference.isChecked()).isTrue();
}
@Test
public void performClick_disableStickyKey_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, ON);
mController.updateState(mSwitchPreference);
mSwitchPreference.performClick();
verify(mSwitchPreference).setChecked(false);
assertThat(mController.isChecked()).isFalse();
assertThat(mSwitchPreference.isChecked()).isFalse();
}
@Test
public void setChecked_setFalse_shouldDisableStickyKey() {
mController.setChecked(false);
assertThat(Settings.Secure.getInt(
mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, UNKNOWN)).isEqualTo(OFF);
}
@Test
public void setChecked_setTrue_shouldEnableStickyKey() {
mController.setChecked(true);
assertThat(Settings.Secure.getInt(
mContext.getContentResolver(), KEY_ACCESSIBILITY_STICKY_KEYS, UNKNOWN)).isEqualTo(ON);
}
}

View File

@@ -23,9 +23,13 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.res.Resources;
import android.os.vibrator.Flags;
@@ -37,6 +41,7 @@ import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.Rule;
@@ -49,7 +54,6 @@ import org.robolectric.RobolectricTestRunner;
/** Tests for {@link KeyboardVibrationTogglePreferenceController}. */
@RunWith(RobolectricTestRunner.class)
public class KeyboardVibrationTogglePreferenceControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -59,8 +63,8 @@ public class KeyboardVibrationTogglePreferenceControllerTest {
private Context mContext;
private Resources mResources;
private KeyboardVibrationTogglePreferenceController mController;
private SwitchPreference mPreference;
private FakeFeatureFactory mFeatureFactory;
@Before
public void setUp() {
@@ -68,6 +72,7 @@ public class KeyboardVibrationTogglePreferenceControllerTest {
mContext = spy(ApplicationProvider.getApplicationContext());
mResources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(mResources);
mFeatureFactory = FakeFeatureFactory.setupForTest();
mController = new KeyboardVibrationTogglePreferenceController(mContext, "preferenceKey");
mPreference = new SwitchPreference(mContext);
when(mPreferenceScreen.findPreference(
@@ -148,6 +153,8 @@ public class KeyboardVibrationTogglePreferenceControllerTest {
mController.setChecked(true);
assertThat(readSystemSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED)).isEqualTo(ON);
verify(mFeatureFactory.metricsFeatureProvider).action(any(),
eq(SettingsEnums.ACTION_KEYBOARD_VIBRATION_CHANGED), eq(true));
}
@Test
@@ -160,6 +167,8 @@ public class KeyboardVibrationTogglePreferenceControllerTest {
mController.setChecked(false);
assertThat(readSystemSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED)).isEqualTo(OFF);
verify(mFeatureFactory.metricsFeatureProvider).action(any(),
eq(SettingsEnums.ACTION_KEYBOARD_VIBRATION_CHANGED), eq(false));
}
private void updateSystemSetting(String key, int value) {

View File

@@ -31,9 +31,14 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
import org.junit.Rule;
@@ -45,6 +50,7 @@ import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
@@ -53,6 +59,9 @@ import java.util.List;
/** Test for {@link RestrictedPreferenceHelper}. */
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowRestrictedLockUtilsInternal.class
})
public class RestrictedPreferenceHelperTest {
private static final String PACKAGE_NAME = "com.android.test";
@@ -72,6 +81,11 @@ public class RestrictedPreferenceHelperTest {
private AccessibilityShortcutInfo mShortcutInfo;
private final RestrictedPreferenceHelper mHelper = new RestrictedPreferenceHelper(mContext);
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Test
public void createAccessibilityServicePreferenceList_hasOneInfo_containsSameKey() {
final String key = COMPONENT_NAME.flattenToString();
@@ -85,6 +99,37 @@ public class RestrictedPreferenceHelperTest {
assertThat(preference.getKey()).isEqualTo(key);
}
@Test
@RequiresFlagsEnabled(value = {android.security.Flags.FLAG_EXTEND_ECM_TO_ALL_SETTINGS,
android.permission.flags.Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED})
public void createAccessibilityServicePreferenceList_ecmRestricted_prefIsEcmRestricted() {
ShadowRestrictedLockUtilsInternal.setEcmRestrictedPkgs(
mServiceInfo.getResolveInfo().serviceInfo.packageName);
final List<AccessibilityServiceInfo> infoList = new ArrayList<>(
singletonList(mServiceInfo));
final List<RestrictedPreference> preferenceList =
mHelper.createAccessibilityServicePreferenceList(infoList);
final RestrictedPreference preference = preferenceList.get(0);
assertThat(preference.isDisabledByEcm()).isTrue();
}
@Test
@RequiresFlagsEnabled(value = {android.security.Flags.FLAG_EXTEND_ECM_TO_ALL_SETTINGS,
android.permission.flags.Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED})
public void createAccessibilityServicePreferenceList_ecmNotRestricted_prefIsNotEcmRestricted() {
ShadowRestrictedLockUtilsInternal.setEcmRestrictedPkgs();
final List<AccessibilityServiceInfo> infoList = new ArrayList<>(
singletonList(mServiceInfo));
final List<RestrictedPreference> preferenceList =
mHelper.createAccessibilityServicePreferenceList(infoList);
final RestrictedPreference preference = preferenceList.get(0);
assertThat(preference.isDisabledByEcm()).isFalse();
}
@Test
public void createAccessibilityActivityPreferenceList_hasOneInfo_containsSameKey() {
final String key = COMPONENT_NAME.flattenToString();

View File

@@ -19,12 +19,13 @@ package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +34,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -40,12 +42,15 @@ import android.service.quicksettings.TileService;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.Flags;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
import com.android.settings.widget.SettingsMainSwitchPreference;
import org.junit.Before;
@@ -53,6 +58,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@@ -298,7 +304,9 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
@Test
@RequiresFlagsEnabled(Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG)
public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning()
@RequiresFlagsDisabled(
com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN)
public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_showDialog()
throws Throwable {
setupServiceWarningRequired(false);
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null);
@@ -309,6 +317,23 @@ public class ToggleAccessibilityServicePreferenceFragmentTest {
AccessibilityDialogUtils.DialogEnums.EDIT_SHORTCUT);
}
@Test
@RequiresFlagsEnabled({Flags.FLAG_CLEANUP_ACCESSIBILITY_WARNING_DIALOG,
com.android.settings.accessibility.Flags.FLAG_EDIT_SHORTCUTS_IN_FULL_SCREEN})
public void clickShortcutSettingsPreference_warningNotRequired_dontShowWarning_launchActivity()
throws Throwable {
setupServiceWarningRequired(false);
mFragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */null);
doNothing().when(mContext).startActivity(any());
mFragment.onSettingsClicked(mFragment.mShortcutPreference);
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).startActivity(captor.capture());
assertThat(captor.getValue().getExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(EditShortcutsPreferenceFragment.class.getName());
}
private void setupTileService(String packageName, String name, String tileName) {
final Intent tileProbe = new Intent(TileService.ACTION_QS_TILE);
final ResolveInfo info = new ResolveInfo();

View File

@@ -169,7 +169,7 @@ public class ToggleFeaturePreferenceFragmentTest {
mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
mFragment.mComponentName.flattenToString());
// Compare to default UserShortcutType
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE);
}
@@ -185,7 +185,7 @@ public class ToggleFeaturePreferenceFragmentTest {
mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
mFragment.mComponentName.flattenToString());
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
}
@@ -199,7 +199,7 @@ public class ToggleFeaturePreferenceFragmentTest {
mFragment.updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
mFragment.mComponentName.flattenToString());
assertThat(expectedType).isEqualTo(UserShortcutType.HARDWARE);
}
@@ -281,7 +281,7 @@ public class ToggleFeaturePreferenceFragmentTest {
mFragment.saveNonEmptyUserShortcutType(value);
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE);
mFragment.mComponentName.flattenToString());
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE);
}

View File

@@ -374,7 +374,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest {
mFragController.get().updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
MAGNIFICATION_CONTROLLER_NAME);
// Compare to default UserShortcutType
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE);
}
@@ -388,7 +388,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest {
mFragController.get().updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
MAGNIFICATION_CONTROLLER_NAME);
assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.TRIPLETAP);
}
@@ -402,7 +402,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest {
mFragController.get().updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
MAGNIFICATION_CONTROLLER_NAME);
assertThat(expectedType).isEqualTo(UserShortcutType.TRIPLETAP);
}
@@ -416,7 +416,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest {
mFragController.get().updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
MAGNIFICATION_CONTROLLER_NAME);
assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP);
}
@@ -431,7 +431,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest {
mFragController.get().updateShortcutPreferenceData();
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
MAGNIFICATION_CONTROLLER_NAME);
assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP);
}
@@ -507,7 +507,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest {
fragment.saveNonEmptyUserShortcutType(value);
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
MAGNIFICATION_CONTROLLER_NAME);
assertThat(value).isEqualTo(6);
assertThat(expectedType).isEqualTo(UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP);
}
@@ -529,7 +529,7 @@ public class ToggleScreenMagnificationPreferenceFragmentTest {
fragment.saveNonEmptyUserShortcutType(value);
final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE);
MAGNIFICATION_CONTROLLER_NAME);
assertThat(value).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP);
assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGERTRIPLETAP);
}

View File

@@ -56,7 +56,7 @@ public class ViewAllBluetoothDevicesPreferenceControllerTest {
private final String TEST_KEY = "test_key";
@Spy
private HearingDevicePairingDetail mFragment = new HearingDevicePairingDetail();
private HearingDevicePairingFragment mFragment = new HearingDevicePairingFragment();
private FragmentActivity mActivity;
@Mock
private PreferenceScreen mScreen;
@@ -74,13 +74,13 @@ public class ViewAllBluetoothDevicesPreferenceControllerTest {
}
@Test
public void handlePreferenceTreeClick_expectedPreference_launchBluetoothPairingDetail() {
doNothing().when(mController).launchBluetoothPairingDetail();
public void handlePreferenceTreeClick_expectedPreference_launchConnectedDevicePage() {
doNothing().when(mController).launchConnectedDevicePage();
mPreference.setKey(TEST_KEY);
boolean status = mController.handlePreferenceTreeClick(mPreference);
verify(mController).launchBluetoothPairingDetail();
verify(mController).launchConnectedDevicePage();
assertThat(status).isTrue();
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Set;
/**
* Tests for {@link AdvancedShortcutsPreferenceController}
*/
@RunWith(RobolectricTestRunner.class)
public class AdvancedShortcutsPreferenceControllerTest {
private static final String PREF_KEY = "prefKey";
private static final String TARGET_MAGNIFICATION =
"com.android.server.accessibility.MagnificationController";
private static final String TARGET_FAKE =
new ComponentName("FakePackage", "FakeClass").flattenToString();
private final Context mContext = ApplicationProvider.getApplicationContext();
private AdvancedShortcutsPreferenceController mController;
@Before
public void setUp() {
mController = new AdvancedShortcutsPreferenceController(mContext, PREF_KEY);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
Preference preference = new Preference(mContext);
preference.setKey(PREF_KEY);
PreferenceScreen preferenceScreen =
new PreferenceManager(mContext).createPreferenceScreen(mContext);
preferenceScreen.addPreference(preference);
}
@Test
public void getAvailabilityStatus_targetIsMagnificationAndIsExpanded_returnsConditionallyUnavailable() {
mController.setExpanded(true);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_targetIsMagnificationAndIsNotExpanded_returnsAvailableUnsearchable() {
mController.setExpanded(false);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
}
@Test
public void getAvailabilityStatus_targetIsNotMagnificationAndIsNotExpanded_returnsConditionallyUnavailable() {
mController.setExpanded(false);
mController.setShortcutTargets(Set.of(TARGET_FAKE));
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_targetIsNotMagnificationAndIsExpanded_returnsConditionallyUnavailable() {
mController.setExpanded(true);
mController.setShortcutTargets(Set.of(TARGET_FAKE));
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void setExpanded_expand_updateExpandedValue() {
mController.setExpanded(true);
assertThat(mController.isExpanded()).isTrue();
}
@Test
public void setExpanded_collapse_updateExpandedValue() {
mController.setExpanded(false);
assertThat(mController.isExpanded()).isFalse();
}
@Test
public void isShortcutAvailable_multipleTargets_returnFalse() {
mController.setShortcutTargets(Set.of(TARGET_FAKE, TARGET_MAGNIFICATION));
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isShortcutAvailable_magnificationTargetOnly_returnTrue() {
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
assertThat(mController.isShortcutAvailable()).isTrue();
}
@Test
public void isShortcutAvailable_nonMagnificationTarget_returnFalse() {
mController.setShortcutTargets(Set.of(TARGET_FAKE));
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isChecked_returnFalse() {
assertThat(mController.isChecked()).isFalse();
}
}

View File

@@ -0,0 +1,556 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment.SHORTCUT_SETTINGS;
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_DEFERRED_SETUP;
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_FIRST_RUN;
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_PRE_DEFERRED_SETUP;
import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SETUP_FLOW;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.util.Pair;
import android.view.accessibility.AccessibilityManager;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.testing.FragmentScenario;
import androidx.lifecycle.Lifecycle;
import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings;
import com.android.settings.accessibility.AccessibilityUtil;
import com.android.settings.accessibility.PreferredShortcuts;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.android.setupcompat.util.WizardManagerHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowAccessibilityManager;
import org.robolectric.shadows.ShadowContentResolver;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* Tests for {@link EditShortcutsPreferenceFragment}
*/
@Config(shadows = SettingsShadowResources.class)
@RunWith(RobolectricTestRunner.class)
public class EditShortcutsPreferenceFragmentTest {
private static final int METRICS_CATEGORY = 123;
private static final CharSequence SCREEN_TITLE = "Fake shortcut title";
private static final ComponentName TARGET_FAKE_COMPONENT =
new ComponentName("FakePackage", "FakeClass");
private static final String TARGET = MAGNIFICATION_CONTROLLER_NAME;
private static final Set<String> TARGETS = Set.of(TARGET);
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private final Context mContext = ApplicationProvider.getApplicationContext();
private FragmentActivity mActivity;
private FragmentScenario<EditShortcutsPreferenceFragment> mFragmentScenario;
@Before
public void setUp() {
SettingsShadowResources.overrideResource(
com.android.internal.R.integer.config_navBarInteractionMode,
NAV_BAR_MODE_GESTURAL);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE);
mActivity = Robolectric.buildActivity(FragmentActivity.class).get();
}
@After
public void cleanUp() {
if (mFragmentScenario != null) {
mFragmentScenario.close();
}
}
@Test
public void showEditShortcutScreen_targetIsMagnification_launchSubSetting() {
EditShortcutsPreferenceFragment.showEditShortcutScreen(
mActivity, METRICS_CATEGORY, SCREEN_TITLE,
MAGNIFICATION_COMPONENT_NAME, /* fromIntent= */ null);
assertLaunchSubSettingWithCurrentTargetComponents(
MAGNIFICATION_CONTROLLER_NAME, /* isInSuw= */ false);
}
@Test
public void showEditShortcutScreen_launchSubSetting() {
EditShortcutsPreferenceFragment.showEditShortcutScreen(
mActivity, METRICS_CATEGORY, SCREEN_TITLE,
TARGET_FAKE_COMPONENT, /* fromIntent= */ null);
assertLaunchSubSettingWithCurrentTargetComponents(
TARGET_FAKE_COMPONENT.flattenToString(), /* isInSuw= */ false);
}
@Test
public void showEditShortcutScreen_inSuw_launchSubSettingWithSuw() {
EditShortcutsPreferenceFragment.showEditShortcutScreen(
mActivity, METRICS_CATEGORY, SCREEN_TITLE,
TARGET_FAKE_COMPONENT, createSuwIntent(new Intent(), /* isInSuw= */ true));
assertLaunchSubSettingWithCurrentTargetComponents(
TARGET_FAKE_COMPONENT.flattenToString(), /* isInSuw= */ true);
}
@Test
public void fragmentCreated_inSuw_controllersTargetsSet() {
mFragmentScenario = createFragScenario(/* isInSuw= */ true);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
mFragmentScenario.onFragment(fragment -> {
List<ShortcutOptionPreferenceController> controllers =
getShortcutOptionPreferenceControllers(fragment);
for (ShortcutOptionPreferenceController controller : controllers) {
assertThat(controller.getShortcutTargets()).containsExactlyElementsIn(TARGETS);
assertThat(controller.isInSetupWizard()).isTrue();
}
});
}
@Test
public void fragmentCreated_notInSuw_controllersTargetsSet() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
mFragmentScenario.onFragment(fragment -> {
List<ShortcutOptionPreferenceController> controllers =
getShortcutOptionPreferenceControllers(fragment);
for (ShortcutOptionPreferenceController controller : controllers) {
assertThat(controller.getShortcutTargets()).containsExactlyElementsIn(TARGETS);
assertThat(controller.isInSetupWizard()).isFalse();
}
});
}
@Test
public void fragmentCreated_settingsObserversAreRegistered() {
ShadowContentResolver contentResolver = shadowOf(mContext.getContentResolver());
for (Uri uri : SHORTCUT_SETTINGS) {
assertThat(contentResolver.getContentObservers(uri)).isEmpty();
}
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
for (Uri uri : SHORTCUT_SETTINGS) {
assertThat(contentResolver.getContentObservers(uri)).isNotEmpty();
}
}
@Test
public void fragmentDestroyed_unregisterSettingsObserver() {
ShadowContentResolver contentResolver = shadowOf(mContext.getContentResolver());
mFragmentScenario = createFragScenario(/* isInSuw= */ false)
.moveToState(Lifecycle.State.CREATED);
mFragmentScenario.onFragment(EditShortcutsPreferenceFragment::onDestroy);
for (Uri uri : SHORTCUT_SETTINGS) {
assertThat(contentResolver.getContentObservers(uri)).isEmpty();
}
}
@Test
public void onVolumeKeysShortcutSettingChanged_volumeKeyControllerUpdated() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
ShortcutUtils.optInValueToSettings(
mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET);
mFragmentScenario.onFragment(fragment -> {
TwoStatePreference preference = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcut_volume_keys_pref));
assertThat(preference.isChecked()).isTrue();
});
}
@Test
public void onSoftwareShortcutSettingChanged_softwareControllersUpdated() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
ShortcutUtils.optInValueToSettings(
mContext, ShortcutConstants.UserShortcutType.SOFTWARE, TARGET);
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
mFragmentScenario.onFragment(fragment -> {
TwoStatePreference preference = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcut_gesture_pref));
assertThat(preference.isChecked()).isTrue();
});
}
@Test
public void onSoftwareShortcutModeChanged_softwareControllersUpdated() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
ShortcutUtils.optInValueToSettings(
mContext, ShortcutConstants.UserShortcutType.SOFTWARE, TARGET);
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
mFragmentScenario.onFragment(fragment -> {
TwoStatePreference preference = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcut_gesture_pref));
assertThat(preference.isChecked()).isTrue();
});
}
@Test
public void onTripleTapShortcutSettingChanged_tripleTapShortcutControllerUpdated() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
Settings.Secure.putInt(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
AccessibilityUtil.State.ON);
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
mFragmentScenario.onFragment(fragment -> {
TwoStatePreference preference = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcut_triple_tap_pref));
assertThat(preference.isChecked()).isTrue();
});
}
@Test
public void onTwoFingersShortcutSettingChanged_twoFingersDoubleTapShortcutControllerUpdated() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
Settings.Secure.putInt(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
AccessibilityUtil.State.ON);
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
mFragmentScenario.onFragment(fragment -> {
TwoStatePreference preference = fragment.findPreference(
mContext.getString(
R.string.accessibility_shortcut_two_fingers_double_tap_pref));
assertThat(preference.isChecked()).isTrue();
});
}
@Test
public void fragmentResumed_enableTouchExploration_gestureShortcutOptionSummaryUpdated() {
String expectedSummary = mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_gesture_talkback)
+ "\n\n"
+ mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating);
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.RESUMED);
ShadowAccessibilityManager am = shadowOf(
mContext.getSystemService(AccessibilityManager.class));
am.setTouchExplorationEnabled(true);
mFragmentScenario.onFragment(fragment -> {
Preference preference = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcut_gesture_pref));
assertThat(preference.getSummary().toString()).isEqualTo(expectedSummary);
});
}
@Test
public void fragmentPaused_enableTouchExploration_gestureShortcutOptionSummaryNotUpdated() {
String expectedSummary = mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_gesture)
+ "\n\n"
+ mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating);
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.RESUMED).moveToState(Lifecycle.State.STARTED);
ShadowAccessibilityManager am = shadowOf(
mContext.getSystemService(AccessibilityManager.class));
am.setTouchExplorationEnabled(true);
mFragmentScenario.onFragment(fragment -> {
Preference preference = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcut_gesture_pref));
assertThat(preference.getSummary().toString()).isEqualTo(expectedSummary);
});
}
@Test
public void onAdvancedPreferenceClicked_advancedShouldBecomeInvisible() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.RESUMED);
mFragmentScenario.onFragment(fragment -> {
Preference advanced = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcuts_advanced_collapsed));
assertThat(advanced.isVisible()).isTrue();
fragment.onPreferenceTreeClick(advanced);
assertThat(advanced.isVisible()).isFalse();
});
}
@Test
public void fragmentRecreated_expanded_advancedRemainInvisible() {
onAdvancedPreferenceClicked_advancedShouldBecomeInvisible();
mFragmentScenario.recreate();
mFragmentScenario.onFragment(fragment -> {
Preference advanced = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcuts_advanced_collapsed));
assertThat(advanced.isVisible()).isFalse();
});
}
@Test
public void fragmentRecreated_collapsed_advancedRemainVisible() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.RESUMED);
mFragmentScenario.recreate();
mFragmentScenario.onFragment(fragment -> {
Preference advanced = fragment.findPreference(
mContext.getString(R.string.accessibility_shortcuts_advanced_collapsed));
assertThat(advanced.isVisible()).isTrue();
});
}
@Test
public void fragmentResumed_preferredShortcutsUpdated() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.RESUMED);
// Move the fragment to the background
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
assertThat(
PreferredShortcuts.retrieveUserShortcutType(
mContext, TARGET)
).isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE);
// Update the chosen shortcut type to Volume keys while the fragment is in the background
ShortcutUtils.optInValueToSettings(
mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET);
mFragmentScenario.moveToState(Lifecycle.State.RESUMED);
assertThat(
PreferredShortcuts.retrieveUserShortcutType(
mContext, TARGET)
).isEqualTo(ShortcutConstants.UserShortcutType.HARDWARE);
}
@Test
public void onVolumeKeysShortcutSettingChanged_preferredShortcutsUpdated() {
mFragmentScenario = createFragScenario(/* isInSuw= */ false);
mFragmentScenario.moveToState(Lifecycle.State.CREATED);
assertThat(
PreferredShortcuts.retrieveUserShortcutType(
mContext, TARGET)
).isEqualTo(ShortcutConstants.UserShortcutType.SOFTWARE);
ShortcutUtils.optInValueToSettings(
mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET);
// Calls onFragment so that the change to Setting is notified to its observer
mFragmentScenario.onFragment(fragment ->
assertThat(
PreferredShortcuts.retrieveUserShortcutType(
mContext, TARGET)
).isEqualTo(ShortcutConstants.UserShortcutType.HARDWARE)
);
}
@Test
public void findTitles_withSingleTarget_hasNullSubtitle() {
final String fake_label = "FAKE";
List<AccessibilityTarget> accessibilityTargets = List.of(
generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label));
Pair<String, String> titles = EditShortcutsPreferenceFragment
.getTitlesFromAccessibilityTargetList(
Set.of(TARGET_FAKE_COMPONENT.flattenToString()),
accessibilityTargets, mActivity.getResources()
);
assertThat(titles.first).isNotNull();
assertThat(titles.first).contains(fake_label);
assertThat(titles.second).isNull();
}
@Test
public void findTitles_withMoreTargets_hasSubtitle() {
final String fake_label = "FAKE";
final String magnification_label = "MAGNIFICATION";
List<AccessibilityTarget> accessibilityTargets = List.of(
generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label),
generateAccessibilityTargetMock(MAGNIFICATION_COMPONENT_NAME, magnification_label));
Pair<String, String> titles = EditShortcutsPreferenceFragment
.getTitlesFromAccessibilityTargetList(
Set.of(TARGET_FAKE_COMPONENT.flattenToString(),
MAGNIFICATION_COMPONENT_NAME.flattenToString()),
accessibilityTargets, mActivity.getResources()
);
assertThat(titles.first).isNotNull();
assertThat(titles.second).isNotNull();
assertThat(titles.second).contains(fake_label);
assertThat(titles.second).contains(magnification_label);
}
@Test
public void findTitles_targetMissing_labelNotInTitles() {
final String fake_label = "FAKE";
List<AccessibilityTarget> accessibilityTargets = List.of(
generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label));
assertThrows(IllegalStateException.class,
() -> EditShortcutsPreferenceFragment
.getTitlesFromAccessibilityTargetList(
Set.of(MAGNIFICATION_COMPONENT_NAME.flattenToString()),
accessibilityTargets, mActivity.getResources()
));
}
private void assertLaunchSubSettingWithCurrentTargetComponents(
String componentName, boolean isInSuw) {
Intent intent = shadowOf(mActivity.getApplication()).getNextStartedActivity();
assertThat(intent).isNotNull();
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN);
assertThat(intent.getComponent()).isEqualTo(
new ComponentName(mActivity, SubSettings.class));
assertThat(intent.getExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(EditShortcutsPreferenceFragment.class.getName());
assertThat(intent.getExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE))
.isEqualTo(SCREEN_TITLE.toString());
assertThat(intent.getExtra(
MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY)).isEqualTo(METRICS_CATEGORY);
Bundle args = (Bundle) intent.getExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
assertThat(args).isNotNull();
assertThat(Arrays.stream(args.getStringArray(
EditShortcutsPreferenceFragment.ARG_KEY_SHORTCUT_TARGETS)).toList())
.containsExactly(componentName);
assertThat(WizardManagerHelper.isAnySetupWizard(intent)).isEqualTo(isInSuw);
}
private List<ShortcutOptionPreferenceController> getShortcutOptionPreferenceControllers(
EditShortcutsPreferenceFragment fragment) {
Collection<List<AbstractPreferenceController>> controllers =
ReflectionHelpers.callInstanceMethod(fragment, "getPreferenceControllers");
List<ShortcutOptionPreferenceController> retControllers = new ArrayList<>();
controllers.stream().flatMap(Collection::stream)
.filter(controller -> controller instanceof ShortcutOptionPreferenceController)
.forEach(controller ->
retControllers.add((ShortcutOptionPreferenceController) controller));
return retControllers;
}
private FragmentScenario<EditShortcutsPreferenceFragment> createFragScenario(boolean isInSuw) {
Bundle args = new Bundle();
args.putStringArray(
EditShortcutsPreferenceFragment.ARG_KEY_SHORTCUT_TARGETS, new String[]{TARGET});
FragmentScenario<EditShortcutsPreferenceFragment> scenario =
FragmentScenario.launch(
EditShortcutsPreferenceFragment.class, args,
/* themeResId= */ 0, Lifecycle.State.INITIALIZED);
scenario.onFragment(fragment -> {
Intent intent = fragment.requireActivity().getIntent();
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, SCREEN_TITLE);
fragment.requireActivity().setIntent(createSuwIntent(intent, isInSuw));
// Since the fragment is attached before we have a chance
// to modify the activity's intent; initialize controllers again
fragment.initializePreferenceControllerArguments();
});
return scenario;
}
private Intent createSuwIntent(Intent intent, boolean isInSuw) {
if (intent == null) {
intent = new Intent();
}
intent.putExtra(EXTRA_IS_SETUP_FLOW, isInSuw);
intent.putExtra(EXTRA_IS_FIRST_RUN, isInSuw);
intent.putExtra(EXTRA_IS_PRE_DEFERRED_SETUP, isInSuw);
intent.putExtra(EXTRA_IS_DEFERRED_SETUP, isInSuw);
return intent;
}
private AccessibilityTarget generateAccessibilityTargetMock(
ComponentName componentName, String label) {
AccessibilityTarget target = mock(AccessibilityTarget.class);
when(target.getComponentName()).thenReturn(componentName);
when(target.getId()).thenReturn(componentName.flattenToString());
when(target.getLabel()).thenReturn(label);
return target;
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import android.provider.Settings;
import android.text.TextUtils;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Set;
/**
* Tests for {@link FloatingButtonShortcutOptionController}
*/
@RunWith(RobolectricTestRunner.class)
public class FloatingButtonShortcutOptionControllerTest {
private static final String PREF_KEY = "prefKey";
private static final String TARGET =
new ComponentName("FakePackage", "FakeClass").flattenToString();
private final Context mContext = ApplicationProvider.getApplicationContext();
private FloatingButtonShortcutOptionController mController;
private ShortcutOptionPreference mShortcutOptionPreference;
private PreferenceScreen mPreferenceScreen;
@Before
public void setUp() {
mController = new FloatingButtonShortcutOptionController(
mContext, PREF_KEY);
mController.setShortcutTargets(Set.of(TARGET));
mShortcutOptionPreference = new ShortcutOptionPreference(mContext);
mShortcutOptionPreference.setKey(PREF_KEY);
mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPreferenceScreen.addPreference(mShortcutOptionPreference);
setFloatingButtonEnabled(true);
}
@Test
public void displayPreference_verifyTitle() {
mController.displayPreference(mPreferenceScreen);
assertThat(mShortcutOptionPreference.getTitle().toString()).isEqualTo(
mContext.getString(R.string.accessibility_shortcut_edit_dialog_title_software));
}
@Test
public void getSummary_inSuw_verifySummaryEmpty() {
mController.setInSetupWizard(true);
assertThat(TextUtils.isEmpty(mController.getSummary())).isTrue();
}
@Test
public void getSummary_notInSuw_verifySummary() {
mController.setInSetupWizard(false);
assertThat(mController.getSummary().toString()).isEqualTo(
mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating));
}
@Test
public void isShortcutAvailable_floatingMenuEnabled_returnTrue() {
setFloatingButtonEnabled(true);
assertThat(mController.isShortcutAvailable()).isTrue();
}
@Test
public void isShortcutAvailable_floatingMenuDisabled_returnFalse() {
setFloatingButtonEnabled(false);
assertThat(mController.isShortcutAvailable()).isFalse();
}
private void setFloatingButtonEnabled(boolean enable) {
int mode = enable
? ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU : ACCESSIBILITY_BUTTON_MODE_GESTURE;
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, mode);
}
}

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.view.accessibility.AccessibilityManager;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.AccessibilityTestUtils;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.Set;
/**
* Tests for {@link GestureShortcutOptionController}
*/
@Config(shadows = SettingsShadowResources.class)
@RunWith(RobolectricTestRunner.class)
public class GestureShortcutOptionControllerTest {
private static final String PREF_KEY = "prefKey";
private static final String TARGET =
new ComponentName("FakePackage", "FakeClass").flattenToString();
private final Context mContext = spy(ApplicationProvider.getApplicationContext());
private GestureShortcutOptionController mController;
private ShortcutOptionPreference mShortcutOptionPreference;
private PreferenceScreen mPreferenceScreen;
@Before
public void setUp() {
mController = new GestureShortcutOptionController(
mContext, PREF_KEY);
mController.setShortcutTargets(Set.of(TARGET));
mShortcutOptionPreference = new ShortcutOptionPreference(mContext);
mShortcutOptionPreference.setKey(PREF_KEY);
mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPreferenceScreen.addPreference(mShortcutOptionPreference);
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ true, /* floatingButtonEnabled= */ false);
enableTouchExploration(false);
}
@Test
public void displayPreference_verifyTitle() {
mController.displayPreference(mPreferenceScreen);
assertThat(mShortcutOptionPreference.getTitle().toString()).isEqualTo(
mContext.getString(
R.string.accessibility_shortcut_edit_dialog_title_software_by_gesture));
}
@Test
public void getSummary_touchExplorationDisabled_verifySummary() {
enableTouchExploration(false);
String expected = mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_gesture)
+ "\n\n"
+ mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating);
assertThat(mController.getSummary().toString()).isEqualTo(expected);
}
@Test
public void getSummary_touchExplorationEnabled_verifySummary() {
enableTouchExploration(true);
String expected = mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_gesture_talkback)
+ "\n\n"
+ mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating);
assertThat(mController.getSummary().toString()).isEqualTo(expected);
}
@Test
public void isShortcutAvailable_inSuw_returnFalse() {
mController.setInSetupWizard(true);
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isShortcutAvailable_notInSuwUseGestureNavSystemUseFab_returnFalse() {
mController.setInSetupWizard(false);
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ true, /* floatingButtonEnabled= */ true);
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isShortcutAvailable_notInSuwUseGestureNavSystemNotUseFab_returnTrue() {
mController.setInSetupWizard(false);
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ true, /* floatingButtonEnabled= */ false);
assertThat(mController.isShortcutAvailable()).isTrue();
}
@Test
public void isShortcutAvailable_notInSuwUseButtonNavSystemUseFab_returnFalse() {
mController.setInSetupWizard(false);
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ false, /* floatingButtonEnabled= */ true);
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isShortcutAvailable_notInSuwUseButtonNavSystemNotUseFab_returnFalse() {
mController.setInSetupWizard(false);
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ false, /* floatingButtonEnabled= */ false);
assertThat(mController.isShortcutAvailable()).isFalse();
}
private void enableTouchExploration(boolean enable) {
AccessibilityManager am = mock(AccessibilityManager.class);
when(mContext.getSystemService(AccessibilityManager.class)).thenReturn(am);
when(am.isTouchExplorationEnabled()).thenReturn(enable);
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import android.content.ComponentName;
import android.content.Context;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.AccessibilityTestUtils;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.Set;
/**
* Tests for {@link NavButtonShortcutOptionController}
*/
@Config(shadows = SettingsShadowResources.class)
@RunWith(RobolectricTestRunner.class)
public class NavButtonShortcutOptionControllerTest {
private static final String PREF_KEY = "prefKey";
private static final String TARGET =
new ComponentName("FakePackage", "FakeClass").flattenToString();
private final Context mContext = spy(ApplicationProvider.getApplicationContext());
private NavButtonShortcutOptionController mController;
private ShortcutOptionPreference mShortcutOptionPreference;
private PreferenceScreen mPreferenceScreen;
@Before
public void setUp() {
mController = new NavButtonShortcutOptionController(
mContext, PREF_KEY);
mController.setShortcutTargets(Set.of(TARGET));
mShortcutOptionPreference = new ShortcutOptionPreference(mContext);
mShortcutOptionPreference.setKey(PREF_KEY);
mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPreferenceScreen.addPreference(mShortcutOptionPreference);
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ false, /* floatingButtonEnabled= */ false);
}
@Test
public void displayPreference_verifyTitle() {
mController.displayPreference(mPreferenceScreen);
assertThat(mShortcutOptionPreference.getTitle().toString()).isEqualTo(
mContext.getString(
R.string.accessibility_shortcut_edit_dialog_title_software));
}
@Test
public void displayPreference_inSuw_verifySummary() {
mController.setInSetupWizard(true);
mController.displayPreference(mPreferenceScreen);
assertThat(mShortcutOptionPreference.getSummary().toString()).isEqualTo(
mContext.getString(R.string.accessibility_shortcut_edit_dialog_summary_software));
}
@Test
public void displayPreference_notInSuw_verifySummary() {
mController.setInSetupWizard(false);
String expected = mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software)
+ "\n\n"
+ mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating);
mController.displayPreference(mPreferenceScreen);
assertThat(mShortcutOptionPreference.getSummary().toString()).isEqualTo(expected);
}
@Test
public void isShortcutAvailable_useGestureNavSystemUseFab_returnFalse() {
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ true, /* floatingButtonEnabled= */ true);
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isShortcutAvailable_useGestureNavSystemNotUseFab_returnFalse() {
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ true, /* floatingButtonEnabled= */ false);
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isShortcutAvailable_useButtonNavSystemUseFab_returnFalse() {
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ false, /* floatingButtonEnabled= */ true);
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isShortcutAvailable_useButtonNavSystemNotUseFab_returnTrue() {
AccessibilityTestUtils.setSoftwareShortcutMode(
mContext, /* gestureNavEnabled= */ false, /* floatingButtonEnabled= */ false);
assertThat(mController.isShortcutAvailable()).isTrue();
}
}

View File

@@ -0,0 +1,130 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.robolectric.RobolectricTestRunner;
import java.util.Set;
/**
* Tests for {@link ShortcutOptionPreferenceController}
*/
@RunWith(RobolectricTestRunner.class)
public class ShortcutOptionPreferenceControllerTest {
private static final String PREF_KEY = "prefKey";
private final Context mContext = ApplicationProvider.getApplicationContext();
private ShortcutOptionPreference mShortcutOptionPreference;
private ShortcutOptionPreferenceController mController;
@Before
public void setUp() {
mShortcutOptionPreference = spy(new ShortcutOptionPreference(mContext));
mShortcutOptionPreference.setKey(PREF_KEY);
mController = spy(new ShortcutOptionPreferenceController(mContext, PREF_KEY) {
@Override
protected boolean isShortcutAvailable() {
return false;
}
@Override
protected boolean isChecked() {
return false;
}
@Override
protected void enableShortcutForTargets(boolean enable) {
// do nothing
}
});
}
@Test
public void updateState_shortcutControllerIsChecked_shouldSetPreferenceChecked() {
when(mController.isChecked()).thenReturn(true);
mController.updateState(mShortcutOptionPreference);
assertThat(mShortcutOptionPreference.isChecked()).isTrue();
}
@Test
public void updateState_shortcutControllerIsNotChecked_shouldSetPreferenceUnchecked() {
when(mController.isChecked()).thenReturn(false);
mController.updateState(mShortcutOptionPreference);
assertThat(mShortcutOptionPreference.isChecked()).isFalse();
}
@Test
public void getAvailabilityStatus_shortcutAvailable_returnAvailableUnsearchable() {
when(mController.isShortcutAvailable()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
}
@Test
public void getAvailabilityStatus_shortcutUnavailable_returnConditionallyUnavailable() {
when(mController.isShortcutAvailable()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void onPreferenceChanged_callEnableShortcutForTargets() {
mController.onPreferenceChange(mShortcutOptionPreference, true);
mController.onPreferenceChange(mShortcutOptionPreference, false);
InOrder inOrder = Mockito.inOrder(mController);
inOrder.verify(mController).enableShortcutForTargets(true);
inOrder.verify(mController).enableShortcutForTargets(false);
}
@Test
public void getShortcutTargets() {
Set<String> targets = Set.of("target1", "target2");
mController.setShortcutTargets(targets);
assertThat(mController.getShortcutTargets())
.containsExactlyElementsIn(targets);
}
@Test
public void isInSetupWizard() {
mController.setInSetupWizard(true);
assertThat(mController.isInSetupWizard()).isTrue();
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import androidx.preference.PreferenceViewHolder;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
/**
* Test for {@link ShortcutOptionPreferenceTest}
*/
@RunWith(RobolectricTestRunner.class)
public class ShortcutOptionPreferenceTest {
private final Context mContext = ApplicationProvider.getApplicationContext();
private ShortcutOptionPreference mShortcutOptionPreference;
private PreferenceViewHolder mViewHolder;
private ImageView mImageView;
@Before
public void setUp() {
mShortcutOptionPreference = new ShortcutOptionPreference(mContext);
int layoutId = mShortcutOptionPreference.getLayoutResource();
View itemView = LayoutInflater.from(mContext).inflate(layoutId, /* root= */null);
mViewHolder = PreferenceViewHolder.createInstanceForTests(itemView);
mImageView = (ImageView) mViewHolder.findViewById(R.id.image);
}
@Test
public void bindViewHolder_imageResNotSet_shouldHideImageView() {
mShortcutOptionPreference.onBindViewHolder(mViewHolder);
assertThat(mImageView.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void bindViewHolder_imageResIdSet_shouldShowImageView() {
mShortcutOptionPreference.setIntroImageResId(R.drawable.a11y_shortcut_type_hardware);
mShortcutOptionPreference.onBindViewHolder(mViewHolder);
assertThat(mImageView.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void bindViewHolder_imageRawResIdSet_shouldShowImageView() {
mShortcutOptionPreference.setIntroImageRawResId(
com.android.settings.R.raw.accessibility_color_inversion_banner);
mShortcutOptionPreference.onBindViewHolder(mViewHolder);
assertThat(mImageView.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void bindViewHolder_shouldUpdateSummaryTextLineHeight() {
assertThat(mShortcutOptionPreference.getSummaryTextLineHeight()).isEqualTo(0);
mShortcutOptionPreference.onBindViewHolder(mViewHolder);
assertThat(mShortcutOptionPreference.getSummaryTextLineHeight()).isNotEqualTo(0);
}
}

View File

@@ -0,0 +1,330 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.provider.Settings;
import android.text.SpannableStringBuilder;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import androidx.fragment.app.FragmentActivity;
import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SubSettings;
import com.android.settings.accessibility.AccessibilityButtonFragment;
import com.android.settings.accessibility.FloatingMenuSizePreferenceController;
import com.android.settings.utils.AnnotationSpan;
import com.android.settingslib.accessibility.AccessibilityUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
* Tests for {@link SoftwareShortcutOptionPreferenceController}
*/
@RunWith(RobolectricTestRunner.class)
public class SoftwareShortcutOptionPreferenceControllerTest {
private static final String PREF_KEY = "prefKey";
private static final String TARGET_MAGNIFICATION =
"com.android.server.accessibility.MagnificationController";
private static final ComponentName TARGET_ALWAYS_ON_A11Y_SERVICE =
new ComponentName("FakePackage", "AlwaysOnA11yService");
private static final ComponentName TARGET_STANDARD_A11Y_SERVICE =
new ComponentName("FakePackage", "StandardA11yService");
private static final String SOFTWARE_SHORTCUT_SETTING_NAME =
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
private Context mContext;
private TestSoftwareShortcutOptionPreferenceController mController;
@Before
public void setUp() {
mContext = spy(Robolectric.buildActivity(FragmentActivity.class).get());
AccessibilityServiceInfo mAlwaysOnServiceInfo = createAccessibilityServiceInfo(
TARGET_ALWAYS_ON_A11Y_SERVICE, /* isAlwaysOnService= */ true);
AccessibilityServiceInfo mStandardServiceInfo = createAccessibilityServiceInfo(
TARGET_STANDARD_A11Y_SERVICE, /* isAlwaysOnService= */ false);
AccessibilityManager am = mock(AccessibilityManager.class);
when(mContext.getSystemService(Context.ACCESSIBILITY_SERVICE)).thenReturn(am);
when(am.getInstalledAccessibilityServiceList()).thenReturn(
List.of(mAlwaysOnServiceInfo, mStandardServiceInfo));
mController = new TestSoftwareShortcutOptionPreferenceController(mContext, PREF_KEY);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
}
@Test
public void isChecked_allTargetsHasShortcutConfigured_returnTrue() {
Settings.Secure.putString(
mContext.getContentResolver(), SOFTWARE_SHORTCUT_SETTING_NAME,
String.join(String.valueOf(SERVICES_SEPARATOR),
TARGET_MAGNIFICATION,
TARGET_STANDARD_A11Y_SERVICE.flattenToString(),
TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString())
);
mController.setShortcutTargets(
Set.of(TARGET_MAGNIFICATION,
TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(),
TARGET_STANDARD_A11Y_SERVICE.flattenToString()));
assertThat(mController.isChecked()).isTrue();
}
@Test
public void isChecked_someTargetsHasShortcutConfigured_returnFalse() {
Settings.Secure.putString(
mContext.getContentResolver(), SOFTWARE_SHORTCUT_SETTING_NAME,
String.join(String.valueOf(SERVICES_SEPARATOR),
TARGET_MAGNIFICATION,
TARGET_STANDARD_A11Y_SERVICE.flattenToString())
);
mController.setShortcutTargets(
Set.of(TARGET_MAGNIFICATION,
TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(),
TARGET_STANDARD_A11Y_SERVICE.flattenToString()));
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_noTargetsHasShortcutConfigured_returnFalse() {
Settings.Secure.putString(
mContext.getContentResolver(), SOFTWARE_SHORTCUT_SETTING_NAME, "");
mController.setShortcutTargets(
Set.of(TARGET_MAGNIFICATION,
TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString(),
TARGET_STANDARD_A11Y_SERVICE.flattenToString()));
assertThat(mController.isChecked()).isFalse();
}
@Test
public void getCustomizedAccessibilityButtonLink_verifyText() {
String expected =
mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating);
CharSequence spannable = mController.getCustomizeAccessibilityButtonLink();
assertThat(spannable.toString()).isEqualTo(expected);
}
@Test
public void getCustomizedAccessibilityButtonLink_verifyClickAction() {
String expected =
mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_software_floating);
CharSequence spannable = mController.getCustomizeAccessibilityButtonLink();
assertThat(spannable).isInstanceOf(SpannableStringBuilder.class);
AnnotationSpan[] spans = ((SpannableStringBuilder) spannable).getSpans(
0, expected.length(), AnnotationSpan.class);
spans[0].onClick(new View(mContext));
assertLaunchSettingsPage(AccessibilityButtonFragment.class.getName());
}
@Test
public void enableShortcutForTargets_enableShortcut_shortcutTurnedOn() {
String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
mController.setShortcutTargets(Set.of(target));
assertThat(ShortcutUtils.isComponentIdExistingInSettings(
mContext, ShortcutConstants.UserShortcutType.SOFTWARE, target
)).isFalse();
mController.enableShortcutForTargets(true);
assertThat(ShortcutUtils.isComponentIdExistingInSettings(
mContext, ShortcutConstants.UserShortcutType.SOFTWARE, target
)).isTrue();
}
@Test
public void enableShortcutForTargets_disableShortcut_shortcutTurnedOff() {
String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
ShortcutUtils.optInValueToSettings(
mContext, ShortcutConstants.UserShortcutType.SOFTWARE, target);
assertThat(ShortcutUtils.isComponentIdExistingInSettings(
mContext, ShortcutConstants.UserShortcutType.SOFTWARE, target
)).isTrue();
mController.setShortcutTargets(Set.of(target));
mController.enableShortcutForTargets(false);
assertThat(ShortcutUtils.isComponentIdExistingInSettings(
mContext, ShortcutConstants.UserShortcutType.SOFTWARE, target
)).isFalse();
}
@Test
public void enableShortcutForTargets_enableShortcutWithMagnification_menuSizeIncreased() {
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
mController.enableShortcutForTargets(true);
assertThat(
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
FloatingMenuSizePreferenceController.Size.UNKNOWN))
.isEqualTo(FloatingMenuSizePreferenceController.Size.LARGE);
}
@Test
public void enableShortcutForTargets_enableShortcutWithMagnification_userConfigureSmallMenuSize_menuSizeNotChanged() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
FloatingMenuSizePreferenceController.Size.SMALL);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
mController.enableShortcutForTargets(true);
assertThat(
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
FloatingMenuSizePreferenceController.Size.UNKNOWN))
.isEqualTo(FloatingMenuSizePreferenceController.Size.SMALL);
}
@Test
public void enableShortcutForTargets_enableAlwaysOnServiceShortcut_turnsOnAlwaysOnService() {
mController.setShortcutTargets(
Set.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()));
mController.enableShortcutForTargets(true);
assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext))
.contains(TARGET_ALWAYS_ON_A11Y_SERVICE);
}
@Test
public void enableShortcutForTargets_disableAlwaysOnServiceShortcut_turnsOffAlwaysOnService() {
mController.setShortcutTargets(
Set.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()));
mController.enableShortcutForTargets(false);
assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext))
.doesNotContain(TARGET_ALWAYS_ON_A11Y_SERVICE);
}
@Test
public void enableShortcutForTargets_enableStandardServiceShortcut_wontTurnOnService() {
mController.setShortcutTargets(
Set.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()));
mController.enableShortcutForTargets(true);
assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext))
.doesNotContain(TARGET_STANDARD_A11Y_SERVICE);
}
@Test
public void enableShortcutForTargets_disableStandardServiceShortcutWithServiceOn_wontTurnOffService() {
mController.setShortcutTargets(
Set.of(TARGET_STANDARD_A11Y_SERVICE.flattenToString()));
AccessibilityUtils.setAccessibilityServiceState(
mContext, TARGET_STANDARD_A11Y_SERVICE, /* enabled= */ true);
mController.enableShortcutForTargets(false);
assertThat(AccessibilityUtils.getEnabledServicesFromSettings(mContext))
.contains(TARGET_STANDARD_A11Y_SERVICE);
}
private void assertLaunchSettingsPage(String page) {
ContextWrapper applicationContext = (Application) mContext.getApplicationContext();
final Intent intent = Shadows.shadowOf(applicationContext).getNextStartedActivity();
assertThat(intent).isNotNull();
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN);
assertThat(intent.getComponent()).isEqualTo(
new ComponentName(applicationContext, SubSettings.class));
assertThat(intent.getExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(page);
}
private AccessibilityServiceInfo createAccessibilityServiceInfo(
ComponentName componentName, boolean isAlwaysOnService) {
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
final ServiceInfo serviceInfo = new ServiceInfo();
applicationInfo.packageName = componentName.getPackageName();
serviceInfo.packageName = componentName.getPackageName();
serviceInfo.name = componentName.getClassName();
serviceInfo.applicationInfo = applicationInfo;
final ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.serviceInfo = serviceInfo;
try {
final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
mContext);
info.setComponentName(componentName);
if (isAlwaysOnService) {
info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
}
return info;
} catch (XmlPullParserException | IOException e) {
// Do nothing
}
return null;
}
private static class TestSoftwareShortcutOptionPreferenceController
extends SoftwareShortcutOptionPreferenceController {
TestSoftwareShortcutOptionPreferenceController(
Context context, String preferenceKey) {
super(context, preferenceKey);
}
@Override
protected boolean isShortcutAvailable() {
return true;
}
}
}

View File

@@ -0,0 +1,185 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import android.icu.text.MessageFormat;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.accessibility.AccessibilityUtil;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Set;
/**
* Tests for {@link TripleTapShortcutOptionController}
*/
@RunWith(RobolectricTestRunner.class)
public class TripleTapShortcutOptionControllerTest {
private static final String PREF_KEY = "prefKey";
private static final String TARGET_MAGNIFICATION =
"com.android.server.accessibility.MagnificationController";
private static final String TARGET_FAKE =
new ComponentName("FakePackage", "FakeClass").flattenToString();
private final Context mContext = ApplicationProvider.getApplicationContext();
private TripleTapShortcutOptionController mController;
private ShortcutOptionPreference mShortcutOptionPreference;
private PreferenceScreen mPreferenceScreen;
@Before
public void setUp() {
mController = new TripleTapShortcutOptionController(mContext, PREF_KEY);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
mShortcutOptionPreference = new ShortcutOptionPreference(mContext);
mShortcutOptionPreference.setKey(PREF_KEY);
mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPreferenceScreen.addPreference(mShortcutOptionPreference);
}
@Test
public void displayPreference_verifyScreenTestSet() {
mController.displayPreference(mPreferenceScreen);
assertThat(mShortcutOptionPreference.getTitle().toString()).isEqualTo(
mContext.getString(R.string.accessibility_shortcut_edit_dialog_title_triple_tap));
assertThat(mShortcutOptionPreference.getSummary().toString()).isEqualTo(
MessageFormat.format(
mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_triple_tap),
3));
}
@Test
public void getAvailabilityStatus_targetIsMagnificationAndIsExpanded_returnsAvailableUnsearchable() {
mController.setExpanded(true);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
}
@Test
public void getAvailabilityStatus_targetIsMagnificationAndIsNotExpanded_returnsConditionallyUnavailable() {
mController.setExpanded(false);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_targetIsNotMagnificationAndIsNotExpanded_returnsConditionallyUnavailable() {
mController.setExpanded(false);
mController.setShortcutTargets(Set.of(TARGET_FAKE));
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_targetIsNotMagnificationAndIsExpanded_returnsConditionallyUnavailable() {
mController.setExpanded(true);
mController.setShortcutTargets(Set.of(TARGET_FAKE));
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void setExpanded_expand_updateExpandedValue() {
mController.setExpanded(true);
assertThat(mController.isExpanded()).isTrue();
}
@Test
public void setExpanded_collapse_updateExpandedValue() {
mController.setExpanded(false);
assertThat(mController.isExpanded()).isFalse();
}
@Test
public void isShortcutAvailable_multipleTargets_returnFalse() {
mController.setShortcutTargets(Set.of(TARGET_FAKE, TARGET_MAGNIFICATION));
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isShortcutAvailable_magnificationTargetOnly_returnTrue() {
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
assertThat(mController.isShortcutAvailable()).isTrue();
}
@Test
public void isShortcutAvailable_nonMagnificationTarget_returnFalse() {
mController.setShortcutTargets(Set.of(TARGET_FAKE));
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isChecked_tripleTapConfigured_returnTrue() {
mController.enableShortcutForTargets(true);
assertThat(mController.isChecked()).isTrue();
}
@Test
public void isChecked_tripleTapNotConfigured_returnFalse() {
mController.enableShortcutForTargets(false);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void enableShortcutForTargets_enableShortcut_settingUpdated() {
mController.enableShortcutForTargets(true);
assertThat(
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
AccessibilityUtil.State.OFF)
).isEqualTo(AccessibilityUtil.State.ON);
}
@Test
public void enableShortcutForTargets_disableShortcut_settingUpdated() {
mController.enableShortcutForTargets(false);
assertThat(
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
AccessibilityUtil.State.OFF)
).isEqualTo(AccessibilityUtil.State.OFF);
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import android.icu.text.MessageFormat;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.server.accessibility.Flags;
import com.android.settings.R;
import com.android.settings.accessibility.AccessibilityUtil;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Set;
/**
* Tests for {@link TwoFingersDoubleTapShortcutOptionController}
*/
@RunWith(RobolectricTestRunner.class)
public class TwoFingersDoubleTapShortcutOptionControllerTest {
private static final String PREF_KEY = "prefKey";
private static final String TARGET_MAGNIFICATION =
"com.android.server.accessibility.MagnificationController";
private static final String TARGET_FAKE =
new ComponentName("FakePackage", "FakeClass").flattenToString();
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private final Context mContext = ApplicationProvider.getApplicationContext();
private TwoFingersDoubleTapShortcutOptionController mController;
private ShortcutOptionPreference mShortcutOptionPreference;
private PreferenceScreen mPreferenceScreen;
@Before
public void setUp() {
mController = new TwoFingersDoubleTapShortcutOptionController(mContext, PREF_KEY);
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
mShortcutOptionPreference = new ShortcutOptionPreference(mContext);
mShortcutOptionPreference.setKey(PREF_KEY);
mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPreferenceScreen.addPreference(mShortcutOptionPreference);
}
@Test
public void displayPreference_verifyScreenTextSet() {
mController.displayPreference(mPreferenceScreen);
assertThat(mShortcutOptionPreference.getTitle().toString()).isEqualTo(
mContext.getString(
R.string.accessibility_shortcut_edit_dialog_title_two_finger_double_tap));
assertThat(mShortcutOptionPreference.getSummary().toString()).isEqualTo(
MessageFormat.format(mContext.getString(
R.string.accessibility_shortcut_edit_dialog_summary_two_finger_double_tap),
2));
}
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
@Test
public void isShortcutAvailable_featureFlagTurnedOff_returnFalse() {
assertThat(mController.isShortcutAvailable()).isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
@Test
public void isShortcutAvailable_multipleTargets_returnFalse() {
mController.setShortcutTargets(Set.of(TARGET_FAKE, TARGET_MAGNIFICATION));
assertThat(mController.isShortcutAvailable()).isFalse();
}
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
@Test
public void isShortcutAvailable_magnificationTargetOnly_returnTrue() {
mController.setShortcutTargets(Set.of(TARGET_MAGNIFICATION));
assertThat(mController.isShortcutAvailable()).isTrue();
}
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
@Test
public void isShortcutAvailable_nonMagnificationTarget_returnFalse() {
mController.setShortcutTargets(Set.of(TARGET_FAKE));
assertThat(mController.isShortcutAvailable()).isFalse();
}
@Test
public void isChecked_twoFingersDoubleTapConfigured_returnTrue() {
mController.enableShortcutForTargets(true);
assertThat(mController.isChecked()).isTrue();
}
@Test
public void isChecked_twoFingersDoubleTapNotConfigured_returnFalse() {
mController.enableShortcutForTargets(false);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void enableShortcutForTargets_enableShortcut_settingUpdated() {
mController.enableShortcutForTargets(true);
assertThat(
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
AccessibilityUtil.State.OFF)
).isEqualTo(AccessibilityUtil.State.ON);
}
@Test
public void enableShortcutForTargets_disableShortcut_settingUpdated() {
mController.enableShortcutForTargets(false);
assertThat(
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
AccessibilityUtil.State.OFF)
).isEqualTo(AccessibilityUtil.State.OFF);
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2023 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.accessibility.shortcuts;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Set;
/**
* Tests for {@link VolumeKeysShortcutOptionController}
*/
@RunWith(RobolectricTestRunner.class)
public class VolumeKeysShortcutOptionControllerTest {
private static final String PREF_KEY = "prefKey";
private static final String TARGET =
new ComponentName("FakePackage", "FakeClass").flattenToString();
private final Context mContext = ApplicationProvider.getApplicationContext();
private VolumeKeysShortcutOptionController mController;
private ShortcutOptionPreference mShortcutOptionPreference;
private PreferenceScreen mPreferenceScreen;
@Before
public void setUp() {
mController = new VolumeKeysShortcutOptionController(
mContext, PREF_KEY);
mController.setShortcutTargets(Set.of(TARGET));
mShortcutOptionPreference = new ShortcutOptionPreference(mContext);
mShortcutOptionPreference.setKey(PREF_KEY);
mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPreferenceScreen.addPreference(mShortcutOptionPreference);
}
@Test
public void displayPreference_verifyScreenTextSet() {
mController.displayPreference(mPreferenceScreen);
assertThat(mShortcutOptionPreference.getTitle().toString()).isEqualTo(
mContext.getString(R.string.accessibility_shortcut_edit_dialog_title_hardware));
assertThat(mShortcutOptionPreference.getSummary().toString()).isEqualTo(
mContext.getString(R.string.accessibility_shortcut_edit_dialog_summary_hardware));
}
@Test
public void isShortcutAvailable_returnsTrue() {
assertThat(mController.isShortcutAvailable()).isTrue();
}
@Test
public void isChecked_targetUseVolumeKeyShortcut_returnTrue() {
ShortcutUtils.optInValueToSettings(
mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET);
assertThat(mController.isChecked()).isTrue();
}
@Test
public void isChecked_targetNotUseVolumeKeyShortcut_returnFalse() {
ShortcutUtils.optOutValueFromSettings(
mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void enableShortcutForTargets_enableVolumeKeysShortcut_shortcutSet() {
mController.enableShortcutForTargets(true);
assertThat(
ShortcutUtils.isComponentIdExistingInSettings(
mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET)).isTrue();
}
@Test
public void enableShortcutForTargets_disableVolumeKeysShortcut_shortcutNotSet() {
mController.enableShortcutForTargets(false);
assertThat(
ShortcutUtils.isComponentIdExistingInSettings(
mContext, ShortcutConstants.UserShortcutType.HARDWARE, TARGET)).isFalse();
}
}

View File

@@ -254,25 +254,26 @@ public class AccountPreferenceControllerTest {
}
@Test
public void updateRawDataToIndex_ManagedProfile_shouldNotUpdate() {
public void updateRawDataToIndex_noManagedProfile_shouldContainAddAccount() {
final List<SearchIndexableRaw> data = new ArrayList<>();
when(mUserManager.isManagedProfile()).thenReturn(false);
mController.updateRawDataToIndex(data);
assertThat(data).hasSize(1);
assertThat(data.get(0).key).isEqualTo("add_account");
}
@Test
public void updateRawDataToIndex_ManagedProfile_shouldContainAddAccount() {
final List<SearchIndexableRaw> data = new ArrayList<>();
when(mUserManager.isManagedProfile()).thenReturn(true);
mController.updateRawDataToIndex(data);
assertThat(data).isEmpty();
}
@Test
public void updateRawDataToIndex_DisabledUser_shouldNotUpdate() {
final List<SearchIndexableRaw> data = new ArrayList<>();
final List<UserInfo> infos = new ArrayList<>();
infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_DISABLED));
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
mController.updateRawDataToIndex(data);
assertThat(data).isEmpty();
assertThat(data).hasSize(1);
assertThat(data.get(0).key).isEqualTo("add_account");
}
@Test

View File

@@ -23,6 +23,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
@@ -35,6 +36,7 @@ import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
@@ -44,33 +46,38 @@ import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class,
ShadowRestrictedLockUtilsInternal.class})
public class ChooseAccountPreferenceControllerTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private Context mContext;
private ChooseAccountPreferenceController mController;
private Activity mActivity;
private PreferenceManager mPreferenceManager;
private PreferenceScreen mPreferenceScreen;
private ShadowAccountManager mAccountManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mContext = ApplicationProvider.getApplicationContext();
mController = spy(new ChooseAccountPreferenceController(mContext, "controller_key"));
mActivity = Robolectric.setupActivity(FragmentActivity.class);
mPreferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
mAccountManager = (ShadowAccountManager) Shadows.shadowOf(AccountManager.get(mContext));
}
@After
@@ -108,7 +115,7 @@ public class ChooseAccountPreferenceControllerTest {
final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1",
"com.android.settings",
R.string.header_add_an_account, 0, 0, 0, false);
ShadowAccountManager.addAuthenticator(authDesc);
mAccountManager.addAuthenticator(authDesc);
final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */,
"com.acct1" /* accountType */, false /* userVisible */,
@@ -133,7 +140,7 @@ public class ChooseAccountPreferenceControllerTest {
final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1",
"com.android.settings",
R.string.header_add_an_account, 0, 0, 0, false);
ShadowAccountManager.addAuthenticator(authDesc);
mAccountManager.addAuthenticator(authDesc);
final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */,
"com.acct1" /* accountType */, false /* userVisible */,
@@ -158,7 +165,7 @@ public class ChooseAccountPreferenceControllerTest {
final AuthenticatorDescription authDesc = new AuthenticatorDescription("com.acct1",
"com.android.settings",
R.string.header_add_an_account, 0, 0, 0, false);
ShadowAccountManager.addAuthenticator(authDesc);
mAccountManager.addAuthenticator(authDesc);
final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */,
"com.acct1" /* accountType */, false /* userVisible */,
@@ -184,8 +191,8 @@ public class ChooseAccountPreferenceControllerTest {
final AuthenticatorDescription authDesc2 = new AuthenticatorDescription("com.acct2",
"com.android.settings",
R.string.header_add_an_account, 0, 0, 0, false);
ShadowAccountManager.addAuthenticator(authDesc);
ShadowAccountManager.addAuthenticator(authDesc2);
mAccountManager.addAuthenticator(authDesc);
mAccountManager.addAuthenticator(authDesc2);
final SyncAdapterType[] syncAdapters = {new SyncAdapterType("authority" /* authority */,
"com.acct1" /* accountType */, false /* userVisible */,

View File

@@ -41,13 +41,12 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.ParameterizedRobolectricTestRunner;
import org.robolectric.RobolectricTestRunner;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@RunWith(ParameterizedRobolectricTestRunner.class)
public class WorkModePreferenceControllerTest {
private static final String PREF_KEY = "work_mode";

View File

@@ -38,13 +38,20 @@ import android.os.Build;
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.webkit.Flags;
import com.android.settings.testutils.ApplicationTestUtils;
import com.android.settings.webview.WebViewUpdateServiceWrapper;
import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager;
import com.android.settingslib.testutils.shadow.ShadowSmsApplication;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -68,6 +75,9 @@ import java.util.Set;
@LooperMode(LooperMode.Mode.LEGACY)
public final class ApplicationFeatureProviderImplTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private final int MAIN_USER_ID = 0;
private final int MANAGED_PROFILE_ID = 10;
@@ -96,6 +106,8 @@ public final class ApplicationFeatureProviderImplTest {
@Mock
private LocationManager mLocationManager;
@Mock
private WebViewUpdateServiceWrapper mWebViewUpdateServiceWrapper;
@Mock
private SystemConfigManager mSystemConfigManager;
private ApplicationFeatureProvider mProvider;
@@ -113,7 +125,7 @@ public final class ApplicationFeatureProviderImplTest {
when(mContext.getSystemService(SystemConfigManager.class)).thenReturn(mSystemConfigManager);
mProvider = new ApplicationFeatureProviderImpl(mContext, mPackageManager,
mPackageManagerService, mDevicePolicyManager);
mPackageManagerService, mDevicePolicyManager, mWebViewUpdateServiceWrapper);
}
private void verifyCalculateNumberOfPolicyInstalledApps(boolean async) {
@@ -348,6 +360,26 @@ public final class ApplicationFeatureProviderImplTest {
assertThat(allowlist).contains("com.android.settings.intelligence");
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_UPDATE_SERVICE_V2)
public void getKeepEnabledPackages_shouldContainWebViewPackage() {
final String testWebViewPackageName = "com.android.webview";
when(mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName())
.thenReturn(testWebViewPackageName);
final Set<String> allowlist = mProvider.getKeepEnabledPackages();
assertThat(allowlist).contains(testWebViewPackageName);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_UPDATE_SERVICE_V2)
public void getKeepEnabledPackages_shouldNotContainWebViewPackageIfFlagDisabled() {
final String testWebViewPackageName = "com.android.webview";
when(mWebViewUpdateServiceWrapper.getDefaultWebViewPackageName())
.thenReturn(testWebViewPackageName);
final Set<String> allowlist = mProvider.getKeepEnabledPackages();
assertThat(allowlist).doesNotContain(testWebViewPackageName);
}
@Test
@Config(shadows = {ShadowSmsApplication.class, ShadowDefaultDialerManager.class})
public void getKeepEnabledPackages_shouldContainPackageInstaller() {

View File

@@ -41,8 +41,11 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.flag.junit.SetFlagsRule;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
@@ -84,6 +87,9 @@ public final class InstalledAppCounterTest {
@Mock
private PackageManager mPackageManager;
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private int mInstalledAppCount = -1;
private ApplicationInfo mApp1;
private ApplicationInfo mApp2;
@@ -189,11 +195,13 @@ public final class InstalledAppCounterTest {
mPackageManager, mApp6)).isFalse();
}
@Ignore("b/313578776")
@Test
public void testCountInstalledAppsAcrossAllUsersSync() {
testCountInstalledAppsAcrossAllUsers(false /* async */);
}
@Ignore("b/313578776")
@Test
public void testCountInstalledAppsAcrossAllUsersAsync() {
testCountInstalledAppsAcrossAllUsers(true /* async */);
@@ -215,6 +223,7 @@ public final class InstalledAppCounterTest {
eq(MAIN_USER_ID))).thenReturn(Arrays.asList(mApp2));
mFakeFeatureFlags.setFlag(Flags.FLAG_ARCHIVING, false);
mSetFlagsRule.disableFlags(com.android.settings.flags.Flags.FLAG_APP_ARCHIVING);
// Count the number of all apps installed, irrespective of install reason.
count(InstalledAppCounter.IGNORE_INSTALL_REASON, mFakeFeatureFlags);
assertThat(mInstalledAppCount).isEqualTo(1);

View File

@@ -16,12 +16,21 @@
package com.android.settings.applications.appcompat;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
import static com.android.settings.applications.AppInfoBase.ARG_PACKAGE_NAME;
import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_PREF_3_2;
import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_PREF_DEFAULT;
import static com.android.settings.applications.appcompat.UserAspectRatioDetails.KEY_PREF_FULLSCREEN;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -30,15 +39,20 @@ import static org.mockito.Mockito.when;
import android.app.IActivityManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import androidx.fragment.app.testing.EmptyFragmentActivity;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowActivityManager;
import com.android.settings.testutils.shadow.ShadowFragment;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
@@ -51,9 +65,13 @@ import org.robolectric.annotation.Config;
* To run test: atest SettingsRoboTests:UserAspectRatioDetailsTest
*/
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowActivityManager.class})
@Config(shadows = {ShadowActivityManager.class, ShadowFragment.class})
public class UserAspectRatioDetailsTest {
@Rule
public ActivityScenarioRule<EmptyFragmentActivity> rule =
new ActivityScenarioRule<>(EmptyFragmentActivity.class);
@Mock
private UserAspectRatioManager mUserAspectRatioManager;
@Mock
@@ -72,6 +90,8 @@ public class UserAspectRatioDetailsTest {
mFragment = spy(new UserAspectRatioDetails());
when(mFragment.getContext()).thenReturn(mContext);
when(mFragment.getAspectRatioManager()).thenReturn(mUserAspectRatioManager);
when(mUserAspectRatioManager.isOverrideToFullscreenEnabled(anyString(), anyInt()))
.thenReturn(false);
ShadowActivityManager.setService(mAm);
mRadioButtonPref = new RadioWithImagePreference(mContext);
final FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest();
@@ -80,6 +100,8 @@ public class UserAspectRatioDetailsTest {
@Test
public void onRadioButtonClicked_prefChange_shouldStopActivity() throws RemoteException {
doReturn(USER_MIN_ASPECT_RATIO_UNSET).when(mFragment)
.getSelectedUserMinAspectRatio(anyString());
// Default was already selected
mRadioButtonPref.setKey(KEY_PREF_DEFAULT);
mFragment.onRadioButtonClicked(mRadioButtonPref);
@@ -92,6 +114,8 @@ public class UserAspectRatioDetailsTest {
@Test
public void onRadioButtonClicked_prefChange_shouldSetAspectRatio() throws RemoteException {
doReturn(USER_MIN_ASPECT_RATIO_UNSET).when(mFragment)
.getSelectedUserMinAspectRatio(anyString());
// Default was already selected
mRadioButtonPref.setKey(KEY_PREF_DEFAULT);
mFragment.onRadioButtonClicked(mRadioButtonPref);
@@ -105,6 +129,8 @@ public class UserAspectRatioDetailsTest {
@Test
public void onRadioButtonClicked_prefChange_logMetrics() throws NullPointerException {
doReturn(USER_MIN_ASPECT_RATIO_UNSET).when(mFragment)
.getSelectedUserMinAspectRatio(anyString());
// Default was already selected
mRadioButtonPref.setKey(KEY_PREF_DEFAULT);
mFragment.onRadioButtonClicked(mRadioButtonPref);
@@ -129,4 +155,47 @@ public class UserAspectRatioDetailsTest {
any(),
anyInt());
}
@Test
public void onButtonClicked_overrideEnabled_fullscreenPreselected()
throws RemoteException {
doReturn(true).when(mUserAspectRatioManager)
.isOverrideToFullscreenEnabled(anyString(), anyInt());
doReturn(USER_MIN_ASPECT_RATIO_UNSET).when(mUserAspectRatioManager)
.getUserMinAspectRatioValue(anyString(), anyInt());
doReturn(mRadioButtonPref).when(mFragment).findPreference(KEY_PREF_DEFAULT);
doReturn(mRadioButtonPref).when(mFragment).findPreference(KEY_PREF_FULLSCREEN);
doReturn(true).when(mUserAspectRatioManager)
.hasAspectRatioOption(anyInt(), anyString());
rule.getScenario().onActivity(a -> doReturn(a).when(mFragment).getActivity());
final Bundle args = new Bundle();
args.putString(ARG_PACKAGE_NAME, anyString());
mFragment.setArguments(args);
mFragment.onCreate(Bundle.EMPTY);
// Fullscreen should be pre-selected
assertEquals(KEY_PREF_FULLSCREEN, mFragment.mSelectedKey);
assertEquals(USER_MIN_ASPECT_RATIO_FULLSCREEN,
mFragment.getSelectedUserMinAspectRatio(mFragment.mSelectedKey));
// Revert to app default, should be set to app default from unset
mRadioButtonPref.setKey(KEY_PREF_DEFAULT);
mFragment.onRadioButtonClicked(mRadioButtonPref);
verify(mUserAspectRatioManager).setUserMinAspectRatio(
any(), anyInt(), anyInt());
assertEquals(USER_MIN_ASPECT_RATIO_APP_DEFAULT,
mFragment.getSelectedUserMinAspectRatio(mFragment.mSelectedKey));
assertEquals(KEY_PREF_DEFAULT, mFragment.mSelectedKey);
// Fullscreen override disabled, should be changed to unset from app default
when(mUserAspectRatioManager.isOverrideToFullscreenEnabled(anyString(), anyInt()))
.thenReturn(false);
mFragment.mKeyToAspectRatioMap.clear();
mFragment.onCreate(Bundle.EMPTY);
assertEquals(KEY_PREF_DEFAULT, mFragment.mSelectedKey);
assertEquals(USER_MIN_ASPECT_RATIO_UNSET,
mFragment.getSelectedUserMinAspectRatio(mFragment.mSelectedKey));
}
}

View File

@@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -38,15 +39,18 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.Flags;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.UserManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.util.ArraySet;
import android.view.View;
@@ -107,7 +111,7 @@ public class AppButtonsPreferenceControllerTest {
@Mock
private OverlayManager mOverlayManager;
@Mock
private PackageManager mPackageManger;
private PackageManager mPackageManager;
@Mock
private DevicePolicyManager mDpm;
@Mock
@@ -132,7 +136,7 @@ public class AppButtonsPreferenceControllerTest {
mContext = RuntimeEnvironment.application;
doReturn(mDpm).when(mSettingsActivity).getSystemService(Context.DEVICE_POLICY_SERVICE);
doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE);
doReturn(mPackageManger).when(mSettingsActivity).getPackageManager();
doReturn(mPackageManager).when(mSettingsActivity).getPackageManager();
doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE);
doReturn(mOverlayManager).when(mSettingsActivity).
getSystemService(OverlayManager.class);
@@ -184,7 +188,7 @@ public class AppButtonsPreferenceControllerTest {
@Test
public void retrieveAppEntry_hasAppEntry_notNull()
throws PackageManager.NameNotFoundException {
doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(anyString(), anyInt());
mController.retrieveAppEntry();
@@ -195,7 +199,7 @@ public class AppButtonsPreferenceControllerTest {
@Test
public void retrieveAppEntry_noAppEntry_null() throws PackageManager.NameNotFoundException {
doReturn(null).when(mState).getEntry(eq(PACKAGE_NAME), anyInt());
doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(anyString(), anyInt());
mController.retrieveAppEntry();
@@ -207,7 +211,7 @@ public class AppButtonsPreferenceControllerTest {
public void retrieveAppEntry_throwException_null() throws
PackageManager.NameNotFoundException {
doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt());
doThrow(new PackageManager.NameNotFoundException()).when(mPackageManger).getPackageInfo(
doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo(
anyString(), anyInt());
mController.retrieveAppEntry();
@@ -225,7 +229,7 @@ public class AppButtonsPreferenceControllerTest {
@Test
public void updateOpenButton_haveLaunchIntent_buttonShouldBeEnable() {
doReturn(new Intent()).when(mPackageManger).getLaunchIntentForPackage(anyString());
doReturn(new Intent()).when(mPackageManager).getLaunchIntentForPackage(anyString());
mController.updateOpenButton();
@@ -346,6 +350,35 @@ public class AppButtonsPreferenceControllerTest {
verify(mButtonPrefs).setButton2Enabled(false);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_IMPROVE_HOME_APP_BEHAVIOR)
public void updateUninstallButton_isNotSystemAndIsCurrentHomeAndHasOneHome_setButtonDisable() {
doReturn(false).when(mController).isSystemPackage(any(), any(), any());
doReturn(new ComponentName(PACKAGE_NAME, "cls")).when(mPackageManager).getHomeActivities(
anyList());
mController.mHomePackages.add(PACKAGE_NAME);
mController.updateUninstallButton();
verify(mButtonPrefs).setButton2Enabled(false);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_IMPROVE_HOME_APP_BEHAVIOR)
public void updateUninstallButton_isNotSystemAndIsCurrentHomeAndHasOtherHome_setButtonEnable() {
doReturn(false).when(mController).isSystemPackage(any(), any(), any());
doReturn(new ComponentName(PACKAGE_NAME, "cls")).when(mPackageManager).getHomeActivities(
anyList());
mController.mHomePackages.add(PACKAGE_NAME);
mController.mHomePackages.add("com.android.home.fake");
mController.updateUninstallButton();
verify(mButtonPrefs).setButton2Enabled(true);
}
@Test
public void updateUninstallButton_isSystemRro_setButtonDisable() {
mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
@@ -477,7 +510,7 @@ public class AppButtonsPreferenceControllerTest {
throws PackageManager.NameNotFoundException {
doReturn(AppButtonsPreferenceController.AVAILABLE)
.when(mController).getAvailabilityStatus();
doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(anyString(), anyInt());
doReturn(mButtonPrefs).when(mScreen).findPreference(anyString());
mController.displayPreference(mScreen);
mController.mButtonsPref = null;

View File

@@ -35,6 +35,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
import android.app.ecm.EnhancedConfirmationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -90,7 +91,8 @@ public final class AppInfoDashboardFragmentTest {
private DevicePolicyManager mDevicePolicyManager;
@Mock
private PackageManager mPackageManager;
@Mock
private EnhancedConfirmationManager mEcManager;
private AppInfoDashboardFragment mFragment;
private Context mShadowContext;
@@ -102,6 +104,7 @@ public final class AppInfoDashboardFragmentTest {
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mShadowContext).when(mFragment).getContext();
doReturn(mPackageManager).when(mActivity).getPackageManager();
doReturn(mEcManager).when(mActivity).getSystemService(EnhancedConfirmationManager.class);
when(mUserManager.isAdminUser()).thenReturn(true);
ReflectionHelpers.setField(mFragment, "mUserManager", mUserManager);

View File

@@ -18,6 +18,7 @@ package com.android.settings.applications.appinfo;
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.verify;
@@ -25,10 +26,12 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.SettingsActivity;
import com.android.settings.applications.ProcStatsData;
@@ -37,14 +40,14 @@ import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.shadow.ShadowUserManager;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@@ -54,6 +57,8 @@ import org.robolectric.util.ReflectionHelpers;
com.android.settings.testutils.shadow.ShadowFragment.class,
})
public class AppMemoryPreferenceControllerTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private SettingsActivity mActivity;
@@ -69,9 +74,11 @@ public class AppMemoryPreferenceControllerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
ShadowUserManager.getShadow().setIsAdminUser(true);
mContext = spy(ApplicationProvider.getApplicationContext());
UserManager userManager = mock(UserManager.class);
when(userManager.isAdminUser()).thenReturn(true);
doReturn(userManager).when(mContext).getSystemService(Context.USER_SERVICE);
mController =
spy(new AppMemoryPreferenceController(mContext, mFragment, null /* lifecycle */));
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
@@ -80,7 +87,6 @@ public class AppMemoryPreferenceControllerTest {
when(mFragment.getActivity()).thenReturn(mActivity);
}
@Ignore("b/313582035")
@Test
@Config(qualifiers = "mcc999")
public void getAvailabilityStatus_developmentSettingsEnabled_shouldReturnAvailable() {

View File

@@ -19,16 +19,28 @@ package com.android.settings.applications.specialaccess;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.nfc.NfcAdapter;
import android.nfc.cardemulation.CardEmulation;
import android.os.UserManager;
import android.permission.flags.Flags;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.preference.Preference;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
@@ -37,6 +49,10 @@ import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class DefaultPaymentSettingsPreferenceControllerTest {
private static final String PREF_KEY = "key";
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private NfcAdapter mNfcAdapter;
@Mock
@@ -45,6 +61,10 @@ public class DefaultPaymentSettingsPreferenceControllerTest {
private UserManager mUserManager;
@Mock
private PackageManager mPackageManager;
@Mock
private RoleManager mRoleManager;
@Mock
private Preference mPreference;
private DefaultPaymentSettingsPreferenceController mController;
@@ -55,7 +75,8 @@ public class DefaultPaymentSettingsPreferenceControllerTest {
when(mContext.getApplicationContext()).thenReturn(mContext);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mController = new DefaultPaymentSettingsPreferenceController(mContext, "key");
when(mContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager);
mController = new DefaultPaymentSettingsPreferenceController(mContext, PREF_KEY);
ReflectionHelpers.setField(mController, "mNfcAdapter", mNfcAdapter);
}
@@ -86,4 +107,20 @@ public class DefaultPaymentSettingsPreferenceControllerTest {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
DefaultPaymentSettingsPreferenceController.DISABLED_DEPENDENT_SETTING);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_WALLET_ROLE_ENABLED)
public void handlePreferenceTreeClick_walletRoleEnabled_shouldReturnTrue() {
when(mRoleManager.isRoleAvailable(anyString())).thenReturn(true);
when(mPreference.getKey()).thenReturn(PREF_KEY);
ArgumentCaptor<String> roleTypeCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue();
verify(mRoleManager).isRoleAvailable(roleTypeCaptor.capture());
verify(mContext).startActivity(intentArgumentCaptor.capture());
assertThat(roleTypeCaptor.getValue()).isEqualTo(RoleManager.ROLE_WALLET);
assertThat(intentArgumentCaptor.getValue().getAction())
.isEqualTo(CardEmulation.ACTION_CHANGE_DEFAULT);
}
}

View File

@@ -16,13 +16,35 @@
package com.android.settings.applications.specialaccess.premiumsms;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Process;
import android.telephony.SmsManager;
import android.view.LayoutInflater;
import android.view.View;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.R;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.datausage.AppStateDataUsageBridge;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedDropDownPreference;
import com.android.settingslib.applications.ApplicationsState;
import org.junit.Before;
import org.junit.Test;
@@ -30,19 +52,28 @@ import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowRestrictedLockUtilsInternal.class
})
public class PremiumSmsAccessTest {
private FakeFeatureFactory mFeatureFactory;
private PremiumSmsAccess mFragment;
private Context mContext;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFeatureFactory = FakeFeatureFactory.setupForTest();
mFragment = new PremiumSmsAccess();
mFragment.onAttach(RuntimeEnvironment.application);
mContext = RuntimeEnvironment.application;
mFragment.onAttach(mContext);
}
@Test
@@ -74,4 +105,89 @@ public class PremiumSmsAccessTest {
"app",
SmsManager.PREMIUM_SMS_CONSENT_ALWAYS_ALLOW);
}
@Test
public void onRebuildComplete_ecmRestricted_shouldBeDisabled() {
mFragment = spy(mFragment);
mContext = spy(mContext);
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.preference_dropdown, null);
PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
PreferenceManager preferenceManager = new PreferenceManager(mContext);
PreferenceScreen preferenceScreen = spy(preferenceManager.createPreferenceScreen(mContext));
doReturn(preferenceManager).when(mFragment).getPreferenceManager();
doReturn(preferenceScreen).when(mFragment).getPreferenceScreen();
final String testPkg = "com.example.disabled";
doNothing().when(mContext).startActivity(any());
ShadowRestrictedLockUtilsInternal.setEcmRestrictedPkgs(testPkg);
doAnswer((invocation) -> {
final RestrictedDropDownPreference preference = invocation.getArgument(0);
// Verify preference is disabled by ecm and the summary is changed accordingly.
assertThat(preference.isDisabledByEcm()).isTrue();
assertThat(preference.getSummary().toString()).isEqualTo(
mContext.getString(
com.android.settingslib.R.string.disabled_by_app_ops_text));
preference.onBindViewHolder(holder);
preference.performClick();
// Verify that when the preference is clicked, ecm details intent is launched
verify(mContext).startActivity(any());
return null;
}).when(preferenceScreen).addPreference(any(RestrictedDropDownPreference.class));
mFragment.onRebuildComplete(createAppEntries(testPkg));
verify(preferenceScreen).addPreference(any(RestrictedDropDownPreference.class));
}
@Test
public void onRebuildComplete_ecmNotRestricted_notDisabled() {
mFragment = spy(mFragment);
mContext = spy(mContext);
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.preference_dropdown, null);
PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
PreferenceManager preferenceManager = new PreferenceManager(mContext);
PreferenceScreen preferenceScreen = spy(preferenceManager.createPreferenceScreen(mContext));
doReturn(preferenceManager).when(mFragment).getPreferenceManager();
doReturn(preferenceScreen).when(mFragment).getPreferenceScreen();
final String testPkg = "com.example.enabled";
ShadowRestrictedLockUtilsInternal.setEcmRestrictedPkgs();
doAnswer((invocation) -> {
final RestrictedDropDownPreference preference = invocation.getArgument(0);
assertThat(preference.isDisabledByEcm()).isFalse();
assertThat(preference.getSummary().toString()).isEqualTo("");
preference.onBindViewHolder(holder);
preference.performClick();
// Verify that when the preference is clicked, ecm details intent is not launched
verify(mContext, never()).startActivity(any());
return null;
}).when(preferenceScreen).addPreference(any(RestrictedDropDownPreference.class));
mFragment.onRebuildComplete(createAppEntries(testPkg));
verify(preferenceScreen).addPreference(any(RestrictedDropDownPreference.class));
}
private ArrayList<ApplicationsState.AppEntry> createAppEntries(String... packageNames) {
final ArrayList<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
for (int i = 0; i < packageNames.length; ++i) {
final ApplicationInfo info = new ApplicationInfo();
info.packageName = packageNames[i];
info.uid = Process.FIRST_APPLICATION_UID + i;
info.sourceDir = info.packageName;
final ApplicationsState.AppEntry appEntry =
spy(new ApplicationsState.AppEntry(mContext, info, i));
appEntry.extraInfo = new AppStateDataUsageBridge
.DataUsageState(false, false);
doNothing().when(appEntry).ensureLabel(any(Context.class));
ReflectionHelpers.setField(appEntry, "info", info);
appEntries.add(appEntry);
}
return appEntries;
}
}

View File

@@ -23,15 +23,15 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import com.android.settings.testutils.shadow.ShadowActivityManager;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowActivityManager;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
@@ -45,7 +45,7 @@ public class VrListenerScreenPreferenceControllerTest {
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mContext = ApplicationProvider.getApplicationContext();
mController = new VrListenerScreenPreferenceController(mContext, "key");
mActivityManager = Shadow.extract(mContext.getSystemService(Context.ACTIVITY_SERVICE));
}

View File

@@ -25,23 +25,20 @@ import static org.mockito.Mockito.verify;
import android.app.NotificationManager;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowActivityManager;
import com.android.settings.testutils.shadow.ShadowNotificationManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowActivityManager.class,
})
public class ZenAccessControllerTest {
private static final String TEST_PKG = "com.test.package";
@@ -49,15 +46,12 @@ public class ZenAccessControllerTest {
private FakeFeatureFactory mFeatureFactory;
private Context mContext;
private ZenAccessController mController;
private ShadowActivityManager mActivityManager;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mContext = ApplicationProvider.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
mController = new ZenAccessController(mContext, "key");
mActivityManager = Shadow.extract(mContext.getSystemService(Context.ACTIVITY_SERVICE));
}
@Test

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2024 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.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static com.google.common.truth.Truth.assertThat;
import android.content.DialogInterface;
import android.hardware.biometrics.BiometricAuthenticator;
import android.os.Looper;
import android.widget.Button;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import com.android.settings.R;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowAlertDialogCompat.class)
public class BiometricsSplitScreenDialogTest {
@Rule
public final MockitoRule mocks = MockitoJUnit.rule();
private FragmentActivity mActivity;
private BiometricsSplitScreenDialog mFragment;
@Before
public void setUp() {
ShadowAlertDialogCompat.reset();
mActivity = Robolectric.buildActivity(FragmentActivity.class).setup().get();
}
@After
public void tearDown() {
ShadowAlertDialogCompat.reset();
}
@Test
public void testTexts_face() {
final AlertDialog dialog = setUpFragment(TYPE_FACE, false /*destroyActivity*/);
final ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(dialog);
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.biometric_settings_add_face_in_split_mode_title));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.biometric_settings_add_face_in_split_mode_message));
}
@Test
public void testTexts_fingerprint() {
final AlertDialog dialog = setUpFragment(TYPE_FINGERPRINT, false /*destroyActivity*/);
final ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(dialog);
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(
R.string.biometric_settings_add_fingerprint_in_split_mode_title));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(
R.string.biometric_settings_add_fingerprint_in_split_mode_message));
}
@Test
public void testButton_destroyActivity() {
final AlertDialog dialog = setUpFragment(TYPE_FACE, true /*destroyActivity*/);
final Button button = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
assertThat(button).isNotNull();
button.performClick();
Shadows.shadowOf(Looper.getMainLooper()).idle();
assertThat(dialog.isShowing()).isFalse();
assertThat(mActivity.isFinishing()).isTrue();
}
@Test
public void testButton_notDestroyActivity() {
final AlertDialog dialog = setUpFragment(TYPE_FACE, false /*destroyActivity*/);
final Button button = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
assertThat(button).isNotNull();
button.performClick();
Shadows.shadowOf(Looper.getMainLooper()).idle();
assertThat(dialog.isShowing()).isFalse();
assertThat(mActivity.isFinishing()).isFalse();
}
private AlertDialog setUpFragment(
@BiometricAuthenticator.Modality int biometricsModality, boolean destroyActivity) {
mFragment = BiometricsSplitScreenDialog.newInstance(biometricsModality, destroyActivity);
mFragment.show(mActivity.getSupportFragmentManager(), null);
Shadows.shadowOf(Looper.getMainLooper()).idle();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
return dialog;
}
}

View File

@@ -16,8 +16,6 @@
package com.android.settings.biometrics.combination;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static com.android.settings.biometrics.combination.BiometricsSettingsBase.CONFIRM_REQUEST;
import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED;
@@ -26,7 +24,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
@@ -37,11 +34,8 @@ import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.Intent;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.util.AndroidRuntimeException;
import android.view.LayoutInflater;
@@ -52,15 +46,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.XmlRes;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricStatusPreferenceController;
import com.android.settings.biometrics.BiometricsSplitScreenDialog;
import com.android.settings.biometrics.face.FaceStatusPreferenceController;
import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceController;
import com.android.settings.password.ChooseLockSettingsHelper;
@@ -72,7 +63,6 @@ import com.android.settingslib.core.AbstractPreferenceController;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -112,8 +102,6 @@ public class CombinedBiometricProfileSettingsTest {
private FaceStatusPreferenceController mFaceStatusPreferenceController;
@Mock
private FaceManager mFaceManager;
@Mock
private FragmentTransaction mFragmentTransaction;
@Before
public void setUp() {
@@ -350,133 +338,6 @@ public class CombinedBiometricProfileSettingsTest {
assertThat(capturedPreferences.get(0).getKey()).isEqualTo(mFragment.getFacePreferenceKey());
}
@Test
public void testClickFingerprintUnlock_inMultiWindow_withoutEnrolledFp_showsDialog() {
testClickFingerprintUnlock(true /* isInMultiWindow */, false /* hasEnrolledFingerprint */);
verifyShowsDialogAfterClickingUnlock(mFragment.getFingerprintPreferenceKey());
}
@Test
public void testClickFingerprintUnlock_inMultiWindow_withEnrolledFp_noDialog() {
testClickFingerprintUnlock(true /* isInMultiWindow */, true /* hasEnrolledFingerprint */);
verifyNoDialogAfterClickingUnlock(mFragment.getFingerprintPreferenceKey());
}
@Test
public void testClickFingerprintUnlock_inFullScreen_withoutEnrolledFp_noDialog() {
testClickFingerprintUnlock(false /* isInMultiWindow */, false /* hasEnrolledFingerprint */);
verifyNoDialogAfterClickingUnlock(mFragment.getFingerprintPreferenceKey());
}
private void testClickFingerprintUnlock(boolean isInMultiWindow,
boolean hasEnrolledFingerprint) {
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();
props.add(new FingerprintSensorPropertiesInternal(
0 /* sensorId */,
SensorProperties.STRENGTH_STRONG,
1 /* maxEnrollmentsPerUser */,
new ArrayList<ComponentInfoInternal>(),
TYPE_UDFPS_OPTICAL,
true /* resetLockoutRequiresHardwareAuthToken */));
doReturn(props).when(mFingerprintManager).getSensorPropertiesInternal();
doAnswer(invocation -> {
final FingerprintManager.GenerateChallengeCallback callback =
invocation.getArgument(1);
callback.onChallengeGenerated(0, 0, 1L);
return null;
}).when(mFingerprintManager).generateChallenge(anyInt(), any());
doReturn(new byte[]{1}).when(mFragment).requestGatekeeperHat(any(), anyLong(), anyInt(),
anyLong());
FragmentManager fragmentManager = mock(FragmentManager.class);
doReturn(fragmentManager).when(mActivity).getSupportFragmentManager();
doReturn(mFragmentTransaction).when(fragmentManager).beginTransaction();
doReturn(isInMultiWindow).when(mActivity).isInMultiWindowMode();
doReturn(hasEnrolledFingerprint).when(mFingerprintManager).hasEnrolledFingerprints(
anyInt());
// Start fragment
mFragment.onAttach(mContext);
mFragment.onCreate(null);
mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
mFragment.onResume();
// User clicks on "Fingerprint Unlock"
final Preference preference = new Preference(mContext);
preference.setKey(mFragment.getFingerprintPreferenceKey());
mFragment.onPreferenceTreeClick(preference);
}
@Test
@Ignore("b/295325503")
public void testClickFaceUnlock_inMultiWindow_withoutEnrolledFp_showsDialog() {
testClickFaceUnlock(true /* isInMultiWindow */, false /*hasEnrolledFace*/);
verifyShowsDialogAfterClickingUnlock(mFragment.getFacePreferenceKey());
}
@Test
public void testClickFaceUnlock_inMultiWindow_withEnrolledFp_noDialog() {
testClickFaceUnlock(true /* isInMultiWindow */, true /* hasEnrolledFace */);
verifyNoDialogAfterClickingUnlock(mFragment.getFacePreferenceKey());
}
@Test
public void testClickFaceUnlock_inFullScreen_withoutEnrolledFp_noDialog() {
testClickFaceUnlock(false /* isInMultiWindow */ , false /* hasEnrolledFace */);
verifyNoDialogAfterClickingUnlock(mFragment.getFacePreferenceKey());
}
private void testClickFaceUnlock(boolean isInMultiWindow, boolean hasEnrolledFace) {
doAnswer(invocation -> {
final FaceManager.GenerateChallengeCallback callback =
invocation.getArgument(1);
callback.onGenerateChallengeResult(0, 0, 1L);
return null;
}).when(mFaceManager).generateChallenge(anyInt(), any());
doReturn(new byte[] { 1 }).when(mFragment).requestGatekeeperHat(any(), anyLong(), anyInt(),
anyLong());
FragmentManager fragmentManager = mock(FragmentManager.class);
doReturn(fragmentManager).when(mActivity).getSupportFragmentManager();
doReturn(mFragmentTransaction).when(fragmentManager).beginTransaction();
doReturn(isInMultiWindow).when(mActivity).isInMultiWindowMode();
doReturn(hasEnrolledFace).when(mFaceManager).hasEnrolledTemplates(
anyInt());
// Start fragment
mFragment.onAttach(mContext);
mFragment.onCreate(null);
mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
mFragment.onResume();
// User clicks on "Face Unlock"
final Preference preference = new Preference(mContext);
preference.setKey(mFragment.getFacePreferenceKey());
mFragment.onPreferenceTreeClick(preference);
}
private void verifyNoDialogAfterClickingUnlock(String preferenceKey) {
final BiometricStatusPreferenceController controller =
preferenceKey.equals(mFragment.getFacePreferenceKey())
? mFaceStatusPreferenceController
: mFingerprintStatusPreferenceController;
verify(controller).handlePreferenceTreeClick(mPreferenceCaptor.capture());
List<Preference> capturedPreferences = mPreferenceCaptor.getAllValues();
assertThat(capturedPreferences).hasSize(1);
assertThat(capturedPreferences.get(0).getKey()).isEqualTo(preferenceKey);
verify(mFragmentTransaction, never()).add(any(),
eq(BiometricsSplitScreenDialog.class.getName()));
}
private void verifyShowsDialogAfterClickingUnlock(String preferenceKey) {
final BiometricStatusPreferenceController controller =
preferenceKey.equals(mFragment.getFacePreferenceKey())
? mFaceStatusPreferenceController
: mFingerprintStatusPreferenceController;
verify(controller, never()).handlePreferenceTreeClick(any());
verify(mFragmentTransaction).add(any(),
eq(BiometricsSplitScreenDialog.class.getName()));
}
@Test
public void testNoCrashIfDetachActivityDuringGeneratingChallengeThroughFaceManager() {
doAnswer(invocation -> {

View File

@@ -38,20 +38,25 @@ import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.hardware.face.Face;
import android.hardware.face.FaceEnrollOptions;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
import android.os.Looper;
import android.os.UserHandle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.widget.LockPatternUtils;
@@ -62,6 +67,7 @@ import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.SettingsShadowResources;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager;
@@ -101,7 +107,8 @@ import java.util.List;
ShadowUtils.class,
ShadowDevicePolicyManager.class,
ShadowSensorPrivacyManager.class,
SettingsShadowResources.class
SettingsShadowResources.class,
ShadowAlertDialogCompat.class
})
public class FaceEnrollIntroductionTest {
@@ -123,8 +130,8 @@ public class FaceEnrollIntroductionTest {
enum GateKeeperAction {CALL_SUPER, RETURN_BYTE_ARRAY, THROW_CREDENTIAL_NOT_MATCH}
public static class TestFaceEnrollIntroduction extends FaceEnrollIntroduction {
private int mRecreateCount = 0;
public boolean mIsMultiWindowMode;
public int getRecreateCount() {
return mRecreateCount;
@@ -161,6 +168,11 @@ public class FaceEnrollIntroductionTest {
protected boolean launchPostureGuidance() {
return super.launchPostureGuidance();
}
@Override
public boolean isInMultiWindowMode() {
return mIsMultiWindowMode;
}
}
@Before
@@ -178,12 +190,15 @@ public class FaceEnrollIntroductionTest {
public void tearDown() {
ShadowUtils.reset();
ShadowLockPatternUtils.reset();
ShadowAlertDialogCompat.reset();
}
private void setupActivity() {
final Intent testIntent = new Intent();
// Set the challenge token so the confirm screen will not be shown
testIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
testIntent.putExtra(BiometricUtils.EXTRA_ENROLL_REASON,
FaceEnrollOptions.ENROLL_REASON_SETTINGS);
when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())).thenReturn(
null /* Simulate no posture intent */);
@@ -208,6 +223,8 @@ public class FaceEnrollIntroductionTest {
testIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
testIntent.putExtra(EXTRA_KEY_NEXT_LAUNCHED, false);
testIntent.putExtra(EXTRA_LAUNCHED_POSTURE_GUIDANCE, false);
testIntent.putExtra(BiometricUtils.EXTRA_ENROLL_REASON,
FaceEnrollOptions.ENROLL_REASON_SETTINGS);
when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())).thenReturn(
testIntent);
@@ -596,4 +613,47 @@ public class FaceEnrollIntroductionTest {
assertThat(result).isEqualTo(0);
}
@Test
public void multiWindow_showsDialog() {
mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class);
mActivity = (TestFaceEnrollIntroduction) mController.get();
mActivity.mIsMultiWindowMode = true;
mController.setup().get();
Shadows.shadowOf(Looper.getMainLooper()).idle();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
final ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(dialog);
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
mActivity.getString(R.string.biometric_settings_add_face_in_split_mode_title));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
mActivity.getString(R.string.biometric_settings_add_face_in_split_mode_message));
final Button button = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
assertThat(button).isNotNull();
button.performClick();
Shadows.shadowOf(Looper.getMainLooper()).idle();
assertThat(dialog.isShowing()).isFalse();
assertThat(mActivity.isFinishing()).isTrue();
}
@Test
public void singleWindow_noDialog() {
Robolectric.buildActivity(TestFaceEnrollIntroduction.class).setup().get();
Shadows.shadowOf(Looper.getMainLooper()).idle();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
public void testFaceEnrollIntroduction_forwardsEnrollOptions() {
setupActivity();
final Intent intent = mActivity.getEnrollingIntent();
assertThat(intent.getIntExtra(BiometricUtils.EXTRA_ENROLL_REASON, -1))
.isEqualTo(FaceEnrollOptions.ENROLL_REASON_SETTINGS);
}
}

View File

@@ -669,7 +669,8 @@ public class FingerprintEnrollEnrollingTest {
any(CancellationSignal.class),
anyInt(),
callbackCaptor.capture(),
eq(FingerprintManager.ENROLL_ENROLL));
eq(FingerprintManager.ENROLL_ENROLL),
any());
return callbackCaptor.getValue();
}

View File

@@ -36,7 +36,6 @@ import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
import android.annotation.NonNull;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
@@ -52,6 +51,7 @@ import android.os.CancellationSignal;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.android.settings.R;
@@ -227,7 +227,8 @@ public class FingerprintEnrollFindSensorTest {
any(CancellationSignal.class),
anyInt(),
callbackCaptor.capture(),
eq(FingerprintManager.ENROLL_FIND_SENSOR));
eq(FingerprintManager.ENROLL_FIND_SENSOR),
any());
return callbackCaptor.getValue();
}

View File

@@ -40,6 +40,7 @@ import android.content.res.Resources;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintEnrollOptions;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -52,6 +53,7 @@ import androidx.annotation.Nullable;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.GatekeeperPasswordProvider;
import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -289,6 +291,18 @@ public class FingerprintEnrollIntroductionTest {
assertThat(mFingerprintEnrollIntroduction.shouldFinishWhenBackgrounded()).isEqualTo(true);
}
@Test
public void testFingerprintEnrollIntroduction_forwardsEnrollOptions() {
final Intent intent = newTokenOnlyIntent();
intent.putExtra(BiometricUtils.EXTRA_ENROLL_REASON,
FingerprintEnrollOptions.ENROLL_REASON_SETTINGS);
setupFingerprintEnrollIntroWith(intent);
final Intent enrollingIntent = mFingerprintEnrollIntroduction.getEnrollingIntent();
assertThat(enrollingIntent.getIntExtra(BiometricUtils.EXTRA_ENROLL_REASON, -1))
.isEqualTo(FingerprintEnrollOptions.ENROLL_REASON_SETTINGS);
}
private Intent newTokenOnlyIntent() {
return new Intent()
.putExtra(EXTRA_KEY_CHALLENGE_TOKEN, new byte[] { 1 });

View File

@@ -20,9 +20,7 @@ import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWE
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.ADD_FINGERPRINT_REQUEST;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.CHOOSE_LOCK_GENERIC_REQUEST;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.KEY_FINGERPRINT_ADD;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.KEY_REQUIRE_SCREEN_ON_TO_AUTH;
import static com.google.common.truth.Truth.assertThat;
@@ -34,9 +32,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -57,10 +53,8 @@ import android.view.ViewGroup;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.biometrics.BiometricsSplitScreenDialog;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowFragment;
@@ -132,35 +126,6 @@ public class FingerprintSettingsFragmentTest {
ShadowUtils.reset();
}
@Test
public void testAddFingerprint_inFullScreen_noDialog() {
setUpFragment(false);
// Click "Add Fingerprint"
final Preference preference = new Preference(mContext);
preference.setKey(KEY_FINGERPRINT_ADD);
mFragment.onPreferenceTreeClick(preference);
verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
verify(mFragmentTransaction, never()).add(any(),
eq(BiometricsSplitScreenDialog.class.getName()));
}
@Test
public void testAddFingerprint_inMultiWindow_showsDialog() {
setUpFragment(false);
doReturn(true).when(mActivity).isInMultiWindowMode();
// Click "Add Fingerprint"
final Preference preference = new Preference(mContext);
preference.setKey(KEY_FINGERPRINT_ADD);
mFragment.onPreferenceTreeClick(preference);
verify(mFragment, times(0)).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
verify(mFragmentTransaction).add(any(), eq(BiometricsSplitScreenDialog.class.getName()));
}
@Test
public void testChooseLockKeyForFingerprint() {
setUpFragment(true);
@@ -262,6 +227,7 @@ public class FingerprintSettingsFragmentTest {
mFragment.onResume();
}
@Ignore("b/315519360")
@Test
public void testFragmentVisibleWhenNoHardwareDetected() {
doReturn(false).when(mFingerprintManager).isHardwareDetected();

View File

@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
import static org.robolectric.RuntimeEnvironment.application;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -28,14 +29,18 @@ import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AlertDialog;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.biometrics.BiometricEnrollIntroduction;
import com.android.settings.password.SetupSkipDialog;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowFingerprintManager;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowStorageManager;
@@ -66,12 +71,23 @@ import java.util.List;
ShadowFingerprintManager.class,
ShadowLockPatternUtils.class,
ShadowStorageManager.class,
ShadowUserManager.class
ShadowUserManager.class,
ShadowAlertDialogCompat.class
})
public class SetupFingerprintEnrollIntroductionTest {
private ActivityController<SetupFingerprintEnrollIntroduction> mController;
public static class TestSetupFingerprintEnrollIntroductionInMultiWindowMode
extends SetupFingerprintEnrollIntroduction {
public boolean mIsMultiWindowMode = true;
@Override
public boolean isInMultiWindowMode() {
return mIsMultiWindowMode;
}
}
@Before
public void setUp() {
Shadows.shadowOf(application.getPackageManager())
@@ -105,6 +121,36 @@ public class SetupFingerprintEnrollIntroductionTest {
@After
public void tearDown() {
ShadowStorageManager.reset();
ShadowAlertDialogCompat.reset();
}
@Test
public void multiWindow_showsDialog() {
Activity activity = Robolectric.buildActivity(
TestSetupFingerprintEnrollIntroductionInMultiWindowMode.class).setup().get();
Shadows.shadowOf(Looper.getMainLooper()).idle();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
final ShadowAlertDialogCompat shadowAlertDialog = ShadowAlertDialogCompat.shadowOf(dialog);
assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo(
activity.getString(
R.string.biometric_settings_add_fingerprint_in_split_mode_title));
assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo(
activity.getString(
R.string.biometric_settings_add_fingerprint_in_split_mode_message));
// TODO(b/299573056): Make WizardManagerHelper.isAnySetupWizard(getIntent()) correct and
// test button click not finishing the activity.
}
@Test
public void singleWindow_noDialog() {
Robolectric.buildActivity(SetupFingerprintEnrollIntroduction.class).setup().get();
Shadows.shadowOf(Looper.getMainLooper()).idle();
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test

View File

@@ -33,16 +33,20 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.runner.AndroidJUnit4
import com.android.settings.R
import com.android.settings.biometrics.fingerprint2.shared.model.Default
import com.android.settings.biometrics.fingerprint2.lib.model.Default
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep.Introduction
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavigationState
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollIntroViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintFlowViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintGatekeeperViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintScrollViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.GatekeeperInfo
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.Intro
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.NavState
import com.android.settings.testutils2.FakeFingerprintManagerInteractor
import com.android.systemui.biometrics.shared.model.FingerprintSensor
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.google.android.setupdesign.GlifLayout
import com.google.android.setupdesign.template.RequireScrollMixin
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -62,18 +66,27 @@ class FingerprintEnrollIntroFragmentTest {
)
private val backgroundDispatcher = StandardTestDispatcher()
private lateinit var fragmentScenario: FragmentScenario<FingerprintEnrollIntroV2Fragment>
private val fingerprintSensor =
FingerprintSensor(1, SensorStrength.STRONG, 5, FingerprintSensorType.POWER_BUTTON)
var enrollFlow = Default
val flowViewModel = FingerprintFlowViewModel(enrollFlow)
private val navigationViewModel =
FingerprintEnrollNavigationViewModel(
backgroundDispatcher,
interactor,
gatekeeperViewModel,
Intro,
NavState(true),
Default,
FingerprintNavigationViewModel(
Introduction,
false,
flowViewModel,
interactor
)
private var fingerprintViewModel =
FingerprintEnrollViewModel(interactor, gatekeeperViewModel, navigationViewModel)
FingerprintEnrollIntroViewModel(
navigationViewModel,
flowViewModel,
interactor,
)
private var fingerprintScrollViewModel = FingerprintScrollViewModel()
@Before
@@ -85,9 +98,9 @@ class FingerprintEnrollIntroFragmentTest {
modelClass: Class<T>,
): T {
return when (modelClass) {
FingerprintEnrollViewModel::class.java -> fingerprintViewModel
FingerprintEnrollIntroViewModel::class.java -> fingerprintViewModel
FingerprintScrollViewModel::class.java -> fingerprintScrollViewModel
FingerprintEnrollNavigationViewModel::class.java -> navigationViewModel
FingerprintNavigationViewModel::class.java -> navigationViewModel
FingerprintGatekeeperViewModel::class.java -> gatekeeperViewModel
else -> null
}

View File

@@ -0,0 +1 @@
include /src/com/android/settings/biometrics/fingerprint2/OWNERS

View File

@@ -59,7 +59,6 @@ import org.robolectric.annotation.Config;
import java.util.HashSet;
import java.util.Set;
@Ignore("b/313014781")
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowEntityHeaderController.class, ShadowDeviceConfig.class})
public class AdvancedBluetoothDetailsHeaderControllerTest {
@@ -386,6 +385,9 @@ public class AdvancedBluetoothDetailsHeaderControllerTest {
.thenReturn("true".getBytes());
Set<CachedBluetoothDevice> cacheBluetoothDevices = new HashSet<>();
when(mCachedDevice.getMemberDevice()).thenReturn(cacheBluetoothDevices);
when(mBluetoothAdapter.addOnMetadataChangedListener(
mBluetoothDevice, mContext.getMainExecutor(), mController.mMetadataListener))
.thenReturn(true);
mController.onStart();

View File

@@ -16,7 +16,6 @@
package com.android.settings.bluetooth;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@@ -25,36 +24,26 @@ import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Pair;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.connecteddevice.audiosharing.AudioSharingFeatureProvider;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowAudioManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -75,9 +64,6 @@ import java.util.Collection;
ShadowBluetoothUtils.class
})
public class AvailableMediaBluetoothDeviceUpdaterTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
@Mock private DashboardFragment mDashboardFragment;
@@ -86,11 +72,7 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
@Mock private BluetoothDevice mBluetoothDevice;
@Mock private Drawable mDrawable;
@Mock private LocalBluetoothManager mLocalBtManager;
@Mock private LocalBluetoothProfileManager mLocalBtProfileManager;
@Mock private CachedBluetoothDeviceManager mCachedDeviceManager;
@Mock private LocalBluetoothLeBroadcast mBroadcast;
@Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
@Mock private BluetoothLeBroadcastReceiveState mBroadcastReceiveState;
private Context mContext;
private AvailableMediaBluetoothDeviceUpdater mBluetoothDeviceUpdater;
@@ -98,12 +80,14 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
private AudioManager mAudioManager;
private BluetoothDevicePreference mPreference;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
private AudioSharingFeatureProvider mFeatureProvider;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mFeatureProvider = FakeFeatureFactory.setupForTest().getAudioSharingFeatureProvider();
mAudioManager = mContext.getSystemService(AudioManager.class);
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBtManager;
mLocalBtManager = Utils.getLocalBtManager(mContext);
@@ -267,13 +251,15 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_addsPreference() {
setUpBroadcast(/* isSupported= */ false, /* isBroadcasting= */ false);
public void
onProfileConnectionStateChanged_leaDeviceConnected_notInCallNoSharing_addsPreference() {
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class)))
.thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
when(mFeatureProvider.isAudioSharingFilterMatched(
any(CachedBluetoothDevice.class), any(LocalBluetoothManager.class)))
.thenReturn(false);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(
mCachedBluetoothDevice,
@@ -284,13 +270,15 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onProfileConnectionStateChanged_leAudioDeviceConnected_inCall_addsPreference() {
setUpBroadcast(/* isSupported= */ false, /* isBroadcasting= */ false);
public void
onProfileConnectionStateChanged_leaDeviceConnected_inCallNoSharing_addsPreference() {
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class)))
.thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
when(mFeatureProvider.isAudioSharingFilterMatched(
any(CachedBluetoothDevice.class), any(LocalBluetoothManager.class)))
.thenReturn(false);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(
mCachedBluetoothDevice,
@@ -301,50 +289,16 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void
onProfileConnectionStateChanged_leaDeviceConnected_notInCall_notInBroadcast_addsPref() {
setUpBroadcast(/* isSupported= */ true, /* isBroadcasting= */ false);
onProfileConnectionStateChanged_leaDeviceConnected_notInCallInSharing_removesPref() {
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class)))
.thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(
mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.LE_AUDIO);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void
onProfileConnectionStateChanged_leaDeviceConnected_inCall_notInBroadcast_addsPref() {
setUpBroadcast(/* isSupported= */ true, /* isBroadcasting= */ false);
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class)))
when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true);
when(mFeatureProvider.isAudioSharingFilterMatched(
any(CachedBluetoothDevice.class), any(LocalBluetoothManager.class)))
.thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(
mCachedBluetoothDevice,
BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.LE_AUDIO);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void
onProfileConnectionStateChanged_leaDeviceConnected_notInCall_inBroadcast_removesPref() {
setUpBroadcast(/* isSupported= */ true, /* isBroadcasting= */ true);
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class)))
.thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(
mCachedBluetoothDevice,
@@ -355,14 +309,15 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void
onProfileConnectionStateChanged_leaDeviceConnected_inCall_inBroadcast_removesPref() {
setUpBroadcast(/* isSupported= */ true, /* isBroadcasting= */ true);
mAudioManager.setMode(AudioManager.MODE_IN_CALL);
public void onProfileConnectionStateChanged_leaDeviceConnected_inCallInSharing_removesPref() {
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class)))
.thenReturn(true);
when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
when(mFeatureProvider.isAudioSharingFilterMatched(
any(CachedBluetoothDevice.class), any(LocalBluetoothManager.class)))
.thenReturn(true);
mBluetoothDeviceUpdater.onProfileConnectionStateChanged(
mCachedBluetoothDevice,
@@ -414,56 +369,9 @@ public class AvailableMediaBluetoothDeviceUpdaterTest {
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onClick_Preference_setActive() {
setUpBroadcast(/* isSupported= */ false, /* isBroadcasting= */ false);
mBluetoothDeviceUpdater.onPreferenceClick(mPreference);
verify(mCachedBluetoothDevice).setActive();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onClick_Preference_isNotBroadcasting_setActive() {
setUpBroadcast(/* isSupported= */ true, /* isBroadcasting= */ false);
mBluetoothDeviceUpdater.onPreferenceClick(mPreference);
verify(mCachedBluetoothDevice).setActive();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onClick_Preference_isBroadcasting_stopBroadcastingAndSetActive() {
setUpBroadcast(/* isSupported= */ true, /* isBroadcasting= */ true);
doNothing().when(mBroadcast).stopBroadcast(anyInt());
mBluetoothDeviceUpdater.onPreferenceClick(mPreference);
verify(mBroadcast).stopBroadcast(anyInt());
verify(mCachedBluetoothDevice).setActive();
}
private void setUpBroadcast(boolean isSupported, boolean isBroadcasting) {
if (isSupported) {
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
when(mLocalBtManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
when(mBroadcast.isEnabled(null)).thenReturn(isBroadcasting);
when(mLocalBtProfileManager.getLeAudioBroadcastAssistantProfile())
.thenReturn(mAssistant);
if (isBroadcasting) {
when(mAssistant.getAllSources(any()))
.thenReturn(ImmutableList.of(mBroadcastReceiveState));
} else {
when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of());
}
} else {
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2024 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.bluetooth;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.DISABLED;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.ENABLED;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.PREF_KEY;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.SETTING_NAME;
import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.UNSET;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.android.settingslib.flags.Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import android.content.ContentResolver;
import android.content.Context;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class BluetoothAutoOnPreferenceControllerTest {
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private Context mContext;
private ContentResolver mContentResolver;
private BluetoothAutoOnPreferenceController mController;
@Before
public void setUp() {
mSetFlagsRule.enableFlags(FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE);
mContext = spy(ApplicationProvider.getApplicationContext());
mContentResolver = mContext.getContentResolver();
mController = new BluetoothAutoOnPreferenceController(mContext, PREF_KEY);
}
@Test
public void getAvailability_valueUnset_returnUnsupported() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, UNSET);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
public void getAvailability_valueSet_returnAvailable() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, DISABLED);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void isChecked_valueEnabled_returnTrue() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, ENABLED);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
assertThat(mController.isChecked()).isEqualTo(true);
}
@Test
public void setChecked_returnTrue() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, DISABLED);
mController.setChecked(true);
assertThat(mController.isChecked()).isEqualTo(true);
}
@Test
public void setChecked_returnFalse() {
Settings.Secure.putInt(mContentResolver, SETTING_NAME, ENABLED);
mController.setChecked(false);
assertThat(mController.isChecked()).isEqualTo(false);
}
}

View File

@@ -112,6 +112,7 @@ public class BluetoothDetailsCompanionAppsControllerTest extends
/* selfManaged */ false,
/* notifyOnDeviceNearby */ true,
/* revoked */ false,
/* pending */ false,
/* timeApprovedMs */ System.currentTimeMillis(),
/* lastTimeConnected */ Long.MAX_VALUE,
/* systemDataSyncFlags */ -1);

View File

@@ -43,6 +43,7 @@ import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowFragment.class,
com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal.class,
})
public abstract class BluetoothDetailsControllerTestBase {

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2024 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.bluetooth;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothDevice;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreferenceCompat;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.google.common.collect.ImmutableList;
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;
import org.robolectric.shadows.ShadowLooper;
@RunWith(RobolectricTestRunner.class)
public class BluetoothDetailsExtraOptionsControllerTest extends BluetoothDetailsControllerTestBase {
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
@Mock private BluetoothDevice mBluetoothDevice;
@Mock private Lifecycle mExtraOptionsLifecycle;
@Mock private PreferenceCategory mOptionsContainer;
@Mock private PreferenceScreen mPreferenceScreen;
private BluetoothDetailsExtraOptionsController mController;
private BluetoothFeatureProvider mFeatureProvider;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mCachedDevice.getAddress()).thenReturn(MAC_ADDRESS);
when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(MAC_ADDRESS);
final FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFeatureProvider = fakeFeatureFactory.getBluetoothFeatureProvider();
mController =
new BluetoothDetailsExtraOptionsController(
mContext, mFragment, mCachedDevice, mExtraOptionsLifecycle);
}
@Test
public void displayPreference_removeAndAddPreferences() {
Preference preference1 = new SwitchPreferenceCompat(mContext);
Preference preference2 = new SwitchPreferenceCompat(mContext);
when(mFeatureProvider.getBluetoothExtraOptions(mContext, mCachedDevice))
.thenReturn(ImmutableList.of(preference1, preference2));
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mOptionsContainer);
mController.displayPreference(mPreferenceScreen);
ShadowLooper.idleMainLooper();
verify(mOptionsContainer).removeAll();
verify(mOptionsContainer).addPreference(preference1);
verify(mOptionsContainer).addPreference(preference2);
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.bluetooth;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -28,23 +29,33 @@ import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.sysprop.BluetoothProperties;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.SwitchPreference;
import androidx.preference.SwitchPreferenceCompat;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowBluetoothDevice;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.bluetooth.MapProfile;
import com.android.settingslib.bluetooth.PbapServerProfile;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -59,30 +70,41 @@ import java.util.Map;
import java.util.Set;
@RunWith(RobolectricTestRunner.class)
@Ignore
@Config(shadows = ShadowBluetoothDevice.class)
public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsControllerTestBase {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String LE_DEVICE_MODEL = "le_audio_headset";
private static final String NON_LE_DEVICE_MODEL = "non_le_audio_headset";
private BluetoothDetailsProfilesController mController;
private List<LocalBluetoothProfile> mConnectableProfiles;
private PreferenceCategory mProfiles;
private BluetoothFeatureProvider mFeatureProvider;
@Mock
private LocalBluetoothManager mLocalManager;
@Mock
private LocalBluetoothProfileManager mProfileManager;
@Mock
private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
@Override
public void setUp() {
super.setUp();
FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
mFeatureProvider = fakeFeatureFactory.getBluetoothFeatureProvider();
mProfiles = spy(new PreferenceCategory(mContext));
when(mProfiles.getPreferenceManager()).thenReturn(mPreferenceManager);
mConnectableProfiles = new ArrayList<>();
when(mLocalManager.getProfileManager()).thenReturn(mProfileManager);
when(mLocalManager.getCachedDeviceManager()).thenReturn(mCachedBluetoothDeviceManager);
when(mCachedBluetoothDeviceManager.getCachedDevicesCopy())
.thenReturn(ImmutableList.of(mCachedDevice));
when(mCachedDevice.getConnectableProfiles()).thenAnswer(invocation ->
new ArrayList<>(mConnectableProfiles)
);
@@ -196,25 +218,26 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
return profile;
}
/** Returns the list of SwitchPreference objects added to the screen - there should be one per
* Bluetooth profile.
/**
* Returns the list of SwitchPreferenceCompat objects added to the screen - there should be one
* per Bluetooth profile.
*/
private List<SwitchPreference> getProfileSwitches(boolean expectOnlyMConnectable) {
private List<SwitchPreferenceCompat> getProfileSwitches(boolean expectOnlyMConnectable) {
if (expectOnlyMConnectable) {
assertThat(mConnectableProfiles).isNotEmpty();
assertThat(mProfiles.getPreferenceCount() - 1).isEqualTo(mConnectableProfiles.size());
}
List<SwitchPreference> result = new ArrayList<>();
List<SwitchPreferenceCompat> result = new ArrayList<>();
for (int i = 0; i < mProfiles.getPreferenceCount(); i++) {
final Preference preference = mProfiles.getPreference(i);
if (preference instanceof SwitchPreference) {
result.add((SwitchPreference) preference);
if (preference instanceof SwitchPreferenceCompat) {
result.add((SwitchPreferenceCompat) preference);
}
}
return result;
}
private void verifyProfileSwitchTitles(List<SwitchPreference> switches) {
private void verifyProfileSwitchTitles(List<SwitchPreferenceCompat> switches) {
for (int i = 0; i < switches.size(); i++) {
String expectedTitle =
mContext.getString(mConnectableProfiles.get(i).getNameResource(mDevice));
@@ -234,7 +257,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
addFakeProfile(com.android.settingslib.R.string.bluetooth_profile_a2dp, true);
addFakeProfile(com.android.settingslib.R.string.bluetooth_profile_headset, false);
showScreen(mController);
List<SwitchPreference> switches = getProfileSwitches(true);
List<SwitchPreferenceCompat> switches = getProfileSwitches(true);
verifyProfileSwitchTitles(switches);
assertThat(switches.get(0).isChecked()).isTrue();
assertThat(switches.get(1).isChecked()).isFalse();
@@ -260,8 +283,8 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
addFakeProfile(com.android.settingslib.R.string.bluetooth_profile_a2dp, true);
addFakeProfile(com.android.settingslib.R.string.bluetooth_profile_headset, true);
showScreen(mController);
List<SwitchPreference> switches = getProfileSwitches(true);
SwitchPreference pref = switches.get(0);
List<SwitchPreferenceCompat> switches = getProfileSwitches(true);
SwitchPreferenceCompat pref = switches.get(0);
// Clicking the pref should cause the profile to become not-preferred.
assertThat(pref.isChecked()).isTrue();
@@ -296,14 +319,16 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
PbapServerProfile psp = mock(PbapServerProfile.class);
when(psp.getNameResource(mDevice))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_pbap);
when(psp.getSummaryResourceForDevice(mDevice))
.thenReturn(R.string.bluetooth_profile_pbap_summary);
when(psp.toString()).thenReturn(PbapServerProfile.NAME);
when(psp.isProfileReady()).thenReturn(true);
when(mProfileManager.getPbapProfile()).thenReturn(psp);
showScreen(mController);
List<SwitchPreference> switches = getProfileSwitches(false);
List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
assertThat(switches.size()).isEqualTo(1);
SwitchPreference pref = switches.get(0);
SwitchPreferenceCompat pref = switches.get(0);
assertThat(pref.getTitle()).isEqualTo(
mContext.getString(com.android.settingslib.R.string.bluetooth_profile_pbap));
assertThat(pref.isChecked()).isTrue();
@@ -321,14 +346,16 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
PbapServerProfile psp = mock(PbapServerProfile.class);
when(psp.getNameResource(mDevice))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_pbap);
when(psp.getSummaryResourceForDevice(mDevice))
.thenReturn(R.string.bluetooth_profile_pbap_summary);
when(psp.toString()).thenReturn(PbapServerProfile.NAME);
when(psp.isProfileReady()).thenReturn(true);
when(mProfileManager.getPbapProfile()).thenReturn(psp);
showScreen(mController);
List<SwitchPreference> switches = getProfileSwitches(false);
List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
assertThat(switches.size()).isEqualTo(1);
SwitchPreference pref = switches.get(0);
SwitchPreferenceCompat pref = switches.get(0);
assertThat(pref.getTitle()).isEqualTo(
mContext.getString(com.android.settingslib.R.string.bluetooth_profile_pbap));
assertThat(pref.isChecked()).isFalse();
@@ -350,9 +377,9 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
when(mProfileManager.getProfileByName(eq(mapProfile.toString()))).thenReturn(mapProfile);
mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
showScreen(mController);
List<SwitchPreference> switches = getProfileSwitches(false);
List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
assertThat(switches.size()).isEqualTo(1);
SwitchPreference pref = switches.get(0);
SwitchPreferenceCompat pref = switches.get(0);
assertThat(pref.getTitle()).isEqualTo(
mContext.getString(com.android.settingslib.R.string.bluetooth_profile_map));
assertThat(pref.isChecked()).isFalse();
@@ -379,8 +406,8 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
return profile;
}
private SwitchPreference getHighQualityAudioPref() {
return (SwitchPreference) mScreen.findPreference(
private SwitchPreferenceCompat getHighQualityAudioPref() {
return (SwitchPreferenceCompat) mScreen.findPreference(
BluetoothDetailsProfilesController.HIGH_QUALITY_AUDIO_PREF_TAG);
}
@@ -389,7 +416,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
setupDevice(makeDefaultDeviceConfig());
addMockA2dpProfile(true, true, true);
showScreen(mController);
SwitchPreference pref = getHighQualityAudioPref();
SwitchPreferenceCompat pref = getHighQualityAudioPref();
assertThat(pref.getKey()).isEqualTo(
BluetoothDetailsProfilesController.HIGH_QUALITY_AUDIO_PREF_TAG);
@@ -407,7 +434,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
addMockA2dpProfile(true, false, false);
showScreen(mController);
assertThat(mProfiles.getPreferenceCount()).isEqualTo(2);
SwitchPreference pref = (SwitchPreference) mProfiles.getPreference(0);
SwitchPreferenceCompat pref = (SwitchPreferenceCompat) mProfiles.getPreference(0);
assertThat(pref.getKey())
.isNotEqualTo(BluetoothDetailsProfilesController.HIGH_QUALITY_AUDIO_PREF_TAG);
assertThat(pref.getTitle()).isEqualTo(
@@ -420,7 +447,7 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
addMockA2dpProfile(true, true, true);
when(mCachedDevice.isBusy()).thenReturn(true);
showScreen(mController);
SwitchPreference pref = getHighQualityAudioPref();
SwitchPreferenceCompat pref = getHighQualityAudioPref();
assertThat(pref.isEnabled()).isFalse();
}
@@ -433,14 +460,14 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
// Disabling media audio should cause the high quality audio switch to disappear, but not
// the regular audio one.
SwitchPreference audioPref =
(SwitchPreference) mScreen.findPreference(audioProfile.toString());
SwitchPreferenceCompat audioPref =
(SwitchPreferenceCompat) mScreen.findPreference(audioProfile.toString());
audioPref.performClick();
verify(audioProfile).setEnabled(mDevice, false);
when(audioProfile.isEnabled(mDevice)).thenReturn(false);
mController.onDeviceAttributesChanged();
assertThat(audioPref.isVisible()).isTrue();
SwitchPreference highQualityAudioPref = getHighQualityAudioPref();
SwitchPreferenceCompat highQualityAudioPref = getHighQualityAudioPref();
assertThat(highQualityAudioPref.isVisible()).isFalse();
// And re-enabling media audio should make high quality switch to reappear.
@@ -457,8 +484,8 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
setupDevice(makeDefaultDeviceConfig());
A2dpProfile audioProfile = addMockA2dpProfile(false, true, true);
showScreen(mController);
SwitchPreference audioPref = mScreen.findPreference(audioProfile.toString());
SwitchPreference highQualityAudioPref = getHighQualityAudioPref();
SwitchPreferenceCompat audioPref = mScreen.findPreference(audioProfile.toString());
SwitchPreferenceCompat highQualityAudioPref = getHighQualityAudioPref();
assertThat(audioPref).isNotNull();
assertThat(audioPref.isChecked()).isFalse();
assertThat(highQualityAudioPref).isNotNull();
@@ -489,4 +516,46 @@ public class BluetoothDetailsProfilesControllerTest extends BluetoothDetailsCont
assertThat(mController.isModelNameInAllowList(null)).isFalse();
assertThat(mController.isModelNameInAllowList(NON_LE_DEVICE_MODEL)).isFalse();
}
@Test
public void prefKeyInBlockingList_hideToggle() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_BLUETOOTH_PROFILE_TOGGLE_VISIBILITY_CHECKER);
setupDevice(makeDefaultDeviceConfig());
LeAudioProfile leAudioProfile = mock(LeAudioProfile.class);
when(leAudioProfile.getNameResource(mDevice))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
when(leAudioProfile.isProfileReady()).thenReturn(true);
when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any()))
.thenReturn(ImmutableSet.of("LE_AUDIO"));
mConnectableProfiles.add(leAudioProfile);
showScreen(mController);
List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
assertThat(switches.get(0).isVisible()).isFalse();
}
@Test
public void prefKeyNotInBlockingList_showToggle() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_BLUETOOTH_PROFILE_TOGGLE_VISIBILITY_CHECKER);
setupDevice(makeDefaultDeviceConfig());
LeAudioProfile leAudioProfile = mock(LeAudioProfile.class);
when(leAudioProfile.getNameResource(mDevice))
.thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
when(leAudioProfile.isProfileReady()).thenReturn(true);
when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
when(mFeatureProvider.getInvisibleProfilePreferenceKeys(any(), any()))
.thenReturn(ImmutableSet.of("A2DP"));
mConnectableProfiles.add(leAudioProfile);
showScreen(mController);
List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
assertThat(switches.get(0).isVisible()).isTrue();
}
}

View File

@@ -43,6 +43,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowLooper;
import java.util.ArrayList;
import java.util.List;
@@ -120,6 +121,7 @@ public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetails
when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
mController.refresh();
ShadowLooper.idleMainLooper();
assertThat(mSpatialAudioPref.isChecked()).isTrue();
}
@@ -130,6 +132,7 @@ public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetails
when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
mController.refresh();
ShadowLooper.idleMainLooper();
assertThat(mSpatialAudioPref.isChecked()).isFalse();
}
@@ -142,6 +145,7 @@ public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetails
when(mSpatializer.hasHeadTracker(mController.mAudioDevice)).thenReturn(true);
mController.refresh();
ShadowLooper.idleMainLooper();
assertThat(mHeadTrackingPref.isVisible()).isTrue();
}
@@ -156,6 +160,7 @@ public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetails
when(mSpatializer.hasHeadTracker(mController.mAudioDevice)).thenReturn(false);
mController.refresh();
ShadowLooper.idleMainLooper();
verify(mProfilesContainer).removePreference(mHeadTrackingPref);
}
@@ -166,6 +171,7 @@ public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetails
when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
mController.refresh();
ShadowLooper.idleMainLooper();
verify(mProfilesContainer).removePreference(mHeadTrackingPref);
}
@@ -181,6 +187,7 @@ public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetails
when(mSpatializer.isHeadTrackerEnabled(mController.mAudioDevice)).thenReturn(true);
mController.refresh();
ShadowLooper.idleMainLooper();
assertThat(mHeadTrackingPref.isChecked()).isTrue();
}
@@ -196,6 +203,7 @@ public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetails
when(mSpatializer.isHeadTrackerEnabled(mController.mAudioDevice)).thenReturn(false);
mController.refresh();
ShadowLooper.idleMainLooper();
assertThat(mHeadTrackingPref.isChecked()).isFalse();
}

View File

@@ -18,6 +18,8 @@ package com.android.settings.bluetooth;
import static android.bluetooth.BluetoothDevice.BOND_NONE;
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceControlsController.KEY_DEVICE_CONTROLS_GENERAL_GROUP;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -29,8 +31,10 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums;
import android.companion.CompanionDeviceManager;
import android.content.Context;
import android.content.Intent;
import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.UserManager;
@@ -49,6 +53,8 @@ import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.common.collect.ImmutableList;
@@ -65,6 +71,8 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.fakes.RoboMenu;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowUserManager.class,
@@ -216,6 +224,38 @@ public class BluetoothDeviceDetailsFragmentTest {
verify(mFragment).finish();
}
@Test
public void createPreferenceControllers_launchFromHAPage_deviceControllerNotExist() {
BluetoothDeviceDetailsFragment fragment = setupFragment();
Intent intent = fragment.getActivity().getIntent();
intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS);
fragment.onAttach(mContext);
List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
mContext);
assertThat(controllerList.stream()
.anyMatch(controller -> controller.getPreferenceKey().equals(
KEY_DEVICE_CONTROLS_GENERAL_GROUP))).isFalse();
}
@Test
public void createPreferenceControllers_notLaunchFromHAPage_deviceControllerExist() {
BluetoothDeviceDetailsFragment fragment = setupFragment();
Intent intent = fragment.getActivity().getIntent();
intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
SettingsEnums.PAGE_UNKNOWN);
fragment.onAttach(mContext);
List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
mContext);
assertThat(controllerList.stream()
.anyMatch(controller -> controller.getPreferenceKey().equals(
KEY_DEVICE_CONTROLS_GENERAL_GROUP))).isTrue();
}
private InputDevice createInputDeviceWithMatchingBluetoothAddress() {
doReturn(new int[]{0}).when(mInputManager).getInputDeviceIds();
InputDevice device = mock(InputDevice.class);

View File

@@ -33,6 +33,8 @@ public class BluetoothNameDialogFragmentTest {
private TestBluetoothNameDialogFragment mBluetoothNameDialogFragment;
private TextView mTextView;
private static final String NAME_FOR_TEST = "test_device_name";
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -51,12 +53,24 @@ public class BluetoothNameDialogFragmentTest {
null)).isTrue();
}
@Test
public void onEditorAction_ImeNull_setsDeviceName() {
mTextView.setText(NAME_FOR_TEST);
assertThat(
mBluetoothNameDialogFragment.onEditorAction(mTextView, EditorInfo.IME_NULL,
null)).isTrue();
assertThat(mBluetoothNameDialogFragment.getDeviceName()).isEqualTo(NAME_FOR_TEST);
}
/**
* Test fragment for {@link BluetoothNameDialogFragment} to test common methods
*/
public static class TestBluetoothNameDialogFragment extends BluetoothNameDialogFragment {
private String mName;
@Override
protected int getDialogTitle() {
return 0;
@@ -64,12 +78,12 @@ public class BluetoothNameDialogFragmentTest {
@Override
protected String getDeviceName() {
return null;
return mName;
}
@Override
protected void setDeviceName(String deviceName) {
mName = deviceName;
}
@Override

View File

@@ -20,6 +20,8 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -28,8 +30,13 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Pair;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
@@ -37,9 +44,12 @@ import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.testutils.shadow.ShadowAudioManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowCachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.flags.Flags;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -58,6 +68,10 @@ import java.util.Collection;
public class ConnectedBluetoothDeviceUpdaterTest {
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
private static final String FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name";
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private DashboardFragment mDashboardFragment;
@@ -69,6 +83,8 @@ public class ConnectedBluetoothDeviceUpdaterTest {
private BluetoothDevice mBluetoothDevice;
@Mock
private Drawable mDrawable;
@Mock
private PackageManager mPackageManager;
private Context mContext;
private ConnectedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
@@ -82,7 +98,7 @@ public class ConnectedBluetoothDeviceUpdaterTest {
MockitoAnnotations.initMocks(this);
Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
mContext = RuntimeEnvironment.application;
mContext = spy(RuntimeEnvironment.application);
mAudioManager = mContext.getSystemService(AudioManager.class);
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
@@ -92,6 +108,7 @@ public class ConnectedBluetoothDeviceUpdaterTest {
mCachedDevices = new ArrayList<>();
mCachedDevices.add(mCachedBluetoothDevice);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
@@ -320,4 +337,97 @@ public class ConnectedBluetoothDeviceUpdaterTest {
assertThat(btPreference.shouldHideSecondTarget()).isTrue();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_notExclusiveManagedDevice_addDevice() {
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
null);
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_notAllowedExclusiveManagedDevice_addDevice() {
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
FAKE_EXCLUSIVE_MANAGER_NAME.getBytes());
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_existingExclusivelyManagedDeviceWithPackageInstalled_removePreference()
throws Exception {
final String exclusiveManagerName =
BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
FAKE_EXCLUSIVE_MANAGER_NAME);
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
exclusiveManagerName.getBytes());
doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_newExclusivelyManagedDeviceWithPackageInstalled_doNotAddPreference()
throws Exception {
final String exclusiveManagerName =
BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
FAKE_EXCLUSIVE_MANAGER_NAME);
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
exclusiveManagerName.getBytes());
doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_exclusivelyManagedDeviceWithoutPackageInstalled_addDevice()
throws Exception {
final String exclusiveManagerName =
BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
FAKE_EXCLUSIVE_MANAGER_NAME);
mAudioManager.setMode(AudioManager.MODE_NORMAL);
when(mBluetoothDeviceUpdater
.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
exclusiveManagerName.getBytes());
doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo(
exclusiveManagerName, 0);
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.bluetooth;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -28,17 +29,26 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Pair;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.flags.Flags;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -56,6 +66,10 @@ import java.util.List;
public class SavedBluetoothDeviceUpdaterTest {
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
private static final String FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name";
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private DashboardFragment mDashboardFragment;
@@ -73,6 +87,8 @@ public class SavedBluetoothDeviceUpdaterTest {
private LocalBluetoothManager mBluetoothManager;
@Mock
private Drawable mDrawable;
@Mock
private PackageManager mPackageManager;
private Context mContext;
private SavedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
@@ -84,12 +100,13 @@ public class SavedBluetoothDeviceUpdaterTest {
MockitoAnnotations.initMocks(this);
Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
mContext = RuntimeEnvironment.application;
mContext = spy(RuntimeEnvironment.application);
doReturn(mContext).when(mDashboardFragment).getContext();
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
mBluetoothDeviceUpdater = spy(new SavedBluetoothDeviceUpdater(mContext,
mDevicePreferenceCallback, false, /* metricsCategory= */ 0));
@@ -103,10 +120,10 @@ public class SavedBluetoothDeviceUpdaterTest {
mCachedDevices.add(mCachedBluetoothDevice);
when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_filterMatch_addPreference() {
doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState();
doReturn(false).when(mBluetoothDevice).isConnected();
@@ -118,6 +135,7 @@ public class SavedBluetoothDeviceUpdaterTest {
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_filterNotMatch_removePreference() {
doReturn(BluetoothDevice.BOND_NONE).when(mBluetoothDevice).getBondState();
doReturn(true).when(mBluetoothDevice).isConnected();
@@ -298,4 +316,125 @@ public class SavedBluetoothDeviceUpdaterTest {
verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_notExclusivelyManagedDevice_addDevice() {
final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
cachedDevices.add(mCachedBluetoothDevice);
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mBluetoothDevice.isConnected()).thenReturn(false);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
null);
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_notAllowedExclusivelyManagedDevice_addDevice() {
final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
cachedDevices.add(mCachedBluetoothDevice);
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mBluetoothDevice.isConnected()).thenReturn(false);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
FAKE_EXCLUSIVE_MANAGER_NAME.getBytes());
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_existingExclusivelyManagedDeviceWithPackageInstalled_removePreference()
throws Exception {
final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
final String exclusiveManagerName =
BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
FAKE_EXCLUSIVE_MANAGER_NAME);
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mBluetoothDevice.isConnected()).thenReturn(false);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
exclusiveManagerName.getBytes());
doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_newExclusivelyManagedDeviceWithPackageInstalled_doNotAddPreference()
throws Exception {
final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
final String exclusiveManagerName =
BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
FAKE_EXCLUSIVE_MANAGER_NAME);
cachedDevices.add(mCachedBluetoothDevice);
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mBluetoothDevice.isConnected()).thenReturn(false);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
exclusiveManagerName.getBytes());
doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_exclusivelyManagedDeviceWithoutPackageInstalled_addDevice()
throws Exception {
final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
final String exclusiveManagerName =
BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
FAKE_EXCLUSIVE_MANAGER_NAME);
cachedDevices.add(mCachedBluetoothDevice);
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mBluetoothDevice.isConnected()).thenReturn(false);
when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
exclusiveManagerName.getBytes());
doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo(
exclusiveManagerName, 0);
mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
}
}

View File

@@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
@@ -31,6 +32,7 @@ import android.content.pm.PackageManager;
import android.text.TextUtils;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settingslib.RestrictedPreference;
@@ -40,9 +42,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplicationPackageManager;
import org.robolectric.util.ReflectionHelpers;
@@ -50,13 +51,13 @@ import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowApplicationPackageManager.class)
public class AddDevicePreferenceControllerTest {
@Mock
private PreferenceScreen mScreen;
@Mock
private BluetoothAdapter mBluetoothAdapter;
private Context mContext;
@Spy
private Context mContext = ApplicationProvider.getApplicationContext();
private AddDevicePreferenceController mAddDevicePreferenceController;
private RestrictedPreference mAddDevicePreference;
private ShadowApplicationPackageManager mPackageManager;
@@ -66,8 +67,7 @@ public class AddDevicePreferenceControllerTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mPackageManager = (ShadowApplicationPackageManager) Shadows.shadowOf(
mPackageManager = (ShadowApplicationPackageManager) shadowOf(
mContext.getPackageManager());
mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, true);

View File

@@ -22,27 +22,23 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
@@ -51,19 +47,16 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater;
import com.android.settings.bluetooth.Utils;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowAudioManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidInfo;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Rule;
@@ -76,16 +69,12 @@ import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import java.util.concurrent.Executor;
/** Tests for {@link AvailableMediaDeviceGroupController}. */
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
ShadowAudioManager.class,
ShadowBluetoothAdapter.class,
ShadowBluetoothUtils.class,
ShadowAlertDialogCompat.class,
})
@@ -105,9 +94,7 @@ public class AvailableMediaDeviceGroupControllerTest {
@Mock private PackageManager mPackageManager;
@Mock private BluetoothEventManager mEventManager;
@Mock private LocalBluetoothManager mLocalBluetoothManager;
@Mock private LocalBluetoothProfileManager mLocalBtProfileManager;
@Mock private CachedBluetoothDeviceManager mCachedDeviceManager;
@Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
@Mock private CachedBluetoothDevice mCachedBluetoothDevice;
private PreferenceGroup mPreferenceGroup;
@@ -115,13 +102,16 @@ public class AvailableMediaDeviceGroupControllerTest {
private Preference mPreference;
private AvailableMediaDeviceGroupController mAvailableMediaDeviceGroupController;
private AudioManager mAudioManager;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mPreference = new Preference(mContext);
mPreference.setKey(PREFERENCE_KEY_1);
mPreferenceGroup = spy(new PreferenceScreen(mContext, null));
@@ -130,24 +120,17 @@ public class AvailableMediaDeviceGroupControllerTest {
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
mAudioManager = mContext.getSystemService(AudioManager.class);
doReturn(mEventManager).when(mLocalBluetoothManager).getEventManager();
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
when(mCachedDeviceManager.findDevice(any(BluetoothDevice.class)))
.thenReturn(mCachedBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
mAvailableMediaDeviceGroupController =
spy(new AvailableMediaDeviceGroupController(mContext));
spy(new AvailableMediaDeviceGroupController(mContext, null, mLifecycle));
mAvailableMediaDeviceGroupController.setBluetoothDeviceUpdater(
mAvailableMediaBluetoothDeviceUpdater);
mAvailableMediaDeviceGroupController.setFragmentManager(
@@ -197,7 +180,7 @@ public class AvailableMediaDeviceGroupControllerTest {
@Test
public void testRegister() {
// register the callback in onStart()
mAvailableMediaDeviceGroupController.onStart();
mAvailableMediaDeviceGroupController.onStart(mLifecycleOwner);
verify(mAvailableMediaBluetoothDeviceUpdater).registerCallback();
verify(mLocalBluetoothManager.getEventManager())
@@ -205,36 +188,15 @@ public class AvailableMediaDeviceGroupControllerTest {
verify(mAvailableMediaBluetoothDeviceUpdater).refreshPreference();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void testRegister_audioSharingOn() {
setUpBroadcast();
// register the callback in onStart()
mAvailableMediaDeviceGroupController.onStart();
verify(mAssistant)
.registerServiceCallBack(
any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
}
@Test
public void testUnregister() {
// unregister the callback in onStop()
mAvailableMediaDeviceGroupController.onStop();
mAvailableMediaDeviceGroupController.onStop(mLifecycleOwner);
verify(mAvailableMediaBluetoothDeviceUpdater).unregisterCallback();
verify(mLocalBluetoothManager.getEventManager())
.unregisterCallback(any(BluetoothCallback.class));
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void testUnregister_audioSharingOn() {
setUpBroadcast();
// unregister the callback in onStop()
mAvailableMediaDeviceGroupController.onStop();
verify(mAssistant)
.unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
}
@Test
public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
@@ -274,7 +236,7 @@ public class AvailableMediaDeviceGroupControllerTest {
mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null;
// Shouldn't crash
mAvailableMediaDeviceGroupController.onStart();
mAvailableMediaDeviceGroupController.onStart(mLifecycleOwner);
}
@Test
@@ -282,7 +244,7 @@ public class AvailableMediaDeviceGroupControllerTest {
mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null;
// Shouldn't crash
mAvailableMediaDeviceGroupController.onStop();
mAvailableMediaDeviceGroupController.onStop(mLifecycleOwner);
}
@Test
@@ -300,19 +262,4 @@ public class AvailableMediaDeviceGroupControllerTest {
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog.isShowing()).isTrue();
}
private void setUpBroadcast() {
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
when(mLocalBtProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
doNothing()
.when(mAssistant)
.registerServiceCallBack(
any(Executor.class), any(BluetoothLeBroadcastAssistant.Callback.class));
doNothing()
.when(mAssistant)
.unregisterServiceCallBack(any(BluetoothLeBroadcastAssistant.Callback.class));
}
}

View File

@@ -20,22 +20,25 @@ import static com.android.settings.connecteddevice.ConnectedDeviceDashboardFragm
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.PackageManager;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.SearchIndexableResource;
import com.android.settings.R;
import com.android.settings.connecteddevice.fastpair.FastPairDeviceUpdater;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerListHelper;
import com.android.settings.flags.Flags;
import com.android.settings.slices.SlicePreferenceController;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -53,20 +56,23 @@ import org.robolectric.annotation.Config;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowUserManager.class,
ShadowConnectivityManager.class, ShadowBluetoothAdapter.class})
@Config(
shadows = {
ShadowUserManager.class,
ShadowConnectivityManager.class,
ShadowBluetoothAdapter.class
})
public class ConnectedDeviceDashboardFragmentTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String KEY_NEARBY_DEVICES = "bt_nearby_slice";
private static final String KEY_DISCOVERABLE_FOOTER = "discoverable_footer";
private static final String KEY_SAVED_DEVICE_SEE_ALL = "previously_connected_devices_see_all";
private static final String KEY_FAST_PAIR_DEVICE_SEE_ALL = "fast_pair_devices_see_all";
private static final String KEY_ADD_BT_DEVICES = "add_bt_devices";
private static final String KEY_AUDIO_SHARING_DEVICE_LIST = "audio_sharing_device_list";
private static final String KEY_AUDIO_SHARING_SETTINGS =
"connected_device_audio_sharing_settings";
private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
@@ -74,8 +80,11 @@ public class ConnectedDeviceDashboardFragmentTest {
private static final String TEST_ACTION = "com.testapp.settings.ACTION_START";
@Mock private PackageManager mPackageManager;
@Mock private FastPairDeviceUpdater mFastPairDeviceUpdater;
private Context mContext;
private ConnectedDeviceDashboardFragment mFragment;
private FakeFeatureFactory mFeatureFactory;
private AvailableMediaDeviceGroupController mMediaDeviceGroupController;
@Before
public void setUp() {
@@ -83,6 +92,22 @@ public class ConnectedDeviceDashboardFragmentTest {
mContext = spy(RuntimeEnvironment.application);
mFragment = new ConnectedDeviceDashboardFragment();
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION);
mFeatureFactory = FakeFeatureFactory.setupForTest();
when(mFeatureFactory
.getFastPairFeatureProvider()
.getFastPairDeviceUpdater(
any(Context.class), any(DevicePreferenceCallback.class)))
.thenReturn(mFastPairDeviceUpdater);
when(mFeatureFactory
.getAudioSharingFeatureProvider()
.createAudioSharingDevicePreferenceController(mContext, null, null))
.thenReturn(null);
mMediaDeviceGroupController = new AvailableMediaDeviceGroupController(mContext, null, null);
when(mFeatureFactory
.getAudioSharingFeatureProvider()
.createAvailableMediaDeviceGroupController(mContext, null, null))
.thenReturn(mMediaDeviceGroupController);
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
}
@@ -98,7 +123,6 @@ public class ConnectedDeviceDashboardFragmentTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void nonIndexableKeys_existInXmlLayout() {
final List<String> niks =
ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(
@@ -111,27 +135,7 @@ public class ConnectedDeviceDashboardFragmentTest {
KEY_NEARBY_DEVICES,
KEY_DISCOVERABLE_FOOTER,
KEY_SAVED_DEVICE_SEE_ALL,
KEY_FAST_PAIR_DEVICE_SEE_ALL,
KEY_AUDIO_SHARING_SETTINGS);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void nonIndexableKeys_existInXmlLayout_flagOff() {
final List<String> niks =
ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(
mContext);
assertThat(niks)
.containsExactly(
KEY_CONNECTED_DEVICES,
KEY_AVAILABLE_DEVICES,
KEY_NEARBY_DEVICES,
KEY_DISCOVERABLE_FOOTER,
KEY_SAVED_DEVICE_SEE_ALL,
KEY_FAST_PAIR_DEVICE_SEE_ALL,
KEY_AUDIO_SHARING_DEVICE_LIST,
KEY_AUDIO_SHARING_SETTINGS);
KEY_FAST_PAIR_DEVICE_SEE_ALL);
}
@Test
@@ -160,10 +164,12 @@ public class ConnectedDeviceDashboardFragmentTest {
PreferenceControllerListHelper.getPreferenceControllersFromXml(
mContext, R.xml.connected_devices);
assertThat(controllers
.stream()
.filter(controller -> controller instanceof SlicePreferenceController)
.count())
assertThat(
controllers.stream()
.filter(
controller ->
controller instanceof SlicePreferenceController)
.count())
.isEqualTo(1);
}
}

View File

@@ -27,9 +27,14 @@ import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Pair;
import androidx.preference.Preference;
@@ -42,11 +47,14 @@ import com.android.settings.bluetooth.BluetoothDevicePreference;
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.connecteddevice.dock.DockUpdater;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.widget.SingleTargetGearPreference;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -70,6 +78,9 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
private static final String FAKE_ADDRESS_4 = "AA:AA:AA:AA:AA:04";
private static final String FAKE_ADDRESS_5 = "AA:AA:AA:AA:AA:05";
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private DashboardFragment mDashboardFragment;
@Mock
@@ -105,6 +116,9 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
@Mock
private Drawable mDrawable;
@Mock private BluetoothManager mBluetoothManager;
@Mock private BluetoothAdapter mBluetoothAdapter;
private Context mContext;
private PreviouslyConnectedDevicePreferenceController mPreConnectedDeviceController;
private PreferenceGroup mPreferenceGroup;
@@ -117,10 +131,8 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
mContext = spy(RuntimeEnvironment.application);
doReturn(mContext).when(mDashboardFragment).getContext();
doReturn(mPackageManager).when(mContext).getPackageManager();
mPreConnectedDeviceController =
new PreviouslyConnectedDevicePreferenceController(mContext, KEY);
mPreConnectedDeviceController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater);
mPreConnectedDeviceController.setSavedDockUpdater(mDockUpdater);
when(mContext.getSystemService(BluetoothManager.class)).thenReturn(mBluetoothManager);
when(mBluetoothManager.getAdapter()).thenReturn(mBluetoothAdapter);
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1);
@@ -145,7 +157,13 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
mMostRecentlyConnectedDevices.add(mBluetoothDevice4);
mMostRecentlyConnectedDevices.add(mBluetoothDevice3);
mShadowBluetoothAdapter.setMostRecentlyConnectedDevices(mMostRecentlyConnectedDevices);
when(mBluetoothAdapter.getMostRecentlyConnectedDevices())
.thenReturn(mMostRecentlyConnectedDevices);
mPreConnectedDeviceController =
new PreviouslyConnectedDevicePreferenceController(mContext, KEY);
mPreConnectedDeviceController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater);
mPreConnectedDeviceController.setSavedDockUpdater(mDockUpdater);
mPreferenceGroup = spy(new PreferenceCategory(mContext));
doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager();
mPreferenceGroup.setVisible(false);
@@ -205,6 +223,7 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
AVAILABLE);
}
@Ignore("b/322712259")
@Test
public void onDeviceAdded_addDevicePreference_displayIt() {
final BluetoothDevicePreference preference1 = new BluetoothDevicePreference(
@@ -215,6 +234,7 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
}
@Ignore("b/322712259")
@Test
public void onDeviceAdded_addDockDevicePreference_displayIt() {
final SingleTargetGearPreference dockPreference = new SingleTargetGearPreference(
@@ -225,6 +245,7 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
}
@Ignore("b/322712259")
@Test
public void onDeviceAdded_addFourDevicePreference_onlyDisplayThree() {
final BluetoothDevicePreference preference1 = new BluetoothDevicePreference(
@@ -249,6 +270,7 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY)
public void onDeviceAdded_addPreferenceNotExistInRecentlyDevices_noCrash() {
final BluetoothDevicePreference preference = new BluetoothDevicePreference(
mContext, mCachedDevice5, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
@@ -259,6 +281,18 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(2);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY)
public void onDeviceAdded_addPreferenceNotExistInRecentlyDevices_doNothing() {
final BluetoothDevicePreference preference = new BluetoothDevicePreference(
mContext, mCachedDevice5, true, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
mPreConnectedDeviceController.onDeviceAdded(preference);
// 1 see all preference
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
}
@Test
public void onDeviceRemoved_removeLastDevice_showSeeAllPreference() {
final BluetoothDevicePreference preference1 = new BluetoothDevicePreference(
@@ -277,6 +311,7 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
@Test
public void updatePreferenceVisibility_bluetoothIsEnable_shouldShowCorrectText() {
mShadowBluetoothAdapter.setEnabled(true);
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
mPreConnectedDeviceController.updatePreferenceVisibility();
verify(mSeeAllPreference).setSummary("");
@@ -285,9 +320,78 @@ public class PreviouslyConnectedDevicePreferenceControllerTest {
@Test
public void updatePreferenceVisibility_bluetoothIsDisable_shouldShowCorrectText() {
mShadowBluetoothAdapter.setEnabled(false);
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
mPreConnectedDeviceController.updatePreferenceVisibility();
verify(mSeeAllPreference).setSummary(
mContext.getString(R.string.connected_device_see_all_summary));
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY)
public void updatePreferenceGroup_bluetoothIsEnable_shouldOrderByMostRecentlyConnected() {
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
final BluetoothDevicePreference preference4 =
new BluetoothDevicePreference(
mContext,
mCachedDevice4,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
final BluetoothDevicePreference preference3 =
new BluetoothDevicePreference(
mContext,
mCachedDevice3,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
final BluetoothDevicePreference preference2 =
new BluetoothDevicePreference(
mContext,
mCachedDevice2,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
mPreConnectedDeviceController.onDeviceAdded(preference4);
mPreConnectedDeviceController.onDeviceAdded(preference3);
mPreConnectedDeviceController.onDeviceAdded(preference2);
mPreConnectedDeviceController.updatePreferenceGroup();
// Refer to the order of {@link #mMostRecentlyConnectedDevices}, the first one is see all
// preference
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(4);
assertThat(preference2.getOrder()).isEqualTo(0);
assertThat(preference4.getOrder()).isEqualTo(1);
assertThat(preference3.getOrder()).isEqualTo(2);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY)
public void updatePreferenceGroup_bluetoothIsDisable_shouldShowOnlySeeAllPreference() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
final BluetoothDevicePreference preference4 =
new BluetoothDevicePreference(
mContext,
mCachedDevice4,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
final BluetoothDevicePreference preference3 =
new BluetoothDevicePreference(
mContext,
mCachedDevice3,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
final BluetoothDevicePreference preference2 =
new BluetoothDevicePreference(
mContext,
mCachedDevice2,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
mPreConnectedDeviceController.onDeviceAdded(preference4);
mPreConnectedDeviceController.onDeviceAdded(preference3);
mPreConnectedDeviceController.onDeviceAdded(preference2);
mPreConnectedDeviceController.updatePreferenceGroup();
// 1 see all preference
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(1);
}
}

View File

@@ -25,29 +25,52 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Pair;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import com.android.settings.bluetooth.BluetoothDevicePreference;
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
import com.android.settings.connecteddevice.dock.DockUpdater;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class SavedDeviceGroupControllerTest {
private static final String FAKE_ADDRESS_1 = "AA:AA:AA:AA:AA:01";
private static final String FAKE_ADDRESS_2 = "AA:AA:AA:AA:AA:02";
private static final String FAKE_ADDRESS_3 = "AA:AA:AA:AA:AA:03";
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private DashboardFragment mDashboardFragment;
@Mock
@@ -56,23 +79,57 @@ public class SavedDeviceGroupControllerTest {
private DockUpdater mSavedDockUpdater;
@Mock
private PackageManager mPackageManager;
@Mock private BluetoothManager mBluetoothManager;
@Mock private BluetoothAdapter mBluetoothAdapter;
@Mock private CachedBluetoothDevice mCachedDevice1;
@Mock private CachedBluetoothDevice mCachedDevice2;
@Mock private CachedBluetoothDevice mCachedDevice3;
@Mock private BluetoothDevice mBluetoothDevice1;
@Mock private BluetoothDevice mBluetoothDevice2;
@Mock private BluetoothDevice mBluetoothDevice3;
@Mock private Drawable mDrawable;
@Mock private PreferenceManager mPreferenceManager;
private Context mContext;
private SavedDeviceGroupController mSavedDeviceGroupController;
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
private PreferenceGroup mPreferenceGroup;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
mContext = spy(RuntimeEnvironment.application);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
doReturn(mContext).when(mDashboardFragment).getContext();
doReturn(mPackageManager).when(mContext).getPackageManager();
when(mCachedDevice1.getDevice()).thenReturn(mBluetoothDevice1);
when(mCachedDevice1.getAddress()).thenReturn(FAKE_ADDRESS_1);
when(mCachedDevice1.getDrawableWithDescription()).thenReturn(pairs);
when(mCachedDevice2.getDevice()).thenReturn(mBluetoothDevice2);
when(mCachedDevice2.getAddress()).thenReturn(FAKE_ADDRESS_2);
when(mCachedDevice2.getDrawableWithDescription()).thenReturn(pairs);
when(mCachedDevice3.getDevice()).thenReturn(mBluetoothDevice3);
when(mCachedDevice3.getAddress()).thenReturn(FAKE_ADDRESS_3);
when(mCachedDevice3.getDrawableWithDescription()).thenReturn(pairs);
final List<BluetoothDevice> mMostRecentlyConnectedDevices = new ArrayList<>();
mMostRecentlyConnectedDevices.add(mBluetoothDevice1);
mMostRecentlyConnectedDevices.add(mBluetoothDevice2);
mMostRecentlyConnectedDevices.add(mBluetoothDevice3);
when(mContext.getSystemService(BluetoothManager.class)).thenReturn(mBluetoothManager);
when(mBluetoothManager.getAdapter()).thenReturn(mBluetoothAdapter);
when(mBluetoothAdapter.getMostRecentlyConnectedDevices())
.thenReturn(mMostRecentlyConnectedDevices);
mPreferenceGroup = spy(new PreferenceCategory(mContext));
when(mPreferenceGroup.getPreferenceManager()).thenReturn(mPreferenceManager);
mSavedDeviceGroupController = new SavedDeviceGroupController(mContext);
mSavedDeviceGroupController.setBluetoothDeviceUpdater(mBluetoothDeviceUpdater);
mSavedDeviceGroupController.setSavedDockUpdater(mSavedDockUpdater);
mSavedDeviceGroupController.setPreferenceGroup(mPreferenceGroup);
}
@Test
@@ -118,4 +175,71 @@ public class SavedDeviceGroupControllerTest {
assertThat(mSavedDeviceGroupController.getAvailabilityStatus()).isEqualTo(
AVAILABLE);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY)
public void updatePreferenceGroup_bluetoothIsEnable_shouldOrderByMostRecentlyConnected() {
when(mBluetoothAdapter.isEnabled()).thenReturn(true);
final BluetoothDevicePreference preference3 =
new BluetoothDevicePreference(
mContext,
mCachedDevice3,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
final BluetoothDevicePreference preference2 =
new BluetoothDevicePreference(
mContext,
mCachedDevice2,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
final BluetoothDevicePreference preference1 =
new BluetoothDevicePreference(
mContext,
mCachedDevice1,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
mSavedDeviceGroupController.onDeviceAdded(preference3);
mSavedDeviceGroupController.onDeviceAdded(preference2);
mSavedDeviceGroupController.onDeviceAdded(preference1);
mSavedDeviceGroupController.updatePreferenceGroup();
// Refer to the order of {@link #mMostRecentlyConnectedDevices}
assertThat(mPreferenceGroup.isVisible()).isTrue();
assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(3);
assertThat(preference1.getOrder()).isEqualTo(0);
assertThat(preference2.getOrder()).isEqualTo(1);
assertThat(preference3.getOrder()).isEqualTo(2);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SAVED_DEVICES_ORDER_BY_RECENCY)
public void updatePreferenceGroup_bluetoothIsDisable_shouldShowNoPreference() {
when(mBluetoothAdapter.isEnabled()).thenReturn(false);
final BluetoothDevicePreference preference3 =
new BluetoothDevicePreference(
mContext,
mCachedDevice3,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
final BluetoothDevicePreference preference2 =
new BluetoothDevicePreference(
mContext,
mCachedDevice2,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
final BluetoothDevicePreference preference1 =
new BluetoothDevicePreference(
mContext,
mCachedDevice2,
true,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
mSavedDeviceGroupController.onDeviceAdded(preference3);
mSavedDeviceGroupController.onDeviceAdded(preference2);
mSavedDeviceGroupController.onDeviceAdded(preference1);
mSavedDeviceGroupController.updatePreferenceGroup();
assertThat(mPreferenceGroup.isVisible()).isFalse();
}
}

View File

@@ -1,228 +0,0 @@
/*
* Copyright (C) 2023 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.connecteddevice.audiosharing;
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.androidx.fragment.FragmentController;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
ShadowAlertDialogCompat.class,
ShadowBluetoothAdapter.class,
})
public class AudioSharingDialogFragmentTest {
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String TEST_DEVICE_NAME1 = "test1";
private static final String TEST_DEVICE_NAME2 = "test2";
private static final String TEST_DEVICE_NAME3 = "test3";
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM1 =
new AudioSharingDeviceItem(TEST_DEVICE_NAME1, /* groupId= */ 1, /* isActive= */ false);
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM2 =
new AudioSharingDeviceItem(TEST_DEVICE_NAME2, /* groupId= */ 2, /* isActive= */ false);
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM3 =
new AudioSharingDeviceItem(TEST_DEVICE_NAME3, /* groupId= */ 3, /* isActive= */ false);
private Fragment mParent;
private AudioSharingDialogFragment mFragment;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
@Before
public void setUp() {
ShadowAlertDialogCompat.reset();
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mFragment = new AudioSharingDialogFragment();
mParent = new Fragment();
FragmentController.setupFragment(
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOff_dialogNotExist() {
mFragment.show(mParent, new ArrayList<>(), (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOn_noConnectedDevice() {
mFragment.show(mParent, new ArrayList<>(), (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
TextView subtitle1 = rootView.findViewById(R.id.share_audio_subtitle1);
ImageView guidance = rootView.findViewById(R.id.share_audio_guidance);
Button shareBtn = rootView.findViewById(R.id.share_btn);
assertThat(dialog.isShowing()).isTrue();
assertThat(subtitle1.getVisibility()).isEqualTo(View.GONE);
assertThat(guidance.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(shareBtn.getVisibility()).isEqualTo(View.GONE);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_noConnectedDevice_dialogDismiss() {
mFragment.show(mParent, new ArrayList<>(), (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
dialog.findViewById(android.R.id.button2).performClick();
shadowMainLooper().idle();
assertThat(dialog.isShowing()).isFalse();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOn_singleConnectedDevice() {
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1);
mFragment.show(mParent, list, (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
TextView subtitle1 = rootView.findViewById(R.id.share_audio_subtitle1);
ImageView guidance = rootView.findViewById(R.id.share_audio_guidance);
Button shareBtn = rootView.findViewById(R.id.share_btn);
assertThat(dialog.isShowing()).isTrue();
assertThat(subtitle1.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(subtitle1.getText().toString()).isEqualTo(TEST_DEVICE_NAME1);
assertThat(guidance.getVisibility()).isEqualTo(View.GONE);
assertThat(shareBtn.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_singleConnectedDevice_dialogDismiss() {
mFragment.show(mParent, new ArrayList<>(), (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
rootView.findViewById(R.id.cancel_btn).performClick();
assertThat(dialog.isShowing()).isFalse();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_singleConnectedDevice_shareClicked() {
AtomicBoolean isShareBtnClicked = new AtomicBoolean(false);
mFragment.show(
mParent,
new ArrayList<>(),
(item) -> {
isShareBtnClicked.set(true);
});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
rootView.findViewById(R.id.share_btn).performClick();
assertThat(dialog.isShowing()).isFalse();
assertThat(isShareBtnClicked.get()).isTrue();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOn_multipleConnectedDevice() {
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1);
list.add(TEST_DEVICE_ITEM2);
list.add(TEST_DEVICE_ITEM3);
mFragment.show(mParent, list, (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
TextView subtitle1 = rootView.findViewById(R.id.share_audio_subtitle1);
ImageView guidance = rootView.findViewById(R.id.share_audio_guidance);
Button shareBtn = rootView.findViewById(R.id.share_btn);
RecyclerView recyclerView = rootView.findViewById(R.id.btn_list);
assertThat(dialog.isShowing()).isTrue();
assertThat(subtitle1.getVisibility()).isEqualTo(View.GONE);
assertThat(guidance.getVisibility()).isEqualTo(View.GONE);
assertThat(shareBtn.getVisibility()).isEqualTo(View.GONE);
assertThat(recyclerView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(recyclerView.getAdapter().getItemCount()).isEqualTo(3);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_multipleConnectedDevice_dialogDismiss() {
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1);
list.add(TEST_DEVICE_ITEM2);
list.add(TEST_DEVICE_ITEM3);
mFragment.show(mParent, list, (item) -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
rootView.findViewById(R.id.cancel_btn).performClick();
assertThat(dialog.isShowing()).isFalse();
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright (C) 2023 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.connecteddevice.audiosharing;
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.View;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.androidx.fragment.FragmentController;
import java.util.ArrayList;
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
ShadowAlertDialogCompat.class,
ShadowBluetoothAdapter.class,
})
public class AudioSharingDisconnectDialogFragmentTest {
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String TEST_DEVICE_NAME1 = "test1";
private static final String TEST_DEVICE_NAME2 = "test2";
private static final String TEST_DEVICE_NAME3 = "test3";
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM1 =
new AudioSharingDeviceItem(TEST_DEVICE_NAME1, /* groupId= */ 1, /* isActive= */ true);
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM2 =
new AudioSharingDeviceItem(TEST_DEVICE_NAME2, /* groupId= */ 2, /* isActive= */ false);
private Fragment mParent;
private AudioSharingDisconnectDialogFragment mFragment;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
@Before
public void setUp() {
ShadowAlertDialogCompat.reset();
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mFragment = new AudioSharingDisconnectDialogFragment();
mParent = new Fragment();
FragmentController.setupFragment(
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM1);
list.add(TEST_DEVICE_ITEM2);
mFragment.show(mParent, list, TEST_DEVICE_NAME3, (item) -> {});
shadowMainLooper().idle();
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOff_dialogNotExist() {
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOn_dialogShowBtnForTwoDevices() {
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
RecyclerView view = rootView.findViewById(R.id.device_btn_list);
assertThat(view.getAdapter().getItemCount()).isEqualTo(2);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_clickCancel_dialogDismiss() {
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
rootView.findViewById(R.id.cancel_btn).performClick();
assertThat(dialog.isShowing()).isFalse();
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2024 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.connecteddevice.audiosharing;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.connecteddevice.AvailableMediaDeviceGroupController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class AudioSharingFeatureProviderImplTest {
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private CachedBluetoothDevice mCachedDevice;
@Mock private LocalBluetoothManager mLocalBtManager;
@Mock private DashboardFragment mFragment;
private Context mContext;
private AudioSharingFeatureProviderImpl mFeatureProvider;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mFeatureProvider = new AudioSharingFeatureProviderImpl();
}
@Test
public void createAudioSharingDevicePreferenceController_returnsNull() {
assertThat(
mFeatureProvider.createAudioSharingDevicePreferenceController(
mContext, mFragment, /* lifecycle= */ null))
.isNull();
}
@Test
public void createAvailableMediaDeviceGroupController_returnsNull() {
assertThat(
mFeatureProvider.createAvailableMediaDeviceGroupController(
mContext, /* fragment= */ null, /* lifecycle= */ null))
.isInstanceOf(AvailableMediaDeviceGroupController.class);
}
@Test
public void isAudioSharingFilterMatched_returnsFalse() {
assertThat(mFeatureProvider.isAudioSharingFilterMatched(mCachedDevice, mLocalBtManager))
.isFalse();
}
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright (C) 2023 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.connecteddevice.audiosharing;
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.androidx.fragment.FragmentController;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
ShadowAlertDialogCompat.class,
ShadowBluetoothAdapter.class,
})
public class AudioSharingJoinDialogFragmentTest {
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String TEST_DEVICE_NAME1 = "test1";
private static final String TEST_DEVICE_NAME2 = "test2";
private static final AudioSharingDeviceItem TEST_DEVICE_ITEM =
new AudioSharingDeviceItem(TEST_DEVICE_NAME1, /* groupId= */ 1, /* isActive= */ true);
private Fragment mParent;
private AudioSharingJoinDialogFragment mFragment;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
@Before
public void setUp() {
ShadowAlertDialogCompat.reset();
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mFragment = new AudioSharingJoinDialogFragment();
mParent = new Fragment();
FragmentController.setupFragment(
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOff_dialogNotExist() {
mFragment.show(mParent, new ArrayList<>(), TEST_DEVICE_NAME2, () -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOn_dialogShowTextForSingleDevice() {
mFragment.show(mParent, new ArrayList<>(), TEST_DEVICE_NAME2, () -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
assertThat(dialog.isShowing()).isTrue();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
TextView subtitle1 = rootView.findViewById(R.id.share_audio_subtitle1);
assertThat(subtitle1.getText()).isEqualTo(TEST_DEVICE_NAME2);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOn_dialogShowTextForTwoDevice() {
ArrayList<AudioSharingDeviceItem> list = new ArrayList<>();
list.add(TEST_DEVICE_ITEM);
mFragment.show(mParent, list, TEST_DEVICE_NAME2, () -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNotNull();
assertThat(dialog.isShowing()).isTrue();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
TextView subtitle1 = rootView.findViewById(R.id.share_audio_subtitle1);
assertThat(subtitle1.getText()).isEqualTo(TEST_DEVICE_NAME1 + " and " + TEST_DEVICE_NAME2);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_clickCancel_dialogDismiss() {
mFragment.show(mParent, new ArrayList<>(), TEST_DEVICE_NAME2, () -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
rootView.findViewById(R.id.cancel_btn).performClick();
assertThat(dialog.isShowing()).isFalse();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_clickShare_callbackTriggered() {
AtomicBoolean isShareBtnClicked = new AtomicBoolean(false);
mFragment.show(
mParent, new ArrayList<>(), TEST_DEVICE_NAME2, () -> isShareBtnClicked.set(true));
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
View rootView = shadowDialog.getView();
rootView.findViewById(R.id.share_btn).performClick();
assertThat(dialog.isShowing()).isFalse();
assertThat(isShareBtnClicked.get()).isTrue();
}
}

View File

@@ -1,117 +0,0 @@
/*
* Copyright (C) 2023 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.connecteddevice.audiosharing;
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.shadows.ShadowLooper.shadowMainLooper;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothStatusCodes;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.androidx.fragment.FragmentController;
import java.util.concurrent.atomic.AtomicBoolean;
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
ShadowAlertDialogCompat.class,
ShadowBluetoothAdapter.class,
})
public class AudioSharingStopDialogFragmentTest {
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String TEST_DEVICE_NAME = "test";
private Fragment mParent;
private AudioSharingStopDialogFragment mFragment;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
@Before
public void setUp() {
ShadowAlertDialogCompat.reset();
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mShadowBluetoothAdapter.setIsLeAudioBroadcastAssistantSupported(
BluetoothStatusCodes.FEATURE_SUPPORTED);
mFragment = new AudioSharingStopDialogFragment();
mParent = new Fragment();
FragmentController.setupFragment(
mParent, FragmentActivity.class, /* containerViewId= */ 0, /* bundle= */ null);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_flagOff_dialogNotExist() {
mFragment.show(mParent, TEST_DEVICE_NAME, () -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
assertThat(dialog).isNull();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_clickCancel_dialogDismiss() {
mFragment.show(mParent, TEST_DEVICE_NAME, () -> {});
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
dialog.findViewById(android.R.id.button2).performClick();
shadowMainLooper().idle();
assertThat(dialog.isShowing()).isFalse();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void onCreateDialog_clickShare_callbackTriggered() {
AtomicBoolean isStopBtnClicked = new AtomicBoolean(false);
mFragment.show(mParent, TEST_DEVICE_NAME, () -> isStopBtnClicked.set(true));
shadowMainLooper().idle();
AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
dialog.findViewById(android.R.id.button1).performClick();
shadowMainLooper().idle();
assertThat(dialog.isShowing()).isFalse();
assertThat(isStopBtnClicked.get()).isTrue();
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright (C) 2023 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.connecteddevice.audiosharing;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.robolectric.Shadows.shadowOf;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.widget.Switch;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.flags.Flags;
import com.android.settings.widget.SettingsMainSwitchBar;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class AudioSharingSwitchBarControllerTest {
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Spy Context mContext = ApplicationProvider.getApplicationContext();
@Mock private Switch mSwitch;
private SettingsMainSwitchBar mSwitchBar;
private AudioSharingSwitchBarController mController;
private AudioSharingSwitchBarController.OnSwitchBarChangedListener mListener;
private boolean mOnSwitchBarChanged;
@Before
public void setUp() {
mSwitchBar = new SettingsMainSwitchBar(mContext);
mOnSwitchBarChanged = false;
mListener = () -> mOnSwitchBarChanged = true;
mController = new AudioSharingSwitchBarController(mContext, mSwitchBar, mListener);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void bluetoothOff_switchDisabled() {
mContext.registerReceiver(
mController.mReceiver,
mController.mIntentFilter,
Context.RECEIVER_EXPORTED_UNAUDITED);
Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
intent.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
mContext.sendBroadcast(intent);
shadowOf(Looper.getMainLooper()).idle();
verify(mSwitch).setEnabled(false);
assertThat(mOnSwitchBarChanged).isTrue();
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2024 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.connecteddevice.fastpair;
import static com.google.common.truth.Truth.assertThat;
import android.app.settings.SettingsEnums;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class FastPairDeviceDashboardFragmentTest {
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private FastPairDeviceDashboardFragment mFragment;
@Before
public void setUp() {
mFragment = new FastPairDeviceDashboardFragment();
}
@Test
public void getPreferenceScreenResId_returnsCorrectXml() {
assertThat(mFragment.getPreferenceScreenResId()).isEqualTo(R.xml.fast_pair_devices);
}
@Test
public void getLogTag_returnsCorrectTag() {
assertThat(mFragment.getLogTag()).isEqualTo("FastPairDeviceFrag");
}
@Test
public void getMetricsCategory_returnsCorrectCategory() {
assertThat(mFragment.getMetricsCategory()).isEqualTo(SettingsEnums.FAST_PAIR_DEVICES);
}
@Test
public void getHelpResource_returnsCorrectResource() {
assertThat(mFragment.getHelpResource())
.isEqualTo(R.string.help_url_connected_devices_fast_pair_devices);
}
}

View File

@@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.bluetooth.BluetoothAdapter;
@@ -41,6 +42,7 @@ import androidx.lifecycle.LifecycleOwner;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
@@ -70,10 +72,13 @@ public class FastPairDeviceGroupControllerTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final String KEY = "fast_pair_device_list";
@Mock private DashboardFragment mDashboardFragment;
@Mock private FastPairDeviceUpdater mFastPairDeviceUpdater;
@Mock private PackageManager mPackageManager;
@Mock private PreferenceManager mPreferenceManager;
@Mock private PreferenceScreen mScreen;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
private Context mContext;
private FastPairDeviceGroupController mFastPairDeviceGroupController;
@@ -96,12 +101,14 @@ public class FastPairDeviceGroupControllerTest {
doReturn(mPreferenceManager).when(mPreferenceGroup).getPreferenceManager();
mPreferenceGroup.setVisible(false);
mFastPairDeviceGroupController.setPreferenceGroup(mPreferenceGroup);
when(mScreen.findPreference(KEY)).thenReturn(mPreferenceGroup);
when(mScreen.getContext()).thenReturn(mContext);
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void testRegister() {
public void onStart_flagOn_registerCallback() {
// register the callback in onStart()
mFastPairDeviceGroupController.onStart(mLifecycleOwner);
verify(mFastPairDeviceUpdater).registerCallback();
@@ -114,7 +121,7 @@ public class FastPairDeviceGroupControllerTest {
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void testUnregister() {
public void onStop_flagOn_unregisterCallback() {
// register broadcast first
mContext.registerReceiver(
mFastPairDeviceGroupController.mReceiver, null, Context.RECEIVER_EXPORTED);
@@ -127,7 +134,33 @@ public class FastPairDeviceGroupControllerTest {
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void testGetAvailabilityStatus_noFastPairFeature_returnUnSupported() {
public void onStart_flagOff_registerCallback() {
// register the callback in onStart()
mFastPairDeviceGroupController.onStart(mLifecycleOwner);
assertThat(mFastPairDeviceUpdater).isNull();
verify(mContext)
.registerReceiver(
mFastPairDeviceGroupController.mReceiver,
mFastPairDeviceGroupController.mIntentFilter,
Context.RECEIVER_EXPORTED);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStop_flagOff_unregisterCallback() {
// register broadcast first
mContext.registerReceiver(
mFastPairDeviceGroupController.mReceiver, null, Context.RECEIVER_EXPORTED);
// unregister the callback in onStop()
mFastPairDeviceGroupController.onStop(mLifecycleOwner);
assertThat(mFastPairDeviceUpdater).isNull();
verify(mContext).unregisterReceiver(mFastPairDeviceGroupController.mReceiver);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_noFastPairFeature_returnUnSupported() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
assertThat(mFastPairDeviceGroupController.getAvailabilityStatus())
@@ -135,8 +168,8 @@ public class FastPairDeviceGroupControllerTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_noBluetoothFastPairFeature_returnUnSupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
assertThat(mFastPairDeviceGroupController.getAvailabilityStatus())
@@ -145,15 +178,23 @@ public class FastPairDeviceGroupControllerTest {
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void testGetAvailabilityStatus_withBluetoothFastPairFeature_returnSupported() {
public void getAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
assertThat(mFastPairDeviceGroupController.getAvailabilityStatus())
.isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_withBluetoothFastPairFeature_returnSupported() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
assertThat(mFastPairDeviceGroupController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void testUpdatePreferenceVisibility_bluetoothIsDisable_shouldHidePreference() {
public void updatePreferenceVisibility_bluetoothIsDisable_shouldHidePreference() {
mShadowBluetoothAdapter.setEnabled(true);
final GearPreference preference1 = new GearPreference(mContext, null /* AttributeSet */);
mFastPairDeviceGroupController.onDeviceAdded(preference1);
@@ -171,4 +212,37 @@ public class FastPairDeviceGroupControllerTest {
shadowOf(Looper.getMainLooper()).idle();
assertThat(mPreferenceGroup.isVisible()).isFalse();
}
@Test
public void onDeviceAdd_bluetoothIsDisable_shouldHidePreference() {
mShadowBluetoothAdapter.setEnabled(true);
final GearPreference preference1 = new GearPreference(mContext, null /* AttributeSet */);
mFastPairDeviceGroupController.onDeviceAdded(preference1);
assertThat(mPreferenceGroup.isVisible()).isTrue();
}
@Test
public void onDeviceRemoved_bluetoothIsDisable_shouldHidePreference() {
mShadowBluetoothAdapter.setEnabled(true);
final GearPreference preference1 = new GearPreference(mContext, null /* AttributeSet */);
mPreferenceGroup.addPreference(preference1);
mFastPairDeviceGroupController.onDeviceRemoved(preference1);
assertThat(mPreferenceGroup.isVisible()).isFalse();
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void displayPreference_notAvailable_doNothing() {
mFastPairDeviceGroupController.displayPreference(mScreen);
assertThat(mPreferenceGroup.isVisible()).isFalse();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void displayPreference_isAvailable_fetchFastPairDevices() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
mFastPairDeviceGroupController.displayPreference(mScreen);
verify(mFastPairDeviceUpdater).forceUpdate();
}
}

View File

@@ -109,7 +109,7 @@ public class FastPairDevicePreferenceControllerTest {
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStart_registerCallback() {
public void onStart_flagOn_registerCallback() {
// register the callback in onStart()
mFastPairDevicePrefController.onStart(mLifecycleOwner);
verify(mFastPairDeviceUpdater).registerCallback();
@@ -120,9 +120,22 @@ public class FastPairDevicePreferenceControllerTest {
Context.RECEIVER_EXPORTED_UNAUDITED);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStart_flagOff_registerCallback() {
// register the callback in onStart()
mFastPairDevicePrefController.onStart(mLifecycleOwner);
assertThat(mFastPairDeviceUpdater).isNull();
verify(mContext)
.registerReceiver(
mFastPairDevicePrefController.mReceiver,
mFastPairDevicePrefController.mIntentFilter,
Context.RECEIVER_EXPORTED_UNAUDITED);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStop_unregisterCallback() {
public void onStop_flagOn_unregisterCallback() {
// register broadcast first
mContext.registerReceiver(
mFastPairDevicePrefController.mReceiver, null, Context.RECEIVER_EXPORTED_UNAUDITED);
@@ -133,6 +146,19 @@ public class FastPairDevicePreferenceControllerTest {
verify(mContext).unregisterReceiver(mFastPairDevicePrefController.mReceiver);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStop_flagOff_unregisterCallback() {
// register broadcast first
mContext.registerReceiver(
mFastPairDevicePrefController.mReceiver, null, Context.RECEIVER_EXPORTED_UNAUDITED);
// unregister the callback in onStop()
mFastPairDevicePrefController.onStop(mLifecycleOwner);
assertThat(mFastPairDeviceUpdater).isNull();
verify(mContext).unregisterReceiver(mFastPairDevicePrefController.mReceiver);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_noBluetoothFeature_returnUnsupported() {
@@ -151,6 +177,15 @@ public class FastPairDevicePreferenceControllerTest {
.isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_noBluetoothFastPairFeature_returnUnsupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
assertThat(mFastPairDevicePrefController.getAvailabilityStatus())
.isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_bothBluetoothFastPairFeature_returnSupported() {
@@ -160,7 +195,6 @@ public class FastPairDevicePreferenceControllerTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onDeviceAdded_addThreeFastPairDevicePreference_displayThreeNoSeeAll() {
mShadowBluetoothAdapter.setEnabled(true);
final GearPreference preference1 = new GearPreference(mContext, null /* AttributeSet */);
@@ -177,7 +211,6 @@ public class FastPairDevicePreferenceControllerTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onDeviceAdded_addFourDevicePreference_onlyDisplayThreeWithSeeAll() {
mShadowBluetoothAdapter.setEnabled(true);
final GearPreference preference1 = new GearPreference(mContext, null /* AttributeSet */);
@@ -206,7 +239,6 @@ public class FastPairDevicePreferenceControllerTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onDeviceRemoved_removeFourthDevice_hideSeeAll() {
mShadowBluetoothAdapter.setEnabled(true);
final GearPreference preference1 = new GearPreference(mContext, null /* AttributeSet */);
@@ -238,7 +270,6 @@ public class FastPairDevicePreferenceControllerTest {
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void updatePreferenceVisibility_bluetoothIsDisable_shouldHidePreference() {
mShadowBluetoothAdapter.setEnabled(true);
final GearPreference preference1 = new GearPreference(mContext, null /* AttributeSet */);

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2024 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.connecteddevice.fastpair;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class FastPairFeatureProviderImplTest {
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private DevicePreferenceCallback mDevicePreferenceCallback;
private Context mContext;
private FastPairFeatureProviderImpl mFeatureProvider;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mFeatureProvider = new FastPairFeatureProviderImpl();
}
@Test
public void getFastPairDeviceUpdater_returnsEmptyClass() {
assertThat(mFeatureProvider.getFastPairDeviceUpdater(mContext, mDevicePreferenceCallback))
.isInstanceOf(FastPairDeviceUpdater.class);
}
}

View File

@@ -108,6 +108,9 @@ public class StylusDevicesControllerTest {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
final var spiedResources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(spiedResources);
PreferenceManager preferenceManager = new PreferenceManager(mContext);
mScreen = preferenceManager.createPreferenceScreen(mContext);
mPreferenceContainer = new PreferenceCategory(mContext);
@@ -144,6 +147,9 @@ public class StylusDevicesControllerTest {
when(mInputDevice.hasKeys(KEYCODE_STYLUS_BUTTON_TAIL)).thenReturn(
new boolean[]{true});
when(spiedResources.getBoolean(
com.android.internal.R.bool.config_enableStylusPointerIcon)).thenReturn(true);
mController = new StylusDevicesController(mContext, mInputDevice, null, mLifecycle);
}
@@ -221,7 +227,7 @@ public class StylusDevicesControllerTest {
showScreen(controller);
assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(3);
assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(4);
}
@Test
@@ -237,7 +243,7 @@ public class StylusDevicesControllerTest {
Preference handwritingPref = mPreferenceContainer.getPreference(0);
Preference buttonPref = mPreferenceContainer.getPreference(1);
assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(2);
assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(3);
assertThat(handwritingPref.getTitle().toString()).isEqualTo(
mContext.getString(R.string.stylus_textfield_handwriting));
assertThat(handwritingPref.isVisible()).isTrue();
@@ -249,11 +255,12 @@ public class StylusDevicesControllerTest {
@Test
public void btStylusInputDevice_showsAllPreferences() {
showScreen(mController);
Preference defaultNotesPref = mPreferenceContainer.getPreference(0);
Preference handwritingPref = mPreferenceContainer.getPreference(1);
Preference buttonPref = mPreferenceContainer.getPreference(2);
Preference stylusPointerIconPref = mPreferenceContainer.getPreference(3);
assertThat(mPreferenceContainer.getPreferenceCount()).isEqualTo(3);
assertThat(defaultNotesPref.getTitle().toString()).isEqualTo(
mContext.getString(R.string.stylus_default_notes_app));
assertThat(defaultNotesPref.isVisible()).isTrue();
@@ -263,6 +270,9 @@ public class StylusDevicesControllerTest {
assertThat(buttonPref.getTitle().toString()).isEqualTo(
mContext.getString(R.string.stylus_ignore_button));
assertThat(buttonPref.isVisible()).isTrue();
assertThat(stylusPointerIconPref.getTitle().toString()).isEqualTo(
mContext.getString(R.string.show_stylus_pointer_icon));
assertThat(stylusPointerIconPref.isVisible()).isTrue();
}
@Test
@@ -551,6 +561,46 @@ public class StylusDevicesControllerTest {
Secure.STYLUS_BUTTONS_ENABLED, -1)).isEqualTo(1);
}
@Test
public void stylusPointerIconPreference_checkedWhenFlagTrue() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.STYLUS_POINTER_ICON_ENABLED, 1);
showScreen(mController);
SwitchPreferenceCompat stylusPointerIconPref =
(SwitchPreferenceCompat) mPreferenceContainer.getPreference(3);
assertThat(stylusPointerIconPref.isChecked()).isEqualTo(true);
}
@Test
public void stylusPointerIconPreference_uncheckedWhenFlagFalse() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.STYLUS_POINTER_ICON_ENABLED, 0);
showScreen(mController);
SwitchPreferenceCompat stylusPointerIconPref =
(SwitchPreferenceCompat) mPreferenceContainer.getPreference(3);
assertThat(stylusPointerIconPref.isChecked()).isEqualTo(false);
}
@Test
public void stylusPointerIconPreference_updatesFlagOnClick() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.STYLUS_POINTER_ICON_ENABLED, 0);
showScreen(mController);
SwitchPreferenceCompat stylusPointerIconPref =
(SwitchPreferenceCompat) mPreferenceContainer.getPreference(3);
stylusPointerIconPref.performClick();
assertThat(stylusPointerIconPref.isChecked()).isEqualTo(true);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Secure.STYLUS_POINTER_ICON_ENABLED, -1)).isEqualTo(1);
}
private void showScreen(StylusDevicesController controller) {
controller.displayPreference(mScreen);
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2023 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.connecteddevice.usb;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
import android.app.KeyguardManager;
import android.content.Context;
import android.hardware.usb.UsbPortStatus;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import com.android.settings.flags.Flags;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowKeyguardManager;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowKeyguardManager.class
})
public class UsbDetailsControllerTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private UsbBackend mUsbBackend;
private Context mContext;
private UsbDetailsController mUsbDetailsController;
private UsbDetailsFragment mUsbDetailsFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = getApplicationContext();
mUsbDetailsFragment = new UsbDetailsFragment();
mUsbDetailsController = new UsbDetailsController(
mContext, mUsbDetailsFragment, mUsbBackend) {
@Override
protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
}
@Override
public String getPreferenceKey() {
return null;
}
};
}
@Test
public void isAvailable_returnsTrue() {
assertThat(mUsbDetailsController.isAvailable()).isTrue();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void requireAuthAndExecute_whenAlreadyAuthenticated_executes() {
mUsbDetailsFragment.setUserAuthenticated(true);
Runnable action = () -> mUsbBackend.setDataRole(UsbPortStatus.DATA_ROLE_HOST);
mUsbDetailsController.requireAuthAndExecute(action);
verify(mUsbBackend).setDataRole(anyInt());
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void requireAuthAndExecute_authenticatesAndExecutes() {
mUsbDetailsFragment.setUserAuthenticated(false);
setAuthPassesAutomatically();
Runnable action = () -> mUsbBackend.setDataRole(UsbPortStatus.DATA_ROLE_HOST);
mUsbDetailsController.requireAuthAndExecute(action);
assertThat(mUsbDetailsFragment.isUserAuthenticated()).isTrue();
verify(mUsbBackend).setDataRole(anyInt());
}
private void setAuthPassesAutomatically() {
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
.setIsKeyguardSecure(false);
}
}

View File

@@ -25,12 +25,15 @@ import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.KeyguardManager;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceCategory;
@@ -38,6 +41,7 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
@@ -49,6 +53,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@@ -63,12 +68,11 @@ public class UsbDetailsDataRoleControllerTest {
private PreferenceCategory mPreference;
private PreferenceManager mPreferenceManager;
private PreferenceScreen mScreen;
private UsbDetailsFragment mFragment;
@Mock
private UsbBackend mUsbBackend;
@Mock
private UsbDetailsFragment mFragment;
@Mock
private FragmentActivity mActivity;
@Mock
private Handler mHandler;
@@ -76,7 +80,7 @@ public class UsbDetailsDataRoleControllerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new UsbDetailsFragment());
mContext = RuntimeEnvironment.application;
mLifecycle = new Lifecycle(() -> mLifecycle);
mPreferenceManager = new PreferenceManager(mContext);
@@ -95,12 +99,12 @@ public class UsbDetailsDataRoleControllerTest {
mScreen.addPreference(mPreference);
mDetailsDataRoleController.mHandler = mHandler;
mDetailsDataRoleController.displayPreference(mScreen);
}
@Test
public void displayRefresh_deviceRole_shouldCheckDevice() {
mDetailsDataRoleController.displayPreference(mScreen);
mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
DATA_ROLE_DEVICE);
@@ -112,8 +116,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void displayRefresh_hostRole_shouldCheckHost() {
mDetailsDataRoleController.displayPreference(mScreen);
mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
DATA_ROLE_HOST);
@@ -125,8 +127,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void displayRefresh_disconnected_shouldDisable() {
mDetailsDataRoleController.displayPreference(mScreen);
mDetailsDataRoleController.refresh(false, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
DATA_ROLE_DEVICE);
@@ -135,7 +135,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDevice_hostEnabled_shouldSetDevice() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -148,7 +147,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDeviceTwice_hostEnabled_shouldSetDeviceOnce() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -162,7 +160,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDeviceAndRefresh_success_shouldClearSubtext() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -180,7 +177,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDeviceAndRefresh_failed_shouldShowFailureText() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -199,7 +195,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDevice_timedOut_shouldShowFailureText() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -218,6 +213,22 @@ public class UsbDetailsDataRoleControllerTest {
.isEqualTo(mContext.getString(R.string.usb_switching_failed));
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void onRadioButtonClicked_userAuthenticated() {
SelectorWithWidgetPreference preference = getRadioPreference(DATA_ROLE_DEVICE);
setAuthPassesAutomatically();
mDetailsDataRoleController.onRadioButtonClicked(preference);
assertThat(mFragment.isUserAuthenticated()).isTrue();
}
private void setAuthPassesAutomatically() {
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
.setIsKeyguardSecure(false);
}
private SelectorWithWidgetPreference getRadioPreference(int role) {
return (SelectorWithWidgetPreference)
mPreference.findPreference(UsbBackend.dataRoleToString(role));

View File

@@ -30,15 +30,18 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.KeyguardManager;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.net.TetheringManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
@@ -51,6 +54,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
@@ -70,12 +74,11 @@ public class UsbDetailsFunctionsControllerTest {
private PreferenceManager mPreferenceManager;
private PreferenceScreen mScreen;
private SelectorWithWidgetPreference mRadioButtonPreference;
private UsbDetailsFragment mFragment;
@Mock
private UsbBackend mUsbBackend;
@Mock
private UsbDetailsFragment mFragment;
@Mock
private FragmentActivity mActivity;
@Mock
private TetheringManager mTetheringManager;
@@ -83,7 +86,7 @@ public class UsbDetailsFunctionsControllerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new UsbDetailsFragment());
mContext = spy(RuntimeEnvironment.application);
mLifecycle = new Lifecycle(() -> mLifecycle);
mPreferenceManager = new PreferenceManager(mContext);
@@ -334,6 +337,23 @@ public class UsbDetailsFunctionsControllerTest {
eq(mDetailsFunctionsController.mOnStartTetheringCallback));
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void onRadioButtonClicked_userAuthenticated() {
mRadioButtonPreference.setKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_PTP));
doReturn(UsbManager.FUNCTION_MTP).when(mUsbBackend).getCurrentFunctions();
setAuthPassesAutomatically();
mDetailsFunctionsController.onRadioButtonClicked(mRadioButtonPreference);
assertThat(mFragment.isUserAuthenticated()).isTrue();
}
private void setAuthPassesAutomatically() {
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
.setIsKeyguardSecure(false);
}
@Test
public void onTetheringFailed_resetPreviousFunctions() {
mDetailsFunctionsController.mPreviousFunction = UsbManager.FUNCTION_PTP;

View File

@@ -21,11 +21,14 @@ import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.KeyguardManager;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.os.SystemProperties;
import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceCategory;
@@ -33,6 +36,7 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowUtils;
import org.junit.Before;
@@ -43,6 +47,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@@ -57,18 +62,18 @@ public class UsbDetailsTranscodeMtpControllerTest {
private PreferenceManager mPreferenceManager;
private PreferenceScreen mScreen;
private UsbDetailsTranscodeMtpController mUnderTest;
private UsbDetailsFragment mFragment;
@Mock
private UsbBackend mUsbBackend;
@Mock
private UsbDetailsFragment mFragment;
@Mock
private FragmentActivity mActivity;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new UsbDetailsFragment());
mContext = RuntimeEnvironment.application;
mPreferenceManager = new PreferenceManager(mContext);
mScreen = mPreferenceManager.createPreferenceScreen(mContext);
@@ -84,11 +89,12 @@ public class UsbDetailsTranscodeMtpControllerTest {
mPreference = new PreferenceCategory(mContext);
mPreference.setKey(mUnderTest.getPreferenceKey());
mScreen.addPreference(mPreference);
mUnderTest.displayPreference(mScreen);
}
@Test
public void displayRefresh_noUsbConnection_shouldDisablePrefCategory() {
mUnderTest.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mUnderTest.refresh(false /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE,
@@ -99,7 +105,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Test
public void displayRefresh_noDataTransfer_shouldDisablePrefCategory() {
mUnderTest.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_NONE, POWER_ROLE_NONE,
@@ -110,7 +115,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Test
public void displayRefresh_noDataRole_shouldDisablePrefCategory() throws InterruptedException {
mUnderTest.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE,
@@ -122,7 +126,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void displayRefresh_fileTransfer_withAbsentProp_shouldCheck() {
mUnderTest.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE,
@@ -134,7 +137,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void displayRefresh_fileTransfer_withUnsetProp_shouldUncheck() {
mUnderTest.displayPreference(mScreen);
SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY, Boolean.toString(false));
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
@@ -147,7 +149,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void displayRefresh_fileTransfer_withSetProp_shouldCheck() {
mUnderTest.displayPreference(mScreen);
SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY, Boolean.toString(true));
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
@@ -160,7 +161,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void click_checked_shouldSetSystemProperty() {
mUnderTest.displayPreference(mScreen);
getSwitchPreference().performClick();
assertThat(SystemProperties.getBoolean(TRANSCODE_MTP_SYS_PROP_KEY, false)).isTrue();
}
@@ -168,7 +168,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void click_unChecked_shouldUnsetSystemProperty() {
mUnderTest.displayPreference(mScreen);
getSwitchPreference().performClick();
getSwitchPreference().performClick();
assertThat(SystemProperties.getBoolean(TRANSCODE_MTP_SYS_PROP_KEY, true)).isFalse();
@@ -181,6 +180,21 @@ public class UsbDetailsTranscodeMtpControllerTest {
assertThat(mUnderTest.isAvailable()).isFalse();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void onClick_userAuthenticated() {
setAuthPassesAutomatically();
mUnderTest.onPreferenceClick(null);
assertThat(mFragment.isUserAuthenticated()).isTrue();
}
private void setAuthPassesAutomatically() {
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
.setIsKeyguardSecure(false);
}
private SwitchPreference getSwitchPreference() {
return (SwitchPreference) mPreference.getPreference(0);
}

View File

@@ -43,6 +43,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -62,6 +63,7 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
@@ -83,16 +85,16 @@ import com.android.settingslib.drawer.Tile;
import com.android.settingslib.drawer.TileUtils;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowActivity;
@@ -104,10 +106,14 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowUserManager.class)
public class DashboardFeatureProviderImplTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private static final String KEY = "key";
private static final String SWITCH_URI = "content://com.android.settings/tile_switch";
private final Application mApplication = ApplicationProvider.getApplicationContext();
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private FragmentActivity mActivity;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -126,9 +132,8 @@ public class DashboardFeatureProviderImplTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
doReturn(RuntimeEnvironment.application).when(mActivity).getApplicationContext();
mContext = spy(mApplication);
doReturn(mApplication).when(mActivity).getApplicationContext();
mForceRoundedIcon = false;
mActivityInfo = new ActivityInfo();
mActivityInfo.packageName = mContext.getPackageName();
@@ -163,7 +168,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_shouldBindAllData() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = spy(new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
doReturn(Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565)))
@@ -183,7 +188,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_shouldBindAllSwitchData() {
final Preference preference = new SwitchPreference(RuntimeEnvironment.application);
final Preference preference = new SwitchPreference(mApplication);
final Tile tile = spy(new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE,
mSwitchMetaData));
mSwitchMetaData.putInt(META_DATA_KEY_ORDER, 10);
@@ -204,7 +209,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_providerTileWithPendingIntent_shouldBindIntent() {
final Preference preference = new SwitchPreference(RuntimeEnvironment.application);
final Preference preference = new SwitchPreference(mApplication);
Bundle metaData = new Bundle();
metaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label);
metaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary);
@@ -212,7 +217,7 @@ public class DashboardFeatureProviderImplTest {
metaData.putString(META_DATA_PREFERENCE_KEYHINT, KEY);
final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, metaData);
PendingIntent pendingIntent =
PendingIntent.getActivity(RuntimeEnvironment.application, 0, new Intent("test"), 0);
PendingIntent.getActivity(mApplication, 0, new Intent("test"), 0);
tile.pendingIntentMap.put(UserHandle.CURRENT, pendingIntent);
mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
@@ -225,7 +230,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_noFragmentMetadata_shouldBindIntent() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
@@ -237,10 +242,9 @@ public class DashboardFeatureProviderImplTest {
assertThat(preference.getOrder()).isEqualTo(tile.getOrder());
}
@Ignore("b/313569889")
@Test
public void bindPreference_noFragmentMetadata_shouldBindToProfileSelector() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
tile.userHandle = new ArrayList<>();
tile.userHandle.add(mock(UserHandle.class));
@@ -255,7 +259,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_noFragmentMetadataSingleUser_shouldBindToDirectLaunchIntent() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
tile.userHandle = new ArrayList<>();
tile.userHandle.add(mock(UserHandle.class));
@@ -276,8 +280,8 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_toInternalSettingActivity_shouldBindToDirectLaunchIntentAndNotLog() {
final Preference preference = new Preference(RuntimeEnvironment.application);
mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
final Preference preference = new Preference(mApplication);
mActivityInfo.packageName = mApplication.getPackageName();
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
tile.userHandle = new ArrayList<>();
tile.userHandle.add(mock(UserHandle.class));
@@ -303,7 +307,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
preference, tile, null /* key */,
@@ -315,7 +319,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_noSummary_shouldSetNullSummary() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
mActivityInfo.metaData.remove(META_DATA_PREFERENCE_SUMMARY);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
@@ -329,7 +333,7 @@ public class DashboardFeatureProviderImplTest {
@Test
@Config(shadows = {ShadowTileUtils.class})
public void bindPreference_hasSummaryUri_shouldLoadSummaryFromContentProviderAndHaveObserver() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
final String uriString = "content://com.android.settings/tile_summary";
mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, uriString);
@@ -349,7 +353,7 @@ public class DashboardFeatureProviderImplTest {
@Test
@Config(shadows = {ShadowTileUtils.class})
public void bindPreference_hasTitleUri_shouldLoadFromContentProviderAndHaveObserver() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
final String uriString = "content://com.android.settings/tile_title";
mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE_URI, uriString);
@@ -369,7 +373,7 @@ public class DashboardFeatureProviderImplTest {
@Test
@Config(shadows = {ShadowTileUtils.class})
public void bindPreference_onCheckedChanged_shouldPutStateToContentProvider() {
final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application);
final SwitchPreference preference = new SwitchPreference(mApplication);
final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE,
mSwitchMetaData);
final Bundle bundle = new Bundle();
@@ -390,7 +394,7 @@ public class DashboardFeatureProviderImplTest {
@Test
@Config(shadows = {ShadowTileUtils.class})
public void bindPreference_onCheckedChangedError_shouldRevertCheckedState() {
final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application);
final SwitchPreference preference = new SwitchPreference(mApplication);
final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE,
mSwitchMetaData);
final Bundle bundle = new Bundle();
@@ -411,7 +415,7 @@ public class DashboardFeatureProviderImplTest {
@Test
@Config(shadows = {ShadowTileUtils.class})
public void bindPreference_callbackOnChanged_shouldLoadFromContentProvider() {
final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application);
final SwitchPreference preference = new SwitchPreference(mApplication);
final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE,
mSwitchMetaData);
final List<DynamicDataObserver> observers = mImpl.bindPreferenceToTileAndGetObservers(
@@ -432,7 +436,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_withNullKeyTileKey_shouldUseTileKey() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
@@ -443,8 +447,8 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindIcon_withStaticIcon_shouldLoadStaticIcon() {
final Preference preference = new Preference(RuntimeEnvironment.application);
mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
final Preference preference = new Preference(mApplication);
mActivityInfo.packageName = mApplication.getPackageName();
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, R.drawable.ic_add_40dp);
@@ -461,8 +465,8 @@ public class DashboardFeatureProviderImplTest {
@Test
@Config(shadows = {ShadowTileUtils.class})
public void bindIcon_withIconUri_shouldLoadIconFromContentProvider() {
final Preference preference = new Preference(RuntimeEnvironment.application);
mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
final Preference preference = new Preference(mApplication);
mActivityInfo.packageName = mApplication.getPackageName();
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_ICON_URI,
@@ -476,8 +480,8 @@ public class DashboardFeatureProviderImplTest {
@Test
@Config(shadows = {ShadowTileUtils.class})
public void bindIcon_withStaticIconAndIconUri_shouldLoadIconFromContentProvider() {
final Preference preference = new Preference(RuntimeEnvironment.application);
mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
final Preference preference = new Preference(mApplication);
mActivityInfo.packageName = mApplication.getPackageName();
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, R.drawable.ic_add_40dp);
@@ -503,8 +507,8 @@ public class DashboardFeatureProviderImplTest {
@Test
@Config(shadows = {ShadowTileUtils.class})
public void bindIcon_noIcon_shouldNotLoadIcon() {
final Preference preference = new Preference(RuntimeEnvironment.application);
mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
final Preference preference = new Preference(mApplication);
mActivityInfo.packageName = mApplication.getPackageName();
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
@@ -516,7 +520,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_withBaseOrder_shouldOffsetOrder() {
final int baseOrder = 100;
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
@@ -528,7 +532,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_withOrderMetadata_shouldUseOrderInMetadata() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final int testOrder = -30;
mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
@@ -541,7 +545,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_invalidOrderMetadata_shouldIgnore() {
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_KEY_ORDER, "hello");
@@ -554,7 +558,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void bindPreference_withIntentActionMetadata_shouldSetLaunchAction() {
FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).get();
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
@@ -583,7 +587,7 @@ public class DashboardFeatureProviderImplTest {
String clickPrefKey = "highlight_pref_key";
String highlightMixinPrefKey = "highlight_pref_key";
FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).get();
Preference preference = new Preference(RuntimeEnvironment.application);
Preference preference = new Preference(mApplication);
Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
@@ -614,7 +618,7 @@ public class DashboardFeatureProviderImplTest {
String clickPrefKey = "not_highlight_pref_key";
String highlightMixinPrefKey = "highlight_pref_key";
FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).get();
Preference preference = new Preference(RuntimeEnvironment.application);
Preference preference = new Preference(mApplication);
Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
@@ -637,9 +641,9 @@ public class DashboardFeatureProviderImplTest {
@Test
public void clickPreference_withUnresolvableIntent_shouldNotLaunchAnything() {
ReflectionHelpers.setField(
mImpl, "mPackageManager", RuntimeEnvironment.application.getPackageManager());
mImpl, "mPackageManager", mApplication.getPackageManager());
FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).get();
final Preference preference = new Preference(RuntimeEnvironment.application);
final Preference preference = new Preference(mApplication);
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
@@ -657,7 +661,7 @@ public class DashboardFeatureProviderImplTest {
@Test
public void clickPreference_providerTileWithPendingIntent_singleUser_executesPendingIntent() {
final Preference preference = new SwitchPreference(RuntimeEnvironment.application);
final Preference preference = new SwitchPreference(mApplication);
Bundle metaData = new Bundle();
metaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label);
metaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary);
@@ -665,7 +669,7 @@ public class DashboardFeatureProviderImplTest {
metaData.putString(META_DATA_PREFERENCE_KEYHINT, KEY);
final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, metaData);
PendingIntent pendingIntent =
PendingIntent.getActivity(RuntimeEnvironment.application, 0, new Intent("test"), 0);
PendingIntent.getActivity(mApplication, 0, new Intent("test"), 0);
tile.pendingIntentMap.put(UserHandle.CURRENT, pendingIntent);
mImpl.bindPreferenceToTileAndGetObservers(mActivity, mFragment, mForceRoundedIcon,
@@ -673,14 +677,14 @@ public class DashboardFeatureProviderImplTest {
preference.performClick();
Intent nextStartedActivity =
Shadows.shadowOf(RuntimeEnvironment.application).peekNextStartedActivity();
Shadows.shadowOf(mApplication).peekNextStartedActivity();
assertThat(nextStartedActivity).isNotNull();
assertThat(nextStartedActivity.getAction()).isEqualTo("test");
}
@Test
public void clickPreference_providerTileWithPendingIntent_multiUser_showsProfileDialog() {
final Preference preference = new SwitchPreference(RuntimeEnvironment.application);
final Preference preference = new SwitchPreference(mApplication);
Bundle metaData = new Bundle();
metaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label);
metaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary);
@@ -688,7 +692,7 @@ public class DashboardFeatureProviderImplTest {
metaData.putString(META_DATA_PREFERENCE_KEYHINT, KEY);
final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE, metaData);
PendingIntent pendingIntent =
PendingIntent.getActivity(RuntimeEnvironment.application, 0, new Intent("test"), 0);
PendingIntent.getActivity(mApplication, 0, new Intent("test"), 0);
tile.pendingIntentMap.put(UserHandle.CURRENT, pendingIntent);
tile.pendingIntentMap.put(new UserHandle(10), pendingIntent);
@@ -700,11 +704,10 @@ public class DashboardFeatureProviderImplTest {
mActivity.getSupportFragmentManager().findFragmentByTag("select_profile");
assertThat(dialogFragment).isNotNull();
Intent nextStartedActivity =
Shadows.shadowOf(RuntimeEnvironment.application).peekNextStartedActivity();
Shadows.shadowOf(mApplication).peekNextStartedActivity();
assertThat(nextStartedActivity).isNull();
}
@Ignore("b/313569889")
@Test
public void openTileIntent_profileSelectionDialog_shouldShow() {
ShadowUserManager.getShadow().addUser(10, "Someone", 0);
@@ -721,7 +724,6 @@ public class DashboardFeatureProviderImplTest {
verify(mActivity).getSupportFragmentManager();
}
@Ignore("b/313569889")
@Test
public void openTileIntent_profileSelectionDialog_explicitMetadataShouldShow() {
ShadowUserManager.getShadow().addUser(10, "Someone", 0);
@@ -739,7 +741,6 @@ public class DashboardFeatureProviderImplTest {
verify(mActivity).getSupportFragmentManager();
}
@Ignore("b/313569889")
@Test
public void openTileIntent_profileSelectionDialog_shouldNotShow() {
ShadowUserManager.getShadow().addUser(10, "Someone", 0);
@@ -757,7 +758,6 @@ public class DashboardFeatureProviderImplTest {
verify(mActivity, never()).getSupportFragmentManager();
}
@Ignore("b/313569889")
@Test
public void openTileIntent_profileSelectionDialog_validUserHandleShouldNotShow() {
final int userId = 10;
@@ -780,7 +780,6 @@ public class DashboardFeatureProviderImplTest {
verify(mActivity, never()).getSupportFragmentManager();
}
@Ignore("b/313569889")
@Test
public void openTileIntent_profileSelectionDialog_invalidUserHandleShouldShow() {
ShadowUserManager.getShadow().addUser(10, "Someone", 0);
@@ -799,7 +798,6 @@ public class DashboardFeatureProviderImplTest {
verify(mActivity).getSupportFragmentManager();
}
@Ignore("b/313569889")
@Test
public void openTileIntent_profileSelectionDialog_unresolvableWorkProfileIntentShouldNotShow() {
final int userId = 10;

View File

@@ -49,7 +49,8 @@ import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.preference.SwitchPreferenceCompat;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
@@ -66,13 +67,13 @@ import com.android.settingslib.drawer.ProviderTile;
import com.android.settingslib.drawer.Tile;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -86,6 +87,10 @@ import java.util.Map;
@RunWith(RobolectricTestRunner.class)
public class DashboardFragmentTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private final Context mAppContext = ApplicationProvider.getApplicationContext();
@Mock
private FakeFeatureFactory mFakeFeatureFactory;
@@ -98,8 +103,7 @@ public class DashboardFragmentTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mContext = spy(mAppContext);
final ActivityInfo activityInfo = new ActivityInfo();
activityInfo.packageName = "pkg";
activityInfo.name = "class";
@@ -120,11 +124,11 @@ public class DashboardFragmentTest {
mProviderTile = new ProviderTile(providerInfo, mDashboardCategory.key, metaData);
mDashboardCategory.addTile(mProviderTile);
mTestFragment = new TestFragment(RuntimeEnvironment.application);
mTestFragment = new TestFragment(mAppContext);
when(mFakeFeatureFactory.dashboardFeatureProvider
.getTilesForCategory(nullable(String.class)))
.thenReturn(mDashboardCategory);
mTestFragment.onAttach(RuntimeEnvironment.application);
mTestFragment.onAttach(mAppContext);
when(mContext.getPackageName()).thenReturn("TestPackage");
mControllers = new ArrayList<>();
}
@@ -297,7 +301,7 @@ public class DashboardFragmentTest {
preferenceControllers.add(mockController2);
when(mockController1.isAvailable()).thenReturn(false);
when(mockController2.isAvailable()).thenReturn(true);
mTestFragment.onAttach(RuntimeEnvironment.application);
mTestFragment.onAttach(mAppContext);
mTestFragment.onResume();
verify(mockController1).getPreferenceKey();
@@ -387,12 +391,11 @@ public class DashboardFragmentTest {
assertThat(mTestFragment.mBlockerController).isNull();
}
@Ignore("b/313569889")
@Test
public void createPreference_isProviderTile_returnSwitchPreference() {
final Preference pref = mTestFragment.createPreference(mProviderTile);
assertThat(pref).isInstanceOf(SwitchPreference.class);
assertThat(pref).isInstanceOf(SwitchPreferenceCompat.class);
}
@Test
@@ -401,7 +404,7 @@ public class DashboardFragmentTest {
assertThat(pref).isInstanceOf(Preference.class);
assertThat(pref).isNotInstanceOf(PrimarySwitchPreference.class);
assertThat(pref).isNotInstanceOf(SwitchPreference.class);
assertThat(pref).isNotInstanceOf(SwitchPreferenceCompat.class);
assertThat(pref.getWidgetLayoutResource()).isEqualTo(0);
}
@@ -431,7 +434,7 @@ public class DashboardFragmentTest {
assertThat(pref).isInstanceOf(Preference.class);
assertThat(pref).isNotInstanceOf(PrimarySwitchPreference.class);
assertThat(pref).isNotInstanceOf(SwitchPreference.class);
assertThat(pref).isNotInstanceOf(SwitchPreferenceCompat.class);
assertThat(pref.getWidgetLayoutResource())
.isEqualTo(R.layout.preference_external_action_icon);
}

View File

@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.UserInfo;
import android.content.pm.UserProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.widget.TextView;
@@ -42,16 +43,19 @@ import com.android.settingslib.drawer.Tile;
import com.google.android.collect.Lists;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class ProfileSelectDialogTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
private static final UserHandle NORMAL_USER = new UserHandle(1111);
private static final UserHandle REMOVED_USER = new UserHandle(2222);
@@ -67,11 +71,12 @@ public class ProfileSelectDialogTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
final UserInfo userInfo = new UserInfo(
NORMAL_USER.getIdentifier(), "test_user", UserInfo.FLAG_RESTRICTED);
when(mUserManager.getUserInfo(NORMAL_USER.getIdentifier())).thenReturn(userInfo);
final UserProperties userProperties = new UserProperties.Builder().build();
when(mUserManager.getUserProperties(NORMAL_USER)).thenReturn(userProperties);
mActivityInfo = new ActivityInfo();
mActivityInfo.packageName = "pkg";
mActivityInfo.name = "cls";
@@ -89,7 +94,6 @@ public class ProfileSelectDialogTest {
verify(mUserManager, never()).getUserInfo(NORMAL_USER.getIdentifier());
}
@Ignore("b/313569889")
@Test
public void updateUserHandlesIfNeeded_Remove() {
final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
@@ -105,7 +109,6 @@ public class ProfileSelectDialogTest {
verify(mUserManager, times(2)).getUserInfo(REMOVED_USER.getIdentifier());
}
@Ignore("b/313569889")
@Test
public void updateUserHandlesIfNeeded_removesCloneProfile() {
final UserInfo userInfo = new UserInfo(CLONE_USER.getIdentifier(), "clone_user", null,
@@ -122,7 +125,6 @@ public class ProfileSelectDialogTest {
verify(mUserManager, times(1)).getUserInfo(CLONE_USER.getIdentifier());
}
@Ignore("b/313569889")
@Test
public void updatePendingIntentsIfNeeded_removesUsersWithNoPendingIntentsAndCloneProfile() {
final UserInfo userInfo = new UserInfo(CLONE_USER.getIdentifier(), "clone_user", null,

View File

@@ -16,27 +16,58 @@
package com.android.settings.dashboard.profileselector;
import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
import static com.android.settings.dashboard.profileselector.ProfileSelectFragment.EXTRA_PROFILE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.pm.UserInfo;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.testutils.shadow.ShadowUserManager;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@Ignore("b/313569889")
@Config(shadows = {
ShadowUserManager.class,
})
@RunWith(RobolectricTestRunner.class)
public class ProfileSelectLocationFragmentTest {
private static final String PERSONAL_PROFILE_NAME = "personal";
private static final String WORK_PROFILE_NAME = "work";
private static final String PRIVATE_PROFILE_NAME = "private";
@Rule
public final MockitoRule rule = MockitoJUnit.rule();
private ShadowUserManager mUserManager;
private ProfileSelectLocationFragment mProfileSelectLocationFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mProfileSelectLocationFragment = new ProfileSelectLocationFragment();
mUserManager = ShadowUserManager.getShadow();
mUserManager.addProfile(
new UserInfo(0, PERSONAL_PROFILE_NAME, null, 0, USER_TYPE_FULL_SYSTEM));
mUserManager.addProfile(
new UserInfo(1, WORK_PROFILE_NAME, null, 0, USER_TYPE_PROFILE_MANAGED));
mUserManager.addProfile(
new UserInfo(11, PRIVATE_PROFILE_NAME, null, 0, USER_TYPE_PROFILE_PRIVATE));
mProfileSelectLocationFragment = spy(new ProfileSelectLocationFragment());
when(mProfileSelectLocationFragment.getContext()).thenReturn(
ApplicationProvider.getApplicationContext());
}
@Test
@@ -46,7 +77,7 @@ public class ProfileSelectLocationFragmentTest {
EXTRA_PROFILE, -1)).isEqualTo(ProfileSelectFragment.ProfileType.PERSONAL);
assertThat(mProfileSelectLocationFragment.getFragments()[1].getArguments().getInt(
EXTRA_PROFILE, -1)).isEqualTo(ProfileSelectFragment.ProfileType.WORK);
assertThat(mProfileSelectLocationFragment.getFragments()[1].getArguments().getInt(
assertThat(mProfileSelectLocationFragment.getFragments()[2].getArguments().getInt(
EXTRA_PROFILE, -1)).isEqualTo(ProfileSelectFragment.ProfileType.PRIVATE);
}
}

View File

@@ -1,168 +0,0 @@
/*
* Copyright (C) 2023 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.datausage
import android.content.Context
import android.content.Intent
import android.net.NetworkTemplate
import android.os.Bundle
import android.os.UserManager
import android.provider.Settings
import androidx.preference.Preference
import androidx.test.core.app.ApplicationProvider
import com.android.settings.datausage.DataUsageListTest.ShadowDataUsageBaseFragment
import com.android.settings.datausage.TemplatePreference.NetworkServices
import com.android.settings.datausage.lib.BillingCycleRepository
import com.android.settings.testutils.FakeFeatureFactory
import com.android.settingslib.NetworkPolicyEditor
import com.android.settingslib.core.AbstractPreferenceController
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.annotation.Implementation
import org.robolectric.annotation.Implements
import org.robolectric.util.ReflectionHelpers
@RunWith(RobolectricTestRunner::class)
@Config(shadows = [ShadowDataUsageBaseFragment::class])
class DataUsageListTest {
@get:Rule
val mockito: MockitoRule = MockitoJUnit.rule()
@Mock
private lateinit var networkServices: NetworkServices
@Mock
private lateinit var userManager: UserManager
@Mock
private lateinit var billingCycleRepository: BillingCycleRepository
@Mock
private lateinit var dataUsageListHeaderController: DataUsageListHeaderController
@Spy
private val context: Context = ApplicationProvider.getApplicationContext()
@Spy
private val dataUsageList = TestDataUsageList()
@Before
fun setUp() {
FakeFeatureFactory.setupForTest()
networkServices.mPolicyEditor = mock(NetworkPolicyEditor::class.java)
doReturn(context).`when`(dataUsageList).context
doReturn(userManager).`when`(context).getSystemService(UserManager::class.java)
doReturn(false).`when`(userManager).isGuestUser
ReflectionHelpers.setField(dataUsageList, "services", networkServices)
doNothing().`when`(dataUsageList).updateSubscriptionInfoEntity()
`when`(billingCycleRepository.isBandwidthControlEnabled()).thenReturn(true)
dataUsageList.dataUsageListHeaderController = dataUsageListHeaderController
}
@Test
fun onCreate_isNotGuestUser_shouldNotFinish() {
dataUsageList.template = mock<NetworkTemplate>(NetworkTemplate::class.java)
doReturn(false).`when`(userManager).isGuestUser
doNothing().`when`(dataUsageList).processArgument()
dataUsageList.onCreate(null)
verify(dataUsageList, never()).finish()
}
@Test
fun onCreate_isGuestUser_shouldFinish() {
doReturn(true).`when`(userManager).isGuestUser
dataUsageList.onCreate(null)
verify(dataUsageList).finish()
}
@Test
fun processArgument_shouldGetTemplateFromArgument() {
val args = Bundle()
args.putParcelable(
DataUsageList.EXTRA_NETWORK_TEMPLATE, mock(
NetworkTemplate::class.java
)
)
args.putInt(DataUsageList.EXTRA_SUB_ID, 3)
dataUsageList.arguments = args
dataUsageList.processArgument()
assertThat(dataUsageList.template).isNotNull()
assertThat(dataUsageList.subId).isEqualTo(3)
}
@Test
fun processArgument_fromIntent_shouldGetTemplateFromIntent() {
val intent = Intent()
intent.putExtra(
Settings.EXTRA_NETWORK_TEMPLATE, mock(
NetworkTemplate::class.java
)
)
intent.putExtra(Settings.EXTRA_SUB_ID, 3)
doReturn(intent).`when`(dataUsageList).intent
dataUsageList.processArgument()
assertThat(dataUsageList.template).isNotNull()
assertThat(dataUsageList.subId).isEqualTo(3)
}
@Test
fun updatePolicy_setConfigButtonVisible() {
dataUsageList.template = mock(NetworkTemplate::class.java)
dataUsageList.onCreate(null)
dataUsageList.updatePolicy()
verify(dataUsageListHeaderController).setConfigButtonVisible(true)
}
@Implements(DataUsageBaseFragment::class)
class ShadowDataUsageBaseFragment {
@Implementation
fun onCreate(@Suppress("UNUSED_PARAMETER") icicle: Bundle?) {
// do nothing
}
}
open inner class TestDataUsageList : DataUsageList() {
override fun <T : AbstractPreferenceController?> use(clazz: Class<T>): T = mock(clazz)
@Suppress("UNCHECKED_CAST")
override fun <T : Preference?> findPreference(key: CharSequence): T =
mock(Preference::class.java) as T
public override fun getIntent() = Intent()
override fun createBillingCycleRepository() = billingCycleRepository
override fun isBillingCycleModifiable() = true
}
}

View File

@@ -1,352 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.datausage;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.NetworkTemplate;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
import android.util.RecurrenceRule;
import androidx.fragment.app.FragmentActivity;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.net.DataUsageController;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowEntityHeaderController.class)
public class DataUsageSummaryPreferenceControllerTest {
private static final long UPDATE_BACKOFF_MS = TimeUnit.MINUTES.toMillis(13);
private static final long CYCLE_BACKOFF_MS = TimeUnit.DAYS.toMillis(6);
private static final long CYCLE_LENGTH_MS = TimeUnit.DAYS.toMillis(30);
private static final long USAGE1 = 373 * BillingCycleSettings.MIB_IN_BYTES;
private static final long LIMIT1 = BillingCycleSettings.GIB_IN_BYTES;
private static final String CARRIER_NAME = "z-mobile";
private static final String PERIOD = "Feb";
@Mock
private DataUsageController mDataUsageController;
@Mock
private DataUsageSummaryPreference mSummaryPreference;
@Mock
private NetworkTemplate mNetworkTemplate;
@Mock
private SubscriptionInfo mSubscriptionInfo;
@Mock
private SubscriptionPlan mSubscriptionPlan;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private EntityHeaderController mHeaderController;
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private PackageManager mPm;
private DataUsageInfoController mDataInfoController;
private FakeFeatureFactory mFactory;
private FragmentActivity mActivity;
private Context mContext;
private DataUsageSummaryPreferenceController mController;
private int mDefaultSubscriptionId;
private List<SubscriptionPlan> mSubscriptionPlans;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
doReturn("%1$s %2%s").when(mContext)
.getString(com.android.internal.R.string.fileSizeSuffix);
mDefaultSubscriptionId = 1234;
mSubscriptionPlans = new ArrayList<SubscriptionPlan>();
mFactory = FakeFeatureFactory.setupForTest();
when(mFactory.metricsFeatureProvider.getMetricsCategory(any(Object.class)))
.thenReturn(MetricsProto.MetricsEvent.SETTINGS_APP_NOTIF_CATEGORY);
ShadowEntityHeaderController.setUseMock(mHeaderController);
mDataInfoController = spy(new DataUsageInfoController());
doReturn(-1L).when(mDataInfoController).getSummaryLimit(any());
mActivity = spy(Robolectric.buildActivity(FragmentActivity.class).get());
doReturn(mTelephonyManager).when(mActivity).getSystemService(TelephonyManager.class);
doReturn(mTelephonyManager).when(mTelephonyManager)
.createForSubscriptionId(mDefaultSubscriptionId);
doReturn(mPm).when(mActivity).getPackageManager();
doReturn(TelephonyManager.SIM_STATE_READY).when(mTelephonyManager).getSimState();
mController = spy(new DataUsageSummaryPreferenceController(
mDataUsageController,
mDataInfoController,
mNetworkTemplate,
mActivity, mDefaultSubscriptionId));
doReturn(null).when(mController).getSubscriptionInfo(
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
doReturn(null).when(mController).getSubscriptionPlans(
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
doReturn(CARRIER_NAME).when(mSubscriptionInfo).getCarrierName();
doReturn(mSubscriptionInfo).when(mController).getSubscriptionInfo(mDefaultSubscriptionId);
doReturn(mSubscriptionPlans).when(mController).getSubscriptionPlans(mDefaultSubscriptionId);
}
@After
public void tearDown() {
ShadowEntityHeaderController.reset();
}
@Test
public void testSummaryUpdate_onePlan_basic() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
doReturn(info).when(mDataUsageController).getDataUsageInfo(any());
setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS);
createTestDataPlan(info.cycleStart, info.cycleEnd);
mController.updateState(mSummaryPreference);
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mSummaryPreference).setLimitInfo(captor.capture());
CharSequence value = captor.getValue();
assertThat(value.toString()).isEqualTo("512 MB data warning / 1.00 GB data limit");
// TODO (b/170330084): return intent instead of null for mSummaryPreference
verify(mSummaryPreference).setUsageInfo((info.cycleEnd / 1000) * 1000,
now - UPDATE_BACKOFF_MS,
CARRIER_NAME, 1 /* numPlans */);
verify(mSummaryPreference).setChartEnabled(true);
}
@Test
public void testSummaryUpdate_noPlan_basic() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
doReturn(info).when(mDataUsageController).getDataUsageInfo(any());
setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS);
mController.updateState(mSummaryPreference);
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mSummaryPreference).setLimitInfo(captor.capture());
CharSequence value = captor.getValue();
assertThat(value.toString()).isEqualTo("512 MB data warning / 1.00 GB data limit");
verify(mSummaryPreference).setUsageInfo(
info.cycleEnd,
-1L /* snapshotTime */,
CARRIER_NAME,
0 /* numPlans */);
verify(mSummaryPreference).setChartEnabled(true);
}
@Test
public void testSummaryUpdate_noCarrier_basic() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
doReturn(info).when(mDataUsageController).getDataUsageInfo(any());
doReturn(null).when(mSubscriptionInfo).getCarrierName();
setupTestDataUsage(LIMIT1, USAGE1, -1L /* snapshotTime */);
mController.updateState(mSummaryPreference);
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mSummaryPreference).setLimitInfo(captor.capture());
CharSequence value = captor.getValue();
assertThat(value.toString()).isEqualTo("512 MB data warning / 1.00 GB data limit");
verify(mSummaryPreference).setUsageInfo(
info.cycleEnd,
-1L /* snapshotTime */,
null /* carrierName */,
0 /* numPlans */);
verify(mSummaryPreference).setChartEnabled(true);
}
@Test
public void testSummaryUpdate_noPlanData_basic() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
doReturn(info).when(mDataUsageController).getDataUsageInfo(any());
doReturn(null).when(mSubscriptionInfo).getCarrierName();
setupTestDataUsage(-1L /* dataPlanSize */, USAGE1, -1L /* snapshotTime */);
mController.updateState(mSummaryPreference);
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mSummaryPreference).setLimitInfo(captor.capture());
CharSequence value = captor.getValue();
assertThat(value.toString()).isEqualTo("512 MB data warning / 1.00 GB data limit");
verify(mSummaryPreference).setUsageInfo(
info.cycleEnd,
-1L /* snapshotTime */,
null /* carrierName */,
0 /* numPlans */);
verify(mSummaryPreference).setChartEnabled(false);
}
@Test
public void testSummaryUpdate_noLimitNoWarning() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
info.warningLevel = 0L;
info.limitLevel = 0L;
doReturn(info).when(mDataUsageController).getDataUsageInfo(any());
setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS);
mController.updateState(mSummaryPreference);
verify(mSummaryPreference).setLimitInfo(null);
}
@Test
public void testSummaryUpdate_warningOnly() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
info.warningLevel = BillingCycleSettings.MIB_IN_BYTES;
info.limitLevel = 0L;
doReturn(info).when(mDataUsageController).getDataUsageInfo(any());
setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS);
mController.updateState(mSummaryPreference);
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mSummaryPreference).setLimitInfo(captor.capture());
CharSequence value = captor.getValue();
assertThat(value.toString()).isEqualTo("1.00 MB data warning");
}
@Test
public void testSummaryUpdate_limitOnly() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
info.warningLevel = 0L;
info.limitLevel = BillingCycleSettings.MIB_IN_BYTES;
doReturn(info).when(mDataUsageController).getDataUsageInfo(any());
setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS);
mController.updateState(mSummaryPreference);
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mSummaryPreference).setLimitInfo(captor.capture());
CharSequence value = captor.getValue();
assertThat(value.toString()).isEqualTo("1.00 MB data limit");
}
@Test
public void testSummaryUpdate_limitAndWarning() {
final long now = System.currentTimeMillis();
final DataUsageController.DataUsageInfo info = createTestDataUsageInfo(now);
info.warningLevel = BillingCycleSettings.MIB_IN_BYTES;
info.limitLevel = BillingCycleSettings.MIB_IN_BYTES;
doReturn(info).when(mDataUsageController).getDataUsageInfo(any());
setupTestDataUsage(LIMIT1, USAGE1, now - UPDATE_BACKOFF_MS);
mController.updateState(mSummaryPreference);
ArgumentCaptor<CharSequence> captor = ArgumentCaptor.forClass(CharSequence.class);
verify(mSummaryPreference).setLimitInfo(captor.capture());
CharSequence value = captor.getValue();
assertThat(value.toString()).isEqualTo("1.00 MB data warning / 1.00 MB data limit");
}
@Test
public void testMobileData_preferenceAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void testMobileData_noSim_preferenceDisabled() {
final int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
mController.init(subscriptionId);
mController.mDataUsageController = mDataUsageController;
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
private DataUsageController.DataUsageInfo createTestDataUsageInfo(long now) {
DataUsageController.DataUsageInfo info = new DataUsageController.DataUsageInfo();
info.carrier = CARRIER_NAME;
info.period = PERIOD;
info.startDate = now;
info.limitLevel = LIMIT1;
info.warningLevel = LIMIT1 >> 1;
info.usageLevel = USAGE1;
info.cycleStart = now - CYCLE_BACKOFF_MS;
info.cycleEnd = info.cycleStart + CYCLE_LENGTH_MS;
return info;
}
private void setupTestDataUsage(long dataPlanSize, long dataUsageSize, long snapshotTime) {
doReturn(dataPlanSize).when(mSubscriptionPlan).getDataLimitBytes();
doReturn(dataUsageSize).when(mSubscriptionPlan).getDataUsageBytes();
doReturn(snapshotTime).when(mSubscriptionPlan).getDataUsageTime();
doReturn(dataPlanSize).when(mDataInfoController).getSummaryLimit(any());
}
private void createTestDataPlan(long startTime, long endTime) {
final RecurrenceRule recurrenceRule = new RecurrenceRule(
Instant.ofEpochMilli(startTime).atZone(ZoneId.systemDefault()),
Instant.ofEpochMilli(endTime).atZone(ZoneId.systemDefault()),
null);
doReturn(recurrenceRule).when(mSubscriptionPlan).getCycleRule();
mSubscriptionPlans.add(mSubscriptionPlan);
}
}

View File

@@ -25,6 +25,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -163,6 +164,81 @@ public class UnrestrictedDataAccessPreferenceControllerTest {
mController.onRebuildComplete(createAppEntries(testPkg1, testPkg2));
}
@Test
public void onRebuildComplete_ecmRestricted_shouldBeDisabled() {
mFragment = spy(new UnrestrictedDataAccess());
mContext = spy(mContext);
doNothing().when(mFragment).setLoading(anyBoolean(), anyBoolean());
mController.setParentFragment(mFragment);
mPreferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = spy(mPreferenceManager.createPreferenceScreen(mContext));
doReturn(mPreferenceManager).when(mFragment).getPreferenceManager();
doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen();
doReturn(0).when(mPreferenceScreen).getPreferenceCount();
final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class);
ReflectionHelpers.setField(mController, "mDataSaverBackend", dataSaverBackend);
ReflectionHelpers.setField(mController, "mScreen", mPreferenceScreen);
final String testPkg = "com.example.disabled";
doNothing().when(mContext).startActivity(any());
ShadowRestrictedLockUtilsInternal.setEcmRestrictedPkgs(testPkg);
doAnswer((invocation) -> {
final UnrestrictedDataAccessPreference preference = invocation.getArgument(0);
// Verify preference is disabled by ecm and the summary is changed accordingly.
assertThat(preference.isDisabledByEcm()).isTrue();
assertThat(preference.getSummary().toString()).isEqualTo(
mContext.getString(
com.android.settingslib.R.string.disabled_by_app_ops_text));
assertThat(preference.isChecked()).isFalse();
preference.performClick();
// Verify that when the preference is clicked, ecm details intent is launched
assertThat(preference.isChecked()).isFalse();
verify(mContext).startActivity(any());
return null;
}).when(mPreferenceScreen).addPreference(any(UnrestrictedDataAccessPreference.class));
mController.onRebuildComplete(createAppEntries(testPkg));
verify(mPreferenceScreen).addPreference(any(UnrestrictedDataAccessPreference.class));
}
@Test
public void onRebuildComplete_ecmNotRestricted_notDisabled() {
mFragment = spy(new UnrestrictedDataAccess());
mContext = spy(mContext);
doNothing().when(mFragment).setLoading(anyBoolean(), anyBoolean());
mController.setParentFragment(mFragment);
mPreferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = spy(mPreferenceManager.createPreferenceScreen(mContext));
doReturn(mPreferenceManager).when(mFragment).getPreferenceManager();
doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen();
doReturn(0).when(mPreferenceScreen).getPreferenceCount();
final DataSaverBackend dataSaverBackend = mock(DataSaverBackend.class);
ReflectionHelpers.setField(mController, "mDataSaverBackend", dataSaverBackend);
ReflectionHelpers.setField(mController, "mScreen", mPreferenceScreen);
final String testPkg = "com.example.enabled";
doNothing().when(mContext).startActivity(any());
ShadowRestrictedLockUtilsInternal.setEcmRestrictedPkgs();
doAnswer((invocation) -> {
final UnrestrictedDataAccessPreference preference = invocation.getArgument(0);
assertThat(preference.isDisabledByEcm()).isFalse();
assertThat(preference.getSummary()).isEqualTo("");
assertThat(preference.isChecked()).isFalse();
preference.performClick();
// Verify that when the preference is clicked, ecm details intent is not launched
assertThat(preference.isChecked()).isTrue();
verify(mContext, never()).startActivity(any());
return null;
}).when(mPreferenceScreen).addPreference(any(UnrestrictedDataAccessPreference.class));
mController.onRebuildComplete(createAppEntries(testPkg));
verify(mPreferenceScreen).addPreference(any(UnrestrictedDataAccessPreference.class));
}
private ArrayList<AppEntry> createAppEntries(String... packageNames) {
final ArrayList<AppEntry> appEntries = new ArrayList<>();
for (int i = 0; i < packageNames.length; ++i) {

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2022 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.development;
import static com.android.settings.development.BluetoothLeAudioModePreferenceController
.LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.os.SystemProperties;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
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;
@RunWith(RobolectricTestRunner.class)
public class BluetoothLeAudioModePreferenceControllerTest {
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private DevelopmentSettingsDashboardFragment mFragment;
@Mock
private BluetoothAdapter mBluetoothAdapter;
@Mock
private ListPreference mPreference;
private Context mContext;
private BluetoothLeAudioModePreferenceController mController;
private String[] mListValues;
private String[] mListSummaries;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mListValues = mContext.getResources().getStringArray(
R.array.bluetooth_leaudio_mode_values);
mListSummaries = mContext.getResources().getStringArray(
R.array.bluetooth_leaudio_mode);
mController = spy(new BluetoothLeAudioModePreferenceController(mContext, mFragment));
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
mController.mBluetoothAdapter = mBluetoothAdapter;
mController.displayPreference(mPreferenceScreen);
}
@Test
public void onRebootDialogConfirmed_changeLeAudioMode_shouldSetLeAudioMode() {
mController.mChanged = true;
SystemProperties.set(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, mListValues[0]);
mController.mNewMode = mListValues[1];
mController.onRebootDialogConfirmed();
assertThat(SystemProperties.get(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, mListValues[0])
.equals(mController.mNewMode)).isTrue();
}
@Test
public void onRebootDialogConfirmed_notChangeLeAudioMode_shouldNotSetLeAudioMode() {
mController.mChanged = false;
SystemProperties.set(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, mListValues[0]);
mController.mNewMode = mListValues[1];
mController.onRebootDialogConfirmed();
assertThat(SystemProperties.get(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, mListValues[0])
.equals(mController.mNewMode)).isFalse();
}
@Test
public void onRebootDialogCanceled_shouldNotSetLeAudioMode() {
mController.mChanged = true;
SystemProperties.set(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, mListValues[0]);
mController.mNewMode = mListValues[1];
mController.onRebootDialogCanceled();
assertThat(SystemProperties.get(LE_AUDIO_DYNAMIC_SWITCHER_MODE_PROPERTY, mListValues[0])
.equals(mController.mNewMode)).isFalse();
}
}

View File

@@ -16,6 +16,8 @@
package com.android.settings.development;
import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
import static com.android.settings.development.ForcePeakRefreshRatePreferenceController.NO_CONFIG;
@@ -24,19 +26,28 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.testing.TestableContext;
import android.view.Display;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.display.feature.flags.Flags;
import org.junit.Before;
import org.junit.Rule;
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;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@@ -46,14 +57,51 @@ public class ForcePeakRefreshRatePreferenceControllerTest {
private SwitchPreference mPreference;
@Mock
private PreferenceScreen mScreen;
@Mock
private DisplayManager mDisplayManagerMock;
@Mock
private Display mDisplayMock;
@Mock
private Display mDisplayMock2;
private Context mContext;
private ForcePeakRefreshRatePreferenceController mController;
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Rule
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getContext());
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock);
Display.Mode[] modes = new Display.Mode[]{
new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
/* refreshRate= */ 60),
new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
/* refreshRate= */ 120),
new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
/* refreshRate= */ 90)
};
when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
when(mDisplayMock.getSupportedModes()).thenReturn(modes);
Display.Mode[] modes2 = new Display.Mode[]{
new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
/* refreshRate= */ 70),
new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
/* refreshRate= */ 130),
new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
/* refreshRate= */ 80)
};
when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2);
when(mDisplayMock2.getSupportedModes()).thenReturn(modes2);
when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED))
.thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 });
mController = new ForcePeakRefreshRatePreferenceController(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
@@ -61,7 +109,19 @@ public class ForcePeakRefreshRatePreferenceControllerTest {
}
@Test
public void onPreferenceChange_preferenceChecked_shouldEnableForcePeak() {
@RequiresFlagsDisabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE)
public void onPreferenceChange_preferenceChecked_shouldEnableForcePeak_featureFlagOff() {
mController.mPeakRefreshRate = 88f;
mController.onPreferenceChange(mPreference, true);
assertThat(Settings.System.getFloat(mContext.getContentResolver(),
Settings.System.MIN_REFRESH_RATE, NO_CONFIG)).isEqualTo(88f);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE)
public void onPreferenceChange_preferenceChecked_shouldEnableForcePeak_featureFlagOn() {
mController.mPeakRefreshRate = 88f;
mController.onPreferenceChange(mPreference, true);
@@ -88,6 +148,7 @@ public class ForcePeakRefreshRatePreferenceControllerTest {
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
assertThat(mController.isForcePeakRefreshRateEnabled()).isTrue();
}
@Test
@@ -98,6 +159,7 @@ public class ForcePeakRefreshRatePreferenceControllerTest {
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
assertThat(mController.isForcePeakRefreshRateEnabled()).isFalse();
}
@Test
@@ -129,4 +191,16 @@ public class ForcePeakRefreshRatePreferenceControllerTest {
assertThat(mPreference.isChecked()).isFalse();
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
@RequiresFlagsDisabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE)
public void peakRefreshRate_highestOfDefaultDisplay_featureFlagOff() {
assertThat(mController.mPeakRefreshRate).isEqualTo(120);
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE)
public void peakRefreshRate_highestOfAllDisplays_featureFlagOn() {
assertThat(mController.mPeakRefreshRate).isEqualTo(130);
}
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright (C) 2023 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.development;
import static com.android.settings.development.GameDefaultFrameRatePreferenceController.Injector;
import static com.android.settings.development.GameDefaultFrameRatePreferenceController.PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.IGameManagerService;
import android.content.Context;
import android.os.RemoteException;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;
import com.android.settings.flags.Flags;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class GameDefaultFrameRatePreferenceControllerTest {
@Mock
private Context mContext;
@Mock
private PreferenceScreen mScreen;
@Mock
private TwoStatePreference mPreference;
@Mock
private IGameManagerService mGameManagerService;
@Mock
private DevelopmentSystemPropertiesWrapper mSysPropsMock;
private GameDefaultFrameRatePreferenceController mController;
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new GameDefaultFrameRatePreferenceController(mContext, mGameManagerService,
new Injector(){
@Override
public DevelopmentSystemPropertiesWrapper createSystemPropertiesWrapper() {
return mSysPropsMock;
}
});
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
mController.displayPreference(mScreen);
}
@Test
public void onPreferenceChange_settingEnabled_shouldChecked() throws RemoteException {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVELOPMENT_GAME_DEFAULT_FRAME_RATE);
assertTrue(mController.isAvailable());
when(mSysPropsMock.getBoolean(
ArgumentMatchers.eq(PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED),
ArgumentMatchers.eq(false)))
.thenReturn(true);
mController.onPreferenceChange(mPreference, true /* new value */);
verify(mPreference).setChecked(true);
}
@Test
public void onPreferenceChange_settingDisabled_shouldUnchecked() throws RemoteException {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVELOPMENT_GAME_DEFAULT_FRAME_RATE);
assertTrue(mController.isAvailable());
when(mSysPropsMock.getBoolean(
ArgumentMatchers.eq(PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED),
ArgumentMatchers.eq(false)))
.thenReturn(false);
mController.onPreferenceChange(mPreference, false /* new value */);
verify(mPreference).setChecked(false);
}
@Test
public void updateState_settingEnabled_shouldChecked() throws RemoteException {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVELOPMENT_GAME_DEFAULT_FRAME_RATE);
assertTrue(mController.isAvailable());
when(mSysPropsMock.getBoolean(
ArgumentMatchers.eq(PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED),
ArgumentMatchers.eq(false)))
.thenReturn(true);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
@Test
public void updateState_settingDisabled_shouldUnchecked() throws RemoteException {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVELOPMENT_GAME_DEFAULT_FRAME_RATE);
assertTrue(mController.isAvailable());
when(mSysPropsMock.getBoolean(
ArgumentMatchers.eq(PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED),
ArgumentMatchers.eq(false)))
.thenReturn(false);
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
}
@Test
public void settingNotAvailable_flagsOff() {
mSetFlagsRule.disableFlags(Flags.FLAG_DEVELOPMENT_GAME_DEFAULT_FRAME_RATE);
mController = new GameDefaultFrameRatePreferenceController(
mContext, mGameManagerService, new Injector());
assertFalse(mController.isAvailable());
}
@Test
public void settingAvailable_flagsOn() {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVELOPMENT_GAME_DEFAULT_FRAME_RATE);
mController = new GameDefaultFrameRatePreferenceController(
mContext, mGameManagerService, new Injector());
assertTrue(mController.isAvailable());
}
@Test
public void onDeveloperOptionsSwitchDisabled_preferenceUnchecked_shouldNotTurnOffPreference()
throws RemoteException {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVELOPMENT_GAME_DEFAULT_FRAME_RATE);
when(mSysPropsMock.getBoolean(
ArgumentMatchers.eq(PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED),
ArgumentMatchers.eq(false)))
.thenReturn(false);
assertTrue(mController.isAvailable());
when(mPreference.isChecked()).thenReturn(false);
mController.onDeveloperOptionsSwitchDisabled();
verify(mPreference).setChecked(false);
verify(mPreference).setEnabled(false);
}
@Test
public void onDeveloperOptionsSwitchDisabled_preferenceChecked_shouldTurnOffPreference()
throws RemoteException {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVELOPMENT_GAME_DEFAULT_FRAME_RATE);
when(mSysPropsMock.getBoolean(
ArgumentMatchers.eq(PROPERTY_DEBUG_GFX_GAME_DEFAULT_FRAME_RATE_DISABLED),
ArgumentMatchers.eq(false)))
.thenReturn(true);
assertTrue(mController.isAvailable());
when(mPreference.isChecked()).thenReturn(true);
mController.onDeveloperOptionsSwitchDisabled();
verify(mPreference).setChecked(false);
verify(mPreference).setEnabled(false);
}
}

Some files were not shown because too many files have changed in this diff Show More