Merge "Merge sc-dev-plus-aosp-without-vendor@7634622" into stage-aosp-master

This commit is contained in:
Xin Li
2021-08-17 18:14:14 +00:00
committed by Android (Google) Code Review
2494 changed files with 218431 additions and 77065 deletions

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2020 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;
import static com.google.common.truth.Truth.assertThat;
import android.text.Spannable;
import android.text.style.ClickableSpan;
import android.widget.TextView;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class LinkifyUtilsTest {
private static final String TEST_STRING = "to LINK_BEGINscanning settingsLINK_END.";
private static final String WRONG_STRING = "to scanning settingsLINK_END.";
private final LinkifyUtils.OnClickListener mClickListener = () -> { /* Do nothing */ };
private StringBuilder mSpanStringBuilder;
private StringBuilder mWrongSpanStringBuilder;
TextView mTextView;
@Before
public void setUp() throws Exception {
mSpanStringBuilder = new StringBuilder(TEST_STRING);
mWrongSpanStringBuilder = new StringBuilder(WRONG_STRING);
mTextView = new TextView(ApplicationProvider.getApplicationContext());
}
@Test
public void linkify_whenSpanStringCorrect_shouldReturnTrue() {
final boolean linkifyResult = LinkifyUtils.linkify(mTextView, mSpanStringBuilder,
mClickListener);
assertThat(linkifyResult).isTrue();
}
@Test
public void linkify_whenSpanStringWrong_shouldReturnFalse() {
final boolean linkifyResult = LinkifyUtils.linkify(mTextView, mWrongSpanStringBuilder,
mClickListener);
assertThat(linkifyResult).isFalse();
}
@Test
public void linkify_whenSpanStringCorrect_shouldContainClickableSpan() {
LinkifyUtils.linkify(mTextView, mSpanStringBuilder, mClickListener);
final Spannable spannableContent = (Spannable) mTextView.getText();
final int len = spannableContent.length();
final Object[] spans = spannableContent.getSpans(0, len, Object.class);
assertThat(spans[1] instanceof ClickableSpan).isTrue();
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2020 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;
/**
* Convenience methods and constants for testing.
*/
public class TestUtils {
public static final long KILOBYTE = 1024L; // TODO: Change to 1000 in O Robolectric.
public static final long MEGABYTE = KILOBYTE * KILOBYTE;
public static final long GIGABYTE = KILOBYTE * MEGABYTE;
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2016 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;
import static com.android.settings.UserCredentialsSettings.Credential;
import android.os.Parcel;
import android.os.Process;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
/**
* User credentials settings fragment tests
*
* To run the test, use command:
* adb shell am instrument -e class com.android.settings.UserCredentialsTest
* -w com.android.settings.tests.unit/androidx.test.runner.AndroidJUnitRunner
*
*/
public class UserCredentialsTest extends InstrumentationTestCase {
private static final String TAG = "UserCredentialsTests";
@SmallTest
public void testCredentialIsParcelable() {
final String alias = "credential-test-alias";
Credential c = new Credential(alias, Process.SYSTEM_UID);
c.storedTypes.add(Credential.Type.CA_CERTIFICATE);
c.storedTypes.add(Credential.Type.USER_KEY);
Parcel p = Parcel.obtain();
c.writeToParcel(p, /* flags */ 0);
p.setDataPosition(0);
Credential r = Credential.CREATOR.createFromParcel(p);
assertEquals(c.alias, r.alias);
assertEquals(c.uid, r.uid);
assertEquals(c.storedTypes, r.storedTypes);
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright (C) 2016 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;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.when;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
public class UtilsTest extends AndroidTestCase {
private static final int TEST_PRIMARY_USER_ID = 10;
private static final int TEST_MANAGED_PROFILE_ID = 11;
@Mock private UserManager mUserManager;
@Override
public void setUp() throws Exception {
super.setUp();
// // this is necessary for mockito to work
System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
MockitoAnnotations.initMocks(this);
when(mUserManager.getUserHandle()).thenReturn(TEST_PRIMARY_USER_ID);
UserInfo primaryUser = new UserInfo(TEST_PRIMARY_USER_ID, null,
UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_PRIMARY);
when(mUserManager.getUserInfo(TEST_PRIMARY_USER_ID)).thenReturn(primaryUser);
UserInfo managedProfile = new UserInfo(TEST_MANAGED_PROFILE_ID, null,
UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
when(mUserManager.getUserInfo(eq(TEST_MANAGED_PROFILE_ID))).thenReturn(managedProfile);
}
@SmallTest
public void testGetManagedProfile() {
UserHandle[] userHandles = new UserHandle[] {
new UserHandle(TEST_PRIMARY_USER_ID),
new UserHandle(TEST_MANAGED_PROFILE_ID)
};
when(mUserManager.getUserProfiles())
.thenReturn(new ArrayList<UserHandle>(Arrays.asList(userHandles)));
assertEquals(TEST_MANAGED_PROFILE_ID,
Utils.getManagedProfile(mUserManager).getIdentifier());
}
@SmallTest
public void testGetManagedProfile_notPresent() {
UserHandle[] userHandles = new UserHandle[] {
new UserHandle(TEST_PRIMARY_USER_ID)
};
when(mUserManager.getUserProfiles())
.thenReturn(new ArrayList<UserHandle>(Arrays.asList(userHandles)));
assertNull(Utils.getManagedProfile(mUserManager));
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2020 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 androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class AccessibilityShortcutPreferenceControllerTest {
private Context mContext;
private SwitchPreference mPreference;
private AccessibilityShortcutPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mPreference = new SwitchPreference(mContext);
mController = new AccessibilityShortcutPreferenceController(mContext,
"accessibility_shortcut_preference");
}
@Test
public void isChecked_enabledShortcutOnLockScreen_shouldReturnTrue() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, ON, UserHandle.USER_CURRENT);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void isChecked_disabledShortcutOnLockScreen_shouldReturnFalse() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, OFF,
UserHandle.USER_CURRENT);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void setChecked_setTrue_shouldEnableShortcutOnLockScreen() {
mController.setChecked(true);
assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, OFF,
UserHandle.USER_CURRENT)).isEqualTo(ON);
}
@Test
public void setChecked_setFalse_shouldDisableShortcutOnLockScreen() {
mController.setChecked(false);
assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, ON,
UserHandle.USER_CURRENT)).isEqualTo(OFF);
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2020 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.DisableAnimationsPreferenceController.ANIMATION_OFF_VALUE;
import static com.android.settings.accessibility.DisableAnimationsPreferenceController.ANIMATION_ON_VALUE;
import static com.android.settings.accessibility.DisableAnimationsPreferenceController.TOGGLE_ANIMATION_TARGETS;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class DisableAnimationsPreferenceControllerTest {
private Context mContext;
private SwitchPreference mPreference;
private DisableAnimationsPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mPreference = new SwitchPreference(mContext);
mController = new DisableAnimationsPreferenceController(mContext, "disable_animation");
}
@Test
public void getAvailabilityStatus_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void isChecked_enabledAnimation_shouldReturnFalse() {
for (String animationPreference : TOGGLE_ANIMATION_TARGETS) {
Settings.Global.putString(mContext.getContentResolver(), animationPreference,
ANIMATION_ON_VALUE);
}
mController.updateState(mPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void isChecked_disabledAnimation_shouldReturnTrue() {
for (String animationPreference : TOGGLE_ANIMATION_TARGETS) {
Settings.Global.putString(mContext.getContentResolver(), animationPreference,
ANIMATION_OFF_VALUE);
}
mController.updateState(mPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void setChecked_disabledAnimation_shouldDisableAnimationTargets() {
mController.setChecked(true);
for (String animationSetting : TOGGLE_ANIMATION_TARGETS) {
assertThat(Settings.Global.getString(mContext.getContentResolver(), animationSetting))
.isEqualTo(ANIMATION_OFF_VALUE);
}
}
@Test
public void setChecked_enabledAnimation_shouldEnableAnimationTargets() {
mController.setChecked(false);
for (String animationSetting : TOGGLE_ANIMATION_TARGETS) {
assertThat(Settings.Global.getString(mContext.getContentResolver(), animationSetting))
.isEqualTo(ANIMATION_ON_VALUE);
}
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2020 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.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class FontWeightAdjustmentPreferenceControllerTest {
private static final int ON = FontWeightAdjustmentPreferenceController.BOLD_TEXT_ADJUSTMENT;
private static final int OFF = 0;
private Context mContext;
private SwitchPreference mPreference;
private FontWeightAdjustmentPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mPreference = new SwitchPreference(mContext);
mController = new FontWeightAdjustmentPreferenceController(
mContext, "font_weight_adjustment");
}
@Test
public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void isChecked_enabledBoldText_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.FONT_WEIGHT_ADJUSTMENT, ON);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void isChecked_disabledBoldText_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.FONT_WEIGHT_ADJUSTMENT, OFF);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void setChecked_setTrue_shouldEnableBoldText() {
mController.setChecked(true);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.FONT_WEIGHT_ADJUSTMENT, OFF)).isEqualTo(ON);
}
@Test
public void setChecked_setFalse_shouldDisableBoldText() {
mController.setChecked(false);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.FONT_WEIGHT_ADJUSTMENT, OFF)).isEqualTo(OFF);
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2020 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.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class HighTextContrastPreferenceControllerTest {
private static final int ON = 1;
private static final int OFF = 0;
private static final int UNKNOWN = -1;
private Context mContext;
private SwitchPreference mPreference;
private HighTextContrastPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mPreference = new SwitchPreference(mContext);
mController = new HighTextContrastPreferenceController(mContext, "text_contrast");
}
@Test
public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void isChecked_enabledTextContrast_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, ON);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void isChecked_disabledTextContrast_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, OFF);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void setChecked_setTrue_shouldEnableTextContrast() {
mController.setChecked(true);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, UNKNOWN)).isEqualTo(ON);
}
@Test
public void setChecked_setFalse_shouldDisableTextContrast() {
mController.setChecked(false);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, UNKNOWN)).isEqualTo(OFF);
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2020 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.LargePointerIconPreferenceController.OFF;
import static com.android.settings.accessibility.LargePointerIconPreferenceController.ON;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class LargePointerIconPreferenceControllerTest {
private static final int UNKNOWN = -1;
private Context mContext;
private SwitchPreference mPreference;
private LargePointerIconPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mPreference = new SwitchPreference(mContext);
mController = new LargePointerIconPreferenceController(mContext, "large_pointer");
}
@Test
public void getAvailabilityStatus_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void isChecked_enabledLargePointer_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, ON);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void isChecked_disabledLargePointer_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, OFF);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void setChecked_enabled_shouldEnableLargePointer() {
mController.setChecked(true);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, UNKNOWN)).isEqualTo(ON);
}
@Test
public void setChecked_disabled_shouldDisableLargePointer() {
mController.setChecked(false);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON, UNKNOWN)).isEqualTo(OFF);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2020 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 androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class MagnificationPreferenceControllerTest {
private Context mContext;
private MagnificationPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new MagnificationPreferenceController(mContext, "magnification");
}
@Test
public void getAvailabilityStatus_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2020 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.ComponentName;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Tests for {@link PreferredShortcut} */
@RunWith(AndroidJUnit4.class)
public class PreferredShortcutTest {
private static final String STUB_COMPONENT_NAME = new ComponentName("com.example",
"com.example.testActivity").flattenToString();
private static final int STUB_TYPE = 3;
@Test
public void fromString_matchMemberObject() {
final String preferredShortcutString = STUB_COMPONENT_NAME + ":" + STUB_TYPE;
final PreferredShortcut shortcut = PreferredShortcut.fromString(preferredShortcutString);
assertThat(shortcut.getComponentName()).isEqualTo(STUB_COMPONENT_NAME);
assertThat(shortcut.getType()).isEqualTo(STUB_TYPE);
}
@Test
public void toString_matchString() {
final PreferredShortcut shortcut = new PreferredShortcut(STUB_COMPONENT_NAME, STUB_TYPE);
final String preferredShortcutString = shortcut.toString();
assertThat(preferredShortcutString).isEqualTo(STUB_COMPONENT_NAME + ":" + STUB_TYPE);
}
@Test
public void assertSameObject() {
final String preferredShortcutString = STUB_COMPONENT_NAME + ":" + STUB_TYPE;
final PreferredShortcut targetShortcut = PreferredShortcut.fromString(
preferredShortcutString);
assertThat(targetShortcut).isEqualTo(new PreferredShortcut(STUB_COMPONENT_NAME, STUB_TYPE));
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2020 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.ComponentName;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Tests for {@link PreferredShortcuts} */
@RunWith(AndroidJUnit4.class)
public class PreferredShortcutsTest {
private static final String PACKAGE_NAME_1 = "com.test1.example";
private static final String CLASS_NAME_1 = PACKAGE_NAME_1 + ".test1";
private static final ComponentName COMPONENT_NAME_1 = new ComponentName(PACKAGE_NAME_1,
CLASS_NAME_1);
private static final String PACKAGE_NAME_2 = "com.test2.example";
private static final String CLASS_NAME_2 = PACKAGE_NAME_2 + ".test2";
private static final ComponentName COMPONENT_NAME_2 = new ComponentName(PACKAGE_NAME_2,
CLASS_NAME_2);
private Context mContext = ApplicationProvider.getApplicationContext();
@Test
public void retrieveUserShortcutType_fromSingleData_matchSavedType() {
final int type = 1;
final PreferredShortcut shortcut = new PreferredShortcut(COMPONENT_NAME_1.flattenToString(),
type);
PreferredShortcuts.saveUserShortcutType(mContext, shortcut);
final int retrieveType = PreferredShortcuts.retrieveUserShortcutType(mContext,
COMPONENT_NAME_1.flattenToString(), 0);
assertThat(retrieveType).isEqualTo(type);
}
@Test
public void retrieveUserShortcutType_fromMultiData_matchSavedType() {
final int type1 = 1;
final int type2 = 2;
final PreferredShortcut shortcut1 = new PreferredShortcut(
COMPONENT_NAME_1.flattenToString(), type1);
final PreferredShortcut shortcut2 = new PreferredShortcut(
COMPONENT_NAME_2.flattenToString(), type2);
PreferredShortcuts.saveUserShortcutType(mContext, shortcut1);
PreferredShortcuts.saveUserShortcutType(mContext, shortcut2);
final int retrieveType = PreferredShortcuts.retrieveUserShortcutType(mContext,
COMPONENT_NAME_1.flattenToString(), 0);
assertThat(retrieveType).isEqualTo(type1);
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2020 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.os.UserHandle;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class PrimaryMonoPreferenceControllerTest {
private static final int ON = 1;
private static final int OFF = 0;
private static final int UNKNOWN = -1;
private Context mContext;
private SwitchPreference mPreference;
private PrimaryMonoPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mPreference = new SwitchPreference(mContext);
mController = new PrimaryMonoPreferenceController(mContext, "test_key");
}
@Test
public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void isChecked_enabledMonoAudio_shouldReturnTrue() {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.MASTER_MONO, ON, UserHandle.USER_CURRENT);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void isChecked_disabledMonoAudio_shouldReturnFalse() {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.MASTER_MONO, OFF, UserHandle.USER_CURRENT);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void setChecked_setTrue_shouldEnableMonoAudio() {
mController.setChecked(true);
assertThat(Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.MASTER_MONO, UNKNOWN, UserHandle.USER_CURRENT)).isEqualTo(ON);
}
@Test
public void setChecked_setFalse_shouldDisableMonoAudio() {
mController.setChecked(false);
assertThat(Settings.System.getIntForUser(mContext.getContentResolver(),
Settings.System.MASTER_MONO, UNKNOWN, UserHandle.USER_CURRENT)).isEqualTo(OFF);
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2020 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.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class ReduceBrightColorsIntensityPreferenceControllerTest {
private Context mContext;
private Resources mResources;
private ReduceBrightColorsIntensityPreferenceController mPreferenceController;
@Before
public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext());
mResources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(mResources);
mPreferenceController = new ReduceBrightColorsIntensityPreferenceController(mContext,
"rbc_intensity");
}
@Test
public void isAvailable_configuredRbcAvailable_enabledRbc_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
doReturn(true).when(mResources).getBoolean(
R.bool.config_reduceBrightColorsAvailable);
assertThat(mPreferenceController.isAvailable()).isTrue();
}
@Test
public void isAvailable_configuredRbcAvailable_disabledRbc_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0);
doReturn(true).when(mResources).getBoolean(
R.bool.config_reduceBrightColorsAvailable);
assertThat(mPreferenceController.isAvailable()).isTrue();
}
@Test
public void isAvailable_configuredRbcUnavailable_enabledRbc_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
doReturn(false).when(mResources).getBoolean(
R.bool.config_reduceBrightColorsAvailable);
assertThat(mPreferenceController.isAvailable()).isFalse();
}
@Test
public void onPreferenceChange_changesTemperature() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
mPreferenceController.onPreferenceChange(/* preference= */ null, 20);
assertThat(
Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0))
.isEqualTo(80);
}
@Test
public void rangeOfSlider_staysWithinValidRange() {
when(mResources.getInteger(
R.integer.config_reduceBrightColorsStrengthMax)).thenReturn(90);
when(mResources.getInteger(
R.integer.config_reduceBrightColorsStrengthMin)).thenReturn(15);
assertThat(mPreferenceController.getMax()).isEqualTo(85);
assertThat(mPreferenceController.getMin()).isEqualTo(10);
assertThat(mPreferenceController.getMax() - mPreferenceController.getMin())
.isEqualTo(75);
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (C) 2020 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.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class ReduceBrightColorsPersistencePreferenceControllerTest {
private static final String PREF_KEY = "rbc_persist";
private static final String RBC_PERSIST =
Settings.Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS;
private static final int ON = 1;
private static final int OFF = 0;
private static final int UNKNOWN = -1;
private final Context mContext = ApplicationProvider.getApplicationContext();
private final SwitchPreference mPreference = new SwitchPreference(mContext);
private final ReduceBrightColorsPersistencePreferenceController mController =
new ReduceBrightColorsPersistencePreferenceController(mContext, PREF_KEY);
@Test
public void isChecked_enabledRbc_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(), RBC_PERSIST, ON);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void isChecked_disabledRbc_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(), RBC_PERSIST, OFF);
mController.updateState(mPreference);
assertThat(mController.isChecked()).isFalse();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void setChecked_setTrue_shouldEnableRbc() {
mController.setChecked(true);
assertThat(
Settings.Secure.getInt(mContext.getContentResolver(), RBC_PERSIST, UNKNOWN))
.isEqualTo(ON);
}
@Test
public void setChecked_setFalse_shouldDisableRbc() {
mController.setChecked(false);
assertThat(
Settings.Secure.getInt(mContext.getContentResolver(), RBC_PERSIST, UNKNOWN))
.isEqualTo(OFF);
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2021 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.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.R;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class ReduceBrightColorsPreferenceControllerTest {
private static final String PREF_KEY = "rbc_preference";
private Context mContext;
private Resources mResources;;
private ReduceBrightColorsPreferenceController mController;
@Before
public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext());
mResources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(mResources);
mController = new ReduceBrightColorsPreferenceController(mContext,
PREF_KEY);
}
@Test
public void getSummary_returnSummary() {
assertThat(mController.getSummary().toString().contains(
resourceString("reduce_bright_colors_preference_summary"))).isTrue();
}
@Ignore("ColorDisplayManager runs in a different thread which results in a race condition")
@Test
public void isChecked_reduceBrightColorsIsActivated_returnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
assertThat(mController.isChecked()).isTrue();
}
@Ignore("ColorDisplayManager runs in a different thread which results in a race condition")
@Test
public void isChecked_reduceBrightColorsIsNotActivated_returnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0);
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isAvailable_configuredRbcAvailable_shouldReturnTrue() {
doReturn(true).when(mResources).getBoolean(
R.bool.config_reduceBrightColorsAvailable);
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void isAvailable_configuredRbcUnAvailable_shouldReturnFalse() {
doReturn(false).when(mResources).getBoolean(
R.bool.config_reduceBrightColorsAvailable);
assertThat(mController.isAvailable()).isFalse();
}
private int resourceId(String type, String name) {
return mContext.getResources().getIdentifier(name, type, mContext.getPackageName());
}
private String resourceString(String name) {
return mContext.getResources().getString(resourceId("string", name));
}
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2020 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.provider.Settings;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class SelectLongPressTimeoutPreferenceControllerTest {
private static final int VALID_VALUE = 1500;
private static final int INVALID_VALUE = 0;
private static final int DEFAULT_VALUE = 400;
private Context mContext;
private SelectLongPressTimeoutPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new SelectLongPressTimeoutPreferenceController(mContext, "press_timeout");
}
@Test
public void getAvailabilityStatus_byDefault_shouldReturnAvailable() {
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void getSummary_byDefault_shouldReturnShort() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LONG_PRESS_TIMEOUT, DEFAULT_VALUE);
final String expected = "Short";
assertThat(mController.getSummary()).isEqualTo(expected);
}
@Test
public void getSummary_validValue_shouldReturnLong() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LONG_PRESS_TIMEOUT, VALID_VALUE);
final String expected = "Long";
assertThat(mController.getSummary()).isEqualTo(expected);
}
@Test
public void getSummary_invalidValue_shouldReturnNull() {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LONG_PRESS_TIMEOUT, INVALID_VALUE);
assertThat(mController.getSummary()).isNull();
}
}

View File

@@ -1,95 +0,0 @@
/*
* Copyright (C) 2017 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 androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import android.app.Instrumentation;
import android.os.Bundle;
import android.os.Looper;
import androidx.test.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.Settings.AccessibilitySettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.SubSettingLauncher;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class ToggleFeaturePreferenceFragmentTest {
private static final String SUMMARY_TEXT = "Here's some summary text";
@Rule
public final ActivityTestRule<AccessibilitySettingsActivity> mActivityRule =
new ActivityTestRule<>(AccessibilitySettingsActivity.class, true);
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
@BeforeClass
public static void oneTimeSetup() {
if (Looper.myLooper() == null) {
Looper.prepare();
}
}
@Before
public void setUp() {
mInstrumentation.runOnMainSync(() -> {
MyToggleFeaturePreferenceFragment fragment = new MyToggleFeaturePreferenceFragment();
Bundle args = new Bundle();
args.putString(AccessibilitySettings.EXTRA_SUMMARY, SUMMARY_TEXT);
fragment.setArguments(args);
new SubSettingLauncher(mActivityRule.getActivity())
.setDestination(MyToggleFeaturePreferenceFragment.class.getName())
.setArguments(args)
.setSourceMetricsCategory(
InstrumentedPreferenceFragment.METRICS_CATEGORY_UNKNOWN)
.launch();
});
}
@Test
public void testSummaryTestDisplayed() {
onView(withText(SUMMARY_TEXT)).check(matches(isDisplayed()));
}
public static class MyToggleFeaturePreferenceFragment extends ToggleFeaturePreferenceFragment {
@Override
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
}
@Override
public int getMetricsCategory() {
return 0;
}
@Override
int getUserShortcutTypes() {
return 0;
}
}
}

View File

@@ -1,91 +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.accounts;
import static com.google.common.truth.Truth.assertThat;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class AccountsSettingsTest {
private static final String ACCOUNTS = "Accounts";
private static final String ACCOUNT_TYPE = "com.settingstest.account-prefs";
private static final String PREF_TITLE = "Test preference for external account";
private UiDevice mDevice;
private Context mContext;
private String mTargetPackage;
@Before
public void setUp() {
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mContext.getPackageName();
}
@Test
public void testExternalAccountInfoExists() throws UiObjectNotFoundException {
// add a test account
final String testAccountName = "Test Account";
final Account account = new Account(testAccountName, ACCOUNT_TYPE);
final AccountManager accountManager = AccountManager.get(mContext);
final boolean accountAdded =
accountManager.addAccountExplicitly(account, null /* password */, null /* userdata */);
assertThat(accountAdded).isTrue();
// launch Accounts Settings and select the test account
launchAccountsSettings();
mDevice.findObject(new UiSelector().text(testAccountName)).click();
final UiObject testPreference = mDevice.findObject(new UiSelector().text(PREF_TITLE));
// remove test account
accountManager.removeAccountExplicitly(account);
assertThat(testPreference.exists()).isTrue();
}
private void launchAccountsSettings() throws UiObjectNotFoundException {
// launch settings
Intent settingsIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setPackage(mTargetPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(settingsIntent);
// selects Accounts
final UiScrollable settings = new UiScrollable(
new UiSelector().packageName(mTargetPackage).scrollable(true));
final String titleAccounts = ACCOUNTS;
settings.scrollTextIntoView(titleAccounts);
mDevice.findObject(new UiSelector().text(titleAccounts)).click();
}
}

View File

@@ -1,74 +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.accounts;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.os.Bundle;
public class Authenticator extends AbstractAccountAuthenticator {
public Authenticator(Context context) {
super(context);
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse r, String s) {
return null;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse r, String s, String s2, String[] strings,
Bundle bundle) throws NetworkErrorException {
final Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, "Test Account");
result.putString(AccountManager.KEY_ACCOUNT_TYPE, s);
return result;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse r, Account account, Bundle bundle)
throws NetworkErrorException {
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse r, Account account, String s,
Bundle bundle) throws NetworkErrorException {
return null;
}
@Override
public String getAuthTokenLabel(String s) {
return s;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse r, Account account, String s,
Bundle bundle) throws NetworkErrorException {
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse r, Account account, String[] strings)
throws NetworkErrorException {
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 The Android Open Source Project
* Copyright (C) 2020 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.
@@ -14,23 +14,24 @@
* limitations under the License.
*/
package com.android.settings.applications;
package com.android.settings.accounts;
import android.app.AppOpsManager;
import android.provider.Settings;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Modifier;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DrawOverlaySettingsTest extends AppOpsSettingsTest {
public class RemoveUserFragmentTest {
public DrawOverlaySettingsTest() {
super(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, AppOpsManager.OP_SYSTEM_ALERT_WINDOW);
@Test
public void testClassModifier_shouldBePublic() {
final int modifiers = RemoveUserFragment.class.getModifiers();
assertThat(Modifier.isPublic(modifiers)).isTrue();
}
// Test cases are in the superclass.
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2020 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.accounts;
import static com.google.common.truth.Truth.assertThat;
import android.accounts.Account;
import android.content.Context;
import android.os.UserHandle;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class SyncStateSwitchPreferenceTest {
private Context mContext;
private SyncStateSwitchPreference mPreference;
@Before
public void setup() {
mContext = ApplicationProvider.getApplicationContext();
}
@Test
public void setup_validAuthority_shouldBeVisible() {
mPreference = new SyncStateSwitchPreference(mContext, null /* attrs */);
mPreference.setup(new Account("name", "type"), "authority", mContext.getPackageName(),
UserHandle.USER_CURRENT);
assertThat(mPreference.isVisible()).isTrue();
}
@Test
public void setup_emptyAuthority_shouldBeInvisible() {
mPreference = new SyncStateSwitchPreference(mContext, null /* attrs */);
mPreference.setup(new Account("name", "type"), null /* authority */,
mContext.getPackageName(), UserHandle.USER_CURRENT);
assertThat(mPreference.isVisible()).isFalse();
}
}

View File

@@ -1,211 +0,0 @@
/*
* Copyright (C) 2017 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.applications;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_ERRORED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.widget.Switch;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.InstrumentationRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/**
* An abstract parent for testing settings activities that manage an AppOps permission.
*/
abstract public class AppOpsSettingsTest {
private static final String WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard";
private static final long START_ACTIVITY_TIMEOUT = 5000;
private Context mContext;
private UiDevice mUiDevice;
private PackageManager mPackageManager;
private AppOpsManager mAppOpsManager;
private List<UserInfo> mProfiles;
private String mPackageName;
// These depend on which app op's settings UI is being tested.
private final String mActivityAction;
private final int mAppOpCode;
protected AppOpsSettingsTest(String activityAction, int appOpCode) {
mActivityAction = activityAction;
mAppOpCode = appOpCode;
}
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mPackageName = InstrumentationRegistry.getContext().getPackageName();
mPackageManager = mContext.getPackageManager();
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mProfiles = mContext.getSystemService(UserManager.class).getProfiles(UserHandle.myUserId());
resetAppOpModeForAllProfiles();
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mUiDevice.wakeUp();
mUiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND);
}
private void resetAppOpModeForAllProfiles() throws Exception {
for (UserInfo user : mProfiles) {
final int uid = mPackageManager.getPackageUidAsUser(mPackageName, user.id);
mAppOpsManager.setMode(mAppOpCode, uid, mPackageName, MODE_DEFAULT);
}
}
/**
* Creates an intent for showing the permission settings for all apps.
*/
private Intent createManageAllAppsIntent() {
final Intent intent = new Intent(mActivityAction);
intent.addFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
return intent;
}
/**
* Creates an intent for showing the permission setting for a single app.
*/
private Intent createManageSingleAppIntent(String packageName) {
final Intent intent = createManageAllAppsIntent();
intent.setData(Uri.parse("package:" + packageName));
return intent;
}
private String getApplicationLabel(String packageName) throws Exception {
final ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
return mPackageManager.getApplicationLabel(info).toString();
}
private UiObject2 findAndVerifySwitchState(boolean checked) {
final BySelector switchSelector = By.clazz(Switch.class).res("android:id/switch_widget");
final UiObject2 switchPref = mUiDevice.wait(Until.findObject(switchSelector),
START_ACTIVITY_TIMEOUT);
assertNotNull("Switch not shown", switchPref);
assertTrue("Switch in invalid state", switchPref.isChecked() == checked);
return switchPref;
}
@Test
public void testAppList() throws Exception {
final String testAppLabel = getApplicationLabel(mPackageName);
mContext.startActivity(createManageAllAppsIntent());
final BySelector preferenceListSelector =
By.clazz(RecyclerView.class).res("com.android.settings:id/apps_list");
final UiObject2 preferenceList = mUiDevice.wait(Until.findObject(preferenceListSelector),
START_ACTIVITY_TIMEOUT);
assertNotNull("App list not shown", preferenceList);
final BySelector appLabelTextViewSelector = By.clazz(TextView.class)
.res("android:id/title")
.text(testAppLabel);
List<UiObject2> listOfMatchingTextViews;
do {
listOfMatchingTextViews = preferenceList.findObjects(appLabelTextViewSelector);
// assuming the number of profiles will be sufficiently small so that all the entries
// for the same package will fit in one screen at some time during the scroll.
} while (listOfMatchingTextViews.size() != mProfiles.size() &&
preferenceList.scroll(Direction.DOWN, 0.2f));
assertEquals("Test app not listed for each profile", mProfiles.size(),
listOfMatchingTextViews.size());
for (UiObject2 matchingObject : listOfMatchingTextViews) {
matchingObject.click();
findAndVerifySwitchState(true);
mUiDevice.pressBack();
}
}
private void testAppDetailScreenForAppOp(int appOpMode, int userId) throws Exception {
final String testAppLabel = getApplicationLabel(mPackageName);
final BySelector appDetailTitleSelector = By.clazz(TextView.class)
.res("com.android.settings:id/app_detail_title")
.text(testAppLabel);
mAppOpsManager.setMode(mAppOpCode,
mPackageManager.getPackageUidAsUser(mPackageName, userId), mPackageName, appOpMode);
mContext.startActivityAsUser(createManageSingleAppIntent(mPackageName),
UserHandle.of(userId));
mUiDevice.wait(Until.findObject(appDetailTitleSelector), START_ACTIVITY_TIMEOUT);
findAndVerifySwitchState(appOpMode == MODE_ALLOWED || appOpMode == MODE_DEFAULT);
mUiDevice.pressBack();
}
@Test
public void testSingleApp() throws Exception {
// App op MODE_DEFAULT is already tested in #testAppList
for (UserInfo user : mProfiles) {
testAppDetailScreenForAppOp(MODE_ALLOWED, user.id);
testAppDetailScreenForAppOp(MODE_ERRORED, user.id);
}
}
private void testSwitchToggle(int fromAppOp, int toAppOp) throws Exception {
final int packageUid = mPackageManager.getPackageUid(mPackageName, 0);
final boolean initialState = (fromAppOp == MODE_ALLOWED || fromAppOp == MODE_DEFAULT);
mAppOpsManager.setMode(mAppOpCode, packageUid, mPackageName, fromAppOp);
mContext.startActivity(createManageSingleAppIntent(mPackageName));
final UiObject2 switchPref = findAndVerifySwitchState(initialState);
switchPref.click();
Thread.sleep(1000);
assertEquals("Toggling switch did not change app op", toAppOp,
mAppOpsManager.checkOpNoThrow(mAppOpCode, packageUid,
mPackageName));
mUiDevice.pressBack();
}
@Test
public void testIfSwitchTogglesAppOp() throws Exception {
testSwitchToggle(MODE_ALLOWED, MODE_ERRORED);
testSwitchToggle(MODE_ERRORED, MODE_ALLOWED);
}
@After
public void tearDown() throws Exception {
mUiDevice.pressHome();
resetAppOpModeForAllProfiles();
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2021 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.applications;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import android.app.AlarmManager;
import android.content.Context;
import android.os.UserHandle;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class AppStateAlarmsAndRemindersBridgeTest {
private static final String TEST_PACKAGE_1 = "com.example.test.1";
private static final String TEST_PACKAGE_2 = "com.example.test.2";
private static final int UID_1 = 12345;
private static final int UID_2 = 7654321;
@Mock
private AlarmManager mAlarmManager;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@Test
public void shouldBeVisible_permissionRequestedIsTrue_isTrue() {
assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState(
true /* permissionRequested */,
true /* permissionGranted */)
.shouldBeVisible()).isTrue();
assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState(
true /* permissionRequested */,
false /* permissionGranted */)
.shouldBeVisible()).isTrue();
assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState(
false /* permissionRequested */,
true /* permissionGranted */)
.shouldBeVisible()).isFalse();
assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState(
false /* permissionRequested */,
false /* permissionGranted */)
.shouldBeVisible()).isFalse();
}
@Test
public void isAllowed_permissionGrantedIsTrue_isTrue() {
assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState(
true /* permissionRequested */,
true /* permissionGranted */)
.isAllowed()).isTrue();
assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState(
true /* permissionRequested */,
false /* permissionGranted */)
.isAllowed()).isFalse();
assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState(
false /* permissionRequested */,
true /* permissionGranted */)
.isAllowed()).isTrue();
assertThat(new AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState(
false /* permissionRequested */,
false /* permissionGranted */)
.isAllowed()).isFalse();
}
@Test
public void createPermissionState() {
AppStateAlarmsAndRemindersBridge bridge = new AppStateAlarmsAndRemindersBridge(mContext,
null, null);
bridge.mAlarmManager = mAlarmManager;
bridge.mRequesterPackages = new String[]{TEST_PACKAGE_1, "some.other.package"};
doReturn(false).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE_1,
UserHandle.getUserId(UID_1));
doReturn(true).when(mAlarmManager).hasScheduleExactAlarm(TEST_PACKAGE_2,
UserHandle.getUserId(UID_2));
AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state1 =
bridge.createPermissionState(TEST_PACKAGE_1, UID_1);
assertThat(state1.shouldBeVisible()).isTrue();
assertThat(state1.isAllowed()).isFalse();
AppStateAlarmsAndRemindersBridge.AlarmsAndRemindersState state2 =
bridge.createPermissionState(TEST_PACKAGE_2, UID_2);
assertThat(state2.shouldBeVisible()).isFalse();
assertThat(state2.isAllowed()).isTrue();
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2020 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.applications;
import static com.google.common.truth.Truth.assertThat;
import android.app.AppOpsManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class AppStateInstallAppsBridgeTest {
@Test
public void testInstallAppsStateCanInstallApps() {
AppStateInstallAppsBridge.InstallAppsState appState =
new AppStateInstallAppsBridge.InstallAppsState();
assertThat(appState.canInstallApps()).isFalse();
appState.permissionRequested = true;
assertThat(appState.canInstallApps()).isFalse();
appState.appOpMode = AppOpsManager.MODE_ALLOWED;
assertThat(appState.canInstallApps()).isTrue();
appState.appOpMode = AppOpsManager.MODE_ERRORED;
assertThat(appState.canInstallApps()).isFalse();
}
@Test
public void testInstallAppsStateIsPotentialAppSource() {
AppStateInstallAppsBridge.InstallAppsState appState =
new AppStateInstallAppsBridge.InstallAppsState();
assertThat(appState.isPotentialAppSource()).isFalse();
appState.appOpMode = AppOpsManager.MODE_ERRORED;
assertThat(appState.isPotentialAppSource()).isTrue();
appState.permissionRequested = true;
appState.appOpMode = AppOpsManager.MODE_DEFAULT;
assertThat(appState.isPotentialAppSource()).isTrue();
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2020 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.applications;
import static org.junit.Assert.assertTrue;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.R;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class EnterpriseDefaultAppsTest {
@Test
public void testNumberOfIntentsCorrelateWithUI() {
final int[] concatenation_templates =
new int[]{0 /* no need for single app name */,
R.string.app_names_concatenation_template_2,
R.string.app_names_concatenation_template_3};
for (EnterpriseDefaultApps app : EnterpriseDefaultApps.values()) {
assertTrue("Number of intents should be limited by number of apps the UI can show",
app.getIntents().length <= concatenation_templates.length);
}
}
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright (C) 2021 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.applications;
import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
import static com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.apphibernation.AppHibernationManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.os.Looper;
import android.os.RemoteException;
import android.provider.DeviceConfig;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
public class HibernatedAppsPreferenceControllerTest {
public static final String HIBERNATED_PACKAGE_NAME = "hibernated_package";
public static final String AUTO_REVOKED_PACKAGE_NAME = "auto_revoked_package";
public static final String PERMISSION = "permission";
@Mock
PackageManager mPackageManager;
@Mock
AppHibernationManager mAppHibernationManager;
@Mock
IUsageStatsManager mIUsageStatsManager;
PreferenceScreen mPreferenceScreen;
private static final String KEY = "key";
private Context mContext;
private HibernatedAppsPreferenceController mController;
@Before
public void setUp() {
if (Looper.myLooper() == null) {
Looper.prepare();
}
MockitoAnnotations.initMocks(this);
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
"true", false);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(AppHibernationManager.class))
.thenReturn(mAppHibernationManager);
when(mContext.getSystemService(UsageStatsManager.class)).thenReturn(
new UsageStatsManager(mContext, mIUsageStatsManager));
PreferenceManager manager = new PreferenceManager(mContext);
mPreferenceScreen = manager.createPreferenceScreen(mContext);
Preference preference = mock(Preference.class);
when(preference.getKey()).thenReturn(KEY);
mPreferenceScreen.addPreference(preference);
mController = new HibernatedAppsPreferenceController(mContext, KEY,
command -> command.run(), command -> command.run());
}
@Test
public void getAvailabilityStatus_featureDisabled_shouldNotReturnAvailable() {
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
"false", true);
assertThat((mController).getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
}
@Test
public void getSummary_getsRightCountForHibernatedPackage() {
final PackageInfo hibernatedPkg = getHibernatedPackage();
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(
Arrays.asList(hibernatedPkg, new PackageInfo()));
when(mContext.getResources()).thenReturn(mock(Resources.class));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mContext.getResources()).getQuantityString(anyInt(), eq(1), eq(1));
}
@Test
public void getSummary_getsRightCountForUnusedAutoRevokedPackage() {
final PackageInfo autoRevokedPkg = getAutoRevokedPackage();
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(
Arrays.asList(autoRevokedPkg, new PackageInfo()));
when(mContext.getResources()).thenReturn(mock(Resources.class));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mContext.getResources()).getQuantityString(anyInt(), eq(1), eq(1));
}
@Test
public void getSummary_getsRightCountForUsedAutoRevokedPackage() {
final PackageInfo usedAutoRevokedPkg = getAutoRevokedPackage();
setAutoRevokedPackageUsageStats();
when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(
Arrays.asList(usedAutoRevokedPkg, new PackageInfo()));
when(mContext.getResources()).thenReturn(mock(Resources.class));
mController.displayPreference(mPreferenceScreen);
mController.onResume();
verify(mContext.getResources()).getQuantityString(anyInt(), eq(0), eq(0));
}
private PackageInfo getHibernatedPackage() {
final PackageInfo pi = new PackageInfo();
pi.packageName = HIBERNATED_PACKAGE_NAME;
pi.requestedPermissions = new String[] {PERMISSION};
when(mAppHibernationManager.getHibernatingPackagesForUser())
.thenReturn(Arrays.asList(pi.packageName));
when(mPackageManager.getPermissionFlags(
pi.requestedPermissions[0], pi.packageName, mContext.getUser()))
.thenReturn(PackageManager.FLAG_PERMISSION_AUTO_REVOKED);
return pi;
}
private PackageInfo getAutoRevokedPackage() {
final PackageInfo pi = new PackageInfo();
pi.packageName = AUTO_REVOKED_PACKAGE_NAME;
pi.requestedPermissions = new String[] {PERMISSION};
when(mPackageManager.getPermissionFlags(
pi.requestedPermissions[0], pi.packageName, mContext.getUser()))
.thenReturn(PackageManager.FLAG_PERMISSION_AUTO_REVOKED);
return pi;
}
private void setAutoRevokedPackageUsageStats() {
final UsageStats us = new UsageStats();
us.mPackageName = AUTO_REVOKED_PACKAGE_NAME;
us.mLastTimeVisible = System.currentTimeMillis();
try {
when(mIUsageStatsManager.queryUsageStats(
anyInt(), anyLong(), anyLong(), anyString(), anyInt()))
.thenReturn(new ParceledListSlice(Arrays.asList(us)));
} catch (RemoteException e) {
// no-op
}
}
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2021 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.applications.appinfo;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED;
import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION;
import static com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED;
import static com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.provider.DeviceConfig;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class HibernationSwitchPreferenceControllerTest {
private static final int PACKAGE_UID = 1;
private static final String INVALID_PACKAGE_NAME = "invalid_package";
private static final String KEY = "key";
private static final String VALID_PACKAGE_NAME = "package";
private static final String EXEMPTED_PACKAGE_NAME = "exempted_package";
private static final String UNEXEMPTED_PACKAGE_NAME = "unexempted_package";
@Mock
private AppOpsManager mAppOpsManager;
@Mock
private PackageManager mPackageManager;
@Mock
private SwitchPreference mPreference;
private HibernationSwitchPreferenceController mController;
private Context mContext;
@Before
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
when(mPackageManager.getPackageUid(eq(VALID_PACKAGE_NAME), anyInt()))
.thenReturn(PACKAGE_UID);
when(mPackageManager.getPackageUid(eq(INVALID_PACKAGE_NAME), anyInt()))
.thenThrow(new PackageManager.NameNotFoundException());
when(mPackageManager.getTargetSdkVersion(eq(EXEMPTED_PACKAGE_NAME)))
.thenReturn(android.os.Build.VERSION_CODES.Q);
when(mPackageManager.getTargetSdkVersion(eq(UNEXEMPTED_PACKAGE_NAME)))
.thenReturn(android.os.Build.VERSION_CODES.S);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
"true", true /* makeDefault */);
mController = new HibernationSwitchPreferenceController(mContext, KEY);
when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
}
@Test
public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable() {
mController.setPackage(VALID_PACKAGE_NAME);
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_APP_HIBERNATION_ENABLED,
"false", true /* makeDefault */);
assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_invalidPackage_shouldReturnNotAvailable() {
mController.setPackage(INVALID_PACKAGE_NAME);
assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_validPackage_shouldReturnAvailable() {
mController.setPackage(VALID_PACKAGE_NAME);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void updateState_exemptedByDefaultPackage_shouldNotCheck() {
when(mAppOpsManager.unsafeCheckOpNoThrow(
eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(EXEMPTED_PACKAGE_NAME)))
.thenReturn(MODE_DEFAULT);
mController.setPackage(EXEMPTED_PACKAGE_NAME);
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
}
@Test
public void updateState_exemptedPackageOverrideByUser_shouldCheck() {
when(mAppOpsManager.unsafeCheckOpNoThrow(
eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(EXEMPTED_PACKAGE_NAME)))
.thenReturn(MODE_ALLOWED);
mController.setPackage(EXEMPTED_PACKAGE_NAME);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
@Test
public void updateState_unexemptedPackageOverrideByUser_shouldNotCheck() {
when(mAppOpsManager.unsafeCheckOpNoThrow(
eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(UNEXEMPTED_PACKAGE_NAME)))
.thenReturn(MODE_IGNORED);
mController.setPackage(UNEXEMPTED_PACKAGE_NAME);
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
}
@Test
public void updateState_exemptedByDefaultPackageOverriddenByPreSFlag_shouldCheck() {
DeviceConfig.setProperty(NAMESPACE_APP_HIBERNATION, PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS,
"true", true /* makeDefault */);
when(mAppOpsManager.unsafeCheckOpNoThrow(
eq(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED), anyInt(), eq(EXEMPTED_PACKAGE_NAME)))
.thenReturn(MODE_DEFAULT);
mController.setPackage(EXEMPTED_PACKAGE_NAME);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 The Android Open Source Project
* Copyright (C) 2020 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.
@@ -14,24 +14,32 @@
* limitations under the License.
*/
package com.android.settings.applications;
package com.android.settings.applications.assist;
import android.app.AppOpsManager;
import android.provider.Settings;
import android.net.Uri;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ExternalSourcesSettingsTest extends AppOpsSettingsTest {
public class AssistSettingObserverTest {
public ExternalSourcesSettingsTest() {
super(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
AppOpsManager.OP_REQUEST_INSTALL_PACKAGES);
@Test
public void callConstructor_shouldNotCrash() {
new AssistSettingObserver() {
@Override
protected List<Uri> getSettingUris() {
return null;
}
@Override
public void onSettingChange() {
}
};
}
// Test cases are in the superclass.
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (C) 2021 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.applications.autofill;
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.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
import android.os.UserHandle;
import android.service.autofill.AutofillServiceInfo;
import androidx.lifecycle.Lifecycle;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.util.Collections;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class PasswordsPreferenceControllerTest {
private Context mContext;
private PreferenceScreen mScreen;
private PreferenceCategory mPasswordsPreferenceCategory;
@Before
public void setUp() {
mContext = spy(ApplicationProvider.getApplicationContext());
if (Looper.myLooper() == null) {
Looper.prepare(); // needed to create the preference screen
}
mScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
mPasswordsPreferenceCategory = new PreferenceCategory(mContext);
mPasswordsPreferenceCategory.setKey("passwords");
mScreen.addPreference(mPasswordsPreferenceCategory);
}
@Test
// Tests that getAvailabilityStatus() does not throw an exception if it's called before the
// Controller is initialized (this can happen during indexing).
public void getAvailabilityStatus_withoutInit_returnsUnavailable() {
PasswordsPreferenceController controller =
new PasswordsPreferenceController(mContext, mPasswordsPreferenceCategory.getKey());
assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_noServices_returnsUnavailable() {
PasswordsPreferenceController controller =
createControllerWithServices(Collections.emptyList());
assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_noPasswords_returnsUnavailable() {
AutofillServiceInfo service = new AutofillServiceInfo.TestDataBuilder().build();
PasswordsPreferenceController controller =
createControllerWithServices(Lists.newArrayList(service));
assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_withPasswords_returnsAvailable() {
PasswordsPreferenceController controller =
createControllerWithServices(Lists.newArrayList(createServiceWithPasswords()));
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void displayPreference_noServices_noPreferencesAdded() {
PasswordsPreferenceController controller =
createControllerWithServices(Collections.emptyList());
controller.displayPreference(mScreen);
assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(0);
}
@Test
public void displayPreference_noPasswords_noPreferencesAdded() {
AutofillServiceInfo service = new AutofillServiceInfo.TestDataBuilder().build();
PasswordsPreferenceController controller =
createControllerWithServices(Lists.newArrayList(service));
controller.displayPreference(mScreen);
assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(0);
}
@Test
@UiThreadTest
public void displayPreference_withPasswords_addsPreference() {
AutofillServiceInfo service = createServiceWithPasswords();
service.getServiceInfo().packageName = "";
service.getServiceInfo().name = "";
PasswordsPreferenceController controller =
createControllerWithServices(Lists.newArrayList(service));
doReturn(false).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any());
controller.displayPreference(mScreen);
assertThat(mPasswordsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
Preference pref = mPasswordsPreferenceCategory.getPreference(0);
assertThat(pref.getIcon()).isNotNull();
pref.performClick();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
UserHandle user = mContext.getUser();
verify(mContext).startActivityAsUser(intentCaptor.capture(), eq(user));
assertThat(intentCaptor.getValue().getComponent())
.isEqualTo(
new ComponentName(
service.getServiceInfo().packageName,
service.getPasswordsActivity()));
}
private PasswordsPreferenceController createControllerWithServices(
List<AutofillServiceInfo> availableServices) {
PasswordsPreferenceController controller =
new PasswordsPreferenceController(mContext, mPasswordsPreferenceCategory.getKey());
controller.init(() -> mock(Lifecycle.class), availableServices);
return controller;
}
private AutofillServiceInfo createServiceWithPasswords() {
return new AutofillServiceInfo.TestDataBuilder()
.setPasswordsActivity("com.android.test.Passwords")
.build();
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2020 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.applications.manageapplications;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_ALARMS_AND_REMINDERS;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_INSTALL_SOURCES;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_MEDIA_MANAGEMENT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_ALLOWLIST;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_RECENT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_USAGE_ACCESS;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WITH_OVERLAY;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WRITE_SETTINGS;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MANAGE_SOURCES;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MEDIA_MANAGEMENT_APPS;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_OVERLAY;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_STORAGE;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_USAGE_ACCESS;
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_WRITE_SETTINGS;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class AppFilterRegistryTest {
@Test
public void getDefaultType_shouldMatchForAllListType() {
final AppFilterRegistry registry = AppFilterRegistry.getInstance();
assertThat(registry.getDefaultFilterType(LIST_TYPE_USAGE_ACCESS))
.isEqualTo(FILTER_APPS_USAGE_ACCESS);
assertThat(registry.getDefaultFilterType(LIST_TYPE_HIGH_POWER))
.isEqualTo(FILTER_APPS_POWER_ALLOWLIST);
assertThat(registry.getDefaultFilterType(LIST_TYPE_OVERLAY))
.isEqualTo(FILTER_APPS_WITH_OVERLAY);
assertThat(registry.getDefaultFilterType(LIST_TYPE_WRITE_SETTINGS))
.isEqualTo(FILTER_APPS_WRITE_SETTINGS);
assertThat(registry.getDefaultFilterType(LIST_TYPE_MANAGE_SOURCES))
.isEqualTo(FILTER_APPS_INSTALL_SOURCES);
assertThat(registry.getDefaultFilterType(LIST_TYPE_ALARMS_AND_REMINDERS))
.isEqualTo(FILTER_ALARMS_AND_REMINDERS);
assertThat(registry.getDefaultFilterType(LIST_TYPE_MEDIA_MANAGEMENT_APPS))
.isEqualTo(FILTER_APPS_MEDIA_MANAGEMENT);
assertThat(registry.getDefaultFilterType(LIST_TYPE_MAIN)).isEqualTo(FILTER_APPS_ALL);
assertThat(registry.getDefaultFilterType(LIST_TYPE_NOTIFICATION))
.isEqualTo(FILTER_APPS_RECENT);
assertThat(registry.getDefaultFilterType(LIST_TYPE_STORAGE)).isEqualTo(FILTER_APPS_ALL);
assertThat(registry.getDefaultFilterType(LIST_TYPE_GAMES)).isEqualTo(FILTER_APPS_ALL);
}
}

View File

@@ -1,138 +0,0 @@
/*
* Copyright (C) 2017 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.applications.manageapplications;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import android.content.pm.ApplicationInfo;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Field;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ManageApplicationsUnitTest {
@Test
public void getCompositeFilter_filtersVolumeForAudio() {
AppFilter filter =
ManageApplications.getCompositeFilter(
ManageApplications.LIST_TYPE_STORAGE,
ManageApplications.STORAGE_TYPE_MUSIC,
"uuid");
final ApplicationInfo info = new ApplicationInfo();
info.volumeUuid = "uuid";
info.category = ApplicationInfo.CATEGORY_AUDIO;
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
appEntry.info = info;
assertThat(filter.filterApp(appEntry)).isTrue();
}
@Test
public void getCompositeFilter_filtersVolumeForVideo() {
AppFilter filter =
ManageApplications.getCompositeFilter(
ManageApplications.LIST_TYPE_MOVIES,
ManageApplications.STORAGE_TYPE_DEFAULT,
"uuid");
final ApplicationInfo info = new ApplicationInfo();
info.volumeUuid = "uuid";
info.category = ApplicationInfo.CATEGORY_VIDEO;
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
appEntry.info = info;
assertThat(filter.filterApp(appEntry)).isTrue();
}
@Test
public void getCompositeFilter_filtersVolumeForGames() {
ApplicationsState.AppFilter filter =
ManageApplications.getCompositeFilter(
ManageApplications.LIST_TYPE_GAMES,
ManageApplications.STORAGE_TYPE_DEFAULT,
"uuid");
final ApplicationInfo info = new ApplicationInfo();
info.volumeUuid = "uuid";
info.category = ApplicationInfo.CATEGORY_GAME;
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
appEntry.info = info;
assertThat(filter.filterApp(appEntry)).isTrue();
}
@Test
public void getCompositeFilter_isEmptyNormally() {
ApplicationsState.AppFilter filter =
ManageApplications.getCompositeFilter(
ManageApplications.LIST_TYPE_MAIN,
ManageApplications.STORAGE_TYPE_DEFAULT,
"uuid");
assertThat(filter).isNull();
}
@Test
public void getCompositeFilter_worksWithInstantApps() throws Exception {
Field field = AppUtils.class.getDeclaredField("sInstantAppDataProvider");
field.setAccessible(true);
field.set(AppUtils.class, (InstantAppDataProvider) (i -> true));
AppFilter filter =
ManageApplications.getCompositeFilter(
ManageApplications.LIST_TYPE_STORAGE,
ManageApplications.STORAGE_TYPE_MUSIC,
"uuid");
AppFilter composedFilter = new CompoundFilter(ApplicationsState.FILTER_INSTANT, filter);
final ApplicationInfo info = new ApplicationInfo();
info.volumeUuid = "uuid";
info.category = ApplicationInfo.CATEGORY_AUDIO;
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
appEntry.info = info;
assertThat(composedFilter.filterApp(appEntry)).isTrue();
}
@Test
public void getCompositeFilter_worksForLegacyPrivateSettings() throws Exception {
ApplicationsState.AppFilter filter =
ManageApplications.getCompositeFilter(
ManageApplications.LIST_TYPE_STORAGE,
ManageApplications.STORAGE_TYPE_LEGACY,
"uuid");
final ApplicationInfo info = new ApplicationInfo();
info.volumeUuid = "uuid";
info.category = ApplicationInfo.CATEGORY_GAME;
final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
appEntry.info = info;
assertThat(filter.filterApp(appEntry)).isTrue();
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2021 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.applications.specialaccess.notificationaccess;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ServiceInfo;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class AlertingTypeFilterPreferenceControllerTest {
private Context mContext;
private AlertingTypeFilterPreferenceController mController;
@Mock
NotificationBackend mNm;
ComponentName mCn = new ComponentName("a", "b");
ServiceInfo mSi = new ServiceInfo();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new AlertingTypeFilterPreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setServiceInfo(mSi);
mController.setUserId(0);
}
@Test
public void getType() {
assertThat(mController.getType()).isEqualTo(FLAG_FILTER_TYPE_ALERTING);
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2020 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.applications.specialaccess.notificationaccess;
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;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class ApprovalPreferenceControllerTest {
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
@Mock
private NotificationAccessDetails mFragment;
private ApprovalPreferenceController mController;
@Mock
NotificationManager mNm;
@Mock
PackageManager mPm;
PackageInfo mPkgInfo;
ComponentName mCn = new ComponentName("a", "b");
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFeatureFactory = FakeFeatureFactory.setupForTest();
mContext = spy(ApplicationProvider.getApplicationContext());
doReturn(mContext).when(mFragment).getContext();
mPkgInfo = new PackageInfo();
mPkgInfo.applicationInfo = mock(ApplicationInfo.class);
when(mPkgInfo.applicationInfo.loadLabel(mPm)).thenReturn("LABEL");
mController = new ApprovalPreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setParent(mFragment);
mController.setPkgInfo(mPkgInfo);
}
@Test
public void updateState_checked() {
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
SwitchPreference pref = new SwitchPreference(mContext);
mController.updateState(pref);
assertThat(pref.isChecked()).isTrue();
}
@Test
public void enable() {
mController.enable(mCn);
verify(mFeatureFactory.metricsFeatureProvider).action(
mContext,
MetricsProto.MetricsEvent.APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW,
"a");
verify(mNm).setNotificationListenerAccessGranted(mCn, true);
}
@Test
public void disable() {
mController.disable(mCn);
verify(mFeatureFactory.metricsFeatureProvider).action(
mContext,
MetricsProto.MetricsEvent.APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW,
"a");
verify(mNm).setNotificationListenerAccessGranted(mCn, false);
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2021 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.applications.specialaccess.notificationaccess;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.os.Build;
import android.service.notification.NotificationListenerFilter;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class BridgedAppsLinkPreferenceControllerTest {
private Context mContext;
private BridgedAppsLinkPreferenceController mController;
@Mock
NotificationBackend mNm;
ComponentName mCn = new ComponentName("a", "b");
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new BridgedAppsLinkPreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setUserId(0);
}
@Test
public void testAvailable_notGranted() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(false);
mController.setTargetSdk(Build.VERSION_CODES.CUR_DEVELOPMENT + 1);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void testAvailable_lowTargetSdk_noCustomizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.S);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void testAvailable_lowTargetSdk_customizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.S);
NotificationListenerFilter nlf = new NotificationListenerFilter();
nlf.setTypes(FLAG_FILTER_TYPE_CONVERSATIONS);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void testAvailable_highTargetSdk_noCustomizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.CUR_DEVELOPMENT + 1);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
}

View File

@@ -0,0 +1,221 @@
/*
* Copyright (C) 2021 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.applications.specialaccess.notificationaccess;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.VersionedPackage;
import android.graphics.drawable.Drawable;
import android.os.Looper;
import android.service.notification.NotificationListenerFilter;
import android.util.ArraySet;
import androidx.preference.CheckBoxPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
import com.android.settingslib.applications.ApplicationsState;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@RunWith(AndroidJUnit4.class)
public class BridgedAppsPreferenceControllerTest {
private Context mContext;
private BridgedAppsPreferenceController mController;
@Mock
NotificationBackend mNm;
ComponentName mCn = new ComponentName("a", "b");
PreferenceScreen mScreen;
@Mock
ApplicationsState mAppState;
private ApplicationsState.AppEntry mAppEntry;
private ApplicationsState.AppEntry mAppEntry2;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
if (Looper.myLooper() == null) {
Looper.prepare();
}
PreferenceManager preferenceManager = new PreferenceManager(mContext);
mScreen = preferenceManager.createPreferenceScreen(mContext);
ApplicationInfo ai = new ApplicationInfo();
ai.packageName = "pkg";
ai.uid = 12300;
ai.sourceDir = "";
ApplicationInfo ai2 = new ApplicationInfo();
ai2.packageName = "another";
ai2.uid = 18800;
ai2.sourceDir = "";
mAppEntry = new ApplicationsState.AppEntry(mContext, ai, 0);
mAppEntry2 = new ApplicationsState.AppEntry(mContext, ai2, 1);
mAppEntry.info = ai;
mAppEntry.label = "hi";
Drawable icon = mock(Drawable.class);
mAppEntry.icon = icon;
mController = new BridgedAppsPreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setUserId(0);
mController.setAppState(mAppState);
mController.displayPreference(mScreen);
}
@Test
public void onRebuildComplete_AddsToScreen() {
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
entries.add(mAppEntry);
entries.add(mAppEntry2);
mController.onRebuildComplete(entries);
assertThat(mScreen.getPreferenceCount()).isEqualTo(2);
}
@Test
public void onRebuildComplete_doesNotReaddToScreen() {
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
CheckBoxPreference p = mock(CheckBoxPreference.class);
when(p.getKey()).thenReturn("pkg|12300");
mScreen.addPreference(p);
ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
entries.add(mAppEntry);
entries.add(mAppEntry2);
mController.onRebuildComplete(entries);
assertThat(mScreen.getPreferenceCount()).isEqualTo(2);
}
@Test
public void onRebuildComplete_removesExtras() {
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
Preference p = mock(Preference.class);
when(p.getKey()).thenReturn("pkg|123");
mScreen.addPreference(p);
ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
entries.add(mAppEntry);
entries.add(mAppEntry2);
mController.onRebuildComplete(entries);
assertThat((Preference) mScreen.findPreference("pkg|123")).isNull();
}
@Test
public void onRebuildComplete_buildsSetting() {
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
ArrayList<ApplicationsState.AppEntry> entries = new ArrayList<>();
entries.add(mAppEntry);
mController.onRebuildComplete(entries);
CheckBoxPreference actual = mScreen.findPreference("pkg|12300");
assertThat(actual.isChecked()).isTrue();
assertThat(actual.getTitle()).isEqualTo("hi");
assertThat(actual.getIcon()).isEqualTo(mAppEntry.icon);
}
@Test
public void onPreferenceChange_false() {
VersionedPackage vp = new VersionedPackage("pkg", 10567);
ArraySet<VersionedPackage> vps = new ArraySet<>();
vps.add(vp);
NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ONGOING
| FLAG_FILTER_TYPE_CONVERSATIONS, vps);
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
CheckBoxPreference pref = new CheckBoxPreference(mContext);
pref.setKey("pkg|567");
mController.onPreferenceChange(pref, false);
ArgumentCaptor<NotificationListenerFilter> captor =
ArgumentCaptor.forClass(NotificationListenerFilter.class);
verify(mNm).setListenerFilter(eq(mCn), eq(0), captor.capture());
assertThat(captor.getValue().getDisallowedPackages()).contains(
new VersionedPackage("pkg", 567));
assertThat(captor.getValue().getDisallowedPackages()).contains(
new VersionedPackage("pkg", 10567));
}
@Test
public void onPreferenceChange_true() {
VersionedPackage vp = new VersionedPackage("pkg", 567);
VersionedPackage vp2 = new VersionedPackage("pkg", 10567);
ArraySet<VersionedPackage> vps = new ArraySet<>();
vps.add(vp);
vps.add(vp2);
NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ONGOING
| FLAG_FILTER_TYPE_CONVERSATIONS, vps);
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
CheckBoxPreference pref = new CheckBoxPreference(mContext);
pref.setKey("pkg|567");
mController.onPreferenceChange(pref, true);
ArgumentCaptor<NotificationListenerFilter> captor =
ArgumentCaptor.forClass(NotificationListenerFilter.class);
verify(mNm).setListenerFilter(eq(mCn), eq(0), captor.capture());
assertThat(captor.getValue().getDisallowedPackages().size()).isEqualTo(1);
assertThat(captor.getValue().getDisallowedPackages()).contains(
new VersionedPackage("pkg", 10567));
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2021 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.applications.specialaccess.notificationaccess;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ServiceInfo;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class ConversationTypeFilterPreferenceControllerTest {
private Context mContext;
private ConversationTypeFilterPreferenceController mController;
@Mock
NotificationBackend mNm;
ComponentName mCn = new ComponentName("a", "b");
ServiceInfo mSi = new ServiceInfo();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new ConversationTypeFilterPreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setServiceInfo(mSi);
mController.setUserId(0);
}
@Test
public void getType() {
assertThat(mController.getType()).isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS);
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2021 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.applications.specialaccess.notificationaccess;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ServiceInfo;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class OngoingTypeFilterPreferenceControllerTest {
private Context mContext;
private OngoingTypeFilterPreferenceController mController;
@Mock
NotificationBackend mNm;
ComponentName mCn = new ComponentName("a", "b");
ServiceInfo mSi = new ServiceInfo();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new OngoingTypeFilterPreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setServiceInfo(mSi);
mController.setUserId(0);
}
@Test
public void getType() {
assertThat(mController.getType()).isEqualTo(FLAG_FILTER_TYPE_ONGOING);
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2021 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.applications.specialaccess.notificationaccess;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
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.when;
import android.content.ComponentName;
import android.content.Context;
import android.os.Build;
import android.service.notification.NotificationListenerFilter;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class PreUpgradePreferenceControllerTest {
private Context mContext;
private PreUpgradePreferenceController mController;
@Mock
NotificationBackend mNm;
ComponentName mCn = new ComponentName("a", "b");
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new PreUpgradePreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setUserId(0);
}
@Test
public void testAvailable_notGranted() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(false);
mController.setTargetSdk(Build.VERSION_CODES.S);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void testAvailable_lowTargetSdk_noCustomizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.S);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void testAvailable_lowTargetSdk_customizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.S);
NotificationListenerFilter nlf = new NotificationListenerFilter();
nlf.setTypes(FLAG_FILTER_TYPE_CONVERSATIONS);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
@Test
public void testAvailable_highTargetSdk_noCustomizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.CUR_DEVELOPMENT + 1);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2021 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.applications.specialaccess.notificationaccess;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static com.google.common.truth.Truth.assertThat;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ServiceInfo;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class SilentTypeFilterPreferenceControllerTest {
private Context mContext;
private SilentTypeFilterPreferenceController mController;
@Mock
NotificationBackend mNm;
ComponentName mCn = new ComponentName("a", "b");
ServiceInfo mSi = new ServiceInfo();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new SilentTypeFilterPreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setServiceInfo(mSi);
mController.setUserId(0);
}
@Test
public void getType() {
assertThat(mController.getType()).isEqualTo(FLAG_FILTER_TYPE_SILENT);
}
}

View File

@@ -0,0 +1,264 @@
/*
* Copyright (C) 2021 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.applications.specialaccess.notificationaccess;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
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.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.Bundle;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.util.ArraySet;
import androidx.preference.CheckBoxPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.notification.NotificationBackend;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
public class TypeFilterPreferenceControllerTest {
private Context mContext;
private TypeFilterPreferenceController mController;
@Mock
NotificationBackend mNm;
ComponentName mCn = new ComponentName("a", "b");
ServiceInfo mSi = new ServiceInfo();
private static class TestTypeFilterPreferenceController extends TypeFilterPreferenceController {
public TestTypeFilterPreferenceController(Context context, String key) {
super(context, key);
}
@Override
protected int getType() {
return 32;
}
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mController = new TestTypeFilterPreferenceController(mContext, "key");
mController.setCn(mCn);
mController.setNm(mNm);
mController.setServiceInfo(mSi);
mController.setUserId(0);
mController.setTargetSdk(Build.VERSION_CODES.CUR_DEVELOPMENT + 1);
}
@Test
public void testAvailable_notGranted() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(false);
mController.setTargetSdk(Build.VERSION_CODES.CUR_DEVELOPMENT + 1);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void testAvailable_lowTargetSdk_noCustomizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.S);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void testAvailable_lowTargetSdk_customizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.S);
NotificationListenerFilter nlf = new NotificationListenerFilter();
nlf.setTypes(FLAG_FILTER_TYPE_CONVERSATIONS);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void testAvailable_highTargetSdk_noCustomizations() {
when(mNm.isNotificationListenerAccessGranted(any())).thenReturn(true);
mController.setTargetSdk(Build.VERSION_CODES.CUR_DEVELOPMENT + 1);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void updateState_enabled_noMetaData() {
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.updateState(pref);
assertThat(pref.isEnabled()).isTrue();
}
@Test
public void updateState_enabled_metaData_notTheDisableFilter() {
mSi.metaData = new Bundle();
mSi.metaData.putCharSequence("test", "value");
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.updateState(pref);
assertThat(pref.isEnabled()).isTrue();
}
@Test
public void updateState_enabled_metaData_disableFilter_notThisField() {
mSi.metaData = new Bundle();
mSi.metaData.putCharSequence(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES,
"1|alerting");
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.updateState(pref);
assertThat(pref.isEnabled()).isTrue();
}
@Test
public void updateState_enabled_metaData_disableFilter_thisField_stateIsChecked() {
mSi.metaData = new Bundle();
mSi.metaData.putCharSequence(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES,
"conversations|2|32");
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(
new NotificationListenerFilter(32, new ArraySet<>()));
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.updateState(pref);
assertThat(pref.isEnabled()).isTrue();
}
@Test
public void updateState_disabled() {
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(false);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(new NotificationListenerFilter());
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.updateState(pref);
assertThat(pref.isEnabled()).isFalse();
}
@Test
public void updateState_disabled_metaData_disableFilter_thisField_stateIsNotChecked() {
mSi.metaData = new Bundle();
mSi.metaData.putCharSequence(NotificationListenerService.META_DATA_DISABLED_FILTER_TYPES,
"1|2|32");
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
NotificationListenerFilter before = new NotificationListenerFilter(4, new ArraySet<>());
when(mNm.getListenerFilter(mCn, 0)).thenReturn(before);
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.updateState(pref);
assertThat(pref.isChecked()).isFalse();
assertThat(pref.isEnabled()).isFalse();
}
@Test
public void updateState_checked() {
NotificationListenerFilter nlf = new NotificationListenerFilter(mController.getType(),
new ArraySet<>());
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.updateState(pref);
assertThat(pref.isChecked()).isTrue();
}
@Test
public void updateState_unchecked() {
NotificationListenerFilter nlf = new NotificationListenerFilter(mController.getType() - 1,
new ArraySet<>());
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.updateState(pref);
assertThat(pref.isChecked()).isFalse();
}
@Test
public void onPreferenceChange_true() {
NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ONGOING
| FLAG_FILTER_TYPE_CONVERSATIONS, new ArraySet<>());
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.onPreferenceChange(pref, true);
ArgumentCaptor<NotificationListenerFilter> captor =
ArgumentCaptor.forClass(NotificationListenerFilter.class);
verify(mNm).setListenerFilter(eq(mCn), eq(0), captor.capture());
assertThat(captor.getValue().getTypes()).isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS
| FLAG_FILTER_TYPE_ONGOING | mController.getType());
}
@Test
public void onPreferenceChange_false() {
NotificationListenerFilter nlf = new NotificationListenerFilter(FLAG_FILTER_TYPE_ONGOING
| FLAG_FILTER_TYPE_CONVERSATIONS | mController.getType(), new ArraySet<>());
when(mNm.isNotificationListenerAccessGranted(mCn)).thenReturn(true);
when(mNm.getListenerFilter(mCn, 0)).thenReturn(nlf);
CheckBoxPreference pref = new CheckBoxPreference(mContext);
mController.onPreferenceChange(pref, false);
ArgumentCaptor<NotificationListenerFilter> captor =
ArgumentCaptor.forClass(NotificationListenerFilter.class);
verify(mNm).setListenerFilter(eq(mCn), eq(0), captor.capture());
assertThat(captor.getValue().getTypes()).isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS
| FLAG_FILTER_TYPE_ONGOING);
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright (C) 2017 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.backup;
import static com.google.common.truth.Truth.assertThat;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class BackupIntentTest {
private static final String INTENT_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
private static final String BACKUP_SETTINGS_ACTIVITY =
"com.android.settings.Settings$PrivacyDashboardActivity";
private Context mContext;
@Before
public void setUp() throws Exception {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mContext = instrumentation.getTargetContext();
}
@Test
public void testPrivacySettingsIntentResolvesToOnlyOneActivity(){
PackageManager pm = mContext.getPackageManager();
Intent intent = new Intent(INTENT_PRIVACY_SETTINGS);
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
assertThat(activities).isNotNull();
assertThat(activities.size()).isEqualTo(1);
assertThat(activities.get(0).activityInfo.getComponentName().getClassName()).
isEqualTo(BACKUP_SETTINGS_ACTIVITY);
}
}

View File

@@ -0,0 +1,224 @@
/*
* Copyright (C) 2021 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 android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_MODALITY;
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_DENIED;
import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_GRANTED;
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.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Intent;
import android.hardware.biometrics.BiometricAuthenticator;
import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.biometrics.face.FaceEnrollParentalConsent;
import com.android.settings.biometrics.fingerprint.FingerprintEnrollParentalConsent;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
public class ParentalConsentHelperTest {
private static final int REQUEST_CODE = 12;
@Rule
public final MockitoRule mMocks = MockitoJUnit.rule();
@Mock
private Activity mRootActivity;
@Mock
private Intent mRootActivityIntent;
@Captor
ArgumentCaptor<Intent> mLastStarted;
@Before
public void setup() {
when(mRootActivity.getIntent()).thenAnswer(invocation -> mRootActivityIntent);
when(mRootActivityIntent.getBundleExtra(any())).thenAnswer(invocation -> null);
when(mRootActivityIntent.getStringExtra(any())).thenAnswer(invocation -> null);
when(mRootActivityIntent.getBooleanExtra(any(), anyBoolean()))
.thenAnswer(invocation -> invocation.getArguments()[1]);
}
@Test
public void testLaunchNext_face_and_fingerprint_all_consent() {
testLaunchNext(
true /* requireFace */, true /* grantFace */,
true /* requireFingerprint */, true /* grantFace */,
90 /* gkpw */);
}
@Test
public void testLaunchNext_nothing_to_consent() {
testLaunchNext(
false /* requireFace */, false /* grantFace */,
false /* requireFingerprint */, false /* grantFace */,
80 /* gkpw */);
}
@Test
public void testLaunchNext_face_and_fingerprint_no_consent() {
testLaunchNext(
true /* requireFace */, false /* grantFace */,
true /* requireFingerprint */, false /* grantFace */,
70 /* gkpw */);
}
@Test
public void testLaunchNext_face_and_fingerprint_only_face_consent() {
testLaunchNext(
true /* requireFace */, true /* grantFace */,
true /* requireFingerprint */, false /* grantFace */,
60 /* gkpw */);
}
@Test
public void testLaunchNext_face_and_fingerprint_only_fingerprint_consent() {
testLaunchNext(
true /* requireFace */, false /* grantFace */,
true /* requireFingerprint */, true /* grantFace */,
50 /* gkpw */);
}
@Test
public void testLaunchNext_face_with_consent() {
testLaunchNext(
true /* requireFace */, true /* grantFace */,
false /* requireFingerprint */, false /* grantFace */,
40 /* gkpw */);
}
@Test
public void testLaunchNext_face_without_consent() {
testLaunchNext(
true /* requireFace */, false /* grantFace */,
false /* requireFingerprint */, false /* grantFace */,
30 /* gkpw */);
}
@Test
public void testLaunchNext_fingerprint_with_consent() {
testLaunchNext(
false /* requireFace */, false /* grantFace */,
true /* requireFingerprint */, true /* grantFace */,
20 /* gkpw */);
}
@Test
public void testLaunchNext_fingerprint_without_consent() {
testLaunchNext(
false /* requireFace */, false /* grantFace */,
true /* requireFingerprint */, false /* grantFace */,
10 /* gkpw */);
}
private void testLaunchNext(
boolean requireFace, boolean grantFace,
boolean requireFingerprint, boolean grantFingerprint,
long gkpw) {
final List<Pair<String, Boolean>> expectedLaunches = new ArrayList<>();
if (requireFace) {
expectedLaunches.add(new Pair(FaceEnrollParentalConsent.class.getName(), grantFace));
}
if (requireFingerprint) {
expectedLaunches.add(
new Pair(FingerprintEnrollParentalConsent.class.getName(), grantFingerprint));
}
// initial consent status
final ParentalConsentHelper helper =
new ParentalConsentHelper(requireFace, requireFingerprint, gkpw);
assertThat(ParentalConsentHelper.hasFaceConsent(helper.getConsentResult()))
.isFalse();
assertThat(ParentalConsentHelper.hasFingerprintConsent(helper.getConsentResult()))
.isFalse();
// check expected launches
for (int i = 0; i <= expectedLaunches.size(); i++) {
final Pair<String, Boolean> expected = i > 0 ? expectedLaunches.get(i - 1) : null;
final boolean launchedNext = i == 0
? helper.launchNext(mRootActivity, REQUEST_CODE)
: helper.launchNext(mRootActivity, REQUEST_CODE,
expected.second ? RESULT_CONSENT_GRANTED : RESULT_CONSENT_DENIED,
getResultIntent(getStartedModality(expected.first)));
assertThat(launchedNext).isEqualTo(i < expectedLaunches.size());
}
verify(mRootActivity, times(expectedLaunches.size()))
.startActivityForResult(mLastStarted.capture(), eq(REQUEST_CODE));
assertThat(mLastStarted.getAllValues()
.stream().map(i -> i.getComponent().getClassName()).collect(Collectors.toList()))
.containsExactlyElementsIn(
expectedLaunches.stream().map(i -> i.first).collect(Collectors.toList()))
.inOrder();
if (!expectedLaunches.isEmpty()) {
assertThat(mLastStarted.getAllValues()
.stream().map(BiometricUtils::getGatekeeperPasswordHandle).distinct()
.collect(Collectors.toList()))
.containsExactly(gkpw);
}
// final consent status
assertThat(ParentalConsentHelper.hasFaceConsent(helper.getConsentResult()))
.isEqualTo(requireFace && grantFace);
assertThat(ParentalConsentHelper.hasFingerprintConsent(helper.getConsentResult()))
.isEqualTo(requireFingerprint && grantFingerprint);
}
private static Intent getResultIntent(@BiometricAuthenticator.Modality int modality) {
final Intent intent = new Intent();
intent.putExtra(EXTRA_KEY_MODALITY, modality);
return intent;
}
@BiometricAuthenticator.Modality
private static int getStartedModality(String name) {
if (name.equals(FaceEnrollParentalConsent.class.getName())) {
return TYPE_FACE;
}
if (name.equals(FingerprintEnrollParentalConsent.class.getName())) {
return TYPE_FINGERPRINT;
}
return TYPE_NONE;
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2021 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 junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertNull;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
import android.hardware.biometrics.BiometricAuthenticator;
import android.os.UserHandle;
import android.os.UserManager;
import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.RestrictedLockUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class ParentalControlsUtilsTest {
@Mock
private Context mContext;
@Mock
private DevicePolicyManager mDpm;
private ComponentName mSupervisionComponentName = new ComponentName("pkg", "cls");
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
}
/**
* Helper that sets the appropriate mocks and testing behavior before returning the actual
* EnforcedAdmin from ParentalControlsUtils.
*/
@Nullable
private RestrictedLockUtils.EnforcedAdmin getEnforcedAdminForCombination(
@Nullable ComponentName supervisionComponentName,
@BiometricAuthenticator.Modality int modality, int keyguardDisabledFlags) {
when(mDpm.getProfileOwnerOrDeviceOwnerSupervisionComponent(any(UserHandle.class)))
.thenReturn(supervisionComponentName);
when(mDpm.getKeyguardDisabledFeatures(eq(supervisionComponentName)))
.thenReturn(keyguardDisabledFlags);
return ParentalControlsUtils.parentConsentRequiredInternal(mDpm, modality,
new UserHandle(UserHandle.myUserId()));
}
@Test
public void testEnforcedAdmin_whenDpmDisablesBiometricsAndSupervisionComponentExists() {
int[][] tests = {
{TYPE_FINGERPRINT, DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT},
{TYPE_FACE, DevicePolicyManager.KEYGUARD_DISABLE_FACE},
{TYPE_IRIS, DevicePolicyManager.KEYGUARD_DISABLE_IRIS},
};
for (int i = 0; i < tests.length; i++) {
RestrictedLockUtils.EnforcedAdmin admin = getEnforcedAdminForCombination(
mSupervisionComponentName, tests[i][0] /* modality */,
tests[i][1] /* keyguardDisableFlags */);
assertNotNull(admin);
assertEquals(UserManager.DISALLOW_BIOMETRIC, admin.enforcedRestriction);
assertEquals(mSupervisionComponentName, admin.component);
}
}
@Test
public void testNoEnforcedAdmin_whenNoSupervisionComponent() {
// Even if DPM flag exists, returns null EnforcedAdmin when no supervision component exists
RestrictedLockUtils.EnforcedAdmin admin = getEnforcedAdminForCombination(
null /* supervisionComponentName */, TYPE_FINGERPRINT,
DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT);
assertNull(admin);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2020 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.face;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class FaceSettingsAttentionPreferenceControllerTest {
private Context mContext;
private FaceSettingsAttentionPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new FaceSettingsAttentionPreferenceController(mContext);
}
@Test
public void isSliceable_returnFalse() {
assertThat(mController.isSliceable()).isFalse();
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright (C) 2017 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.fingerprint;
import static androidx.test.InstrumentationRegistry.getTargetContext;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.intent.Intents.intended;
import static androidx.test.espresso.intent.Intents.intending;
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.Activity;
import android.app.Instrumentation.ActivityResult;
import android.content.ComponentName;
import androidx.test.espresso.intent.rule.IntentsTestRule;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.R;
import com.google.android.setupcompat.PartnerCustomizationLayout;
import com.google.android.setupcompat.template.FooterBarMixin;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class FingerprintEnrollFinishTest {
@Rule
public IntentsTestRule<FingerprintEnrollFinish> mActivityRule =
new IntentsTestRule<>(FingerprintEnrollFinish.class);
@Test
public void clickAddAnother_shouldLaunchEnrolling() {
final ComponentName enrollingComponent = new ComponentName(
getTargetContext(),
FingerprintEnrollEnrolling.class);
intending(hasComponent(enrollingComponent))
.respondWith(new ActivityResult(Activity.RESULT_CANCELED, null));
PartnerCustomizationLayout layout =
mActivityRule.getActivity().findViewById(R.id.setup_wizard_layout);
layout.getMixin(FooterBarMixin.class).getPrimaryButtonView().performClick();
intended(hasComponent(enrollingComponent));
assertFalse(mActivityRule.getActivity().isFinishing());
}
@Test
public void clickAddAnother_shouldPropagateResults() {
final ComponentName enrollingComponent = new ComponentName(
getTargetContext(),
FingerprintEnrollEnrolling.class);
intending(hasComponent(enrollingComponent))
.respondWith(new ActivityResult(Activity.RESULT_OK, null));
PartnerCustomizationLayout layout =
mActivityRule.getActivity().findViewById(R.id.setup_wizard_layout);
layout.getMixin(FooterBarMixin.class).getPrimaryButtonView().performClick();
intended(hasComponent(enrollingComponent));
assertTrue(mActivityRule.getActivity().isFinishing());
}
@Test
public void clickNext_shouldFinish() {
onView(withId(R.id.next_button)).perform(click());
assertTrue(mActivityRule.getActivity().isFinishing());
}
}

View File

@@ -1,113 +0,0 @@
/*
* Copyright (C) 2016 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.fingerprint;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.test.ActivityUnitTestCase;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.android.settings.R;
import com.google.android.setupcompat.PartnerCustomizationLayout;
import com.google.android.setupcompat.template.FooterBarMixin;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
public class FingerprintEnrollIntroductionTest
extends ActivityUnitTestCase<FingerprintEnrollIntroduction> {
private TestContext mContext;
@Mock
private FingerprintManager mFingerprintManager;
private FingerprintEnrollIntroduction mActivity;
public FingerprintEnrollIntroductionTest() {
super(FingerprintEnrollIntroduction.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
mContext = new TestContext(getInstrumentation().getTargetContext());
setActivityContext(mContext);
getInstrumentation().runOnMainSync(() -> {
final Intent intent = new Intent();
mActivity = startActivity(intent,
null /* savedInstanceState */, null /* lastNonConfigurationInstance */);
});
}
public void testMaxFingerprint_shouldShowErrorMessage() {
final int max = mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
doReturn(generateFingerprintList(max)).when(mFingerprintManager)
.getEnrolledFingerprints(anyInt());
getInstrumentation().runOnMainSync(() -> {
getInstrumentation().callActivityOnCreate(mActivity, null);
getInstrumentation().callActivityOnResume(mActivity);
});
final TextView errorTextView = (TextView) mActivity.findViewById(R.id.error_text);
assertNotNull(errorTextView.getText().toString());
PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
final Button nextButton = layout.getMixin(FooterBarMixin.class).getPrimaryButtonView();
assertEquals(View.GONE, nextButton.getVisibility());
}
private List<Fingerprint> generateFingerprintList(int num) {
ArrayList<Fingerprint> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
list.add(new Fingerprint("Fingerprint " + i, 0, i, 0));
}
return list;
}
public class TestContext extends ContextWrapper {
public TestContext(Context base) {
super(base);
}
@Override
public Object getSystemService(String name) {
if (Context.FINGERPRINT_SERVICE.equals(name)) {
return mFingerprintManager;
}
return super.getSystemService(name);
}
}
}

View File

@@ -1,94 +0,0 @@
/*
* Copyright (C) 2010 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 android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.InputFilter;
import android.text.SpannableStringBuilder;
public class Utf8ByteLengthFilterTest extends AndroidTestCase {
@SmallTest
public void testFilter() {
// Define the variables
CharSequence source;
SpannableStringBuilder dest;
// Constructor to create a LengthFilter
InputFilter lengthFilter = new Utf8ByteLengthFilter(10);
InputFilter[] filters = {lengthFilter};
// filter() implicitly invoked. If the total length > filter length, the filter will
// cut off the source CharSequence from beginning to fit the filter length.
source = "abc";
dest = new SpannableStringBuilder("abcdefgh");
dest.setFilters(filters);
dest.insert(1, source);
String expectedString1 = "aabbcdefgh";
assertEquals(expectedString1, dest.toString());
dest.replace(5, 8, source);
String expectedString2 = "aabbcabcgh";
assertEquals(expectedString2, dest.toString());
dest.insert(2, source);
assertEquals(expectedString2, dest.toString());
dest.delete(1, 3);
String expectedString3 = "abcabcgh";
assertEquals(expectedString3, dest.toString());
dest.append("12345");
String expectedString4 = "abcabcgh12";
assertEquals(expectedString4, dest.toString());
source = "\u60a8\u597d"; // 2 Chinese chars == 6 bytes in UTF-8
dest.replace(8, 10, source);
assertEquals(expectedString3, dest.toString());
dest.replace(0, 1, source);
String expectedString5 = "\u60a8bcabcgh";
assertEquals(expectedString5, dest.toString());
dest.replace(0, 4, source);
String expectedString6 = "\u60a8\u597dbcgh";
assertEquals(expectedString6, dest.toString());
source = "\u00a3\u00a5"; // 2 Latin-1 chars == 4 bytes in UTF-8
dest.delete(2, 6);
dest.insert(0, source);
String expectedString7 = "\u00a3\u00a5\u60a8\u597d";
assertEquals(expectedString7, dest.toString());
dest.replace(2, 3, source);
String expectedString8 = "\u00a3\u00a5\u00a3\u597d";
assertEquals(expectedString8, dest.toString());
dest.replace(3, 4, source);
String expectedString9 = "\u00a3\u00a5\u00a3\u00a3\u00a5";
assertEquals(expectedString9, dest.toString());
// filter() explicitly invoked
dest = new SpannableStringBuilder("abcdefgh");
CharSequence beforeFilterSource = "TestLengthFilter";
String expectedAfterFilter = "TestLength";
CharSequence actualAfterFilter = lengthFilter.filter(beforeFilterSource, 0,
beforeFilterSource.length(), dest, 0, dest.length());
assertEquals(expectedAfterFilter, actualAfterFilter);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 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.core;
import android.content.Context;
public class BadPreferenceController extends BasePreferenceController {
public BadPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
throw new IllegalArgumentException("error");
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
@Override
public boolean useDynamicSliceSummary() {
return true;
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2020 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.core;
import static com.google.common.truth.Truth.assertWithMessage;
import android.content.Context;
import com.android.settings.core.codeinspection.CodeInspector;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
public class BasePreferenceControllerSignatureInspector extends CodeInspector {
private final List<String> mExemptList;
public BasePreferenceControllerSignatureInspector(List<Class<?>> classes) {
super(classes);
mExemptList = new ArrayList<>();
initializeExemptList(mExemptList,
"exempt_invalid_base_preference_controller_constructor");
}
@Override
public void run() {
StringBuilder badClasses = new StringBuilder();
for (Class c : mClasses) {
if (!isConcreteSettingsClass(c)) {
// Not a Settings class, or is abstract, don't care.
continue;
}
if (!BasePreferenceController.class.isAssignableFrom(c)) {
// Not a BasePreferenceController, don't care.
continue;
}
final String className = c.getName();
if (mExemptList.remove(className)) {
continue;
}
final Constructor[] constructors = c.getDeclaredConstructors();
if (constructors == null || constructors.length == 0) {
badClasses.append(c.getName()).append(",");
}
boolean hasValidConstructor = false;
for (Constructor constructor : constructors) {
if (hasValidConstructorSignature(constructor)) {
hasValidConstructor = true;
break;
}
}
if (!hasValidConstructor) {
badClasses.append(className).append(",");
}
}
assertWithMessage("All BasePreferenceController (and subclasses) constructor must either"
+ " only take Context, or (Context, String). No other types are allowed")
.that(badClasses.toString())
.isEmpty();
assertWithMessage("Something in the exempt list is no longer relevant. Please remove"
+ "it from packages/apps/Settings/tests/robotests/assets/"
+ "exempt_invalid_base_preference_controller_constructor")
.that(mExemptList)
.isEmpty();
}
private static boolean hasValidConstructorSignature(Constructor constructor) {
final Class[] parameterTypes = constructor.getParameterTypes();
if (parameterTypes.length == 1) {
return Context.class.isAssignableFrom(parameterTypes[0]);
} else if (parameterTypes.length == 2) {
return Context.class.isAssignableFrom(parameterTypes[0])
&& String.class.isAssignableFrom(parameterTypes[1]);
}
return false;
}
}

View File

@@ -1,82 +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.core;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.platform.test.annotations.Presubmit;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.development.featureflags.FeatureFlagsDashboard;
import com.android.settingslib.core.instrumentation.Instrumentable;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class LifecycleEventHandlingTest {
private static final long TIMEOUT = 2000;
private Context mContext;
private String mTargetPackage;
private UiDevice mDevice;
@Before
public void setUp() throws Exception {
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mDevice.wakeUp();
mDevice.executeShellCommand("wm dismiss-keyguard");
mContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mContext.getPackageName();
}
@Test
@Presubmit
@Ignore("b/133334887")
public void launchDashboard_shouldSeeFooter() {
new SubSettingLauncher(mContext)
.setDestination(FeatureFlagsDashboard.class.getName())
.setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN)
.addFlags(FLAG_ACTIVITY_NEW_TASK)
.launch();
final String footerText = "Experimental";
// Scroll to bottom
final UiObject2 view = mDevice.wait(
Until.findObject(By.res(mTargetPackage, "main_content")),
TIMEOUT);
view.scroll(Direction.DOWN, 100f);
assertThat(mDevice.wait(Until.findObject(By.text(footerText)), TIMEOUT))
.isNotNull();
}
}

View File

@@ -1,95 +0,0 @@
/*
* Copyright (C) 2017 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.core;
import static junit.framework.Assert.fail;
import android.content.Context;
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexableData;
import com.android.settingslib.search.SearchIndexableResources;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class PreferenceControllerContractTest {
private Context mContext;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
}
@Test
@Presubmit
public void controllersInSearchShouldImplementPreferenceControllerMixin() {
Looper.prepare(); // Required by AutofillLoggingLevelPreferenceController
final Set<String> errorClasses = new ArraySet<>();
final SearchIndexableResources resources =
FeatureFactory.getFactory(mContext).getSearchFeatureProvider()
.getSearchIndexableResources();
for (SearchIndexableData bundle : resources.getProviderValues()) {
final BaseSearchIndexProvider provider =
(BaseSearchIndexProvider) bundle.getSearchIndexProvider();
if (provider == null) {
continue;
}
final List<AbstractPreferenceController> controllers =
provider.getPreferenceControllers(mContext);
if (controllers == null) {
continue;
}
for (AbstractPreferenceController controller : controllers) {
if (!(controller instanceof PreferenceControllerMixin)
&& !(controller instanceof BasePreferenceController)) {
errorClasses.add(controller.getClass().getName());
}
}
}
if (!errorClasses.isEmpty()) {
final StringBuilder errorMessage = new StringBuilder()
.append("Each preference must implement PreferenceControllerMixin ")
.append("or extend BasePreferenceController, ")
.append("the following classes don't:\n");
for (String c : errorClasses) {
errorMessage.append(c).append("\n");
}
fail(errorMessage.toString());
}
}
}

View File

@@ -1,120 +0,0 @@
/*
* Copyright (C) 2017 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.core;
import static android.content.pm.PackageManager.GET_ACTIVITIES;
import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static com.android.settings.SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertFalse;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.platform.test.annotations.Presubmit;
import android.text.TextUtils;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.core.gateway.SettingsGateway;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SettingsGatewayTest {
private static final String TAG = "SettingsGatewayTest";
private Context mContext;
private PackageManager mPackageManager;
private String mPackageName;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mPackageManager = mContext.getPackageManager();
mPackageName = mContext.getPackageName();
}
@Test
@Presubmit
public void allRestrictedActivityMustBeDefinedInManifest() {
for (String className : SettingsGateway.SETTINGS_FOR_RESTRICTED) {
final Intent intent = new Intent();
intent.setComponent(new ComponentName(mPackageName, className));
List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
MATCH_DISABLED_COMPONENTS);
Log.d(TAG, mPackageName + "/" + className + "; resolveInfo size: "
+ resolveInfos.size());
assertFalse(className + " is not-defined in manifest", resolveInfos.isEmpty());
}
}
@Test
@Presubmit
public void publicFragmentMustAppearInSettingsGateway()
throws PackageManager.NameNotFoundException {
final List<String> whitelistedFragment = new ArrayList<>();
final StringBuilder error = new StringBuilder();
for (String fragment : SettingsGateway.ENTRY_FRAGMENTS) {
whitelistedFragment.add(fragment);
}
final PackageInfo pi = mPackageManager.getPackageInfo(mPackageName,
GET_META_DATA | MATCH_DISABLED_COMPONENTS | GET_ACTIVITIES);
final List<ActivityInfo> activities = Arrays.asList(pi.activities);
for (ActivityInfo activity : activities) {
final Bundle metaData = activity.metaData;
if (metaData == null || !metaData.containsKey(META_DATA_KEY_FRAGMENT_CLASS)) {
continue;
}
final String fragmentName = metaData.getString(META_DATA_KEY_FRAGMENT_CLASS);
assertThat(fragmentName).isNotNull();
if (!whitelistedFragment.contains(fragmentName)) {
error.append("SettingsGateway.ENTRY_FRAGMENTS must contain " + fragmentName
+ " because this fragment is used in manifest for " + activity.name)
.append("\n");
}
}
final String message = error.toString();
if (!TextUtils.isEmpty(message)) {
fail(message);
}
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2020 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.core;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.slices.SliceData;
import com.android.settings.widget.SeekBarPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class SettingsSliderPreferenceControllerTest {
private FakeSliderPreferenceController mSliderController;
private SeekBarPreference mPreference;
@Before
public void setUp() {
mPreference = new SeekBarPreference(ApplicationProvider.getApplicationContext());
mSliderController = new FakeSliderPreferenceController(
ApplicationProvider.getApplicationContext(), "key");
mPreference.setContinuousUpdates(true);
mPreference.setMin(mSliderController.getMin());
mPreference.setMax(mSliderController.getMax());
}
@Test
public void onPreferenceChange_updatesPosition() {
final int newValue = 28;
mSliderController.onPreferenceChange(mPreference, newValue);
assertThat(mSliderController.getSliderPosition()).isEqualTo(newValue);
}
@Test
public void updateState_setsPreferenceToCurrentValue() {
final int newValue = 28;
mSliderController.setSliderPosition(newValue);
mSliderController.updateState(mPreference);
assertThat(mPreference.getProgress()).isEqualTo(newValue);
}
@Test
public void testSliceType_returnsSliceType() {
assertThat(mSliderController.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER);
}
private class FakeSliderPreferenceController extends SliderPreferenceController {
private static final int MAX_STEPS = 2112;
private int mPosition;
private FakeSliderPreferenceController(Context context, String key) {
super(context, key);
}
@Override
public int getSliderPosition() {
return mPosition;
}
@Override
public boolean setSliderPosition(int position) {
mPosition = position;
return true;
}
@Override
public int getMax() {
return MAX_STEPS;
}
@Override
public int getMin() {
return 0;
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (C) 2020 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.core;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.slices.SliceData;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class TogglePreferenceControllerTest {
private FakeToggle mToggleController;
private Context mContext;
private SwitchPreference mPreference;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mPreference = new SwitchPreference(mContext);
mToggleController = new FakeToggle(mContext, "key");
}
@Test
public void testSetsPreferenceValue_setsChecked() {
mToggleController.setChecked(true);
mPreference.setChecked(false);
mToggleController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void testSetsPreferenceValue_setsNotChecked() {
mToggleController.setChecked(false);
mPreference.setChecked(true);
mToggleController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void testUpdatesPreferenceOnChange_turnsOn() {
boolean newValue = true;
mToggleController.setChecked(!newValue);
mToggleController.onPreferenceChange(mPreference, newValue);
assertThat(mToggleController.isChecked()).isEqualTo(newValue);
}
@Test
public void testUpdatesPreferenceOnChange_turnsOff() {
boolean newValue = false;
mToggleController.setChecked(!newValue);
mToggleController.onPreferenceChange(mPreference, newValue);
assertThat(mToggleController.isChecked()).isEqualTo(newValue);
}
@Test
public void testSliceType_returnsSliceType() {
assertThat(mToggleController.getSliceType()).isEqualTo(
SliceData.SliceType.SWITCH);
}
@Test
public void isSliceable_returnTrue() {
assertThat(mToggleController.isSliceable()).isTrue();
}
@Test
public void isPublicSlice_returnFalse() {
assertThat(mToggleController.isPublicSlice()).isFalse();
}
private static class FakeToggle extends TogglePreferenceController {
private boolean mCheckedFlag;
private FakeToggle(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@Override
public boolean isChecked() {
return mCheckedFlag;
}
@Override
public boolean setChecked(boolean isChecked) {
mCheckedFlag = isChecked;
return true;
}
@Override
public int getAvailabilityStatus() {
return AVAILABLE;
}
}
}

View File

@@ -1,219 +0,0 @@
/*
* Copyright (C) 2017 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.core;
import static junit.framework.Assert.fail;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.platform.test.annotations.Presubmit;
import android.provider.SearchIndexableResource;
import android.text.TextUtils;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexableData;
import com.android.settingslib.search.SearchIndexableRaw;
import com.android.settingslib.search.SearchIndexableResources;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class UniquePreferenceTest {
private static final String TAG = "UniquePreferenceTest";
private static final List<String> IGNORE_PREF_TYPES = Arrays.asList(
"com.android.settingslib.widget.FooterPreference");
private static final List<String> WHITELISTED_DUPLICATE_KEYS = Arrays.asList(
"owner_info_settings", // Lock screen message in security - multiple xml files
// contain this because security page is constructed by
// combining small xml chunks. Eventually the page
// should be formed as one single xml and this entry
// should be removed.
"dashboard_tile_placeholder", // This is the placeholder pref for injecting dynamic
// tiles.
// Dup keys from About Phone v2 experiment.
"ims_reg_state",
"bt_address",
"device_model",
"firmware_version",
"regulatory_info",
"manual",
"legal_container",
"device_feedback",
"fcc_equipment_id",
"sim_status",
"build_number",
"phone_number",
"imei_info",
"wifi_ip_address",
"wifi_mac_address",
"safety_info",
// Dupe keys from data usage v2.
"data_usage_screen",
"cellular_data_usage",
"data_usage_wifi_screen",
"status_header",
"billing_preference",
"data_usage_cellular_screen",
"wifi_data_usage",
"data_usage_enable"
);
private Context mContext;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
}
/**
* All preferences should have their unique key. It's especially important for many parts of
* Settings to work properly: we assume pref keys are unique in displaying, search ranking,\
* search result suppression, and many other areas.
* <p/>
* So in this test we are checking preferences participating in search.
* <p/>
* Note: Preference is not limited to just <Preference/> object. Everything in preference xml
* should have a key.
*/
@Test
@Presubmit
public void allPreferencesShouldHaveUniqueKey()
throws IOException, XmlPullParserException, Resources.NotFoundException {
final Set<String> uniqueKeys = new HashSet<>();
final Set<String> nullKeyClasses = new HashSet<>();
final Set<String> duplicatedKeys = new HashSet<>();
final SearchIndexableResources resources =
FeatureFactory.getFactory(mContext).getSearchFeatureProvider()
.getSearchIndexableResources();
for (SearchIndexableData SearchIndexableData : resources.getProviderValues()) {
verifyPreferenceKeys(uniqueKeys, duplicatedKeys, nullKeyClasses, SearchIndexableData);
}
if (!nullKeyClasses.isEmpty()) {
final StringBuilder nullKeyErrors = new StringBuilder()
.append("Each preference/SearchIndexableData must have a key, ")
.append("the following classes have null keys:\n");
for (String c : nullKeyClasses) {
nullKeyErrors.append(c).append("\n");
}
fail(nullKeyErrors.toString());
}
if (!duplicatedKeys.isEmpty()) {
final StringBuilder dupeKeysError = new StringBuilder(
"The following keys are not unique\n");
for (String c : duplicatedKeys) {
dupeKeysError.append(c).append("\n");
}
fail(dupeKeysError.toString());
}
}
private void verifyPreferenceKeys(Set<String> uniqueKeys, Set<String> duplicatedKeys,
Set<String> nullKeyClasses, SearchIndexableData searchIndexableData)
throws IOException, XmlPullParserException, Resources.NotFoundException {
final String className = searchIndexableData.getTargetClass().getName();
final Indexable.SearchIndexProvider provider =
searchIndexableData.getSearchIndexProvider();
final List<SearchIndexableRaw> rawsToIndex = provider.getRawDataToIndex(mContext, true);
final List<SearchIndexableResource> resourcesToIndex =
provider.getXmlResourcesToIndex(mContext, true);
verifyResources(className, resourcesToIndex, uniqueKeys, duplicatedKeys, nullKeyClasses);
verifyRaws(className, rawsToIndex, uniqueKeys, duplicatedKeys, nullKeyClasses);
}
private void verifyResources(String className, List<SearchIndexableResource> resourcesToIndex,
Set<String> uniqueKeys, Set<String> duplicatedKeys, Set<String> nullKeyClasses)
throws IOException, XmlPullParserException, Resources.NotFoundException {
if (resourcesToIndex == null) {
Log.d(TAG, className + "is not providing SearchIndexableResource, skipping");
return;
}
for (SearchIndexableResource sir : resourcesToIndex) {
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
sir.xmlResId,
MetadataFlag.FLAG_INCLUDE_PREF_SCREEN
| MetadataFlag.FLAG_NEED_KEY
| MetadataFlag.FLAG_NEED_PREF_TYPE);
for (Bundle bundle : metadata) {
final String type = bundle.getString(PreferenceXmlParserUtils.METADATA_PREF_TYPE);
if (IGNORE_PREF_TYPES.contains(type)) {
continue;
}
final String key = bundle.getString(PreferenceXmlParserUtils.METADATA_KEY);
if (TextUtils.isEmpty(key)) {
Log.e(TAG, "Every preference must have an key; found null key"
+ " in " + className);
nullKeyClasses.add(className);
continue;
}
if (uniqueKeys.contains(key) && !WHITELISTED_DUPLICATE_KEYS.contains(key)) {
Log.e(TAG, "Every preference key must unique; found "
+ " in " + className
+ " / " + key);
duplicatedKeys.add(key);
}
uniqueKeys.add(key);
}
}
}
private void verifyRaws(String className, List<SearchIndexableRaw> rawsToIndex,
Set<String> uniqueKeys, Set<String> duplicatedKeys, Set<String> nullKeyClasses) {
if (rawsToIndex == null) {
Log.d(TAG, className + "is not providing SearchIndexableRaw, skipping");
return;
}
for (SearchIndexableRaw raw : rawsToIndex) {
if (TextUtils.isEmpty(raw.key)) {
Log.e(TAG, "Every SearchIndexableRaw must have an key; found null key"
+ " in " + className);
nullKeyClasses.add(className);
continue;
}
if (uniqueKeys.contains(raw.key) && !WHITELISTED_DUPLICATE_KEYS.contains(raw.key)) {
Log.e(TAG, "Every SearchIndexableRaw key must unique; found " + raw.key
+ " in " + className);
duplicatedKeys.add(raw.key);
}
}
}
}

View File

@@ -1,157 +0,0 @@
/*
* Copyright (C) 2017 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.core;
import static junit.framework.Assert.fail;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.UserManager;
import android.provider.SearchIndexableResource;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.search.SearchIndexableData;
import com.android.settingslib.search.SearchIndexableResources;
import com.google.android.collect.Sets;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.List;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class UserRestrictionTest {
private static final String TAG = "UserRestrictionTest";
private Context mContext;
private static final Set<String> USER_RESTRICTIONS = Sets.newHashSet(
UserManager.DISALLOW_CONFIG_DATE_TIME,
UserManager.DISALLOW_CONFIG_CREDENTIALS,
UserManager.DISALLOW_NETWORK_RESET,
UserManager.DISALLOW_FACTORY_RESET,
UserManager.DISALLOW_CONFIG_TETHERING,
UserManager.DISALLOW_CONFIG_VPN,
UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
UserManager.DISALLOW_AIRPLANE_MODE,
UserManager.DISALLOW_CONFIG_BRIGHTNESS,
UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT
);
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
}
/**
* Verity that userRestriction attributes are entered and parsed successfully.
*/
@Test
public void userRestrictionAttributeShouldBeValid()
throws IOException, XmlPullParserException, Resources.NotFoundException {
final SearchIndexableResources resources =
FeatureFactory.getFactory(mContext).getSearchFeatureProvider()
.getSearchIndexableResources();
for (SearchIndexableData bundle : resources.getProviderValues()) {
verifyUserRestriction(bundle);
}
}
private void verifyUserRestriction(SearchIndexableData searchIndexableData)
throws IOException, XmlPullParserException, Resources.NotFoundException {
final Indexable.SearchIndexProvider provider =
searchIndexableData.getSearchIndexProvider();
final List<SearchIndexableResource> resourcesToIndex =
provider.getXmlResourcesToIndex(mContext, true);
final String className = searchIndexableData.getTargetClass().getName();
if (resourcesToIndex == null) {
Log.d(TAG, className + "is not providing SearchIndexableResource, skipping");
return;
}
for (SearchIndexableResource sir : resourcesToIndex) {
if (sir.xmlResId <= 0) {
Log.d(TAG, className + " doesn't have a valid xml to index.");
continue;
}
final XmlResourceParser parser = mContext.getResources().getXml(sir.xmlResId);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
// Parse next until start tag is found
}
final int outerDepth = parser.getDepth();
do {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String nodeName = parser.getName();
if (!nodeName.endsWith("Preference")) {
continue;
}
final AttributeSet attrs = Xml.asAttributeSet(parser);
final String userRestriction = getDataUserRestrictions(mContext, attrs);
if (userRestriction != null) {
if(!isValidRestriction(userRestriction)) {
fail("userRestriction in " + className + " not valid.");
}
}
} while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth));
}
}
boolean isValidRestriction(String userRestriction) {
return USER_RESTRICTIONS.contains(userRestriction);
}
private String getDataUserRestrictions(Context context, AttributeSet attrs) {
return getData(context, attrs,
com.android.settingslib.R.styleable.RestrictedPreference,
com.android.settingslib.R.styleable.RestrictedPreference_userRestriction);
}
private String getData(Context context, AttributeSet set, int[] attrs, int resId) {
final TypedArray ta = context.obtainStyledAttributes(set, attrs);
String data = ta.getString(resId);
ta.recycle();
return data;
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2020 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.core.codeinspection;
import com.google.common.reflect.ClassPath;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Scans and builds all classes in current classloader.
*/
public class ClassScanner {
public List<Class<?>> getClassesForPackage(String packageName) throws ClassNotFoundException {
final List<Class<?>> classes = new ArrayList<>();
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassPath classPath = ClassPath.from(classLoader);
// Some anonymous classes don't return true when calling isAnonymousClass(), but they
// always seem to be nested anonymous classes like com.android.settings.Foo$1$2. In
// general we don't want any anonymous classes so we just filter these out by searching
// for $[0-9] in the name.
Pattern anonymousClassPattern = Pattern.compile(".*\\$\\d+.*");
Matcher anonymousClassMatcher = anonymousClassPattern.matcher("");
for (ClassPath.ClassInfo info : classPath.getAllClasses()) {
if (info.getPackageName().startsWith(packageName)) {
try {
Class clazz = classLoader.loadClass(info.getName());
if (clazz.isAnonymousClass() || anonymousClassMatcher.reset(
clazz.getName()).matches()) {
continue;
}
classes.add(clazz);
} catch (NoClassDefFoundError e) {
// do nothing. this class hasn't been found by the
// loader, and we don't care.
}
}
}
} catch (final IOException e) {
throw new ClassNotFoundException("Error when parsing " + packageName, e);
}
return classes;
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2020 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.core.codeinspection;
import static com.google.common.truth.Truth.assertWithMessage;
import androidx.test.core.app.ApplicationProvider;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Modifier;
import java.util.List;
/**
* Inspector takes a list of class objects and perform static code analysis in its {@link #run()}
* method.
*/
public abstract class CodeInspector {
protected static final String PACKAGE_NAME = "com.android.settings";
private static final String TEST_CLASS_SUFFIX = "Test";
private static final String TEST_INNER_CLASS_SIGNATURE = "Test$";
protected final List<Class<?>> mClasses;
public CodeInspector(List<Class<?>> classes) {
mClasses = classes;
}
/**
* Code inspection runner method.
*/
public abstract void run();
protected void assertNoObsoleteInExemptList(String listName, List<String> list) {
final StringBuilder obsoleteExemptItems = new StringBuilder(listName).append(
" contains item that should not be exempted.\n");
for (String c : list) {
obsoleteExemptItems.append(c).append("\n");
}
assertWithMessage(obsoleteExemptItems.toString()).that(list).isEmpty();
}
protected boolean isConcreteSettingsClass(Class clazz) {
// Abstract classes
if (Modifier.isAbstract(clazz.getModifiers())) {
return false;
}
final String packageName = clazz.getPackage().getName();
// Classes that are not in Settings
if (!packageName.contains(PACKAGE_NAME + ".") && !packageName.endsWith(PACKAGE_NAME)) {
return false;
}
final String className = clazz.getName();
// Classes from tests
if (className.endsWith(TEST_CLASS_SUFFIX)) {
return false;
}
if (className.contains(TEST_INNER_CLASS_SIGNATURE)) {
return false;
}
return true;
}
public static void initializeExemptList(List<String> exemptList, String filename) {
try {
final InputStream in = ApplicationProvider.getApplicationContext()
.getAssets().open(filename);
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
exemptList.add(line);
}
} catch (Exception e) {
throw new IllegalArgumentException("Error initializing exempt list " + filename, e);
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2020 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.core.codeinspection;
import static org.junit.Assert.fail;
import android.util.ArraySet;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnAttach;
import com.android.settingslib.core.lifecycle.events.OnCreate;
import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnPrepareOptionsMenu;
import com.android.settingslib.core.lifecycle.events.OnResume;
import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.core.lifecycle.events.SetPreferenceScreen;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class LifecycleObserverCodeInspector extends CodeInspector {
private static final List<Class> LIFECYCLE_EVENTS = Arrays.asList(
OnAttach.class,
OnCreate.class,
OnCreateOptionsMenu.class,
OnDestroy.class,
OnOptionsItemSelected.class,
OnPause.class,
OnPrepareOptionsMenu.class,
OnResume.class,
OnSaveInstanceState.class,
OnStart.class,
OnStop.class,
SetPreferenceScreen.class
);
public LifecycleObserverCodeInspector(List<Class<?>> classes) {
super(classes);
}
@Override
public void run() {
final Set<String> notImplementingLifecycleObserver = new ArraySet<>();
for (Class clazz : mClasses) {
if (!isConcreteSettingsClass(clazz)) {
continue;
}
boolean classObservesLifecycleEvent = false;
for (Class event : LIFECYCLE_EVENTS) {
if (event.isAssignableFrom(clazz)) {
classObservesLifecycleEvent = true;
break;
}
}
if (classObservesLifecycleEvent && !LifecycleObserver.class.isAssignableFrom(clazz)) {
// Observes LifecycleEvent but not implementing LifecycleObserver. Something is
// wrong.
notImplementingLifecycleObserver.add(clazz.getName());
}
}
if (!notImplementingLifecycleObserver.isEmpty()) {
final String errorTemplate =
"The following class(es) implements lifecycle.events.*, but don't "
+ "implement LifecycleObserver. Something is wrong:\n";
final StringBuilder error = new StringBuilder(errorTemplate);
for (String name : notImplementingLifecycleObserver) {
error.append(name).append('\n');
}
fail(error.toString());
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2020 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.core.instrumentation;
import static com.google.common.truth.Truth.assertWithMessage;
import android.util.ArraySet;
import androidx.fragment.app.Fragment;
import com.android.settings.core.codeinspection.CodeInspector;
import com.android.settingslib.core.instrumentation.Instrumentable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* {@link CodeInspector} that verifies all fragments implements Instrumentable.
*/
public class InstrumentableFragmentCodeInspector extends CodeInspector {
private final List<String> mNotImplementingInstrumentableExemptList;
public InstrumentableFragmentCodeInspector(List<Class<?>> classes) {
super(classes);
mNotImplementingInstrumentableExemptList = new ArrayList<>();
initializeExemptList(mNotImplementingInstrumentableExemptList,
"exempt_not_implementing_instrumentable");
}
@Override
public void run() {
final Set<String> broken = new ArraySet<>();
for (Class clazz : mClasses) {
if (!isConcreteSettingsClass(clazz)) {
continue;
}
final String className = clazz.getName();
// If it's a fragment, it must also be instrumentable.
final boolean allowlisted =
mNotImplementingInstrumentableExemptList.remove(className);
if (Fragment.class.isAssignableFrom(clazz)
&& !Instrumentable.class.isAssignableFrom(clazz)
&& !allowlisted) {
broken.add(className);
}
}
final StringBuilder sb = new StringBuilder(
"All fragments should implement Instrumentable, but the following are not:\n");
for (String c : broken) {
sb.append(c).append("\n");
}
assertWithMessage(sb.toString()).that(broken.isEmpty()).isTrue();
assertNoObsoleteInExemptList("exempt_not_implementing_instrumentable",
mNotImplementingInstrumentableExemptList);
}
}

View File

@@ -0,0 +1,339 @@
/*
* Copyright (C) 2020 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.dashboard;
import static com.android.settingslib.drawer.CategoryKey.CATEGORY_HOMEPAGE;
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ProviderInfo;
import android.os.Bundle;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.drawer.ActivityTile;
import com.android.settingslib.drawer.CategoryKey;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.ProviderTile;
import com.android.settingslib.drawer.Tile;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.HashMap;
import java.util.Map;
@RunWith(AndroidJUnit4.class)
public class CategoryManagerTest {
private ActivityInfo mActivityInfo;
private Context mContext;
private CategoryManager mCategoryManager;
private Map<Pair<String, String>, Tile> mTileByComponentCache;
private Map<String, DashboardCategory> mCategoryByKeyMap;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mActivityInfo = new ActivityInfo();
mActivityInfo.packageName = "pkg";
mActivityInfo.name = "class";
mActivityInfo.applicationInfo = new ApplicationInfo();
mTileByComponentCache = new HashMap<>();
mCategoryByKeyMap = new HashMap<>();
mCategoryManager = CategoryManager.get(mContext);
}
@Test
public void getInstance_shouldBeSingleton() {
assertThat(mCategoryManager).isSameInstanceAs(CategoryManager.get(mContext));
}
@Test
public void backwardCompatCleanupForCategory_shouldNotChangeCategoryForNewKeys() {
final Tile tile1 = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_ACCOUNT);
final Tile tile2 = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_ACCOUNT);
final DashboardCategory category = new DashboardCategory(CategoryKey.CATEGORY_ACCOUNT);
category.addTile(tile1);
category.addTile(tile2);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_ACCOUNT, category);
mTileByComponentCache.put(new Pair<>("PACKAGE", "1"), tile1);
mTileByComponentCache.put(new Pair<>("PACKAGE", "2"), tile2);
mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
assertThat(mCategoryByKeyMap.size()).isEqualTo(1);
assertThat(mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT)).isNotNull();
}
@Test
public void backwardCompatCleanupForCategory_shouldNotChangeCategoryForMixedKeys() {
final Tile tile1 = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_ACCOUNT);
final String oldCategory = "com.android.settings.category.wireless";
final Tile tile2 = new ActivityTile(mActivityInfo, oldCategory);
final DashboardCategory category1 = new DashboardCategory(CategoryKey.CATEGORY_ACCOUNT);
category1.addTile(tile1);
final DashboardCategory category2 = new DashboardCategory(oldCategory);
category2.addTile(tile2);
mCategoryByKeyMap.put(CategoryKey.CATEGORY_ACCOUNT, category1);
mCategoryByKeyMap.put(oldCategory, category2);
mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tile1);
mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS2"), tile2);
mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
assertThat(
mCategoryByKeyMap.get(CategoryKey.CATEGORY_ACCOUNT).getTilesCount()).isEqualTo(1);
assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
}
@Test
public void backwardCompatCleanupForCategory_shouldChangeCategoryForOldKeys() {
final String oldCategory = "com.android.settings.category.wireless";
final Tile tile1 = new ActivityTile(mActivityInfo, oldCategory);
tile1.setCategory(oldCategory);
final DashboardCategory category1 = new DashboardCategory(oldCategory);
category1.addTile(tile1);
mCategoryByKeyMap.put(oldCategory, category1);
mTileByComponentCache.put(new Pair<>("PACKAGE", "CLASS1"), tile1);
mCategoryManager.backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap);
// Added 1 more category to category map.
assertThat(mCategoryByKeyMap.size()).isEqualTo(2);
// The new category map has CATEGORY_NETWORK type now, which contains 1 tile.
assertThat(
mCategoryByKeyMap.get(CategoryKey.CATEGORY_NETWORK).getTilesCount()).isEqualTo(1);
// Old category still exists.
assertThat(mCategoryByKeyMap.get(oldCategory).getTilesCount()).isEqualTo(1);
}
@Test
public void sortCategories_singlePackage_shouldReorderBasedOnPriority() {
// Create some fake tiles that are not sorted.
final String testPackage = "com.android.test";
final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE);
final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 100);
final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 50);
final Tile tile3 = createActivityTile(category.key, testPackage, "class3", 200);
category.addTile(tile1);
category.addTile(tile2);
category.addTile(tile3);
mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category);
// Sort their priorities
mCategoryManager.sortCategories(ApplicationProvider.getApplicationContext(),
mCategoryByKeyMap);
// Verify they are now sorted.
assertThat(category.getTile(0)).isSameInstanceAs(tile3);
assertThat(category.getTile(1)).isSameInstanceAs(tile1);
assertThat(category.getTile(2)).isSameInstanceAs(tile2);
}
@Test
public void sortCategories_multiPackage_shouldReorderBasedOnPackageAndPriority() {
// Create some fake tiles that are not sorted.
final String testPackage1 = "com.android.test1";
final String testPackage2 = "com.android.test2";
final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE);
final Tile tile1 = createActivityTile(category.key, testPackage2, "class1", 100);
final Tile tile2 = createActivityTile(category.key, testPackage1, "class2", 100);
final Tile tile3 = createActivityTile(category.key, testPackage1, "class3", 50);
category.addTile(tile1);
category.addTile(tile2);
category.addTile(tile3);
mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category);
// Sort their priorities
mCategoryManager.sortCategories(mContext, mCategoryByKeyMap);
// Verify they are now sorted.
assertThat(category.getTile(0)).isSameInstanceAs(tile2);
assertThat(category.getTile(1)).isSameInstanceAs(tile1);
assertThat(category.getTile(2)).isSameInstanceAs(tile3);
}
@Test
public void sortCategories_internalPackageTiles_shouldSkipTileForInternalPackage() {
// Create some fake tiles that are not sorted.
final String testPackage = mContext.getPackageName();
final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE);
final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 100);
final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 100);
final Tile tile3 = createActivityTile(category.key, testPackage, "class3", 50);
category.addTile(tile1);
category.addTile(tile2);
category.addTile(tile3);
mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category);
// Sort their priorities
mCategoryManager.sortCategories(mContext, mCategoryByKeyMap);
// Verify the sorting order is not changed
assertThat(category.getTile(0)).isSameInstanceAs(tile1);
assertThat(category.getTile(1)).isSameInstanceAs(tile2);
assertThat(category.getTile(2)).isSameInstanceAs(tile3);
}
@Test
public void sortCategories_internalAndExternalPackageTiles_shouldRetainPriorityOrdering() {
// Inject one external tile among internal tiles.
final String testPackage = mContext.getPackageName();
final String testPackage2 = "com.google.test2";
final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE);
final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 2);
final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 1);
final Tile tile3 = createActivityTile(category.key, testPackage2, "class0", 0);
final Tile tile4 = createActivityTile(category.key, testPackage, "class3", -1);
category.addTile(tile1);
category.addTile(tile2);
category.addTile(tile3);
category.addTile(tile4);
mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category);
// Sort their priorities
mCategoryManager.sortCategories(mContext, mCategoryByKeyMap);
// Verify the sorting order is not changed
assertThat(category.getTile(0)).isSameInstanceAs(tile1);
assertThat(category.getTile(1)).isSameInstanceAs(tile2);
assertThat(category.getTile(2)).isSameInstanceAs(tile3);
assertThat(category.getTile(3)).isSameInstanceAs(tile4);
}
@Test
public void sortCategories_samePriority_internalPackageTileShouldTakePrecedence() {
// Inject one external tile among internal tiles with same priority.
final String testPackage = mContext.getPackageName();
final String testPackage2 = "com.google.test2";
final String testPackage3 = "com.abcde.test3";
final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE);
final Tile tile1 = createActivityTile(category.key, testPackage2, "class1", 1);
final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 1);
final Tile tile3 = createActivityTile(category.key, testPackage3, "class3", 1);
category.addTile(tile1);
category.addTile(tile2);
category.addTile(tile3);
mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category);
// Sort their priorities
mCategoryManager.sortCategories(mContext, mCategoryByKeyMap);
// Verify the sorting order is internal first, follow by package name ordering
assertThat(category.getTile(0)).isSameInstanceAs(tile2);
assertThat(category.getTile(1)).isSameInstanceAs(tile3);
assertThat(category.getTile(2)).isSameInstanceAs(tile1);
}
@Test
public void filterTiles_noDuplicate_noChange() {
// Create some unique tiles
final String testPackage = mContext.getPackageName();
final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE);
final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 100);
final Tile tile2 = createActivityTile(category.key, testPackage, "class2", 100);
final Tile tile3 = createActivityTile(category.key, testPackage, "class3", 50);
final Tile tile4 = createProviderTile(category.key, testPackage, "class1", "authority1",
"key1", 100);
final Tile tile5 = createProviderTile(category.key, testPackage, "class1", "authority2",
"key2", 100);
final Tile tile6 = createProviderTile(category.key, testPackage, "class1", "authority1",
"key2", 50);
category.addTile(tile1);
category.addTile(tile2);
category.addTile(tile3);
category.addTile(tile4);
category.addTile(tile5);
category.addTile(tile6);
mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category);
mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
assertThat(category.getTilesCount()).isEqualTo(6);
}
@Test
public void filterTiles_hasDuplicateActivityTiles_shouldOnlyKeepUniqueTiles() {
// Create tiles pointing to same intent.
final String testPackage = mContext.getPackageName();
final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE);
final Tile tile1 = createActivityTile(category.key, testPackage, "class1", 100);
final Tile tile2 = createActivityTile(category.key, testPackage, "class1", 100);
final Tile tile3 = createActivityTile(category.key, testPackage, "class1", 50);
category.addTile(tile1);
category.addTile(tile2);
category.addTile(tile3);
mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category);
mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
assertThat(category.getTilesCount()).isEqualTo(1);
}
@Test
public void filterTiles_hasDuplicateProviderTiles_shouldOnlyKeepUniqueTiles() {
// Create tiles pointing to same authority and key.
final String testPackage = mContext.getPackageName();
final DashboardCategory category = new DashboardCategory(CATEGORY_HOMEPAGE);
final Tile tile1 = createProviderTile(category.key, testPackage, "class1", "authority1",
"key1", 100);
final Tile tile2 = createProviderTile(category.key, testPackage, "class2", "authority1",
"key1", 100);
final Tile tile3 = createProviderTile(category.key, testPackage, "class3", "authority1",
"key1", 50);
category.addTile(tile1);
category.addTile(tile2);
category.addTile(tile3);
mCategoryByKeyMap.put(CATEGORY_HOMEPAGE, category);
mCategoryManager.filterDuplicateTiles(mCategoryByKeyMap);
assertThat(category.getTilesCount()).isEqualTo(1);
}
private Tile createActivityTile(String categoryKey, String packageName, String className,
int order) {
final ActivityInfo activityInfo = new ActivityInfo();
activityInfo.packageName = packageName;
activityInfo.name = className;
activityInfo.metaData = new Bundle();
activityInfo.metaData.putInt(META_DATA_KEY_ORDER, order);
return new ActivityTile(activityInfo, categoryKey);
}
private Tile createProviderTile(String categoryKey, String packageName, String className,
String authority, String key, int order) {
final ProviderInfo providerInfo = new ProviderInfo();
final Bundle metaData = new Bundle();
providerInfo.packageName = packageName;
providerInfo.name = className;
providerInfo.authority = authority;
metaData.putString(META_DATA_PREFERENCE_KEYHINT, key);
metaData.putInt(META_DATA_KEY_ORDER, order);
return new ProviderTile(providerInfo, categoryKey, metaData);
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2020 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.dashboard;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.accounts.AccountDashboardFragment;
import com.android.settingslib.drawer.CategoryKey;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class DashboardFragmentRegistryTest {
@Test
public void pageAndKeyShouldHave1to1Mapping() {
assertThat(DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP.size())
.isEqualTo(DashboardFragmentRegistry.PARENT_TO_CATEGORY_KEY_MAP.size());
}
@Test
public void accountDetailCategoryShouldRedirectToAccountDashboardFragment() {
final String fragment = DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP.get(
CategoryKey.CATEGORY_ACCOUNT_DETAIL);
assertThat(fragment).isEqualTo(AccountDashboardFragment.class.getName());
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2020 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.dashboard;
import android.content.Context;
import androidx.fragment.app.Fragment;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerListHelper;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.List;
public class DashboardFragmentSearchIndexProviderInspector {
public static boolean isSharingPreferenceControllers(Class clazz) {
final Context context = ApplicationProvider.getApplicationContext();
final Fragment fragment;
try {
fragment = Fragment.instantiate(context, clazz.getName());
} catch (Throwable e) {
// Can't do much with exception, assume the test passed.
return true;
}
if (!(fragment instanceof DashboardFragment)) {
return true;
}
final BaseSearchIndexProvider provider =
(BaseSearchIndexProvider) DatabaseIndexingUtils.getSearchIndexProvider(clazz);
if (provider == null) {
return true;
}
final List<AbstractPreferenceController> controllersFromSearchIndexProvider;
final List<AbstractPreferenceController> controllersFromFragment;
try {
controllersFromSearchIndexProvider = provider.getPreferenceControllers(context);
} catch (Throwable e) {
// Can't do much with exception, assume the test passed.
return true;
}
try {
controllersFromFragment =
((DashboardFragment) fragment).createPreferenceControllers(context);
List<BasePreferenceController> controllersFromXml = PreferenceControllerListHelper
.getPreferenceControllersFromXml(context,
((DashboardFragment) fragment).getPreferenceScreenResId());
final List<BasePreferenceController> uniqueControllerFromXml =
PreferenceControllerListHelper.filterControllers(
controllersFromXml, controllersFromFragment);
controllersFromFragment.addAll(uniqueControllerFromXml);
} catch (Throwable e) {
// Can't do much with exception, assume the test passed.
return true;
}
if (controllersFromFragment == controllersFromSearchIndexProvider) {
return true;
} else if (controllersFromFragment != null && controllersFromSearchIndexProvider != null) {
return controllersFromFragment.size() == controllersFromSearchIndexProvider.size();
} else {
return false;
}
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright (C) 2016 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.dashboard;
import android.content.res.Resources;
import android.view.View;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
/***
* Matches on the first view with id if there are multiple views using the same Id.
*/
public class FirstIdViewMatcher {
public static Matcher<View> withFirstId(final int id) {
return new TypeSafeMatcher<View>() {
Resources resources = null;
private boolean mMatched;
public void describeTo(Description description) {
String idDescription = Integer.toString(id);
if (resources != null) {
try {
idDescription = resources.getResourceName(id);
} catch (Resources.NotFoundException e) {
// No big deal, will just use the int value.
idDescription = String.format("%s (resource name not found)", id);
}
}
description.appendText("with first id: " + idDescription);
}
public boolean matchesSafely(View view) {
this.resources = view.getResources();
if (mMatched) {
return false;
} else {
mMatched = id == view.getId();
return mMatched;
}
}
};
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright (C) 2016 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.dashboard;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static org.hamcrest.Matchers.allOf;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import androidx.test.InstrumentationRegistry;
import androidx.test.espresso.matcher.ViewMatchers.Visibility;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PreferenceThemeTest {
private Instrumentation mInstrumentation;
private Context mTargetContext;
private String mTargetPackage;
@Before
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mTargetContext = mInstrumentation.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
}
@Test
public void startSetupWizardLockScreen_preferenceIconSpaceNotReserved() {
launchSetupWizardLockScreen();
// Icons should not be shown, and the frame should not occupy extra space.
onView(allOf(withId(R.id.icon_frame), withEffectiveVisibility(Visibility.VISIBLE)))
.check(doesNotExist());
onView(withId(R.id.icon_container)).check(doesNotExist());
}
private void launchSetupWizardLockScreen() {
final Intent settingsIntent = new Intent("com.android.settings.SETUP_LOCK_SCREEN")
.addCategory(Intent.CATEGORY_DEFAULT)
.setPackage(mTargetPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
InstrumentationRegistry.getInstrumentation().startActivitySync(settingsIntent);
}
}

View File

@@ -1,69 +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.dashboard;
import static com.google.common.truth.Truth.assertThat;
import android.app.Instrumentation;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class UiBlockerControllerTest {
private static final long TIMEOUT = 600;
private static final String KEY_1 = "key1";
private static final String KEY_2 = "key2";
private Instrumentation mInstrumentation;
private UiBlockerController mSyncableController;
@Before
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mSyncableController = new UiBlockerController(Arrays.asList(KEY_1, KEY_2));
}
@Test
public void start_isSyncedReturnFalseUntilAllWorkDone() throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
mSyncableController.start(() -> latch.countDown());
// Return false at first
assertThat(mSyncableController.isBlockerFinished()).isFalse();
// Return false if only one job is done
mSyncableController.countDown(KEY_1);
assertThat(mSyncableController.isBlockerFinished()).isFalse();
// Return true if all jobs done
mSyncableController.countDown(KEY_2);
assertThat(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue();
assertThat(mSyncableController.isBlockerFinished()).isTrue();
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2021 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.dashboard.profileselector;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.os.Looper;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class ProfileSelectStorageFragmentTest {
private ProfileSelectStorageFragment mFragment;
@Before
@UiThreadTest
public void setUp() {
MockitoAnnotations.initMocks(this);
if (Looper.myLooper() == null) {
Looper.prepare();
}
mFragment = new ProfileSelectStorageFragment();
}
@Test
@UiThreadTest
public void test_initializeOptionsMenuInvalidatesExistingMenu() {
final Activity activity = mock(Activity.class);
mFragment.initializeOptionsMenu(activity);
verify(activity).invalidateOptionsMenu();
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2020 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.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.util.ArraySet;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class AppPrefLoaderTest {
@Mock
private PackageManager mPackageManager;
private AppPrefLoader mLoader;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
final ArraySet<String> pkgs = new ArraySet<>(2);
pkgs.add("pkg0");
pkgs.add("pkg1");
mLoader = new AppPrefLoader(
ApplicationProvider.getApplicationContext(), pkgs, mPackageManager);
}
@Test
public void loadInBackground_packageNotFound_shouldReturnEmptySet()
throws NameNotFoundException {
when(mPackageManager.getApplicationInfo(anyString(), anyInt()))
.thenThrow(new NameNotFoundException());
assertThat(mLoader.loadInBackground()).isEmpty();
}
@Test
public void loadInBackground_shouldReturnPreference() throws NameNotFoundException {
ApplicationInfo info = mock(ApplicationInfo.class);
when(mPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn(info);
final Drawable drawable = mock(Drawable.class);
final String label = "Label1";
when(info.loadIcon(mPackageManager)).thenReturn(drawable);
when(info.loadLabel(mPackageManager)).thenReturn(label);
Preference preference = mLoader.loadInBackground().valueAt(0);
assertThat(preference.getTitle()).isEqualTo(label);
assertThat(preference.getIcon()).isEqualTo(drawable);
assertThat(preference.isSelectable()).isFalse();
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2020 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.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.telephony.SubscriptionInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class CellDataPreferenceTest {
@Mock
private SubscriptionInfo mSubInfo;
private Context mContext;
private CellDataPreference mPreference;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mPreference = new CellDataPreference(mContext, null) {
@Override
SubscriptionInfo getActiveSubscriptionInfo(int subId) {
return mSubInfo;
}
};
final LayoutInflater inflater = LayoutInflater.from(mContext);
final View view = inflater.inflate(mPreference.getLayoutResource(),
new LinearLayout(mContext), false);
}
@Test
public void updateEnabled_noActiveSub_shouldDisable() {
mSubInfo = null;
mPreference.mOnSubscriptionsChangeListener.onChanged();
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
public void updateEnabled_hasActiveSub_shouldEnable() {
mPreference.mOnSubscriptionsChangeListener.onChanged();
assertThat(mPreference.isEnabled()).isTrue();
}
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2020 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.google.common.truth.Truth.assertThat;
import android.net.NetworkPolicy;
import android.net.NetworkTemplate;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.net.DataUsageController.DataUsageInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class DataUsageInfoControllerTest {
private static final int NEGATIVE = -1;
private static final int ZERO = 0;
private static final int POSITIVE_SMALL = 1;
private static final int POSITIVE_LARGE = 5;
private DataUsageInfoController mInfoController;
private DataUsageInfo info;
@Before
public void setUp() {
mInfoController = new DataUsageInfoController();
info = new DataUsageInfo();
}
@Test
public void getSummaryLimit_LowUsageLowWarning_LimitUsed() {
info.warningLevel = POSITIVE_SMALL;
info.limitLevel = POSITIVE_LARGE;
info.usageLevel = POSITIVE_SMALL;
assertThat(mInfoController.getSummaryLimit(info)).isEqualTo(info.limitLevel);
}
@Test
public void getSummaryLimit_LowUsageEqualWarning_LimitUsed() {
info.warningLevel = POSITIVE_LARGE;
info.limitLevel = POSITIVE_LARGE;
info.usageLevel = POSITIVE_SMALL;
assertThat(mInfoController.getSummaryLimit(info)).isEqualTo(info.limitLevel);
}
@Test
public void getSummaryLimit_NoLimitNoUsage_WarningUsed() {
info.warningLevel = POSITIVE_LARGE;
info.limitLevel = ZERO;
info.usageLevel = ZERO;
assertThat(mInfoController.getSummaryLimit(info)).isEqualTo(info.warningLevel);
}
@Test
public void getSummaryLimit_NoLimitLowUsage_WarningUsed() {
info.warningLevel = POSITIVE_LARGE;
info.limitLevel = ZERO;
info.usageLevel = POSITIVE_SMALL;
assertThat(mInfoController.getSummaryLimit(info)).isEqualTo(info.warningLevel);
}
@Test
public void getSummaryLimit_LowWarningNoLimit_UsageUsed() {
info.warningLevel = POSITIVE_SMALL;
info.limitLevel = ZERO;
info.usageLevel = POSITIVE_LARGE;
assertThat(mInfoController.getSummaryLimit(info)).isEqualTo(info.usageLevel);
}
@Test
public void getSummaryLimit_LowWarningLowLimit_UsageUsed() {
info.warningLevel = POSITIVE_SMALL;
info.limitLevel = POSITIVE_SMALL;
info.usageLevel = POSITIVE_LARGE;
assertThat(mInfoController.getSummaryLimit(info)).isEqualTo(info.usageLevel);
}
private NetworkPolicy getDefaultNetworkPolicy() {
NetworkTemplate template = NetworkTemplate.buildTemplateWifi(
NetworkTemplate.WIFI_NETWORKID_ALL, null /* subscriberId */);
int cycleDay = -1;
String cycleTimezone = "UTC";
long warningBytes = -1;
long limitBytes = -1;
return new NetworkPolicy(template, cycleDay, cycleTimezone, warningBytes, limitBytes, true);
}
@Test
public void updateDataLimit_NullArguments_NoError() {
mInfoController.updateDataLimit(null, null);
mInfoController.updateDataLimit(info, null);
mInfoController.updateDataLimit(null, getDefaultNetworkPolicy());
}
@Test
public void updateDataLimit_NegativeWarning_UpdatedToZero() {
NetworkPolicy policy = getDefaultNetworkPolicy();
policy.warningBytes = NEGATIVE;
mInfoController.updateDataLimit(info, policy);
assertThat(info.warningLevel).isEqualTo(ZERO);
}
@Test
public void updateDataLimit_WarningZero_UpdatedToZero() {
NetworkPolicy policy = getDefaultNetworkPolicy();
policy.warningBytes = ZERO;
mInfoController.updateDataLimit(info, policy);
assertThat(info.warningLevel).isEqualTo(ZERO);
}
@Test
public void updateDataLimit_WarningPositive_UpdatedToWarning() {
NetworkPolicy policy = getDefaultNetworkPolicy();
policy.warningBytes = POSITIVE_SMALL;
mInfoController.updateDataLimit(info, policy);
assertThat(info.warningLevel).isEqualTo(policy.warningBytes);
}
@Test
public void updateDataLimit_LimitNegative_UpdatedToZero() {
NetworkPolicy policy = getDefaultNetworkPolicy();
policy.limitBytes = NEGATIVE;
mInfoController.updateDataLimit(info, policy);
assertThat(info.limitLevel).isEqualTo(ZERO);
}
@Test
public void updateDataLimit_LimitZero_UpdatedToZero() {
NetworkPolicy policy = getDefaultNetworkPolicy();
policy.limitBytes = ZERO;
mInfoController.updateDataLimit(info, policy);
assertThat(info.limitLevel).isEqualTo(ZERO);
}
@Test
public void updateDataLimit_LimitPositive_UpdatedToLimit() {
NetworkPolicy policy = getDefaultNetworkPolicy();
policy.limitBytes = POSITIVE_SMALL;
mInfoController.updateDataLimit(info, policy);
assertThat(info.limitLevel).isEqualTo(policy.limitBytes);
}
}

View File

@@ -0,0 +1,573 @@
/*
* Copyright (C) 2020 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.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.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.net.ConnectivityManager;
import android.net.NetworkTemplate;
import android.os.Bundle;
import android.telephony.SubscriptionManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.SettingsActivity;
import com.android.settings.testutils.ResourcesUtils;
import com.android.settingslib.Utils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class DataUsageSummaryPreferenceTest {
private static final long CYCLE_DURATION_MILLIS = 1000000000L;
private static final long UPDATE_LAG_MILLIS = 10000000L;
private static final String FAKE_CARRIER = "z-mobile";
private Context mContext;
private Resources mResources;
private PreferenceViewHolder mHolder;
private DataUsageSummaryPreference mSummaryPreference;
private long mCycleEnd;
private long mUpdateTime;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
mResources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(mResources);
mSummaryPreference = spy(new DataUsageSummaryPreference(mContext, null /* attrs */));
LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
View view = inflater.inflate(
mSummaryPreference.getLayoutResource(),
null /* root */, false /* attachToRoot */);
mHolder = spy(PreferenceViewHolder.createInstanceForTests(view));
assertThat(mSummaryPreference.getDataUsed(mHolder)).isNotNull();
final long now = System.currentTimeMillis();
mCycleEnd = now + CYCLE_DURATION_MILLIS;
mUpdateTime = now - UPDATE_LAG_MILLIS;
}
@UiThreadTest
@Test
public void testSetUsageInfo_withLaunchIntent_launchButtonShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getLaunchButton(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
}
@Test
public void testSetUsageInfo_withoutLaunchIntent_launchButtonNotShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
null /* launchIntent */);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getLaunchButton(mHolder).getVisibility())
.isEqualTo(View.GONE);
}
@Test
public void testSetUsageInfo_withDataPlans_carrierInfoShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
}
@Test
public void testSetUsageInfo_withNoDataPlans_carrierInfoNotShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getVisibility())
.isEqualTo(View.GONE);
}
@Test
public void testCarrierUpdateTime_shouldFormatDaysCorrectly() {
int baseUnit = 2;
int smudge = 6;
final long updateTime = System.currentTimeMillis()
- TimeUnit.DAYS.toMillis(baseUnit) - TimeUnit.HOURS.toMillis(smudge);
mSummaryPreference.setUsageInfo(mCycleEnd, updateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getText().toString())
.isEqualTo("Updated by " + FAKE_CARRIER + " " + baseUnit + " days ago");
}
@Test
public void testCarrierUpdateTime_shouldFormatHoursCorrectly() {
int baseUnit = 2;
int smudge = 6;
final long updateTime = System.currentTimeMillis()
- TimeUnit.HOURS.toMillis(baseUnit) - TimeUnit.MINUTES.toMillis(smudge);
mSummaryPreference.setUsageInfo(mCycleEnd, updateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getText().toString())
.isEqualTo("Updated by " + FAKE_CARRIER + " " + baseUnit + " hr ago");
}
@Test
public void testCarrierUpdateTime_shouldFormatMinutesCorrectly() {
int baseUnit = 2;
int smudge = 6;
final long updateTime = System.currentTimeMillis()
- TimeUnit.MINUTES.toMillis(baseUnit) - TimeUnit.SECONDS.toMillis(smudge);
mSummaryPreference.setUsageInfo(mCycleEnd, updateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getText().toString())
.isEqualTo("Updated by " + FAKE_CARRIER + " " + baseUnit + " min ago");
}
@Test
public void testCarrierUpdateTime_shouldFormatLessThanMinuteCorrectly() {
final long updateTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(45);
mSummaryPreference.setUsageInfo(mCycleEnd, updateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getText().toString())
.isEqualTo("Updated by " + FAKE_CARRIER + " just now");
}
@Test
public void testCarrierUpdateTimeWithNoCarrier_shouldSayJustNow() {
final long updateTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(45);
mSummaryPreference.setUsageInfo(mCycleEnd, updateTime, null /* carrier */,
1 /* numPlans */, new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getText().toString())
.isEqualTo("Updated just now");
}
@Test
public void testCarrierUpdateTimeWithNoCarrier_shouldFormatTime() {
final long updateTime = System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(2);
mSummaryPreference.setUsageInfo(mCycleEnd, updateTime, null /* carrier */,
1 /* numPlans */, new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getText().toString())
.isEqualTo("Updated 2 min ago");
}
@Test
public void setUsageInfo_withRecentCarrierUpdate_doesNotSetCarrierInfoWarningColorAndFont() {
final long updateTime = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
mSummaryPreference.setUsageInfo(mCycleEnd, updateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
TextView carrierInfo = mSummaryPreference.getCarrierInfo(mHolder);
assertThat(carrierInfo.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(carrierInfo.getCurrentTextColor()).isEqualTo(
Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorSecondary));
assertThat(carrierInfo.getTypeface()).isEqualTo(Typeface.SANS_SERIF);
}
@Test
public void testSetUsageInfo_withStaleCarrierUpdate_setsCarrierInfoWarningColorAndFont() {
final long updateTime = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(7);
mSummaryPreference.setUsageInfo(mCycleEnd, updateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
TextView carrierInfo = mSummaryPreference.getCarrierInfo(mHolder);
assertThat(carrierInfo.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(carrierInfo.getCurrentTextColor()).isEqualTo(
Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorError));
assertThat(carrierInfo.getTypeface()).isEqualTo(
DataUsageSummaryPreference.SANS_SERIF_MEDIUM);
}
@Test
public void testSetUsageInfo_withNoDataPlans_usageTitleNotShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getUsageTitle(mHolder).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetUsageInfo_withMultipleDataPlans_usageTitleShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 2 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getUsageTitle(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
}
@Test
public void testSetUsageInfo_cycleRemainingTimeIsLessOneDay() {
// just under one day
final long cycleEnd = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(23);
mSummaryPreference.setUsageInfo(cycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCycleTime(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getCycleTime(mHolder).getText()).isEqualTo(
ResourcesUtils.getResourcesString(
mContext, "billing_cycle_less_than_one_day_left"));
}
@Test
public void testSetUsageInfo_cycleRemainingTimeNegativeDaysLeft_shouldDisplayNoneLeft() {
final long cycleEnd = System.currentTimeMillis() - 1L;
mSummaryPreference.setUsageInfo(cycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCycleTime(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getCycleTime(mHolder).getText()).isEqualTo(
ResourcesUtils.getResourcesString(mContext, "billing_cycle_none_left"));
}
@Test
public void testSetUsageInfo_cycleRemainingTimeDaysLeft_shouldUsePlurals() {
final int daysLeft = 3;
final long cycleEnd = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(daysLeft)
+ TimeUnit.HOURS.toMillis(1);
mSummaryPreference.setUsageInfo(cycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
new Intent());
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getCycleTime(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getCycleTime(mHolder).getText())
.isEqualTo(daysLeft + " days left");
}
@Test
public void testSetLimitInfo_withLimitInfo_dataLimitsShown() {
final String limitText = "test limit text";
mSummaryPreference.setLimitInfo(limitText);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getDataLimits(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getDataLimits(mHolder).getText()).isEqualTo(limitText);
}
@Test
public void testSetLimitInfo_withNullLimitInfo_dataLimitsNotShown() {
mSummaryPreference.setLimitInfo(null);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getDataLimits(mHolder).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetLimitInfo_withEmptyLimitInfo_dataLimitsNotShown() {
final String emptyLimitText = "";
mSummaryPreference.setLimitInfo(emptyLimitText);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getDataLimits(mHolder).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetChartEnabledFalse_hidesLabelBar() {
setValidLabels();
mSummaryPreference.setChartEnabled(false);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getLabelBar(mHolder).getVisibility()).isEqualTo(View.GONE);
assertThat(mSummaryPreference.getProgressBar(mHolder).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetEmptyLabels_hidesLabelBar() {
mSummaryPreference.setLabels("", "");
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getLabelBar(mHolder).getVisibility()).isEqualTo(View.GONE);
assertThat(mSummaryPreference.getProgressBar(mHolder).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testLabelBar_isVisible_whenLabelsSet() {
setValidLabels();
//mChartEnabled defaults to true
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getLabelBar(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getProgressBar(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
}
@Test
public void testSetProgress_updatesProgressBar() {
setValidLabels();
mSummaryPreference.setProgress(.5f);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getProgressBar(mHolder).getProgress()).isEqualTo(50);
}
private void setValidLabels() {
mSummaryPreference.setLabels("0.0 GB", "5.0 GB");
}
@Test
public void testSetUsageAndRemainingInfo_withUsageInfo_dataUsageAndRemainingShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.setUsageNumbers(
BillingCycleSettings.MIB_IN_BYTES,
10 * BillingCycleSettings.MIB_IN_BYTES,
true /* hasMobileData */);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getDataUsed(mHolder).getText().toString())
.isEqualTo("1.00 MB used");
assertThat(mSummaryPreference.getDataRemaining(mHolder).getText().toString())
.isEqualTo("9.00 MB left");
assertThat(mSummaryPreference.getDataRemaining(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
final int colorId = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorAccent);
assertThat(mSummaryPreference.getDataRemaining(mHolder).getCurrentTextColor())
.isEqualTo(colorId);
}
@Test
public void testSetUsageInfo_withDataOverusage() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.setUsageNumbers(
11 * BillingCycleSettings.MIB_IN_BYTES,
10 * BillingCycleSettings.MIB_IN_BYTES,
true /* hasMobileData */);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getDataUsed(mHolder).getText().toString())
.isEqualTo("11.00 MB used");
assertThat(mSummaryPreference.getDataRemaining(mHolder).getText().toString())
.isEqualTo("1.00 MB over");
final int colorId = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorError);
assertThat(mSummaryPreference.getDataRemaining(mHolder).getCurrentTextColor())
.isEqualTo(colorId);
}
@Test
public void testSetUsageInfo_withUsageInfo_dataUsageShown() {
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
new Intent());
mSummaryPreference.setUsageNumbers(
BillingCycleSettings.MIB_IN_BYTES, -1L, true /* hasMobileData */);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getDataUsed(mHolder).getText().toString())
.isEqualTo("1.00 MB used");
assertThat(mSummaryPreference.getDataRemaining(mHolder).getText()).isEqualTo("");
}
@Test
public void testSetAppIntent_toMdpApp_intentCorrect() {
final Intent intent = new Intent(SubscriptionManager.ACTION_MANAGE_SUBSCRIPTION_PLANS);
intent.setPackage("test-owner.example.com");
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 42);
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
intent);
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getLaunchButton(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getLaunchButton(mHolder).getText())
.isEqualTo(ResourcesUtils.getResourcesString(mContext, "launch_mdp_app_text"));
doNothing().when(mContext).startActivity(any(Intent.class));
mSummaryPreference.getLaunchButton(mHolder).callOnClick();
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(
Intent.class);
verify(mContext).startActivity(intentCaptor.capture());
final Intent startedIntent = intentCaptor.getValue();
assertThat(startedIntent.getAction())
.isEqualTo(SubscriptionManager.ACTION_MANAGE_SUBSCRIPTION_PLANS);
assertThat(startedIntent.getPackage()).isEqualTo("test-owner.example.com");
assertThat(startedIntent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, -1))
.isEqualTo(42);
}
@Test
public void testSetUsageInfo_withOverflowStrings_dataRemainingNotShown() {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(mSummaryPreference.getLayoutResource(), null /* root */,
false /* attachToRoot */);
mSummaryPreference.setUsageInfo(mCycleEnd, mUpdateTime, FAKE_CARRIER, 1 /* numPlans */,
new Intent());
mSummaryPreference.setUsageNumbers(
BillingCycleSettings.MIB_IN_BYTES,
10 * BillingCycleSettings.MIB_IN_BYTES,
true /* hasMobileData */);
int data_used_formatted_id = ResourcesUtils.getResourcesId(
mContext, "string", "data_used_formatted");
int data_remaining_id = ResourcesUtils.getResourcesId(
mContext, "string", "data_remaining");
CharSequence data_used_formatted_cs = "^1 ^2 used with long trailing text";
CharSequence data_remaining_cs = "^1 left";
doReturn(data_used_formatted_cs).when(mResources).getText(data_used_formatted_id);
doReturn(data_remaining_cs).when(mResources).getText(data_remaining_id);
mSummaryPreference.onBindViewHolder(mHolder);
TextView dataUsed = mSummaryPreference.getDataUsed(mHolder);
TextView dataRemaining = mSummaryPreference.getDataRemaining(mHolder);
int width = MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY);
dataUsed.measure(width, MeasureSpec.UNSPECIFIED);
dataRemaining.measure(width, MeasureSpec.UNSPECIFIED);
assertThat(dataRemaining.getVisibility()).isEqualTo(View.VISIBLE);
MeasurableLinearLayout layout = mSummaryPreference.getLayout(mHolder);
layout.measure(
MeasureSpec.makeMeasureSpec(800, View.MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY));
assertThat(dataUsed.getText().toString()).isEqualTo("1.00 MB used with long trailing text");
// TODO(b/175389659): re-enable this line once cuttlefish device specs are verified.
// assertThat(dataRemaining.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void testSetWifiMode_withUsageInfo_dataUsageShown() {
final int daysLeft = 3;
final long cycleEnd = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(daysLeft)
+ TimeUnit.HOURS.toMillis(1);
mSummaryPreference.setUsageInfo(cycleEnd, mUpdateTime, FAKE_CARRIER, 0 /* numPlans */,
new Intent());
mSummaryPreference.setUsageNumbers(1000000L, -1L, true);
final String cycleText = "The quick fox";
mSummaryPreference.setWifiMode(true /* isWifiMode */, cycleText, false /* isSingleWifi */);
doReturn(200L).when(mSummaryPreference).getHistoricalUsageLevel();
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getUsageTitle(mHolder).getText().toString())
.isEqualTo(ResourcesUtils.getResourcesString(mContext, "data_usage_wifi_title"));
assertThat(mSummaryPreference.getUsageTitle(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getCycleTime(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getCycleTime(mHolder).getText()).isEqualTo(cycleText);
assertThat(mSummaryPreference.getCarrierInfo(mHolder).getVisibility()).isEqualTo(View.GONE);
assertThat(mSummaryPreference.getDataLimits(mHolder).getVisibility()).isEqualTo(View.GONE);
assertThat(mSummaryPreference.getLaunchButton(mHolder).getVisibility())
.isEqualTo(View.VISIBLE);
assertThat(mSummaryPreference.getLaunchButton(mHolder).getText())
.isEqualTo(ResourcesUtils.getResourcesString(mContext, "launch_wifi_text"));
doNothing().when(mContext).startActivity(any(Intent.class));
mSummaryPreference.getLaunchButton(mHolder).callOnClick();
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(
Intent.class);
verify(mContext).startActivity(intentCaptor.capture());
final Intent startedIntent = intentCaptor.getValue();
final Bundle expect = new Bundle(1);
expect.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE,
NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL,
null /* subscriberId */));
final Bundle actual = startedIntent
.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
assertThat((NetworkTemplate) actual.getParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE))
.isEqualTo(NetworkTemplate.buildTemplateWifi(
NetworkTemplate.WIFI_NETWORKID_ALL, null /* subscriberId */));
assertThat(startedIntent.getIntExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, 0))
.isEqualTo(ResourcesUtils.getResourcesId(mContext, "string", "wifi_data_usage"));
}
@UiThreadTest
@Test
public void testSetWifiMode_noUsageInfo_shouldDisableLaunchButton() {
mSummaryPreference.setWifiMode(true /* isWifiMode */, "Test cycle text",
false /* isSingleWifi */);
doReturn(0L).when(mSummaryPreference).getHistoricalUsageLevel();
mSummaryPreference.onBindViewHolder(mHolder);
assertThat(mSummaryPreference.getLaunchButton(mHolder).isEnabled()).isFalse();
}
@Test
public void launchWifiDataUsage_shouldSetWifiNetworkTypeInIntentExtra() {
doNothing().when(mContext).startActivity(any(Intent.class));
mSummaryPreference.launchWifiDataUsage(mContext);
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(
Intent.class);
verify(mContext).startActivity(intentCaptor.capture());
final Intent launchIntent = intentCaptor.getValue();
final Bundle args =
launchIntent.getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
assertThat(args.getInt(DataUsageList.EXTRA_NETWORK_TYPE))
.isEqualTo(ConnectivityManager.TYPE_WIFI);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 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.datetime.timezone;
import static com.google.common.truth.Truth.assertThat;
import android.icu.text.Collator;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.datetime.timezone.RegionZonePicker.TimeZoneInfoComparator;
import com.android.settings.datetime.timezone.TimeZoneInfo.Formatter;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@RunWith(AndroidJUnit4.class)
public class RegionZonePickerTest {
@Test
public void compareTimeZoneInfo_matchGmtOrder() {
Date now = new Date(0); // 00:00 1, Jan 1970
Formatter formatter = new Formatter(Locale.US, now);
TimeZoneInfo timeZone1 = formatter.format("Pacific/Honolulu");
TimeZoneInfo timeZone2 = formatter.format("America/Los_Angeles");
TimeZoneInfo timeZone3 = formatter.format("America/Indiana/Marengo");
TimeZoneInfo timeZone4 = formatter.format("America/New_York");
TimeZoneInfoComparator comparator =
new TimeZoneInfoComparator(Collator.getInstance(Locale.US), now);
// Verify the sorted order
List<TimeZoneInfo> list = Arrays.asList(timeZone4, timeZone2, timeZone3, timeZone1);
Collections.sort(list, comparator);
assertThat(list).isEqualTo(Arrays.asList(timeZone1, timeZone2, timeZone3, timeZone4));
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2020 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.datetime.timezone;
import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.datetime.timezone.TimeZoneInfo.Formatter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Date;
import java.util.Locale;
@RunWith(AndroidJUnit4.class)
public class TimeZoneInfoPreferenceControllerTest {
private TimeZoneInfo mTimeZoneInfo;
private TimeZoneInfoPreferenceController mController;
@Before
public void setUp() {
final Context context = ApplicationProvider.getApplicationContext();
final Date now = new Date(0L); // 00:00 1/1/1970
final Formatter formatter = new Formatter(Locale.US, now);
mTimeZoneInfo = formatter.format("America/Los_Angeles");
mController = new TimeZoneInfoPreferenceController(context, "key");
mController.mDate = now;
mController.setTimeZoneInfo(mTimeZoneInfo);
}
@Test
public void getSummary_matchExpectedFormattedText() {
assertThat(mController.getSummary().toString()).isEqualTo(
"Uses Pacific Time (GMT-08:00). "
+ "Pacific Daylight Time starts on April 26, 1970.");
}
@Test
public void getAvailabilityStatus_timeZoneInfoSet_shouldReturnAVAILABLE_UNSEARCHABLE() {
mController.setTimeZoneInfo(mTimeZoneInfo);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE);
}
@Test
public void getAvailabilityStatus_noTimeZoneInfoSet_shouldReturnUNSUPPORTED_ON_DEVICE() {
mController.setTimeZoneInfo(null);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2020 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.datetime.timezone;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.datetime.timezone.TimeZoneInfo.Formatter;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Date;
import java.util.Locale;
@RunWith(AndroidJUnit4.class)
public class TimeZoneInfoTest {
@Test
public void testFormat() {
Date now = new Date(0L); // 00:00 1/1/1970
Formatter formatter = new Formatter(Locale.US, now);
TimeZoneInfo timeZoneInfo = formatter.format("America/Los_Angeles");
assertThat(timeZoneInfo.getId()).isEqualTo("America/Los_Angeles");
assertThat(timeZoneInfo.getExemplarLocation()).isEqualTo("Los Angeles");
assertThat(timeZoneInfo.getGmtOffset().toString()).isEqualTo("GMT-08:00");
assertThat(timeZoneInfo.getGenericName()).isEqualTo("Pacific Time");
assertThat(timeZoneInfo.getStandardName()).isEqualTo("Pacific Standard Time");
assertThat(timeZoneInfo.getDaylightName()).isEqualTo("Pacific Daylight Time");
}
@Test
public void getGmtOffset_zoneLordHowe_correctGmtOffset() {
Date date = new Date(1514764800000L); // 00:00 1/1/2018 GMT
Formatter formatter = new Formatter(Locale.US, date);
TimeZoneInfo timeZoneInfo = formatter.format("Australia/Lord_Howe");
assertThat(timeZoneInfo.getGmtOffset().toString()).isEqualTo("GMT+11:00");
}
}

View File

@@ -1,61 +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.datetime.timezone.model;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class TimeZoneDataTest {
private TimeZoneData mTimeZoneData;
@Before
public void setUp() {
mTimeZoneData = TimeZoneData.getInstance();
}
@Test
public void lookupCountryTimeZones_shouldReturnAtLeastOneTimeZoneInEveryRegion() {
Set<String> regionIds = mTimeZoneData.getRegionIds();
for (String regionId : regionIds) {
FilteredCountryTimeZones countryTimeZones =
mTimeZoneData.lookupCountryTimeZones(regionId);
assertThat(countryTimeZones).isNotNull();
assertThat(countryTimeZones.getPreferredTimeZoneIds().size()).isGreaterThan(0);
}
}
@Test
public void lookupCountryCodesForZoneId_shouldNotReturnHiddenZone() {
/*
Simferopol is filtered out for two reasons:
1) because we specifically exclude it with the picker attribute, and
2) because it's the same as Moscow after Oct 2014.
*/
assertThat(mTimeZoneData.lookupCountryCodesForZoneId("Europe/Simferopol")).isEmpty();
assertThat(mTimeZoneData.lookupCountryCodesForZoneId("Europe/London")).isNotEmpty();
assertThat(mTimeZoneData.lookupCountryCodesForZoneId("America/Los_Angeles")).isNotEmpty();
}
}

View File

@@ -1,65 +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.development;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.R;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class BluetoothMaxConnectedAudioDevicesPreferenceControllerInstrumentationTest {
private Context mTargetContext;
private String[] mListValues;
private String[] mListEntries;
private String mDefaultMaxConnectedAudioDevices;
@Before
public void setUp() throws Exception {
mTargetContext = InstrumentationRegistry.getTargetContext();
// Get XML values without mock
mListValues = mTargetContext.getResources()
.getStringArray(R.array.bluetooth_max_connected_audio_devices_values);
mListEntries = mTargetContext.getResources()
.getStringArray(R.array.bluetooth_max_connected_audio_devices);
mDefaultMaxConnectedAudioDevices = String.valueOf(mTargetContext.getResources()
.getInteger(
com.android.internal.R.integer
.config_bluetooth_max_connected_audio_devices));
}
@Test
public void verifyResource() {
// Verify normal list entries and default preference entries have the same size
Assert.assertEquals(mListEntries.length, mListValues.length);
Assert.assertThat(Arrays.asList(mListValues),
CoreMatchers.hasItem(mDefaultMaxConnectedAudioDevices));
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2020 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.settingslib.core.lifecycle.HideNonSystemOverlayMixin.SECURE_OVERLAY_SETTINGS;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class OverlaySettingsPreferenceControllerTest {
private Context mContext;
private SwitchPreference mPreference;
private OverlaySettingsPreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new OverlaySettingsPreferenceController(mContext);
mPreference = new SwitchPreference(mContext);
}
@Test
public void isAvailable_shouldReturnTrue() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void updateState_isOverlaySettingsEnabled_shouldCheckPreference() {
OverlaySettingsPreferenceController.setOverlaySettingsEnabled(mContext, true);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void updateState_isOverlaySettingsDisabled_shouldUncheckPreference() {
OverlaySettingsPreferenceController.setOverlaySettingsEnabled(mContext, false);
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void onPreferenceChange_preferenceChecked_shouldEnableSettings() {
mController.onPreferenceChange(mPreference, true);
assertThat(OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mContext)).isTrue();
}
@Test
public void onPreferenceChange_preferenceUnchecked_shouldDisableSettings() {
mController.onPreferenceChange(mPreference, false);
assertThat(
OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mContext)).isFalse();
}
@Test
public void isOverlaySettingsEnabled_sharePreferenceSetTrue_shouldReturnTrue() {
Settings.Secure.putInt(mContext.getContentResolver(),
SECURE_OVERLAY_SETTINGS, 1);
assertThat(OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mContext)).isTrue();
}
@Test
public void isOverlaySettingsEnabled_sharePreferenceSetFalse_shouldReturnFalse() {
Settings.Secure.putInt(mContext.getContentResolver(),
SECURE_OVERLAY_SETTINGS, 0);
assertThat(
OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mContext)).isFalse();
}
@Test
public void setOverlaySettingsEnabled_setTrue_shouldStoreTrue() {
OverlaySettingsPreferenceController.setOverlaySettingsEnabled(mContext, true);
assertThat(
OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mContext)).isTrue();
}
@Test
public void setOverlaySettingsEnabled_setFalse_shouldStoreTrue() {
OverlaySettingsPreferenceController.setOverlaySettingsEnabled(mContext, false);
assertThat(
OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mContext)).isFalse();
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2020 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.autofill;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
final class AutofillTestingHelper {
private final ContentResolver mResolver;
AutofillTestingHelper(Context context) {
mResolver = context.getContentResolver();
}
public void setLoggingLevel(int max) {
setGlobal(Settings.Global.AUTOFILL_LOGGING_LEVEL, max);
}
public void setMaxPartitionsSize(int max) {
setGlobal(Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, max);
}
public void setMaxVisibleDatasets(int level) {
setGlobal(Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, level);
}
public int getLoggingLevel() throws SettingNotFoundException {
return getGlobal(Settings.Global.AUTOFILL_LOGGING_LEVEL);
}
public int getMaxPartitionsSize() throws SettingNotFoundException {
return getGlobal(Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE);
}
public int getMaxVisibleDatasets() throws SettingNotFoundException {
return getGlobal(Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS);
}
private void setGlobal(String key, int value) {
Settings.Global.putInt(mResolver, key, value);
}
private int getGlobal(String key) throws SettingNotFoundException {
return Settings.Global.getInt(mResolver, key);
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2020 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.featureflags;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.FeatureFlagUtils;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class FeatureFlagPersistentTest {
private static final String TEST_FEATURE_NAME = "test_feature";
private static final String PERSISTENT_FALSE_NAME = "false_persistent";
private static final String PERSISTENT_TRUE_NAME = "true_persistent";
private static final String VOLATILE_FALSE_NAME = "volatile_false_volatile";
private static final String VOLATILE_TRUE_NAME = "volatile_true_volatile";
private Context mContext;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
FeatureFlagPersistent.getAllPersistentFlags().add(TEST_FEATURE_NAME);
FeatureFlagUtils.getAllFeatureFlags().put(TEST_FEATURE_NAME, "false");
FeatureFlagUtils.getAllFeatureFlags().put(VOLATILE_FALSE_NAME, "false");
FeatureFlagUtils.getAllFeatureFlags().put(VOLATILE_TRUE_NAME, "true");
FeatureFlagPersistent.getAllPersistentFlags().add(PERSISTENT_FALSE_NAME);
FeatureFlagUtils.getAllFeatureFlags().put(PERSISTENT_FALSE_NAME, "false");
FeatureFlagPersistent.getAllPersistentFlags().add(PERSISTENT_TRUE_NAME);
FeatureFlagUtils.getAllFeatureFlags().put(PERSISTENT_TRUE_NAME, "true");
}
@After
public void tearDown() {
cleanup(PERSISTENT_FALSE_NAME);
cleanup(PERSISTENT_TRUE_NAME);
cleanup(VOLATILE_FALSE_NAME);
cleanup(VOLATILE_TRUE_NAME);
cleanup(TEST_FEATURE_NAME);
}
private void cleanup(String flagName) {
Settings.Global.putString(mContext.getContentResolver(), flagName, "");
SystemProperties.set(FeatureFlagUtils.FFLAG_PREFIX + flagName, "");
SystemProperties.set(FeatureFlagUtils.FFLAG_OVERRIDE_PREFIX + flagName, "");
SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX + flagName, "");
}
/**
* Test to verify a non-persistent flag is indeed not persistent.
*/
@Test
public void isPersistent_notPersistent_shouldReturnFalse() {
assertThat(FeatureFlagPersistent.isPersistent(VOLATILE_FALSE_NAME)).isFalse();
}
/**
* Test to verify a persistent flag is indeed persistent.
*/
@Test
public void isPersistent_persistent_shouldReturnTrue() {
assertThat(FeatureFlagPersistent.isPersistent(PERSISTENT_TRUE_NAME)).isTrue();
}
/**
* Test to verify a persistent flag that is enabled should return true.
*/
@Test
public void isEnabled_enabled_shouldReturnTrue() {
assertThat(FeatureFlagPersistent.isEnabled(mContext, PERSISTENT_TRUE_NAME)).isTrue();
}
/**
* Test to verify a persistent flag that is disabled should return false.
*/
@Test
public void isEnabled_disabled_shouldReturnFalse() {
assertThat(FeatureFlagPersistent.isEnabled(mContext, PERSISTENT_FALSE_NAME)).isFalse();
}
/**
* Test to verify a persistent flag that has an enabled in system property should return true.
*/
@Test
public void isEnabled_sysPropEnabled_shouldReturnTrue() {
SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX + TEST_FEATURE_NAME, "true");
FeatureFlagUtils.setEnabled(mContext, TEST_FEATURE_NAME, false);
assertThat(FeatureFlagPersistent.isEnabled(mContext, TEST_FEATURE_NAME)).isTrue();
}
/**
* Test to verify a persistent flag that is disabled in system property should return false.
*/
@Test
public void isEnabled_sysPropDisabled_shouldReturnFalse() {
SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX + TEST_FEATURE_NAME, "false");
FeatureFlagUtils.setEnabled(mContext, TEST_FEATURE_NAME, true);
assertThat(FeatureFlagPersistent.isEnabled(mContext, TEST_FEATURE_NAME)).isFalse();
}
/**
* Test to verify setting persistent flag to enable works.
*/
@Test
public void setEnabled_sysPropTrue_shouldSetValues() {
SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX + TEST_FEATURE_NAME, "");
FeatureFlagPersistent.setEnabled(mContext, TEST_FEATURE_NAME, true);
assertThat(SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + TEST_FEATURE_NAME))
.isEqualTo("true");
assertThat(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME)).isTrue();
}
/**
* Test to verify setting persistent flag to disable works.
*/
@Test
public void setEnabled_sysPropFalse_shouldSetValues() {
SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX + TEST_FEATURE_NAME, "");
FeatureFlagPersistent.setEnabled(mContext, TEST_FEATURE_NAME, false);
assertThat(SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + TEST_FEATURE_NAME))
.isEqualTo("false");
assertThat(FeatureFlagUtils.isEnabled(mContext, TEST_FEATURE_NAME)).isFalse();
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2020 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.transcode;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.SystemProperties;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class TranscodeDefaultOptionPreferenceControllerTest {
private static final String TRANSCODE_DEFAULT_SYS_PROP_KEY =
"persist.sys.fuse.transcode_default";
private TranscodeDefaultOptionPreferenceController mUnderTest;
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
mUnderTest = new TranscodeDefaultOptionPreferenceController(context, "some_key");
}
@Test
public void isChecked_whenSysPropSet_shouldReturnFalse() {
SystemProperties.set(TRANSCODE_DEFAULT_SYS_PROP_KEY, "true");
assertThat(mUnderTest.isChecked()).isFalse();
}
@Test
public void isChecked_whenSysPropUnset_shouldReturnTrue() {
SystemProperties.set(TRANSCODE_DEFAULT_SYS_PROP_KEY, "false");
assertThat(mUnderTest.isChecked()).isTrue();
}
@Test
public void setChecked_withTrue_shouldUnsetSysProp() {
mUnderTest.setChecked(true);
assertThat(
SystemProperties.getBoolean(TRANSCODE_DEFAULT_SYS_PROP_KEY, true)).isFalse();
}
@Test
public void setChecked_withFalse_shouldSetSysProp() {
mUnderTest.setChecked(false);
assertThat(
SystemProperties.getBoolean(TRANSCODE_DEFAULT_SYS_PROP_KEY, false)).isTrue();
}
@Test
public void getAvailabilityStatus_shouldReturnAVAILABLE() {
assertThat(mUnderTest.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2021 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.transcode;
import static com.android.settings.development.transcode.TranscodeDisableCachePreferenceController.TRANSCODE_DISABLE_CACHE_SYS_PROP_KEY;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.SystemProperties;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class TranscodeDisableCachePreferenceControllerTest {
private TranscodeDisableCachePreferenceController mUnderTest;
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
mUnderTest = new TranscodeDisableCachePreferenceController(context, "some_key");
}
@Test
public void isChecked_whenSysPropSet_shouldReturnTrue() {
SystemProperties.set(TRANSCODE_DISABLE_CACHE_SYS_PROP_KEY, "true");
assertThat(mUnderTest.isChecked()).isTrue();
}
@Test
public void isChecked_whenSysPropUnset_shouldReturnFalse() {
SystemProperties.set(TRANSCODE_DISABLE_CACHE_SYS_PROP_KEY, "false");
assertThat(mUnderTest.isChecked()).isFalse();
}
@Test
public void setChecked_withTrue_shouldSetSysProp() {
mUnderTest.setChecked(true);
assertThat(
SystemProperties.getBoolean(TRANSCODE_DISABLE_CACHE_SYS_PROP_KEY, false)).isTrue();
}
@Test
public void setChecked_withFalse_shouldUnsetSysProp() {
mUnderTest.setChecked(false);
assertThat(
SystemProperties.getBoolean(TRANSCODE_DISABLE_CACHE_SYS_PROP_KEY, true)).isFalse();
}
@Test
public void getAvailabilityStatus_shouldReturnAVAILABLE() {
assertThat(mUnderTest.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2020 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.transcode;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.SystemProperties;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class TranscodeGlobalTogglePreferenceControllerTest {
private static final String TRANSCODE_ENABLED_PROP_KEY = "persist.sys.fuse.transcode_enabled";
private TranscodeGlobalTogglePreferenceController mController;
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
mController = new TranscodeGlobalTogglePreferenceController(context, "test_key");
}
@Test
public void isAvailable_shouldReturnTrue() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void isChecked_whenDisabled_shouldReturnFalse() {
SystemProperties.set(TRANSCODE_ENABLED_PROP_KEY, "false");
assertThat(mController.isChecked()).isFalse();
}
@Test
public void isChecked_whenEnabled_shouldReturnTrue() {
SystemProperties.set(TRANSCODE_ENABLED_PROP_KEY, "true");
assertThat(mController.isChecked()).isTrue();
}
@Test
public void setChecked_withTrue_shouldUpdateSystemProperty() {
// Simulate the UI being clicked.
mController.setChecked(true);
// Verify the system property was updated.
assertThat(SystemProperties.getBoolean(TRANSCODE_ENABLED_PROP_KEY, false)).isTrue();
}
@Test
public void setChecked_withFalse_shouldUpdateSystemProperty() {
// Simulate the UI being clicked.
mController.setChecked(false);
// Verify the system property was updated.
assertThat(SystemProperties.getBoolean(TRANSCODE_ENABLED_PROP_KEY, true)).isFalse();
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2021 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.transcode;
import static com.android.settings.development.transcode.TranscodeNotificationPreferenceController.TRANSCODE_NOTIFICATION_SYS_PROP_KEY;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.SystemProperties;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class TranscodeNotificationPreferenceControllerTest {
private TranscodeNotificationPreferenceController mUnderTest;
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
mUnderTest = new TranscodeNotificationPreferenceController(context, "notification_key");
}
@Test
public void isChecked_whenSysPropSet_shouldReturnTrue() {
SystemProperties.set(TRANSCODE_NOTIFICATION_SYS_PROP_KEY, "true");
assertThat(mUnderTest.isChecked()).isTrue();
}
@Test
public void isChecked_whenSysPropUnset_shouldReturnFalse() {
SystemProperties.set(TRANSCODE_NOTIFICATION_SYS_PROP_KEY, "false");
assertThat(mUnderTest.isChecked()).isFalse();
}
@Test
public void setChecked_withTrue_shouldSetSysProp() {
mUnderTest.setChecked(true);
assertThat(
SystemProperties.getBoolean(TRANSCODE_NOTIFICATION_SYS_PROP_KEY, false)).isTrue();
}
@Test
public void setChecked_withFalse_shouldUnsetSysProp() {
mUnderTest.setChecked(false);
assertThat(
SystemProperties.getBoolean(TRANSCODE_NOTIFICATION_SYS_PROP_KEY, true)).isFalse();
}
@Test
public void getAvailabilityStatus_shouldReturnAVAILABLE() {
assertThat(mUnderTest.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2020 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.transcode;
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.os.SystemProperties;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class TranscodeUserControlPreferenceControllerTest {
private static final String TRANSCODE_USER_CONTROL_SYS_PROP_KEY =
"persist.sys.fuse.transcode_user_control";
private TranscodeUserControlPreferenceController mUnderTest;
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
mUnderTest = new TranscodeUserControlPreferenceController(context, "some_key");
}
@Test
public void isChecked_whenSysPropSet_shouldReturnTrue() {
SystemProperties.set(TRANSCODE_USER_CONTROL_SYS_PROP_KEY, "true");
assertThat(mUnderTest.isChecked()).isTrue();
}
@Test
public void isChecked_whenSysPropUnset_shouldReturnFalse() {
SystemProperties.set(TRANSCODE_USER_CONTROL_SYS_PROP_KEY, "false");
assertThat(mUnderTest.isChecked()).isFalse();
}
@Test
public void setChecked_withTrue_shouldSetSysProp() {
mUnderTest.setChecked(true);
assertThat(
SystemProperties.getBoolean(TRANSCODE_USER_CONTROL_SYS_PROP_KEY, false)).isTrue();
}
@Test
public void setChecked_withFalse_shouldUnsetSysProp() {
mUnderTest.setChecked(false);
assertThat(
SystemProperties.getBoolean(TRANSCODE_USER_CONTROL_SYS_PROP_KEY, true)).isFalse();
}
@Test
public void getAvailabilityStatus_shouldReturnAVAILABLE() {
assertThat(mUnderTest.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright (C) 2020 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.deviceinfo;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.android.settings.deviceinfo.DeviceNamePreferenceController.RES_SHOW_DEVICE_NAME_BOOL;
import static com.google.common.truth.Truth.assertThat;
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.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.res.Resources;
import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Looper;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.widget.ValidatedEditTextPreference;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class DeviceNamePreferenceControllerTest {
private static final String TESTING_STRING = "Testing";
private static final String TEST_PREFERENCE_KEY = "test_key";
@Mock
private WifiManager mWifiManager;
private PreferenceScreen mScreen;
private ValidatedEditTextPreference mPreference;
private DeviceNamePreferenceController mController;
private Context mContext;
private Resources mResources;
private BluetoothAdapter mBluetoothAdapter;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager);
mResources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(mResources);
if (Looper.myLooper() == null) {
Looper.prepare();
}
PreferenceManager preferenceManager = new PreferenceManager(mContext);
mScreen = preferenceManager.createPreferenceScreen(mContext);
mPreference = new ValidatedEditTextPreference(mContext);
mPreference.setKey(TEST_PREFERENCE_KEY);
mScreen.addPreference(mPreference);
final SoftApConfiguration configuration =
new SoftApConfiguration.Builder().setSsid("test-ap").build();
when(mWifiManager.getSoftApConfiguration()).thenReturn(configuration);
mController = new DeviceNamePreferenceController(mContext, TEST_PREFERENCE_KEY);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
}
@After
public void tearDown() {
Settings.Global.putString(
mContext.getContentResolver(), Settings.Global.DEVICE_NAME, null);
}
@Test
public void getAvailibilityStatus_availableByDefault() {
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_unsupportedWhenSet() {
doReturn(false).when(mResources).getBoolean(RES_SHOW_DEVICE_NAME_BOOL);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
public void constructor_defaultDeviceNameIsModelName() {
assertThat(mController.getSummary()).isEqualTo(Build.MODEL);
}
@Test
public void constructor_deviceNameLoadedIfSet() {
Settings.Global.putString(
mContext.getContentResolver(), Settings.Global.DEVICE_NAME, "Test");
mController = new DeviceNamePreferenceController(mContext, "test_key");
assertThat(mController.getSummary()).isEqualTo("Test");
}
@Test
public void isTextValid_nameUnder33Characters_isValid() {
assertThat(mController.isTextValid("12345678901234567890123456789012")).isTrue();
}
@Test
public void isTextValid_nameTooLong_isInvalid() {
assertThat(mController.isTextValid("123456789012345678901234567890123")).isFalse();
}
@Test
public void setDeviceName_preferenceUpdatedWhenDeviceNameUpdated() {
acceptDeviceName(true);
mController.displayPreference(mScreen);
mController.onPreferenceChange(mPreference, TESTING_STRING);
assertThat(mPreference.getSummary()).isEqualTo(TESTING_STRING);
}
// TODO(b/175389659): Determine why this test case fails for virtual but not local devices.
@Ignore
@Test
public void setDeviceName_bluetoothNameUpdatedWhenDeviceNameUpdated() {
acceptDeviceName(true);
mController.displayPreference(mScreen);
mController.onPreferenceChange(mPreference, TESTING_STRING);
assertThat(mBluetoothAdapter.getName()).isEqualTo(TESTING_STRING);
}
@Test
public void setDeviceName_wifiTetherNameUpdatedWhenDeviceNameUpdated() {
acceptDeviceName(true);
mController.displayPreference(mScreen);
mController.onPreferenceChange(mPreference, TESTING_STRING);
ArgumentCaptor<SoftApConfiguration> captor =
ArgumentCaptor.forClass(SoftApConfiguration.class);
verify(mWifiManager).setSoftApConfiguration(captor.capture());
assertThat(captor.getValue().getSsid()).isEqualTo(TESTING_STRING);
}
@Test
public void displayPreference_defaultDeviceNameIsModelNameOnPreference() {
mController.displayPreference(mScreen);
assertThat(mPreference.getText()).isEqualTo(Build.MODEL);
}
@Test
public void setDeviceName_okInDeviceNameWarningDialog_shouldChangePreferenceText() {
acceptDeviceName(true);
mController.displayPreference(mScreen);
mController.onPreferenceChange(mPreference, TESTING_STRING);
assertThat(mPreference.getSummary()).isEqualTo(TESTING_STRING);
}
@Test
public void setDeviceName_cancelInDeviceNameWarningDialog_shouldNotChangePreferenceText() {
acceptDeviceName(false);
mController.displayPreference(mScreen);
mController.onPreferenceChange(mPreference, TESTING_STRING);
assertThat(mPreference.getSummary()).isNotEqualTo(TESTING_STRING);
assertThat(mPreference.getText()).isEqualTo(mPreference.getSummary());
}
private void acceptDeviceName(boolean accept) {
mController.setHost(deviceName -> mController.updateDeviceName(accept));
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (C) 2017 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.deviceinfo;
import static android.content.Context.CLIPBOARD_SERVICE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
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.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Looper;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.ResourcesUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class PhoneNumberPreferenceControllerTest {
private Preference mPreference;
@Mock
private Preference mSecondPreference;
@Mock
private TelephonyManager mTelephonyManager;
@Mock
private SubscriptionInfo mSubscriptionInfo;
@Mock
private SubscriptionManager mSubscriptionManager;
private PreferenceScreen mScreen;
private PreferenceCategory mCategory;
private Context mContext;
private PhoneNumberPreferenceController mController;
private ClipboardManager mClipboardManager;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
mClipboardManager = (ClipboardManager) spy(mContext.getSystemService(CLIPBOARD_SERVICE));
doReturn(mClipboardManager).when(mContext).getSystemService(CLIPBOARD_SERVICE);
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
mController = spy(new PhoneNumberPreferenceController(mContext, "phone_number"));
if (Looper.myLooper() == null) {
Looper.prepare();
}
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
mScreen = preferenceManager.createPreferenceScreen(mContext);
mPreference = spy(new Preference(mContext));
mPreference.setKey(mController.getPreferenceKey());
mPreference.setVisible(true);
mScreen.addPreference(mPreference);
final String categoryKey = "basic_info_category";
mCategory = new PreferenceCategory(mContext);
mCategory.setKey(categoryKey);
mScreen.addPreference(mCategory);
doReturn(mSubscriptionInfo).when(mController).getSubscriptionInfo(anyInt());
doReturn(mSecondPreference).when(mController).createNewPreference(mContext);
}
@Test
public void getAvailabilityStatus_isVoiceCapable_shouldBeAVAILABLE() {
when(mTelephonyManager.isVoiceCapable()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_isNotVoiceCapable_shouldBeUNSUPPORTED_ON_DEVICE() {
when(mTelephonyManager.isVoiceCapable()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(
BasePreferenceController.UNSUPPORTED_ON_DEVICE);
}
@Test
public void displayPreference_multiSim_shouldAddSecondPreference() {
when(mTelephonyManager.getPhoneCount()).thenReturn(2);
final Preference sim1Preference = new Preference(mContext);
mCategory.addItemFromInflater(sim1Preference);
mController.displayPreference(mScreen);
assertThat(mCategory.getPreferenceCount()).isEqualTo(2);
}
@Test
public void updateState_singleSim_shouldUpdateTitleAndPhoneNumber() {
final String phoneNumber = "1111111111";
doReturn(phoneNumber).when(mController).getFormattedPhoneNumber(mSubscriptionInfo);
when(mTelephonyManager.getPhoneCount()).thenReturn(1);
mController.displayPreference(mScreen);
mController.updateState(mPreference);
verify(mPreference).setTitle(ResourcesUtils.getResourcesString(mContext, "status_number"));
verify(mPreference).setSummary(phoneNumber);
}
@Test
public void updateState_multiSim_shouldUpdateTitleAndPhoneNumberOfMultiplePreferences() {
final String phoneNumber = "1111111111";
doReturn(phoneNumber).when(mController).getFormattedPhoneNumber(mSubscriptionInfo);
when(mTelephonyManager.getPhoneCount()).thenReturn(2);
mController.displayPreference(mScreen);
mController.updateState(mPreference);
verify(mPreference).setTitle(ResourcesUtils.getResourcesString(
mContext, "status_number_sim_slot", 1 /* sim slot */));
verify(mPreference).setSummary(phoneNumber);
verify(mSecondPreference).setTitle(ResourcesUtils.getResourcesString(
mContext, "status_number_sim_slot", 2 /* sim slot */));
verify(mSecondPreference).setSummary(phoneNumber);
}
@Test
public void getSummary_cannotGetActiveSubscriptionInfo_shouldShowUnknown() {
when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(null);
CharSequence primaryNumber = mController.getSummary();
assertThat(primaryNumber).isNotNull();
assertThat(primaryNumber).isEqualTo(ResourcesUtils.getResourcesString(
mContext, "device_info_default"));
}
@Test
public void getSummary_getEmptySubscriptionInfo_shouldShowUnknown() {
List<SubscriptionInfo> infos = new ArrayList<>();
when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(infos);
CharSequence primaryNumber = mController.getSummary();
assertThat(primaryNumber).isEqualTo(ResourcesUtils.getResourcesString(
mContext, "device_info_default"));
}
@Test
@UiThreadTest
public void copy_shouldCopyPhoneNumberToClipboard() {
final List<SubscriptionInfo> list = new ArrayList<>();
list.add(mSubscriptionInfo);
when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(list);
final String phoneNumber = "1111111111";
doReturn(phoneNumber).when(mController).getFormattedPhoneNumber(mSubscriptionInfo);
ArgumentCaptor<ClipData> captor = ArgumentCaptor.forClass(ClipData.class);
doNothing().when(mClipboardManager).setPrimaryClip(captor.capture());
mController.copy();
final CharSequence data = captor.getValue().getItemAt(0).getText();
assertThat(phoneNumber.contentEquals(data)).isTrue();
}
}

View File

@@ -0,0 +1,108 @@
/*
* 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.deviceinfo;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.icu.text.NumberFormat;
import android.os.storage.VolumeInfo;
import android.text.format.Formatter;
import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.testutils.ResourcesUtils;
import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class TopLevelStoragePreferenceControllerTest {
@Mock
private StorageManagerVolumeProvider mStorageManagerVolumeProvider;
private Context mContext;
private TopLevelStoragePreferenceController mController;
private List<VolumeInfo> mVolumes;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
mVolumes = new ArrayList<>();
mVolumes.add(mock(VolumeInfo.class, RETURNS_DEEP_STUBS));
when(mStorageManagerVolumeProvider.getVolumes()).thenReturn(mVolumes);
mController = spy(new TopLevelStoragePreferenceController(mContext, "test_key"));
}
@Test
public void updateSummary_shouldDisplayUsedPercentAndFreeSpace() throws Exception {
final VolumeInfo volumeInfo = mVolumes.get(0);
when(volumeInfo.isMountedReadable()).thenReturn(true);
when(volumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(mStorageManagerVolumeProvider
.getTotalBytes(nullable(StorageStatsManager.class), nullable(VolumeInfo.class)))
.thenReturn(500L);
when(mStorageManagerVolumeProvider
.getFreeBytes(nullable(StorageStatsManager.class), nullable(VolumeInfo.class)))
.thenReturn(0L);
when(mController.getStorageManagerVolumeProvider())
.thenReturn(mStorageManagerVolumeProvider);
final String percentage = NumberFormat.getPercentInstance().format(1);
final String freeSpace = Formatter.formatFileSize(mContext, 0);
final Preference preference = new Preference(mContext);
// Wait for asynchronous thread to finish, otherwise test will flake.
Future thread = mController.refreshSummaryThread(preference);
try {
thread.get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
fail("Exception during automatic selection");
}
// Sleep for 5 seconds because a function is executed on the main thread from within
// the background thread.
TimeUnit.SECONDS.sleep(5);
assertThat(preference.getSummary()).isEqualTo(ResourcesUtils.getResourcesString(
mContext, "storage_summary", percentage, freeSpace));
}
}

View File

@@ -0,0 +1,224 @@
/*
* Copyright (C) 2021 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.deviceinfo;
import static org.mockito.Mockito.atLeastOnce;
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;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.view.Menu;
import androidx.fragment.app.Fragment;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.deviceinfo.storage.StorageEntry;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class VolumeOptionMenuControllerTest {
private static final String INTERNAL_VOLUME_ID = "1";
private static final String EXTERNAL_VOLUME_ID = "2";
private static final String DISK_ID = "3";
private static final String VOLUME_RECORD_FSUUID = "volume_record_fsuuid";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Menu mMenu;
@Mock private PackageManager mPackageManager;
@Mock private StorageManager mStorageManager;
@Mock private VolumeInfo mExternalVolumeInfo;
@Mock private VolumeInfo mInternalVolumeInfo;
private Context mContext;
private VolumeOptionMenuController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager);
when(mInternalVolumeInfo.getId()).thenReturn(INTERNAL_VOLUME_ID);
when(mInternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(mInternalVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
when(mInternalVolumeInfo.isMountedWritable()).thenReturn(true);
when(mExternalVolumeInfo.getId()).thenReturn(EXTERNAL_VOLUME_ID);
final StorageEntry selectedStorageEntry = new StorageEntry(mContext, mInternalVolumeInfo);
mController = new VolumeOptionMenuController(mContext, mock(Fragment.class),
selectedStorageEntry);
}
@Test
public void onPrepareOptionsMenu_unSupportedDiskInfo_formatIsVisible() {
final StorageEntry unsupportedStorageEntry =
new StorageEntry(new DiskInfo(DISK_ID, 0 /* flags */));
mController.setSelectedStorageEntry(unsupportedStorageEntry);
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mFormat, atLeastOnce()).setVisible(true);
verify(mController.mRename, never()).setVisible(true);
verify(mController.mMount, never()).setVisible(true);
verify(mController.mUnmount, never()).setVisible(true);
verify(mController.mFormatAsPortable, never()).setVisible(true);
verify(mController.mFormatAsInternal, never()).setVisible(true);
verify(mController.mMigrate, never()).setVisible(true);
verify(mController.mFree, never()).setVisible(true);
verify(mController.mForget, never()).setVisible(true);
}
@Test
public void onPrepareOptionsMenu_missingVolumeRecord_forgetIsVisible() {
final StorageEntry missingStorageEntry =
new StorageEntry(new VolumeRecord(0 /* type */, VOLUME_RECORD_FSUUID));
mController.setSelectedStorageEntry(missingStorageEntry);
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mForget, atLeastOnce()).setVisible(true);
verify(mController.mRename, never()).setVisible(true);
verify(mController.mMount, never()).setVisible(true);
verify(mController.mUnmount, never()).setVisible(true);
verify(mController.mFormat, never()).setVisible(true);
verify(mController.mFormatAsPortable, never()).setVisible(true);
verify(mController.mFormatAsInternal, never()).setVisible(true);
verify(mController.mMigrate, never()).setVisible(true);
verify(mController.mFree, never()).setVisible(true);
}
@Test
public void onPrepareOptionsMenu_unmountedStorage_mountIsVisible() {
when(mInternalVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_UNMOUNTED);
mController.setSelectedStorageEntry(new StorageEntry(mContext, mInternalVolumeInfo));
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mMount, atLeastOnce()).setVisible(true);
verify(mController.mRename, never()).setVisible(true);
verify(mController.mUnmount, never()).setVisible(true);
verify(mController.mFormat, never()).setVisible(true);
verify(mController.mFormatAsPortable, never()).setVisible(true);
verify(mController.mFormatAsInternal, never()).setVisible(true);
verify(mController.mMigrate, never()).setVisible(true);
verify(mController.mFree, never()).setVisible(true);
verify(mController.mForget, never()).setVisible(true);
}
@Test
public void onPrepareOptionsMenu_privateNotDefaultInternal_someMenusAreVisible() {
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mRename, atLeastOnce()).setVisible(true);
verify(mController.mUnmount, atLeastOnce()).setVisible(true);
verify(mController.mFormatAsPortable, atLeastOnce()).setVisible(true);
verify(mController.mMount, never()).setVisible(true);
verify(mController.mFormat, never()).setVisible(true);
verify(mController.mFormatAsInternal, never()).setVisible(true);
verify(mController.mFree, never()).setVisible(true);
verify(mController.mForget, never()).setVisible(true);
}
@Test
public void onPrepareOptionsMenu_privateDefaultInternal_mostMenusAreNotVisible() {
when(mInternalVolumeInfo.getId()).thenReturn(VolumeInfo.ID_PRIVATE_INTERNAL);
when(mPackageManager.getPrimaryStorageCurrentVolume()).thenReturn(mInternalVolumeInfo);
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mRename, never()).setVisible(true);
verify(mController.mUnmount, never()).setVisible(true);
verify(mController.mFormatAsPortable, never()).setVisible(true);
verify(mController.mMount, never()).setVisible(true);
verify(mController.mFormat, never()).setVisible(true);
verify(mController.mFormatAsInternal, never()).setVisible(true);
verify(mController.mFree, never()).setVisible(true);
verify(mController.mForget, never()).setVisible(true);
}
@Test
public void onPrepareOptionsMenu_publicStorage_someMenusArcVisible() {
when(mExternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PUBLIC);
when(mExternalVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
when(mExternalVolumeInfo.getDiskId()).thenReturn(DISK_ID);
final DiskInfo externalDiskInfo = mock(DiskInfo.class);
when(mStorageManager.findDiskById(DISK_ID)).thenReturn(externalDiskInfo);
mController.setSelectedStorageEntry(new StorageEntry(mContext, mExternalVolumeInfo));
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mRename, atLeastOnce()).setVisible(true);
verify(mController.mUnmount, atLeastOnce()).setVisible(true);
verify(mController.mFormat, atLeastOnce()).setVisible(true);
verify(mController.mMount, never()).setVisible(true);
verify(mController.mFormatAsPortable, never()).setVisible(true);
verify(mController.mFormatAsInternal, never()).setVisible(true);
verify(mController.mFree, never()).setVisible(true);
verify(mController.mForget, never()).setVisible(true);
}
@Test
public void onPrepareOptionsMenu_noExternalStorage_migrateNotVisible() {
when(mPackageManager.getPrimaryStorageCurrentVolume()).thenReturn(mInternalVolumeInfo);
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mMigrate, atLeastOnce()).setVisible(false);
verify(mController.mMigrate, never()).setVisible(true);
}
@Test
public void onPrepareOptionsMenu_externalPrimaryStorageAvailable_migrateIsVisible() {
when(mExternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(mExternalVolumeInfo.isMountedWritable()).thenReturn(true);
when(mPackageManager.getPrimaryStorageCurrentVolume()).thenReturn(mExternalVolumeInfo);
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mMigrate, atLeastOnce()).setVisible(true);
}
@Test
public void onPrepareOptionsMenu_externalUnmounted_migrateIsVisible() {
when(mExternalVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(mExternalVolumeInfo.isMountedWritable()).thenReturn(false);
when(mPackageManager.getPrimaryStorageCurrentVolume()).thenReturn(mExternalVolumeInfo);
mController.onPrepareOptionsMenu(mMenu);
verify(mController.mMigrate, atLeastOnce()).setVisible(false);
verify(mController.mMigrate, never()).setVisible(true);
}
}

View File

@@ -0,0 +1,391 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.deviceinfo.legal;
import static com.android.settings.deviceinfo.legal.ModuleLicenseProvider.LICENSE_FILE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@RunWith(AndroidJUnit4.class)
public class ModuleLicenseProviderTest {
public static final String PACKAGE_NAME = "com.android.test_package";
@Test
public void onCreate_returnsTrue() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
assertThat(provider.onCreate()).isTrue();
}
@Test(expected = UnsupportedOperationException.class)
public void query_throwsUnsupportedOperationException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.query(null, null, null, null, null);
}
@Test(expected = UnsupportedOperationException.class)
public void insert_throwsUnsupportedOperationException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.insert(null, null);
}
@Test(expected = UnsupportedOperationException.class)
public void delete_throwsUnsupportedOperationException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.delete(null, null, null);
}
@Test(expected = UnsupportedOperationException.class)
public void update_throwsUnsupportedOperationException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.update(null, null, null, null);
}
@Test(expected = IllegalArgumentException.class)
public void getType_notContentScheme_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.getType(new Uri.Builder()
.scheme("badscheme")
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.appendPath(LICENSE_FILE_NAME)
.build());
}
@Test(expected = IllegalArgumentException.class)
public void getType_invalidAuthority_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.getType(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority("notmyauthority")
.appendPath(PACKAGE_NAME)
.appendPath(LICENSE_FILE_NAME)
.build());
}
@Test(expected = IllegalArgumentException.class)
public void getType_emptyPath_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.getType(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.build());
}
@Test(expected = IllegalArgumentException.class)
public void getType_missingPackageName_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.getType(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(LICENSE_FILE_NAME)
.build());
}
@Test(expected = IllegalArgumentException.class)
public void getType_missingFileName_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.getType(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.build());
}
@Test(expected = IllegalArgumentException.class)
public void getType_incorrectFileName_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.getType(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.appendPath("badname.txt")
.build());
}
@Test(expected = IllegalArgumentException.class)
public void getType_packageNotAModule_throwsIllegalArgumentException()
throws PackageManager.NameNotFoundException {
ModuleLicenseProvider provider = spy(new ModuleLicenseProvider());
Context context = mock(Context.class);
PackageManager packageManager = mock(PackageManager.class);
when(provider.getModuleContext()).thenReturn(context);
when(context.getPackageManager()).thenReturn(packageManager);
when(packageManager.getModuleInfo(PACKAGE_NAME, 0))
.thenThrow(new PackageManager.NameNotFoundException());
provider.getType(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.appendPath(LICENSE_FILE_NAME)
.build());
}
@Test
public void getType_validUri_returnsHtmlMimeType()
throws PackageManager.NameNotFoundException {
ModuleLicenseProvider provider = spy(new ModuleLicenseProvider());
Context context = mock(Context.class);
PackageManager packageManager = mock(PackageManager.class);
when(provider.getModuleContext()).thenReturn(context);
when(context.getPackageManager()).thenReturn(packageManager);
when(packageManager.getModuleInfo(PACKAGE_NAME, 0))
.thenReturn(new ModuleInfo());
assertThat(provider.getType(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.appendPath(LICENSE_FILE_NAME)
.build())).isEqualTo(ModuleLicenseProvider.LICENSE_FILE_MIME_TYPE);
}
@Test(expected = IllegalArgumentException.class)
public void openFile_notContentScheme_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.openFile(new Uri.Builder()
.scheme("badscheme")
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.appendPath(LICENSE_FILE_NAME)
.build(), "r");
}
@Test(expected = IllegalArgumentException.class)
public void openFile_invalidAuthority_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.openFile(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority("notmyauthority")
.appendPath(PACKAGE_NAME)
.appendPath(LICENSE_FILE_NAME)
.build(), "r");
}
@Test(expected = IllegalArgumentException.class)
public void openFile_emptyPath_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.openFile(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.build(), "r");
}
@Test(expected = IllegalArgumentException.class)
public void openFile_missingPackageName_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.openFile(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(LICENSE_FILE_NAME)
.build(), "r");
}
@Test(expected = IllegalArgumentException.class)
public void openFile_missingFileName_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.openFile(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.build(), "r");
}
@Test(expected = IllegalArgumentException.class)
public void openFile_incorrectFileName_throwsIllegalArgumentException() {
ModuleLicenseProvider provider = new ModuleLicenseProvider();
provider.openFile(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.appendPath("badname.txt")
.build(), "r");
}
@Test(expected = IllegalArgumentException.class)
public void openFile_packageNotAModule_throwsIllegalArgumentException()
throws PackageManager.NameNotFoundException {
ModuleLicenseProvider provider = spy(new ModuleLicenseProvider());
Context context = mock(Context.class);
PackageManager packageManager = mock(PackageManager.class);
when(provider.getModuleContext()).thenReturn(context);
when(context.getPackageManager()).thenReturn(packageManager);
when(packageManager.getModuleInfo(PACKAGE_NAME, 0))
.thenThrow(new PackageManager.NameNotFoundException());
provider.openFile(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.appendPath(LICENSE_FILE_NAME)
.build(), "r");
}
@Test(expected = IllegalArgumentException.class)
public void openFile_validUri_notReadMode_throwsIllegalArgumentException()
throws PackageManager.NameNotFoundException {
ModuleLicenseProvider provider = spy(new ModuleLicenseProvider());
Context context = mock(Context.class);
PackageManager packageManager = mock(PackageManager.class);
when(provider.getModuleContext()).thenReturn(context);
when(context.getPackageManager()).thenReturn(packageManager);
when(packageManager.getModuleInfo(PACKAGE_NAME, 0))
.thenReturn(new ModuleInfo());
provider.openFile(new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(ModuleLicenseProvider.AUTHORITY)
.appendPath(PACKAGE_NAME)
.appendPath(LICENSE_FILE_NAME)
.build(), "badmode");
}
@Test
public void isCachedHtmlFileOutdated_packageNotInSharedPrefs_returnTrue()
throws PackageManager.NameNotFoundException {
Context context = ApplicationProvider.getApplicationContext();
context.getSharedPreferences(ModuleLicenseProvider.PREFS_NAME, Context.MODE_PRIVATE)
.edit().clear().commit();
assertThat(ModuleLicenseProvider.isCachedHtmlFileOutdated(context, PACKAGE_NAME)).isTrue();
}
@Test
public void isCachedHtmlFileOutdated_versionCodeDiffersFromSharedPref_returnTrue()
throws PackageManager.NameNotFoundException {
Context context = spy(ApplicationProvider.getApplicationContext());
SharedPreferences.Editor editor = context.getSharedPreferences(
ModuleLicenseProvider.PREFS_NAME, Context.MODE_PRIVATE)
.edit();
editor.clear().commit();
editor.putLong(PACKAGE_NAME, 900L).commit();
PackageManager packageManager = mock(PackageManager.class);
doReturn(packageManager).when(context).getPackageManager();
PackageInfo packageInfo = new PackageInfo();
packageInfo.setLongVersionCode(1000L);
when(packageManager.getPackageInfo(PACKAGE_NAME, PackageManager.MATCH_APEX))
.thenReturn(packageInfo);
assertThat(ModuleLicenseProvider.isCachedHtmlFileOutdated(context, PACKAGE_NAME)).isTrue();
}
@Test
public void isCachedHtmlFileOutdated_fileDoesNotExist_returnTrue()
throws PackageManager.NameNotFoundException {
Context context = spy(ApplicationProvider.getApplicationContext());
context.getSharedPreferences(ModuleLicenseProvider.PREFS_NAME, Context.MODE_PRIVATE)
.edit().clear().commit();
SharedPreferences.Editor editor = context.getSharedPreferences(
ModuleLicenseProvider.PREFS_NAME, Context.MODE_PRIVATE)
.edit();
editor.clear().commit();
editor.putLong(PACKAGE_NAME, 1000L).commit();
PackageManager packageManager = mock(PackageManager.class);
doReturn(packageManager).when(context).getPackageManager();
PackageInfo packageInfo = new PackageInfo();
packageInfo.setLongVersionCode(1000L);
when(packageManager.getPackageInfo(PACKAGE_NAME, PackageManager.MATCH_APEX))
.thenReturn(packageInfo);
new File(context.getCacheDir() + "/" + PACKAGE_NAME, LICENSE_FILE_NAME).delete();
assertThat(ModuleLicenseProvider.isCachedHtmlFileOutdated(context, PACKAGE_NAME)).isTrue();
}
@Test
public void isCachedHtmlFileOutdated_fileIsEmpty_returnTrue()
throws PackageManager.NameNotFoundException, IOException {
Context context = spy(ApplicationProvider.getApplicationContext());
context.getSharedPreferences(ModuleLicenseProvider.PREFS_NAME, Context.MODE_PRIVATE)
.edit().clear().commit();
SharedPreferences.Editor editor = context.getSharedPreferences(
ModuleLicenseProvider.PREFS_NAME, Context.MODE_PRIVATE)
.edit();
editor.clear().commit();
editor.putLong(PACKAGE_NAME, 1000L).commit();
PackageManager packageManager = mock(PackageManager.class);
doReturn(packageManager).when(context).getPackageManager();
PackageInfo packageInfo = new PackageInfo();
packageInfo.setLongVersionCode(1000L);
when(packageManager.getPackageInfo(PACKAGE_NAME, PackageManager.MATCH_APEX))
.thenReturn(packageInfo);
new File(context.getCacheDir(), PACKAGE_NAME).mkdir();
File file = new File(context.getCacheDir() + "/" + PACKAGE_NAME, LICENSE_FILE_NAME);
file.delete();
file.createNewFile();
assertThat(ModuleLicenseProvider.isCachedHtmlFileOutdated(context, PACKAGE_NAME)).isTrue();
}
@Test
public void isCachedHtmlFileOutdated_notOutdated_returnFalse()
throws PackageManager.NameNotFoundException, IOException {
Context context = spy(ApplicationProvider.getApplicationContext());
context.getSharedPreferences(ModuleLicenseProvider.PREFS_NAME, Context.MODE_PRIVATE)
.edit().clear().commit();
SharedPreferences.Editor editor = context.getSharedPreferences(
ModuleLicenseProvider.PREFS_NAME, Context.MODE_PRIVATE)
.edit();
editor.clear().commit();
editor.putLong(PACKAGE_NAME, 1000L).commit();
PackageManager packageManager = mock(PackageManager.class);
doReturn(packageManager).when(context).getPackageManager();
PackageInfo packageInfo = new PackageInfo();
packageInfo.setLongVersionCode(1000L);
when(packageManager.getPackageInfo(PACKAGE_NAME, PackageManager.MATCH_APEX))
.thenReturn(packageInfo);
new File(context.getCacheDir(), PACKAGE_NAME).mkdir();
File file = new File(context.getCacheDir() + "/" + PACKAGE_NAME, LICENSE_FILE_NAME);
file.delete();
file.createNewFile();
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write("test");
}
assertThat(ModuleLicenseProvider.isCachedHtmlFileOutdated(context, PACKAGE_NAME)).isFalse();
}
@Test
public void getUriForPackage_returnsProperlyFormattedUri() {
assertThat(ModuleLicenseProvider.getUriForPackage(PACKAGE_NAME))
.isEqualTo(Uri.parse(
"content://com.android.settings.module_licenses/"
+ "com.android.test_package/NOTICE.html"));
}
}

View File

@@ -0,0 +1,767 @@
/*
* Copyright (C) 2017 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.deviceinfo.simstatus;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.CELL_DATA_NETWORK_TYPE_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.CELL_VOICE_NETWORK_TYPE_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.EID_INFO_LABEL_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.EID_INFO_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.ICCID_INFO_LABEL_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.ICCID_INFO_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.IMS_REGISTRATION_STATE_LABEL_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.IMS_REGISTRATION_STATE_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.MAX_PHONE_COUNT_SINGLE_SIM;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.NETWORK_PROVIDER_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.OPERATOR_INFO_LABEL_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.OPERATOR_INFO_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.ROAMING_INFO_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.SERVICE_STATE_VALUE_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.SIGNAL_STRENGTH_LABEL_ID;
import static com.android.settings.deviceinfo.simstatus.SimStatusDialogController.SIGNAL_STRENGTH_VALUE_ID;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
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.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.CellSignalStrength;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.UiccCardInfo;
import android.telephony.euicc.EuiccManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.R;
import com.android.settings.testutils.ResourcesUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RunWith(AndroidJUnit4.class)
public class SimStatusDialogControllerTest {
@Mock
private SimStatusDialogFragment mDialog;
private TelephonyManager mTelephonyManager;
@Mock
private SubscriptionInfo mSubscriptionInfo;
@Mock
private ServiceState mServiceState;
@Mock
private SignalStrength mSignalStrength;
@Mock
private CellSignalStrength mCellSignalStrengthCdma;
@Mock
private CellSignalStrength mCellSignalStrengthLte;
@Mock
private CellSignalStrength mCellSignalStrengthWcdma;
@Mock
private CarrierConfigManager mCarrierConfigManager;
private PersistableBundle mPersistableBundle;
@Mock
private EuiccManager mEuiccManager;
private SubscriptionManager mSubscriptionManager;
private SimStatusDialogController mController;
private Context mContext;
@Mock
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
private static final String TEST_EID_FROM_CARD = "11111111111111111111111111111111";
private static final String TEST_EID_FROM_MANAGER = "22222222222222222222222222222222";
private static final int MAX_PHONE_COUNT_DUAL_SIM = 2;
@Before
@UiThreadTest
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mDialog.getContext()).thenReturn(mContext);
mLifecycle = new Lifecycle(mLifecycleOwner);
mTelephonyManager = spy(mContext.getSystemService(TelephonyManager.class));
mSubscriptionManager = spy(mContext.getSystemService(SubscriptionManager.class));
doReturn(mSubscriptionInfo).when(mSubscriptionManager)
.getActiveSubscriptionInfoForSimSlotIndex(anyInt());
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(CarrierConfigManager.class)).thenReturn(
mCarrierConfigManager);
when(mContext.getSystemService(EuiccManager.class)).thenReturn(mEuiccManager);
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
anyInt());
doReturn(2).when(mTelephonyManager).getCardIdForDefaultEuicc();
doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mTelephonyManager).getDataNetworkType();
mController = spy(new SimStatusDialogController(mDialog, mLifecycle, 0 /* phone id */));
// CellSignalStrength setup
doReturn(0).when(mCellSignalStrengthCdma).getDbm();
doReturn(0).when(mCellSignalStrengthCdma).getAsuLevel();
doReturn(0).when(mCellSignalStrengthLte).getDbm();
doReturn(0).when(mCellSignalStrengthLte).getAsuLevel();
doReturn(0).when(mCellSignalStrengthWcdma).getDbm();
doReturn(0).when(mCellSignalStrengthWcdma).getAsuLevel();
doReturn(null).when(mSignalStrength).getCellSignalStrengths();
doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_SINGLE_SIM);
doReturn(new ArrayList<UiccCardInfo>()).when(mTelephonyManager).getUiccCardsInfo();
doReturn(new HashMap<Integer, Integer>()).when(mTelephonyManager)
.getLogicalToPhysicalSlotMapping();
when(mEuiccManager.isEnabled()).thenReturn(false);
when(mEuiccManager.getEid()).thenReturn("");
when(mEuiccManager.createForCardId(anyInt())).thenReturn(mEuiccManager);
mPersistableBundle = new PersistableBundle();
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mPersistableBundle);
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, true);
doReturn(mServiceState).when(mTelephonyManager).getServiceState();
doReturn(mSignalStrength).when(mTelephonyManager).getSignalStrength();
}
@Test
public void initialize_updateNetworkProviderWithFoobarCarrier_shouldUpdateCarrierWithFoobar() {
final CharSequence carrierName = "foobar";
doReturn(carrierName).when(mSubscriptionInfo).getCarrierName();
mController.initialize();
verify(mDialog).setText(NETWORK_PROVIDER_VALUE_ID, carrierName);
}
@Test
public void initialize_shouldUpdatePhoneNumber() {
mController.initialize();
verify(mController).updatePhoneNumber();
}
@Test
public void initialize_updateLatestAreaInfoWithCdmaPhone_shouldRemoveOperatorInfoSetting() {
when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA);
mController.initialize();
verify(mDialog).removeSettingFromScreen(OPERATOR_INFO_LABEL_ID);
verify(mDialog).removeSettingFromScreen(OPERATOR_INFO_VALUE_ID);
}
@Test
public void initialize_updateServiceStateWithInService_shouldUpdateTextToBeCInService() {
when(mServiceState.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
mController.initialize();
final String inServiceText = ResourcesUtils.getResourcesString(
mContext, "radioInfo_service_in");
verify(mDialog).setText(SERVICE_STATE_VALUE_ID, inServiceText);
}
@Test
public void initialize_updateServiceStateWithPowerOff_shouldUpdateTextAndResetSignalStrength() {
when(mServiceState.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
mController.initialize();
final String offServiceText = ResourcesUtils.getResourcesString(
mContext, "radioInfo_service_off");
verify(mDialog).setText(SERVICE_STATE_VALUE_ID, offServiceText);
verify(mDialog).setText(SIGNAL_STRENGTH_VALUE_ID, "0");
}
@Test
public void initialize_updateVoiceDataOutOfService_shouldUpdateSettingAndResetSignalStrength() {
when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(
ServiceState.STATE_OUT_OF_SERVICE);
mController.initialize();
final String offServiceText = ResourcesUtils.getResourcesString(
mContext, "radioInfo_service_out");
verify(mDialog).setText(SERVICE_STATE_VALUE_ID, offServiceText);
verify(mDialog).setText(SIGNAL_STRENGTH_VALUE_ID, "0");
}
@Test
public void initialize_updateVoiceOutOfServiceDataInService_shouldUpdateTextToBeInService() {
when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
mController.initialize();
final String inServiceText = ResourcesUtils.getResourcesString(
mContext, "radioInfo_service_in");
verify(mDialog).setText(SERVICE_STATE_VALUE_ID, inServiceText);
}
@Test
public void initialize_updateSignalStrengthWithLte50Wcdma40_shouldUpdateSignalStrengthTo50() {
final int lteDbm = 50;
final int lteAsu = 50;
final int wcdmaDbm = 40;
final int wcdmaAsu = 40;
setupCellSignalStrength_lteWcdma(lteDbm, lteAsu, wcdmaDbm, wcdmaAsu);
mController.initialize();
final String signalStrengthString = ResourcesUtils.getResourcesString(
mContext, "sim_signal_strength", lteDbm, lteAsu);
verify(mDialog, times(2)).setText(SIGNAL_STRENGTH_VALUE_ID, signalStrengthString);
}
@Test
public void initialize_updateSignalStrengthWithLte50Cdma30_shouldUpdateSignalStrengthTo50() {
final int lteDbm = 50;
final int lteAsu = 50;
final int cdmaDbm = 30;
final int cdmaAsu = 30;
setupCellSignalStrength_lteCdma(lteDbm, lteAsu, cdmaDbm, cdmaAsu);
mController.initialize();
final String signalStrengthString = ResourcesUtils.getResourcesString(
mContext, "sim_signal_strength", lteDbm, lteAsu);
verify(mDialog, times(2)).setText(SIGNAL_STRENGTH_VALUE_ID, signalStrengthString);
}
@Test
public void initialize_updateVoiceOutOfServiceDataInService_shouldUpdateSignalStrengthTo50() {
when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mServiceState.getDataRegistrationState()).thenReturn(ServiceState.STATE_IN_SERVICE);
final int lteDbm = 50;
final int lteAsu = 50;
setupCellSignalStrength_lteOnly(lteDbm, lteAsu);
mController.initialize();
final String signalStrengthString = ResourcesUtils.getResourcesString(
mContext, "sim_signal_strength", lteDbm, lteAsu);
verify(mDialog, times(2)).setText(SIGNAL_STRENGTH_VALUE_ID, signalStrengthString);
}
@Test
public void initialize_updateVoiceNetworkTypeWithEdge_shouldUpdateSettingToEdge() {
when(mTelephonyManager.getVoiceNetworkType()).thenReturn(
TelephonyManager.NETWORK_TYPE_EDGE);
mController.initialize();
verify(mDialog).setText(CELL_VOICE_NETWORK_TYPE_VALUE_ID,
SimStatusDialogController.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_EDGE));
}
@Test
public void initialize_updateDataNetworkTypeWithEdge_shouldUpdateSettingToEdge() {
when(mTelephonyManager.getDataNetworkType()).thenReturn(
TelephonyManager.NETWORK_TYPE_EDGE);
mController.initialize();
verify(mDialog).setText(CELL_DATA_NETWORK_TYPE_VALUE_ID,
SimStatusDialogController.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_EDGE));
}
@Test
public void initialize_updateRoamingStatusIsRoaming_shouldSetSettingToRoaming() {
when(mServiceState.getRoaming()).thenReturn(true);
mController.initialize();
final String roamingOnString = ResourcesUtils.getResourcesString(
mContext, "radioInfo_roaming_in");
verify(mDialog).setText(ROAMING_INFO_VALUE_ID, roamingOnString);
}
@Test
public void initialize_updateRoamingStatusNotRoaming_shouldSetSettingToRoamingOff() {
when(mServiceState.getRoaming()).thenReturn(false);
mController.initialize();
final String roamingOffString = ResourcesUtils.getResourcesString(
mContext, "radioInfo_roaming_not");
verify(mDialog).setText(ROAMING_INFO_VALUE_ID, roamingOffString);
}
@Test
public void initialize_doNotShowIccid_shouldRemoveIccidSetting() {
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
mController.initialize();
verify(mDialog).removeSettingFromScreen(ICCID_INFO_LABEL_ID);
verify(mDialog).removeSettingFromScreen(ICCID_INFO_VALUE_ID);
}
@Test
public void initialize_doNotShowSignalStrength_shouldRemoveSignalStrengthSetting() {
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL, false);
mController.initialize();
verify(mDialog, times(2)).removeSettingFromScreen(SIGNAL_STRENGTH_LABEL_ID);
verify(mDialog, times(2)).removeSettingFromScreen(SIGNAL_STRENGTH_VALUE_ID);
}
@Test
public void initialize_showSignalStrengthAndIccId_shouldShowSignalStrengthAndIccIdSetting() {
// getConfigForSubId is nullable, so make sure the default behavior is correct
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(null);
mController.initialize();
verify(mDialog, times(2)).setText(eq(SIGNAL_STRENGTH_VALUE_ID), any());
verify(mDialog).removeSettingFromScreen(ICCID_INFO_LABEL_ID);
verify(mDialog).removeSettingFromScreen(ICCID_INFO_VALUE_ID);
}
@Test
public void initialize_showIccid_shouldSetIccidToSetting() {
final String iccid = "12351351231241";
mPersistableBundle.putBoolean(CarrierConfigManager.KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, true);
doReturn(iccid).when(mTelephonyManager).getSimSerialNumber();
mController.initialize();
verify(mDialog).setText(ICCID_INFO_VALUE_ID, iccid);
}
@Test
public void initialize_updateEid_shouldNotSetEid() {
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_DUAL_SIM);
ArrayList<UiccCardInfo> uiccCardInfos = new ArrayList<>();
UiccCardInfo uiccCardInfo1 = new UiccCardInfo(
false, // isEuicc
0, // cardId
null, // eid
"123451234567890", // iccid
0, // slotIndex
true); // isRemovable
uiccCardInfos.add(uiccCardInfo1);
UiccCardInfo uiccCardInfo2 = new UiccCardInfo(
true, // isEuicc
1, // cardId
null, // eid (unavailable)
null, // iccid
1, // slotIndex
false); // isRemovable
uiccCardInfos.add(uiccCardInfo2);
when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos);
Map<Integer, Integer> slotMapping = new HashMap<>();
slotMapping.put(0, 1);
slotMapping.put(1, 0);
when(mTelephonyManager.getLogicalToPhysicalSlotMapping()).thenReturn(slotMapping);
when(mEuiccManager.isEnabled()).thenReturn(true);
when(mEuiccManager.getEid()).thenReturn(null);
doNothing().when(mController).requestForUpdateEid();
mController.updateEid(mController.getEid(0));
mController.initialize();
// Keep 'Not available' if neither the card nor the associated manager can provide EID.
verify(mDialog, never()).setText(eq(EID_INFO_VALUE_ID), any());
verify(mDialog, never()).removeSettingFromScreen(eq(EID_INFO_VALUE_ID));
}
@Test
public void initialize_updateEid_shouldSetEidFromCard() {
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_DUAL_SIM);
ArrayList<UiccCardInfo> uiccCardInfos = new ArrayList<>();
UiccCardInfo uiccCardInfo1 = new UiccCardInfo(
true, // isEuicc
0, // cardId
TEST_EID_FROM_CARD, // eid
null, // iccid
0, // slotIndex
false); // isRemovable
uiccCardInfos.add(uiccCardInfo1);
UiccCardInfo uiccCardInfo2 = new UiccCardInfo(
false, // isEuicc
1, // cardId
null, // eid
"123451234567890", // iccid
1, // slotIndex
true); // isRemovable
uiccCardInfos.add(uiccCardInfo2);
when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos);
Map<Integer, Integer> slotMapping = new HashMap<>();
slotMapping.put(0, 0);
slotMapping.put(1, 1);
when(mTelephonyManager.getLogicalToPhysicalSlotMapping()).thenReturn(slotMapping);
when(mEuiccManager.isEnabled()).thenReturn(true);
when(mEuiccManager.getEid()).thenReturn(TEST_EID_FROM_MANAGER);
when(mEuiccManager.createForCardId(0)).thenReturn(mEuiccManager);
doNothing().when(mController).requestForUpdateEid();
mController.updateEid(mController.getEid(0));
mController.initialize();
// Set EID retrieved from the card.
verify(mDialog).setText(EID_INFO_VALUE_ID, TEST_EID_FROM_CARD);
verify(mDialog, never()).removeSettingFromScreen(eq(EID_INFO_VALUE_ID));
}
@Test
public void initialize_updateEid_shouldSetEidFromManager() {
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_DUAL_SIM);
ArrayList<UiccCardInfo> uiccCardInfos = new ArrayList<>();
UiccCardInfo uiccCardInfo1 = new UiccCardInfo(
false, // isEuicc
0, // cardId
null, // eid
"123451234567890", // iccid
0, // slotIndex
true); // isRemovable
uiccCardInfos.add(uiccCardInfo1);
UiccCardInfo uiccCardInfo2 = new UiccCardInfo(
true, // isEuicc
1, // cardId
null, // eid (unavailable)
null, // iccid
1, // slotIndex
false); // isRemovable
uiccCardInfos.add(uiccCardInfo2);
when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos);
Map<Integer, Integer> slotMapping = new HashMap<>();
slotMapping.put(0, 1);
slotMapping.put(1, 0);
when(mTelephonyManager.getLogicalToPhysicalSlotMapping()).thenReturn(slotMapping);
when(mEuiccManager.isEnabled()).thenReturn(true);
when(mEuiccManager.getEid()).thenReturn(TEST_EID_FROM_MANAGER);
when(mEuiccManager.createForCardId(0)).thenThrow(
new RuntimeException("Unexpected card ID was specified"));
when(mEuiccManager.createForCardId(1)).thenReturn(mEuiccManager);
doNothing().when(mController).requestForUpdateEid();
mController.updateEid(mController.getEid(0));
mController.initialize();
// Set EID retrieved from the manager associated with the card which cannot provide EID.
verify(mDialog).setText(EID_INFO_VALUE_ID, TEST_EID_FROM_MANAGER);
verify(mDialog, never()).removeSettingFromScreen(eq(EID_INFO_VALUE_ID));
}
@Test
public void initialize_updateEid_shouldRemoveEid() {
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_DUAL_SIM);
ArrayList<UiccCardInfo> uiccCardInfos = new ArrayList<>();
UiccCardInfo uiccCardInfo1 = new UiccCardInfo(
false, // isEuicc
0, // cardId
null, // eid
"123451234567890", // iccid
0, // slotIndex
true); // isRemovable
uiccCardInfos.add(uiccCardInfo1);
UiccCardInfo uiccCardInfo2 = new UiccCardInfo(
true, // isEuicc
1, // cardId
TEST_EID_FROM_CARD, // eid
null, // iccid
1, // slotIndex
false); // isRemovable
uiccCardInfos.add(uiccCardInfo2);
when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos);
Map<Integer, Integer> slotMapping = new HashMap<>();
slotMapping.put(0, 0);
slotMapping.put(1, 1);
when(mTelephonyManager.getLogicalToPhysicalSlotMapping()).thenReturn(slotMapping);
when(mEuiccManager.isEnabled()).thenReturn(true);
when(mEuiccManager.getEid()).thenReturn(TEST_EID_FROM_MANAGER);
doNothing().when(mController).requestForUpdateEid();
mController.updateEid(mController.getEid(0));
mController.initialize();
// Remove EID if the card is not eUICC.
verify(mDialog, never()).setText(eq(EID_INFO_VALUE_ID), any());
verify(mDialog).removeSettingFromScreen(eq(EID_INFO_LABEL_ID));
verify(mDialog).removeSettingFromScreen(eq(EID_INFO_VALUE_ID));
}
@Test
public void initialize_updateEid_shouldNotSetEidInSingleSimMode() {
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_SINGLE_SIM);
ArrayList<UiccCardInfo> uiccCardInfos = new ArrayList<>();
UiccCardInfo uiccCardInfo = new UiccCardInfo(
true, // isEuicc
0, // cardId
TEST_EID_FROM_CARD, // eid (not used)
null, // iccid
0, // slotIndex
false); // isRemovable
uiccCardInfos.add(uiccCardInfo);
when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos);
Map<Integer, Integer> slotMapping = new HashMap<>();
slotMapping.put(0, 0);
when(mTelephonyManager.getLogicalToPhysicalSlotMapping()).thenReturn(slotMapping);
when(mEuiccManager.isEnabled()).thenReturn(true);
when(mEuiccManager.getEid()).thenReturn(null);
doNothing().when(mController).requestForUpdateEid();
mController.updateEid(mController.getEid(0));
mController.initialize();
// Keep 'Not available' if the default eUICC manager cannot provide EID in Single SIM mode.
verify(mDialog, never()).setText(eq(EID_INFO_VALUE_ID), any());
verify(mDialog, never()).removeSettingFromScreen(eq(EID_INFO_VALUE_ID));
}
@Test
public void initialize_updateEid_shouldSetEidInSingleSimModeWithEnabledEuicc() {
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_SINGLE_SIM);
ArrayList<UiccCardInfo> uiccCardInfos = new ArrayList<>();
UiccCardInfo uiccCardInfo = new UiccCardInfo(
true, // isEuicc (eUICC slot is selected)
0, // cardId
TEST_EID_FROM_CARD, // eid (not used)
null, // iccid
0, // slotIndex
false); // isRemovable
uiccCardInfos.add(uiccCardInfo);
when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos);
Map<Integer, Integer> slotMapping = new HashMap<>();
slotMapping.put(0, 0);
when(mTelephonyManager.getLogicalToPhysicalSlotMapping()).thenReturn(slotMapping);
when(mEuiccManager.isEnabled()).thenReturn(true);
when(mEuiccManager.getEid()).thenReturn(TEST_EID_FROM_MANAGER);
when(mEuiccManager.createForCardId(anyInt())).thenThrow(
new RuntimeException("EID shall be retrieved from the default eUICC manager"));
doNothing().when(mController).requestForUpdateEid();
mController.updateEid(mController.getEid(0));
mController.initialize();
// Set EID retrieved from the default eUICC manager in Single SIM mode.
verify(mDialog).setText(EID_INFO_VALUE_ID, TEST_EID_FROM_MANAGER);
verify(mDialog, never()).removeSettingFromScreen(eq(EID_INFO_VALUE_ID));
}
@Test
public void initialize_updateEid_shouldSetEidInSingleSimModeWithDisabledEuicc() {
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_SINGLE_SIM);
ArrayList<UiccCardInfo> uiccCardInfos = new ArrayList<>();
UiccCardInfo uiccCardInfo = new UiccCardInfo(
false, // isEuicc (eUICC slot is not selected)
0, // cardId
null, // eid
"123451234567890", // iccid
0, // slotIndex
true); // isRemovable
uiccCardInfos.add(uiccCardInfo);
when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos);
Map<Integer, Integer> slotMapping = new HashMap<>();
slotMapping.put(0, 0);
when(mTelephonyManager.getLogicalToPhysicalSlotMapping()).thenReturn(slotMapping);
when(mEuiccManager.isEnabled()).thenReturn(true);
when(mEuiccManager.getEid()).thenReturn(TEST_EID_FROM_MANAGER);
when(mEuiccManager.createForCardId(anyInt())).thenThrow(
new RuntimeException("EID shall be retrieved from the default eUICC manager"));
doNothing().when(mController).requestForUpdateEid();
mController.updateEid(mController.getEid(0));
mController.initialize();
// Set EID retrieved from the default eUICC manager in Single SIM mode.
verify(mDialog).setText(EID_INFO_VALUE_ID, TEST_EID_FROM_MANAGER);
verify(mDialog, never()).removeSettingFromScreen(eq(EID_INFO_VALUE_ID));
}
@Test
public void initialize_updateEid_shouldRemoveEidInSingleSimMode() {
when(mTelephonyManager.getActiveModemCount()).thenReturn(MAX_PHONE_COUNT_SINGLE_SIM);
ArrayList<UiccCardInfo> uiccCardInfos = new ArrayList<>();
UiccCardInfo uiccCardInfo = new UiccCardInfo(
false, // isEuicc
0, // cardId
null, // eid
"123451234567890", // iccid
0, // slotIndex
true); // isRemovable
uiccCardInfos.add(uiccCardInfo);
when(mTelephonyManager.getUiccCardsInfo()).thenReturn(uiccCardInfos);
Map<Integer, Integer> slotMapping = new HashMap<>();
slotMapping.put(0, 0);
when(mTelephonyManager.getLogicalToPhysicalSlotMapping()).thenReturn(slotMapping);
when(mEuiccManager.isEnabled()).thenReturn(false);
when(mEuiccManager.getEid()).thenReturn(null);
doNothing().when(mController).requestForUpdateEid();
mController.updateEid(mController.getEid(0));
mController.initialize();
// Remove EID if the default eUICC manager indicates that eSIM is not enabled.
verify(mDialog, never()).setText(eq(EID_INFO_VALUE_ID), any());
verify(mDialog).removeSettingFromScreen(eq(EID_INFO_LABEL_ID));
verify(mDialog).removeSettingFromScreen(eq(EID_INFO_VALUE_ID));
}
@Test
@Ignore
public void initialize_imsRegistered_shouldSetImsRegistrationStateSummaryToRegisterd() {
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true);
when(mTelephonyManager.isImsRegistered(anyInt())).thenReturn(true);
mController.initialize();
verify(mDialog).setText(IMS_REGISTRATION_STATE_VALUE_ID,
mContext.getString(R.string.ims_reg_status_registered));
}
@Test
@Ignore
public void initialize_imsNotRegistered_shouldSetImsRegistrationStateSummaryToNotRegisterd() {
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true);
when(mTelephonyManager.isImsRegistered(anyInt())).thenReturn(false);
mController.initialize();
verify(mDialog).setText(IMS_REGISTRATION_STATE_VALUE_ID,
mContext.getString(R.string.ims_reg_status_not_registered));
}
@Test
@Ignore
public void initialize_showImsRegistration_shouldNotRemoveImsRegistrationStateSetting() {
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true);
mController.initialize();
verify(mDialog, never()).removeSettingFromScreen(IMS_REGISTRATION_STATE_VALUE_ID);
}
@Test
@Ignore
public void initialize_doNotShowImsRegistration_shouldRemoveImsRegistrationStateSetting() {
mPersistableBundle.putBoolean(
CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
mController.initialize();
verify(mDialog).removeSettingFromScreen(IMS_REGISTRATION_STATE_LABEL_ID);
verify(mDialog).removeSettingFromScreen(IMS_REGISTRATION_STATE_VALUE_ID);
}
@Test
public void initialize_nullSignalStrength_noCrash() {
doReturn(null).when(mTelephonyManager).getSignalStrength();
// we should not crash when running the following line
mController.initialize();
}
private void setupCellSignalStrength_lteWcdma(int lteDbm, int lteAsu, int wcdmaDbm,
int wcdmaAsu) {
doReturn(lteDbm).when(mCellSignalStrengthLte).getDbm();
doReturn(lteAsu).when(mCellSignalStrengthLte).getAsuLevel();
doReturn(wcdmaDbm).when(mCellSignalStrengthWcdma).getDbm();
doReturn(wcdmaAsu).when(mCellSignalStrengthWcdma).getAsuLevel();
List<CellSignalStrength> cellSignalStrengthList = new ArrayList<>(2);
cellSignalStrengthList.add(mCellSignalStrengthLte);
cellSignalStrengthList.add(mCellSignalStrengthWcdma);
doReturn(cellSignalStrengthList).when(mSignalStrength).getCellSignalStrengths();
}
private void setupCellSignalStrength_lteCdma(int lteDbm, int lteAsu, int cdmaDbm, int cdmaAsu) {
doReturn(lteDbm).when(mCellSignalStrengthLte).getDbm();
doReturn(lteAsu).when(mCellSignalStrengthLte).getAsuLevel();
doReturn(cdmaDbm).when(mCellSignalStrengthCdma).getDbm();
doReturn(cdmaAsu).when(mCellSignalStrengthCdma).getAsuLevel();
List<CellSignalStrength> cellSignalStrengthList = new ArrayList<>(2);
cellSignalStrengthList.add(mCellSignalStrengthLte);
cellSignalStrengthList.add(mCellSignalStrengthCdma);
doReturn(cellSignalStrengthList).when(mSignalStrength).getCellSignalStrengths();
}
private void setupCellSignalStrength_lteOnly(int lteDbm, int lteAsu) {
doReturn(lteDbm).when(mCellSignalStrengthLte).getDbm();
doReturn(lteAsu).when(mCellSignalStrengthLte).getAsuLevel();
List<CellSignalStrength> cellSignalStrengthList = new ArrayList<>(2);
cellSignalStrengthList.add(mCellSignalStrengthLte);
doReturn(cellSignalStrengthList).when(mSignalStrength).getCellSignalStrengths();
}
}

View File

@@ -22,7 +22,9 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -30,20 +32,22 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.TrafficStats;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.SparseArray;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.R;
import com.android.settingslib.applications.StorageStatsSource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -57,11 +61,11 @@ public class StorageAsyncLoaderTest {
private static final int SECONDARY_USER_ID = 10;
private static final String PACKAGE_NAME_1 = "com.blah.test";
private static final String PACKAGE_NAME_2 = "com.blah.test2";
private static final String PACKAGE_NAME_3 = "com.blah.test3";
private static final long DEFAULT_QUOTA = 64 * TrafficStats.MB_IN_BYTES;
@Mock
private StorageStatsSource mSource;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@Mock
private PackageManager mPackageManager;
@@ -76,6 +80,7 @@ public class StorageAsyncLoaderTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
mInfo = new ArrayList<>();
mLoader = new StorageAsyncLoader(mContext, mUserManager, "id", mSource, mPackageManager);
when(mPackageManager.getInstalledApplicationsAsUser(eq(PRIMARY_USER_ID), anyInt()))
@@ -85,6 +90,10 @@ public class StorageAsyncLoaderTest {
mUsers.add(info);
when(mUserManager.getUsers()).thenReturn(mUsers);
when(mSource.getCacheQuotaBytes(anyString(), anyInt())).thenReturn(DEFAULT_QUOTA);
final Resources resources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(resources);
doReturn("content://com.android.providers.media.documents/root/videos_root")
.when(resources).getString(R.string.config_videos_storage_category_uri);
}
@Test
@@ -92,22 +101,22 @@ public class StorageAsyncLoaderTest {
addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
addPackage(PACKAGE_NAME_2, 0, 100, 1000, ApplicationInfo.CATEGORY_UNDEFINED);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(PRIMARY_USER_ID).gamesSize).isEqualTo(0L);
assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(1111L);
assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(1111L);
}
@Test
public void testGamesAreFiltered() throws Exception {
addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_GAME);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(PRIMARY_USER_ID).gamesSize).isEqualTo(11L);
assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(0);
assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(0);
}
@Test
@@ -116,21 +125,21 @@ public class StorageAsyncLoaderTest {
addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
info.flags = ApplicationInfo.FLAG_IS_GAME;
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(PRIMARY_USER_ID).gamesSize).isEqualTo(11L);
assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(0);
assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(0);
}
@Test
public void testCacheIsNotIgnored() throws Exception {
addPackage(PACKAGE_NAME_1, 100, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(111L);
assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(111L);
}
@Test
@@ -143,7 +152,7 @@ public class StorageAsyncLoaderTest {
when(mSource.getExternalStorageStats(anyString(), eq(new UserHandle(SECONDARY_USER_ID))))
.thenReturn(new StorageStatsSource.ExternalStorageStats(10, 3, 3, 4, 0));
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(2);
assertThat(result.get(PRIMARY_USER_ID).externalStats.totalBytes).isEqualTo(9L);
@@ -156,21 +165,10 @@ public class StorageAsyncLoaderTest {
addPackage(PACKAGE_NAME_1, 100, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
systemApp.flags = ApplicationInfo.FLAG_SYSTEM & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(111L);
}
@Test
public void testVideoAppsAreFiltered() throws Exception {
addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_VIDEO);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(PRIMARY_USER_ID).videoAppsSize).isEqualTo(11L);
assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(0);
assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(111L);
}
@Test
@@ -182,43 +180,32 @@ public class StorageAsyncLoaderTest {
when(mSource.getStatsForPackage(anyString(), anyString(), any(UserHandle.class)))
.thenThrow(new NameNotFoundException());
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
// Should not crash.
}
@Test
public void testPackageIsNotDoubleCounted() throws Exception {
UserInfo info = new UserInfo();
info.id = SECONDARY_USER_ID;
mUsers.add(info);
when(mSource.getExternalStorageStats(anyString(), eq(UserHandle.SYSTEM)))
.thenReturn(new StorageStatsSource.ExternalStorageStats(9, 2, 3, 4, 0));
when(mSource.getExternalStorageStats(anyString(), eq(new UserHandle(SECONDARY_USER_ID))))
.thenReturn(new StorageStatsSource.ExternalStorageStats(10, 3, 3, 4, 0));
addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_VIDEO);
ArrayList<ApplicationInfo> secondaryUserApps = new ArrayList<>();
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.packageName = PACKAGE_NAME_1;
appInfo.category = ApplicationInfo.CATEGORY_VIDEO;
secondaryUserApps.add(appInfo);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(2);
assertThat(result.get(PRIMARY_USER_ID).videoAppsSize).isEqualTo(11L);
// No code size for the second user.
assertThat(result.get(SECONDARY_USER_ID).videoAppsSize).isEqualTo(10L);
}
@Test
public void testCacheOveragesAreCountedAsFree() throws Exception {
addPackage(PACKAGE_NAME_1, DEFAULT_QUOTA + 100, 1, 10, ApplicationInfo.CATEGORY_UNDEFINED);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = mLoader.loadInBackground();
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(DEFAULT_QUOTA + 11);
assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize)
.isEqualTo(DEFAULT_QUOTA + 11);
}
@Test
public void testAppsAreFiltered() throws Exception {
addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_IMAGE);
addPackage(PACKAGE_NAME_2, 0, 1, 10, ApplicationInfo.CATEGORY_VIDEO);
addPackage(PACKAGE_NAME_3, 0, 1, 10, ApplicationInfo.CATEGORY_AUDIO);
SparseArray<StorageAsyncLoader.StorageResult> result = mLoader.loadInBackground();
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(PRIMARY_USER_ID).allAppsExceptGamesSize).isEqualTo(33L);
}
private ApplicationInfo addPackage(String packageName, long cacheSize, long codeSize,

View File

@@ -0,0 +1,323 @@
/*
* Copyright (C) 2021 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.deviceinfo.storage;
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.Context;
import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.testutils.ResourcesUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.File;
import java.util.Objects;
@RunWith(AndroidJUnit4.class)
public class StorageEntryTest {
private static final String VOLUME_INFO_ID = "volume_info_id";
private static final String DISK_INFO_ID = "disk_info_id";
private static final String VOLUME_RECORD_UUID = "volume_record_id";
@Mock
private VolumeInfo mVolumeInfo;
@Mock
private DiskInfo mDiskInfo;
@Mock
private VolumeRecord mVolumeRecord;
private Context mContext;
@Mock
private StorageManager mStorageManager;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager);
}
@Test
public void equals_volumesOfSameId_shouldBeTheSame() {
final StorageEntry volumeStorage1 = new StorageEntry(mContext,
new VolumeInfo(VOLUME_INFO_ID, 0 /* type */, null /* disk */, null /* partGuid */));
final StorageEntry volumeStorage2 = new StorageEntry(mContext,
new VolumeInfo(VOLUME_INFO_ID, 0 /* type */, null /* disk */, null /* partGuid */));
final StorageEntry diskStorage1 =
new StorageEntry(new DiskInfo(DISK_INFO_ID, 0 /* flags */));
final StorageEntry diskStorage2 =
new StorageEntry(new DiskInfo(DISK_INFO_ID, 0 /* flags */));
final StorageEntry volumeRecordStorage1 = new StorageEntry(new VolumeRecord(0 /* flags */,
VOLUME_RECORD_UUID));
final StorageEntry volumeRecordStorage2 = new StorageEntry(new VolumeRecord(0 /* flags */,
VOLUME_RECORD_UUID));
assertThat(Objects.equals(volumeStorage1, volumeStorage2)).isTrue();
assertThat(Objects.equals(diskStorage1, diskStorage2)).isTrue();
assertThat(Objects.equals(volumeRecordStorage1, volumeRecordStorage2)).isTrue();
}
@Test
public void equals_volumesOfDifferentId_shouldBeDifferent() {
final StorageEntry volumeStorage1 = new StorageEntry(mContext,
new VolumeInfo(VOLUME_INFO_ID, 0 /* type */, null /* disk */, null /* partGuid */));
final StorageEntry volumeStorage2 = new StorageEntry(mContext,
new VolumeInfo("id2", 0 /* type */, null /* disk */, null /* partGuid */));
final StorageEntry diskStorage1 =
new StorageEntry(new DiskInfo(DISK_INFO_ID, 0 /* flags */));
final StorageEntry diskStorage2 =
new StorageEntry(new DiskInfo("id2", 0 /* flags */));
final StorageEntry volumeRecordStorage1 = new StorageEntry(new VolumeRecord(0 /* flags */,
VOLUME_RECORD_UUID));
final StorageEntry volumeRecordStorage2 = new StorageEntry(new VolumeRecord(0 /* flags */,
"id2"));
assertThat(Objects.equals(volumeStorage1, volumeStorage2)).isFalse();
assertThat(Objects.equals(diskStorage1, diskStorage2)).isFalse();
assertThat(Objects.equals(volumeRecordStorage1, volumeRecordStorage2)).isFalse();
}
@Test
public void compareTo_defaultInternalStorage_shouldBeAtTopMost() {
final StorageEntry storage1 = mock(StorageEntry.class);
when(storage1.isDefaultInternalStorage()).thenReturn(true);
final StorageEntry storage2 = mock(StorageEntry.class);
when(storage2.isDefaultInternalStorage()).thenReturn(false);
assertThat(storage1.compareTo(storage2) > 0).isTrue();
}
@Test
public void getDefaultInternalStorageEntry_shouldReturnVolumeInfoStorageOfIdPrivateInternal() {
final VolumeInfo volumeInfo = mock(VolumeInfo.class);
when(mStorageManager.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL)).thenReturn(volumeInfo);
assertThat(StorageEntry.getDefaultInternalStorageEntry(mContext))
.isEqualTo(new StorageEntry(mContext, volumeInfo));
}
@Test
public void isVolumeInfo_shouldReturnTrueForVolumeInfo() {
final VolumeInfo volumeInfo = mock(VolumeInfo.class);
final StorageEntry storage = new StorageEntry(mContext, volumeInfo);
assertThat(storage.isVolumeInfo()).isTrue();
assertThat(storage.isDiskInfoUnsupported()).isFalse();
assertThat(storage.isVolumeRecordMissed()).isFalse();
}
@Test
public void isDiskInfoUnsupported_shouldReturnTrueForDiskInfo() {
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry storage = new StorageEntry(diskInfo);
assertThat(storage.isVolumeInfo()).isFalse();
assertThat(storage.isDiskInfoUnsupported()).isTrue();
assertThat(storage.isVolumeRecordMissed()).isFalse();
}
@Test
public void isVolumeRecordMissed_shouldReturnTrueForVolumeRecord() {
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry storage = new StorageEntry(volumeRecord);
assertThat(storage.isVolumeInfo()).isFalse();
assertThat(storage.isDiskInfoUnsupported()).isFalse();
assertThat(storage.isVolumeRecordMissed()).isTrue();
}
@Test
public void isMounted_mountedOrMountedReadOnly_shouldReturnTrue() {
final VolumeInfo mountedVolumeInfo1 = mock(VolumeInfo.class);
final StorageEntry mountedStorage1 = new StorageEntry(mContext, mountedVolumeInfo1);
when(mountedVolumeInfo1.getState()).thenReturn(VolumeInfo.STATE_MOUNTED);
final VolumeInfo mountedVolumeInfo2 = mock(VolumeInfo.class);
when(mountedVolumeInfo2.getState()).thenReturn(VolumeInfo.STATE_MOUNTED_READ_ONLY);
final StorageEntry mountedStorage2 = new StorageEntry(mContext, mountedVolumeInfo2);
assertThat(mountedStorage1.isMounted()).isTrue();
assertThat(mountedStorage2.isMounted()).isTrue();
}
@Test
public void isMounted_nonVolumeInfo_shouldReturnFalse() {
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry diskStorage = new StorageEntry(diskInfo);
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry recordStorage2 = new StorageEntry(volumeRecord);
assertThat(diskStorage.isMounted()).isFalse();
assertThat(recordStorage2.isMounted()).isFalse();
}
@Test
public void isUnmountable_unmountableVolume_shouldReturnTrue() {
final VolumeInfo unmountableVolumeInfo = mock(VolumeInfo.class);
final StorageEntry mountedStorage = new StorageEntry(mContext, unmountableVolumeInfo);
when(unmountableVolumeInfo.getState()).thenReturn(VolumeInfo.STATE_UNMOUNTABLE);
assertThat(mountedStorage.isUnmountable()).isTrue();
}
@Test
public void isUnmountable_nonVolumeInfo_shouldReturnFalse() {
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry diskStorage = new StorageEntry(diskInfo);
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry recordStorage2 = new StorageEntry(volumeRecord);
assertThat(diskStorage.isUnmountable()).isFalse();
assertThat(recordStorage2.isUnmountable()).isFalse();
}
@Test
public void isPrivate_privateVolume_shouldReturnTrue() {
final VolumeInfo privateVolumeInfo = mock(VolumeInfo.class);
final StorageEntry privateStorage = new StorageEntry(mContext, privateVolumeInfo);
when(privateVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
assertThat(privateStorage.isPrivate()).isTrue();
}
@Test
public void isPublic_prublicVolume_shouldReturnTrue() {
final VolumeInfo publicVolumeInfo = mock(VolumeInfo.class);
final StorageEntry publicStorage = new StorageEntry(mContext, publicVolumeInfo);
when(publicVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PUBLIC);
assertThat(publicStorage.isPublic()).isTrue();
}
@Test
public void isPrivate_nonVolumeInfo_shouldReturnFalse() {
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry diskStorage = new StorageEntry(diskInfo);
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry recordStorage2 = new StorageEntry(volumeRecord);
assertThat(diskStorage.isPrivate()).isFalse();
assertThat(recordStorage2.isPrivate()).isFalse();
}
@Test
public void getDescription_shouldReturnDescription() {
final String description = "description";
final VolumeInfo volumeInfo = mock(VolumeInfo.class);
when(mStorageManager.getBestVolumeDescription(volumeInfo)).thenReturn(description);
final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry diskStorage = new StorageEntry(diskInfo);
when(diskInfo.getDescription()).thenReturn(description);
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry recordStorage = new StorageEntry(volumeRecord);
when(volumeRecord.getNickname()).thenReturn(description);
assertThat(volumeStorage.getDescription()).isEqualTo(description);
assertThat(diskStorage.getDescription()).isEqualTo(description);
assertThat(recordStorage.getDescription()).isEqualTo(description);
}
@Test
public void getDescription_defaultInternalStorage_returnThisDevice() {
final VolumeInfo volumeInfo = mock(VolumeInfo.class);
when(volumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE);
when(volumeInfo.getId()).thenReturn(VolumeInfo.ID_PRIVATE_INTERNAL);
final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
assertThat(volumeStorage.getDescription()).isEqualTo(
ResourcesUtils.getResourcesString(mContext, "storage_default_internal_storage"));
}
@Test
public void getDiskId_shouldReturnDiskId() {
final VolumeInfo volumeInfo = mock(VolumeInfo.class);
final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
when(volumeInfo.getDiskId()).thenReturn(VOLUME_INFO_ID);
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry diskStorage = new StorageEntry(diskInfo);
when(diskInfo.getId()).thenReturn(DISK_INFO_ID);
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry recordStorage = new StorageEntry(volumeRecord);
assertThat(volumeStorage.getDiskId()).isEqualTo(VOLUME_INFO_ID);
assertThat(diskStorage.getDiskId()).isEqualTo(DISK_INFO_ID);
assertThat(recordStorage.getDiskId()).isEqualTo(null);
}
@Test
public void getFsUuid_shouldReturnFsUuid() {
final VolumeInfo volumeInfo = mock(VolumeInfo.class);
final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
when(volumeInfo.getFsUuid()).thenReturn(VOLUME_INFO_ID);
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry diskStorage = new StorageEntry(diskInfo);
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry recordStorage = new StorageEntry(volumeRecord);
when(volumeRecord.getFsUuid()).thenReturn(VOLUME_RECORD_UUID);
assertThat(volumeStorage.getFsUuid()).isEqualTo(VOLUME_INFO_ID);
assertThat(diskStorage.getFsUuid()).isEqualTo(null);
assertThat(recordStorage.getFsUuid()).isEqualTo(VOLUME_RECORD_UUID);
}
@Test
public void getPath_shouldReturnPath() {
final File file = new File("fakePath");
final VolumeInfo volumeInfo = mock(VolumeInfo.class);
final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
when(volumeInfo.getPath()).thenReturn(file);
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry diskStorage = new StorageEntry(diskInfo);
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry recordStorage = new StorageEntry(volumeRecord);
assertThat(volumeStorage.getPath()).isEqualTo(file);
assertThat(diskStorage.getPath()).isEqualTo(null);
assertThat(recordStorage.getPath()).isEqualTo(null);
}
@Test
public void getVolumeInfo_shouldVolumeInfo() {
final VolumeInfo volumeInfo = mock(VolumeInfo.class);
final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo);
final DiskInfo diskInfo = mock(DiskInfo.class);
final StorageEntry diskStorage = new StorageEntry(diskInfo);
final VolumeRecord volumeRecord = mock(VolumeRecord.class);
final StorageEntry recordStorage = new StorageEntry(volumeRecord);
assertThat(volumeStorage.getVolumeInfo()).isEqualTo(volumeInfo);
assertThat(diskStorage.getVolumeInfo()).isEqualTo(null);
assertThat(recordStorage.getVolumeInfo()).isEqualTo(null);
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2021 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.deviceinfo.storage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.os.Looper;
import android.os.storage.StorageManager;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.widget.SettingsSpinnerPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
public class StorageSelectionPreferenceControllerTest {
private static final String PREFERENCE_KEY = "preference_key";
private Context mContext;
private StorageManager mStorageManager;
private StorageSelectionPreferenceController mController;
@Before
public void setUp() throws Exception {
if (Looper.myLooper() == null) {
Looper.prepare();
}
mContext = ApplicationProvider.getApplicationContext();
mStorageManager = mContext.getSystemService(StorageManager.class);
mController = new StorageSelectionPreferenceController(mContext, PREFERENCE_KEY);
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
final PreferenceScreen preferenceScreen =
preferenceManager.createPreferenceScreen(mContext);
final SettingsSpinnerPreference spinnerPreference = new SettingsSpinnerPreference(mContext);
spinnerPreference.setKey(PREFERENCE_KEY);
preferenceScreen.addPreference(spinnerPreference);
mController.displayPreference(preferenceScreen);
}
@Test
public void setStorageEntries_fromStorageManager_correctAdapterItems() {
final List<StorageEntry> storageEntries = mStorageManager.getVolumes().stream()
.map(volumeInfo -> new StorageEntry(mContext, volumeInfo))
.collect(Collectors.toList());
mController.setStorageEntries(storageEntries);
final int adapterItemCount = mController.mStorageAdapter.getCount();
assertThat(adapterItemCount).isEqualTo(storageEntries.size());
for (int i = 0; i < adapterItemCount; i++) {
assertThat(storageEntries.get(i).getDescription())
.isEqualTo(mController.mStorageAdapter.getItem(i).getDescription());
}
}
@Test
public void setSelectedStorageEntry_primaryStorage_correctSelectedAdapterItem() {
final StorageEntry primaryStorageEntry =
StorageEntry.getDefaultInternalStorageEntry(mContext);
mController.setStorageEntries(mStorageManager.getVolumes().stream()
.map(volumeInfo -> new StorageEntry(mContext, volumeInfo))
.collect(Collectors.toList()));
mController.setSelectedStorageEntry(primaryStorageEntry);
assertThat((StorageEntry) mController.mSpinnerPreference.getSelectedItem())
.isEqualTo(primaryStorageEntry);
}
@Test
public void setStorageEntries_1StorageEntry_preferenceInvisible() {
final List<StorageEntry> storageEntries = new ArrayList<>();
storageEntries.add(mock(StorageEntry.class));
mController.setStorageEntries(storageEntries);
assertThat(mController.mSpinnerPreference.isVisible()).isFalse();
}
@Test
public void setStorageEntries_2StorageEntries_preferenceVisible() {
final List<StorageEntry> storageEntries = new ArrayList<>();
storageEntries.add(mock(StorageEntry.class));
storageEntries.add(mock(StorageEntry.class));
mController.setStorageEntries(storageEntries);
assertThat(mController.mSpinnerPreference.isVisible()).isTrue();
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2021 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.deviceinfo.storage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.os.Looper;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.widget.UsageProgressBarPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.IOException;
@RunWith(AndroidJUnit4.class)
public class StorageUsageProgressBarPreferenceControllerTest {
private static final String FAKE_UUID = "95D9-B3A4";
private static final long WAIT_TIMEOUT = 10_000L;
private static final long FREE_BYTES = 123L;
private static final long TOTAL_BYTES = 456L;
private static final long USAGE_BYTES = TOTAL_BYTES - FREE_BYTES;
private Context mContext;
private FakeStorageUsageProgressBarPreferenceController mController;
private PreferenceScreen mPreferenceScreen;
@Mock
private StorageStatsManager mStorageStatsManager;
@Before
public void setUp() throws Exception {
if (Looper.myLooper() == null) {
Looper.prepare();
}
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(StorageStatsManager.class)).thenReturn(mStorageStatsManager);
mController = new FakeStorageUsageProgressBarPreferenceController(mContext, "key");
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = preferenceManager.createPreferenceScreen(mContext);
final UsageProgressBarPreference usageProgressBarPreference =
new UsageProgressBarPreference(mContext);
usageProgressBarPreference.setKey(mController.getPreferenceKey());
mPreferenceScreen.addPreference(usageProgressBarPreference);
}
@Test
public void setSelectedStorageEntry_primaryStorage_getPrimaryStorageBytes() throws IOException {
final StorageEntry defaultInternalStorageEntry =
StorageEntry.getDefaultInternalStorageEntry(mContext);
when(mStorageStatsManager.getTotalBytes(defaultInternalStorageEntry.getFsUuid()))
.thenReturn(TOTAL_BYTES);
when(mStorageStatsManager.getFreeBytes(defaultInternalStorageEntry.getFsUuid()))
.thenReturn(FREE_BYTES);
mController.displayPreference(mPreferenceScreen);
synchronized (mController.mLock) {
mController.setSelectedStorageEntry(defaultInternalStorageEntry);
mController.waitUpdateState(WAIT_TIMEOUT);
}
assertThat(mController.mUsedBytes).isEqualTo(USAGE_BYTES);
assertThat(mController.mTotalBytes).isEqualTo(TOTAL_BYTES);
}
private class FakeStorageUsageProgressBarPreferenceController
extends StorageUsageProgressBarPreferenceController {
private final Object mLock = new Object();
FakeStorageUsageProgressBarPreferenceController(Context context, String key) {
super(context, key);
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
try {
mLock.notifyAll();
} catch (IllegalMonitorStateException e) {
// Catch it for displayPreference to prevent exception by object not locked by
// thread before notify. Do nothing.
}
}
public void waitUpdateState(long timeout) {
try {
mLock.wait(timeout);
} catch (InterruptedException e) {
// Do nothing.
}
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2020 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.deviceinfo.storage;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.os.storage.VolumeInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class VolumeSizesLoaderTest {
@Test
public void getVolumeSize_getsValidSizes() throws Exception {
VolumeInfo info = mock(VolumeInfo.class);
StorageVolumeProvider storageVolumeProvider = mock(StorageVolumeProvider.class);
when(storageVolumeProvider.getTotalBytes(any(), any())).thenReturn(10000L);
when(storageVolumeProvider.getFreeBytes(any(), any())).thenReturn(1000L);
PrivateStorageInfo storageInfo =
VolumeSizesLoader.getVolumeSize(storageVolumeProvider, null, info);
assertThat(storageInfo.freeBytes).isEqualTo(1000L);
assertThat(storageInfo.totalBytes).isEqualTo(10000L);
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2021 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.display;
import static com.google.common.truth.Truth.assertThat;
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.res.Resources;
import android.hardware.display.ColorDisplayManager;
import androidx.preference.Preference;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class ColorModePreferenceControllerTest {
private Preference mPreference;
private ColorModePreferenceController mController;
@Before
public void setup() {
final Context context = spy(ApplicationProvider.getApplicationContext());
mController = spy(new ColorModePreferenceController(context, "test"));
mPreference = new Preference(context);
final Resources res = spy(context.getResources());
when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
new int[]{
ColorDisplayManager.COLOR_MODE_NATURAL,
ColorDisplayManager.COLOR_MODE_BOOSTED,
ColorDisplayManager.COLOR_MODE_SATURATED,
ColorDisplayManager.COLOR_MODE_AUTOMATIC
});
doReturn(res).when(context).getResources();
}
@Test
@UiThreadTest
public void updateState_colorModeAutomatic_shouldSetSummaryToAutomatic() {
doReturn(ColorDisplayManager.COLOR_MODE_AUTOMATIC).when(mController).getColorMode();
mController.updateState(mPreference);
assertThat(mPreference.getSummary()).isEqualTo("Adaptive");
}
@Test
@UiThreadTest
public void updateState_colorModeSaturated_shouldSetSummaryToSaturated() {
doReturn(ColorDisplayManager.COLOR_MODE_SATURATED).when(mController).getColorMode();
mController.updateState(mPreference);
assertThat(mPreference.getSummary()).isEqualTo("Saturated");
}
@Test
public void updateState_colorModeBoosted_shouldSetSummaryToBoosted() {
doReturn(ColorDisplayManager.COLOR_MODE_BOOSTED).when(mController).getColorMode();
mController.updateState(mPreference);
assertThat(mPreference.getSummary()).isEqualTo("Boosted");
}
@Test
public void updateState_colorModeNatural_shouldSetSummaryToNatural() {
doReturn(ColorDisplayManager.COLOR_MODE_NATURAL).when(mController).getColorMode();
mController.updateState(mPreference);
assertThat(mPreference.getSummary()).isEqualTo("Natural");
}
}

View File

@@ -0,0 +1,235 @@
/*
* Copyright (C) 2021 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.display;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
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.content.Context;
import android.content.res.Resources;
import android.hardware.display.ColorDisplayManager;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.widget.CandidateInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
@RunWith(AndroidJUnit4.class)
public class ColorModePreferenceFragmentTest {
private ColorModePreferenceFragment mFragment;
private Context mContext;
@Before
@UiThreadTest
public void setup() {
mContext = spy(ApplicationProvider.getApplicationContext());
mFragment = spy(new ColorModePreferenceFragment());
doNothing().when(mFragment).setColorMode(anyInt());
}
@Test
public void verifyMetricsConstant() {
assertThat(mFragment.getMetricsCategory())
.isEqualTo(MetricsProto.MetricsEvent.COLOR_MODE_SETTINGS);
}
@Test
@UiThreadTest
public void getCandidates_all() {
final Resources res = spy(mContext.getResources());
when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
new int[]{
ColorDisplayManager.COLOR_MODE_NATURAL,
ColorDisplayManager.COLOR_MODE_BOOSTED,
ColorDisplayManager.COLOR_MODE_SATURATED,
ColorDisplayManager.COLOR_MODE_AUTOMATIC
});
doReturn(res).when(mContext).getResources();
mFragment.onAttach(mContext);
final List<? extends CandidateInfo> candidates = mFragment.getCandidates();
assertThat(candidates.size()).isEqualTo(4);
assertThat(candidates.get(0).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
assertThat(candidates.get(1).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED));
assertThat(candidates.get(2).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_SATURATED));
assertThat(candidates.get(3).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC));
}
@Test
@UiThreadTest
public void getCandidates_none() {
final Resources res = spy(mContext.getResources());
when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
new int[]{
});
doReturn(res).when(mContext).getResources();
mFragment.onAttach(mContext);
List<? extends CandidateInfo> candidates = mFragment.getCandidates();
assertThat(candidates.size()).isEqualTo(0);
}
@Test
@UiThreadTest
public void getCandidates_withAutomatic() {
final Resources res = spy(mContext.getResources());
when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
new int[]{
ColorDisplayManager.COLOR_MODE_NATURAL,
ColorDisplayManager.COLOR_MODE_AUTOMATIC
});
doReturn(res).when(mContext).getResources();
mFragment.onAttach(mContext);
List<? extends CandidateInfo> candidates = mFragment.getCandidates();
assertThat(candidates.size()).isEqualTo(2);
assertThat(candidates.get(0).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
assertThat(candidates.get(1).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC));
}
@Test
@UiThreadTest
public void getCandidates_withoutAutomatic() {
final Resources res = spy(mContext.getResources());
when(res.getIntArray(com.android.internal.R.array.config_availableColorModes)).thenReturn(
new int[]{
ColorDisplayManager.COLOR_MODE_NATURAL,
ColorDisplayManager.COLOR_MODE_BOOSTED,
ColorDisplayManager.COLOR_MODE_SATURATED
});
doReturn(res).when(mContext).getResources();
mFragment.onAttach(mContext);
List<? extends CandidateInfo> candidates = mFragment.getCandidates();
assertThat(candidates.size()).isEqualTo(3);
assertThat(candidates.get(0).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
assertThat(candidates.get(1).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED));
assertThat(candidates.get(2).getKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_SATURATED));
}
@Test
@UiThreadTest
public void getKey_natural() {
doReturn(ColorDisplayManager.COLOR_MODE_NATURAL).when(mFragment).getColorMode();
mFragment.onAttach(mContext);
assertThat(mFragment.getDefaultKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
}
@Test
@UiThreadTest
public void getKey_boosted() {
doReturn(ColorDisplayManager.COLOR_MODE_BOOSTED).when(mFragment).getColorMode();
mFragment.onAttach(mContext);
assertThat(mFragment.getDefaultKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED));
}
@Test
@UiThreadTest
public void getKey_saturated() {
doReturn(ColorDisplayManager.COLOR_MODE_SATURATED).when(mFragment).getColorMode();
mFragment.onAttach(mContext);
assertThat(mFragment.getDefaultKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_SATURATED));
}
@Test
@UiThreadTest
public void getKey_automatic() {
doReturn(ColorDisplayManager.COLOR_MODE_AUTOMATIC).when(mFragment).getColorMode();
mFragment.onAttach(mContext);
assertThat(mFragment.getDefaultKey())
.isEqualTo(mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC));
}
@Test
@UiThreadTest
public void setKey_natural() {
mFragment.onAttach(mContext);
mFragment.setDefaultKey(
mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_NATURAL));
verify(mFragment).setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
}
@Test
@UiThreadTest
public void setKey_boosted() {
mFragment.onAttach(mContext);
mFragment.setDefaultKey(
mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED));
verify(mFragment).setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
}
@Test
@UiThreadTest
public void setKey_saturated() {
mFragment.onAttach(mContext);
mFragment.setDefaultKey(
mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_SATURATED));
verify(mFragment).setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED);
}
@Test
@UiThreadTest
public void setKey_automatic() {
mFragment.onAttach(mContext);
mFragment.setDefaultKey(
mFragment.getKeyForColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC));
verify(mFragment).setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC);
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright (C) 2017 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.display;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.settings.Settings.NightDisplaySettingsActivity;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NightDisplaySettingsActivityTest {
private Context mTargetContext;
@Before
public void setUp() throws Exception {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mTargetContext = instrumentation.getTargetContext();
}
@Test
public void nightDisplaySettingsIntent_resolvesCorrectly() {
final boolean nightDisplayAvailable = mTargetContext.getResources().getBoolean(
com.android.internal.R.bool.config_nightDisplayAvailable);
final PackageManager pm = mTargetContext.getPackageManager();
final Intent intent = new Intent(Settings.ACTION_NIGHT_DISPLAY_SETTINGS);
final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (nightDisplayAvailable) {
Assert.assertNotNull("No activity for " + Settings.ACTION_NIGHT_DISPLAY_SETTINGS, ri);
Assert.assertEquals(mTargetContext.getPackageName(), ri.activityInfo.packageName);
Assert.assertEquals(NightDisplaySettingsActivity.class.getName(),
ri.activityInfo.name);
} else {
Assert.assertNull("Should have no activity for "
+ Settings.ACTION_NIGHT_DISPLAY_SETTINGS, ri);
}
}
}

View File

@@ -1,151 +0,0 @@
/*
* Copyright (C) 2017 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.display;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ContextWrapper;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import androidx.preference.ListPreference;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ThemePreferenceControllerTest {
private IOverlayManager mMockOverlayManager;
private ContextWrapper mContext;
private ThemePreferenceController mPreferenceController;
private PackageManager mMockPackageManager;
@Before
public void setup() {
mMockOverlayManager = mock(IOverlayManager.class);
mMockPackageManager = mock(PackageManager.class);
mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
@Override
public PackageManager getPackageManager() {
return mMockPackageManager;
}
};
mPreferenceController = new ThemePreferenceController(mContext, mMockOverlayManager);
}
@Test
public void testUpdateState() throws Exception {
OverlayInfo info1 = new OverlayInfo("com.android.Theme1", "android", "",
OverlayInfo.CATEGORY_THEME, "", OverlayInfo.STATE_ENABLED, 0, 0, true);
OverlayInfo info2 = new OverlayInfo("com.android.Theme2", "android", "",
OverlayInfo.CATEGORY_THEME, "", 0, 0, 0, true);
when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenAnswer(inv -> {
ApplicationInfo info = mock(ApplicationInfo.class);
if ("com.android.Theme1".equals(inv.getArguments()[0])) {
when(info.loadLabel(any())).thenReturn("Theme1");
} else {
when(info.loadLabel(any())).thenReturn("Theme2");
}
return info;
});
when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(
new PackageInfo());
when(mMockOverlayManager.getOverlayInfosForTarget(any(), anyInt())).thenReturn(
list(info1, info2));
ListPreference pref = mock(ListPreference.class);
mPreferenceController.updateState(pref);
ArgumentCaptor<String[]> arg = ArgumentCaptor.forClass(String[].class);
verify(pref).setEntries(arg.capture());
CharSequence[] entries = arg.getValue();
assertThat(entries).asList().containsExactly("Theme1", "Theme2");
verify(pref).setEntryValues(arg.capture());
CharSequence[] entryValues = arg.getValue();
assertThat(entryValues).asList().containsExactly(
"com.android.Theme1", "com.android.Theme2");
verify(pref).setValue(eq("com.android.Theme1"));
}
@Test
public void testUpdateState_withStaticOverlay() throws Exception {
OverlayInfo info1 = new OverlayInfo("com.android.Theme1", "android", "",
OverlayInfo.CATEGORY_THEME, "", OverlayInfo.STATE_ENABLED, 0, 0, true);
OverlayInfo info2 = new OverlayInfo("com.android.Theme2", "android", "",
OverlayInfo.CATEGORY_THEME, "", OverlayInfo.STATE_ENABLED, 0, 0, true);
when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenAnswer(inv -> {
ApplicationInfo info = mock(ApplicationInfo.class);
if ("com.android.Theme1".equals(inv.getArguments()[0])) {
when(info.loadLabel(any())).thenReturn("Theme1");
} else {
when(info.loadLabel(any())).thenReturn("Theme2");
}
return info;
});
PackageInfo pi = mock(PackageInfo.class);
when(pi.isStaticOverlayPackage()).thenReturn(true);
when(mMockPackageManager.getPackageInfo(eq("com.android.Theme1"), anyInt())).thenReturn(pi);
when(mMockPackageManager.getPackageInfo(eq("com.android.Theme2"), anyInt())).thenReturn(
new PackageInfo());
when(mMockOverlayManager.getOverlayInfosForTarget(any(), anyInt())).thenReturn(
list(info1, info2));
ListPreference pref = mock(ListPreference.class);
mPreferenceController.updateState(pref);
ArgumentCaptor<String[]> arg = ArgumentCaptor.forClass(String[].class);
verify(pref).setEntries(arg.capture());
CharSequence[] entries = arg.getValue();
assertThat(entries).asList().containsExactly("Theme2");
verify(pref).setEntryValues(arg.capture());
CharSequence[] entryValues = arg.getValue();
assertThat(entryValues).asList().containsExactly("com.android.Theme2");
verify(pref).setValue(eq("com.android.Theme2"));
}
private ArrayList<OverlayInfo> list(OverlayInfo... infos) {
ArrayList<OverlayInfo> list = new ArrayList<>();
for (OverlayInfo info : infos) {
list.add(info);
}
return list;
}
}

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