Use resource processor for Settings

Bug: 293810334
Test: m Settings
Test: robotests
Change-Id: Ie515e137648eddfdfcab5e8095f5be99721d9e1b
This commit is contained in:
Chaohui Wang
2023-08-11 13:43:02 +08:00
parent b199f3512a
commit 2cab62254c
35 changed files with 114 additions and 512 deletions

View File

@@ -0,0 +1,26 @@
/*
* 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.testutils;
import android.app.Activity;
import android.content.Intent;
import android.os.UserHandle;
public class CustomActivity extends Activity {
@Override
public void startActivityAsUser(Intent intent, UserHandle user) {}
}

View File

@@ -0,0 +1,52 @@
/*
* 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.testutils;
import android.content.Context;
import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
import com.android.settings.slices.SlicesDatabaseHelper;
import org.robolectric.util.ReflectionHelpers;
public class DatabaseTestUtils {
public static void clearDb(Context context) {
clearSlicesDb(context);
clearAnomalyDb(context);
clearAnomalyDbManager();
}
private static void clearSlicesDb(Context context) {
SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(context);
helper.close();
ReflectionHelpers.setStaticField(SlicesDatabaseHelper.class, "sSingleton", null);
}
private static void clearAnomalyDb(Context context) {
AnomalyDatabaseHelper helper = AnomalyDatabaseHelper.getInstance(context);
helper.close();
ReflectionHelpers.setStaticField(AnomalyDatabaseHelper.class, "sSingleton", null);
}
private static void clearAnomalyDbManager() {
ReflectionHelpers.setStaticField(BatteryDatabaseManager.class, "sSingleton", null);
}
}

View File

@@ -0,0 +1,310 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.testutils;
import static org.mockito.Mockito.mock;
import android.content.Context;
import com.android.settings.accessibility.AccessibilityMetricsFeatureProvider;
import com.android.settings.accessibility.AccessibilitySearchFeatureProvider;
import com.android.settings.accounts.AccountFeatureProvider;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.biometrics.face.FaceFeatureProvider;
import com.android.settings.biometrics2.factory.BiometricsRepositoryProvider;
import com.android.settings.bluetooth.BluetoothFeatureProvider;
import com.android.settings.connecteddevice.stylus.StylusFeatureProvider;
import com.android.settings.dashboard.DashboardFeatureProvider;
import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider;
import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProvider;
import com.android.settings.deviceinfo.hardwareinfo.HardwareInfoFeatureProviderImpl;
import com.android.settings.enterprise.EnterprisePrivacyFeatureProvider;
import com.android.settings.fuelgauge.BatterySettingsFeatureProvider;
import com.android.settings.fuelgauge.BatteryStatusFeatureProvider;
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
import com.android.settings.homepage.contextualcards.ContextualCardFeatureProvider;
import com.android.settings.inputmethod.KeyboardSettingsFeatureProvider;
import com.android.settings.localepicker.LocaleFeatureProvider;
import com.android.settings.onboarding.OnboardingFeatureProvider;
import com.android.settings.overlay.DockUpdaterFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.SupportFeatureProvider;
import com.android.settings.overlay.SurveyFeatureProvider;
import com.android.settings.panel.PanelFeatureProvider;
import com.android.settings.search.SearchFeatureProvider;
import com.android.settings.security.SecurityFeatureProvider;
import com.android.settings.security.SecuritySettingsFeatureProvider;
import com.android.settings.slices.SlicesFeatureProvider;
import com.android.settings.users.UserFeatureProvider;
import com.android.settings.vpn2.AdvancedVpnFeatureProvider;
import com.android.settings.wifi.WifiTrackerLibProvider;
import com.android.settings.wifi.factory.WifiFeatureProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import org.jetbrains.annotations.NotNull;
/**
* Test util to provide fake FeatureFactory. To use this factory, call {@code setupForTest} in
* {@code @Before} method of the test class.
*/
public class FakeFeatureFactory extends FeatureFactory {
public final SupportFeatureProvider supportFeatureProvider;
public final MetricsFeatureProvider metricsFeatureProvider;
public final BatteryStatusFeatureProvider batteryStatusFeatureProvider;
public final BatterySettingsFeatureProvider batterySettingsFeatureProvider;
public final PowerUsageFeatureProvider powerUsageFeatureProvider;
public final DashboardFeatureProvider dashboardFeatureProvider;
public final DockUpdaterFeatureProvider dockUpdaterFeatureProvider;
public final LocaleFeatureProvider localeFeatureProvider;
public final ApplicationFeatureProvider applicationFeatureProvider;
public final EnterprisePrivacyFeatureProvider enterprisePrivacyFeatureProvider;
public final SurveyFeatureProvider surveyFeatureProvider;
public final SecurityFeatureProvider securityFeatureProvider;
public final SuggestionFeatureProvider suggestionsFeatureProvider;
public final UserFeatureProvider userFeatureProvider;
public final AccountFeatureProvider mAccountFeatureProvider;
public final BluetoothFeatureProvider mBluetoothFeatureProvider;
public final FaceFeatureProvider mFaceFeatureProvider;
public final BiometricsRepositoryProvider mBiometricsRepositoryProvider;
public PanelFeatureProvider panelFeatureProvider;
public SlicesFeatureProvider slicesFeatureProvider;
public SearchFeatureProvider searchFeatureProvider;
public ContextualCardFeatureProvider mContextualCardFeatureProvider;
public WifiTrackerLibProvider wifiTrackerLibProvider;
public SecuritySettingsFeatureProvider securitySettingsFeatureProvider;
public AccessibilitySearchFeatureProvider mAccessibilitySearchFeatureProvider;
public AccessibilityMetricsFeatureProvider mAccessibilityMetricsFeatureProvider;
public AdvancedVpnFeatureProvider mAdvancedVpnFeatureProvider;
public WifiFeatureProvider mWifiFeatureProvider;
public KeyboardSettingsFeatureProvider mKeyboardSettingsFeatureProvider;
public StylusFeatureProvider mStylusFeatureProvider;
public OnboardingFeatureProvider mOnboardingFeatureProvider;
/**
* Call this in {@code @Before} method of the test class to use fake factory.
*/
public static FakeFeatureFactory setupForTest() {
FakeFeatureFactory factory = new FakeFeatureFactory();
setFactory(getAppContext(), factory);
return factory;
}
/**
* Used by reflection. Do not call directly.
*/
public FakeFeatureFactory() {
supportFeatureProvider = mock(SupportFeatureProvider.class);
metricsFeatureProvider = mock(MetricsFeatureProvider.class);
batteryStatusFeatureProvider = mock(BatteryStatusFeatureProvider.class);
batterySettingsFeatureProvider = mock(BatterySettingsFeatureProvider.class);
powerUsageFeatureProvider = mock(PowerUsageFeatureProvider.class);
dashboardFeatureProvider = mock(DashboardFeatureProvider.class);
dockUpdaterFeatureProvider = mock(DockUpdaterFeatureProvider.class);
localeFeatureProvider = mock(LocaleFeatureProvider.class);
applicationFeatureProvider = mock(ApplicationFeatureProvider.class);
enterprisePrivacyFeatureProvider = mock(EnterprisePrivacyFeatureProvider.class);
searchFeatureProvider = mock(SearchFeatureProvider.class);
surveyFeatureProvider = mock(SurveyFeatureProvider.class);
securityFeatureProvider = mock(SecurityFeatureProvider.class);
suggestionsFeatureProvider = mock(SuggestionFeatureProvider.class);
userFeatureProvider = mock(UserFeatureProvider.class);
slicesFeatureProvider = mock(SlicesFeatureProvider.class);
mAccountFeatureProvider = mock(AccountFeatureProvider.class);
mContextualCardFeatureProvider = mock(ContextualCardFeatureProvider.class);
panelFeatureProvider = mock(PanelFeatureProvider.class);
mBluetoothFeatureProvider = mock(BluetoothFeatureProvider.class);
mFaceFeatureProvider = mock(FaceFeatureProvider.class);
mBiometricsRepositoryProvider = mock(BiometricsRepositoryProvider.class);
wifiTrackerLibProvider = mock(WifiTrackerLibProvider.class);
securitySettingsFeatureProvider = mock(SecuritySettingsFeatureProvider.class);
mAccessibilitySearchFeatureProvider = mock(AccessibilitySearchFeatureProvider.class);
mAccessibilityMetricsFeatureProvider = mock(AccessibilityMetricsFeatureProvider.class);
mAdvancedVpnFeatureProvider = mock(AdvancedVpnFeatureProvider.class);
mWifiFeatureProvider = mock(WifiFeatureProvider.class);
mKeyboardSettingsFeatureProvider = mock(KeyboardSettingsFeatureProvider.class);
mStylusFeatureProvider = mock(StylusFeatureProvider.class);
mOnboardingFeatureProvider = mock(OnboardingFeatureProvider.class);
}
@Override
public SuggestionFeatureProvider getSuggestionFeatureProvider() {
return suggestionsFeatureProvider;
}
@Override
public SupportFeatureProvider getSupportFeatureProvider() {
return supportFeatureProvider;
}
@Override
public MetricsFeatureProvider getMetricsFeatureProvider() {
return metricsFeatureProvider;
}
@NotNull
@Override
public BatteryStatusFeatureProvider getBatteryStatusFeatureProvider() {
return batteryStatusFeatureProvider;
}
@Override
public BatterySettingsFeatureProvider getBatterySettingsFeatureProvider() {
return batterySettingsFeatureProvider;
}
@NotNull
@Override
public PowerUsageFeatureProvider getPowerUsageFeatureProvider() {
return powerUsageFeatureProvider;
}
@NotNull
@Override
public DashboardFeatureProvider getDashboardFeatureProvider() {
return dashboardFeatureProvider;
}
@Override
public DockUpdaterFeatureProvider getDockUpdaterFeatureProvider() {
return dockUpdaterFeatureProvider;
}
@NotNull
@Override
public ApplicationFeatureProvider getApplicationFeatureProvider() {
return applicationFeatureProvider;
}
@Override
public LocaleFeatureProvider getLocaleFeatureProvider() {
return localeFeatureProvider;
}
@NotNull
@Override
public EnterprisePrivacyFeatureProvider getEnterprisePrivacyFeatureProvider() {
return enterprisePrivacyFeatureProvider;
}
@Override
public SearchFeatureProvider getSearchFeatureProvider() {
return searchFeatureProvider;
}
@Override
public SurveyFeatureProvider getSurveyFeatureProvider(Context context) {
return surveyFeatureProvider;
}
@Override
public SecurityFeatureProvider getSecurityFeatureProvider() {
return securityFeatureProvider;
}
@NotNull
@Override
public UserFeatureProvider getUserFeatureProvider() {
return userFeatureProvider;
}
@Override
public SlicesFeatureProvider getSlicesFeatureProvider() {
return slicesFeatureProvider;
}
@Override
public AccountFeatureProvider getAccountFeatureProvider() {
return mAccountFeatureProvider;
}
@Override
public PanelFeatureProvider getPanelFeatureProvider() {
return panelFeatureProvider;
}
@Override
public ContextualCardFeatureProvider getContextualCardFeatureProvider(Context context) {
return mContextualCardFeatureProvider;
}
@Override
public BluetoothFeatureProvider getBluetoothFeatureProvider() {
return mBluetoothFeatureProvider;
}
@Override
public FaceFeatureProvider getFaceFeatureProvider() {
return mFaceFeatureProvider;
}
@Override
public BiometricsRepositoryProvider getBiometricsRepositoryProvider() {
return mBiometricsRepositoryProvider;
}
@Override
public WifiTrackerLibProvider getWifiTrackerLibProvider() {
return wifiTrackerLibProvider;
}
@Override
public SecuritySettingsFeatureProvider getSecuritySettingsFeatureProvider() {
return securitySettingsFeatureProvider;
}
@Override
public AccessibilitySearchFeatureProvider getAccessibilitySearchFeatureProvider() {
return mAccessibilitySearchFeatureProvider;
}
@Override
public AccessibilityMetricsFeatureProvider getAccessibilityMetricsFeatureProvider() {
return mAccessibilityMetricsFeatureProvider;
}
@Override
public HardwareInfoFeatureProvider getHardwareInfoFeatureProvider() {
return HardwareInfoFeatureProviderImpl.INSTANCE;
}
@Override
public AdvancedVpnFeatureProvider getAdvancedVpnFeatureProvider() {
return mAdvancedVpnFeatureProvider;
}
@Override
public WifiFeatureProvider getWifiFeatureProvider() {
return mWifiFeatureProvider;
}
@Override
public KeyboardSettingsFeatureProvider getKeyboardSettingsFeatureProvider() {
return mKeyboardSettingsFeatureProvider;
}
@Override
public StylusFeatureProvider getStylusFeatureProvider() {
return mStylusFeatureProvider;
}
@Override
public OnboardingFeatureProvider getOnboardingFeatureProvider() {
return mOnboardingFeatureProvider;
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.testutils;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import com.google.common.base.Preconditions;
/**
* Helper for building {@link ResolveInfo}s to be used in Robolectric tests.
*
* <p>The resulting {@link PackageInfo}s should typically be added to {@link
* org.robolectric.shadows.ShadowPackageManager#addResolveInfoForIntent(Intent, ResolveInfo)}.
*/
public final class ResolveInfoBuilder {
private final String mPackageName;
private ActivityInfo mActivityInfo;
private ProviderInfo mProviderInfo;
public ResolveInfoBuilder(String packageName) {
this.mPackageName = Preconditions.checkNotNull(packageName);
}
public ResolveInfoBuilder setActivity(String packageName, String className) {
mActivityInfo = new ActivityInfo();
mActivityInfo.packageName = packageName;
mActivityInfo.name = className;
return this;
}
public ResolveInfoBuilder setProvider(
String packageName, String className, String authority, boolean isSystemApp) {
mProviderInfo = new ProviderInfo();
mProviderInfo.authority = authority;
mProviderInfo.applicationInfo = new ApplicationInfo();
if (isSystemApp) {
mProviderInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
}
mProviderInfo.packageName = mPackageName;
mProviderInfo.applicationInfo.packageName = mPackageName;
mProviderInfo.name = className;
return this;
}
public ResolveInfo build() {
ResolveInfo info = new ResolveInfo();
info.activityInfo = mActivityInfo;
info.resolvePackageName = mPackageName;
info.providerInfo = mProviderInfo;
return info;
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.testutils.shadow;
import static org.robolectric.RuntimeEnvironment.application;
import static org.robolectric.shadow.api.Shadow.directlyOn;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.util.SparseArray;
import androidx.annotation.ArrayRes;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.Resetter;
import org.robolectric.shadows.ShadowResources;
import org.robolectric.util.ReflectionHelpers.ClassParameter;
/**
* Shadow Resources and Theme classes to handle resource references that Robolectric shadows cannot
* handle because they are too new or private.
*/
@Implements(value = Resources.class)
public class SettingsShadowResources extends ShadowResources {
@RealObject
public Resources realResources;
private static SparseArray<Object> sResourceOverrides = new SparseArray<>();
public static void overrideResource(int id, Object value) {
sResourceOverrides.put(id, value);
}
public static void overrideResource(String name, Object value) {
final Resources res = application.getResources();
final int resId = res.getIdentifier(name, null, null);
if (resId == 0) {
throw new Resources.NotFoundException("Cannot override \"" + name + "\"");
}
overrideResource(resId, value);
}
@Resetter
public static void reset() {
sResourceOverrides.clear();
}
@Implementation
protected int[] getIntArray(@ArrayRes int id) throws NotFoundException {
final Object override = sResourceOverrides.get(id);
if (override instanceof int[]) {
return (int[]) override;
}
return directlyOn(realResources, Resources.class).getIntArray(id);
}
@Implementation
protected String getString(int id) {
final Object override = sResourceOverrides.get(id);
if (override instanceof String) {
return (String) override;
}
return directlyOn(
realResources, Resources.class, "getString", ClassParameter.from(int.class, id));
}
@Implementation
protected int getInteger(int id) {
final Object override = sResourceOverrides.get(id);
if (override instanceof Integer) {
return (Integer) override;
}
return directlyOn(
realResources, Resources.class, "getInteger", ClassParameter.from(int.class, id));
}
@Implementation
protected boolean getBoolean(int id) {
final Object override = sResourceOverrides.get(id);
if (override instanceof Boolean) {
return (boolean) override;
}
return directlyOn(realResources, Resources.class, "getBoolean",
ClassParameter.from(int.class, id));
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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.testutils.shadow;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.ComponentName;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@Implements(AccessibilityServiceInfo.class)
public class ShadowAccessibilityServiceInfo {
private static ComponentName sComponentName;
public static void setComponentName(String componentName) {
sComponentName = ComponentName.unflattenFromString(componentName);
}
@Implementation
protected ComponentName getComponentName() {
return sComponentName;
}
}

View File

@@ -0,0 +1,34 @@
/*
* 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.testutils.shadow;
import android.content.Intent;
import android.os.UserHandle;
import com.android.settings.testutils.CustomActivity;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@Implements(CustomActivity.class)
public class ShadowActivity extends org.robolectric.shadows.ShadowActivity {
@Implementation
protected void startActivityAsUser(Intent intent, UserHandle user) {
realActivity.startActivity(intent);
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.testutils.shadow;
import android.content.Context;
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
/**
* Shadow class for {@link ActivityEmbeddingUtils} to test embedding activity features.
*/
@Implements(ActivityEmbeddingUtils.class)
public class ShadowActivityEmbeddingUtils {
private static boolean sIsEmbeddingActivityEnabled;
@Implementation
public static boolean isEmbeddingActivityEnabled(Context context) {
return sIsEmbeddingActivityEnabled;
}
public static void setIsEmbeddingActivityEnabled(boolean isEmbeddingActivityEnabled) {
sIsEmbeddingActivityEnabled = isEmbeddingActivityEnabled;
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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.testutils.shadow;
import android.annotation.SuppressLint;
import android.view.View;
import androidx.appcompat.app.AlertDialog;
import org.robolectric.Shadows;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
import org.robolectric.annotation.Resetter;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowDialog;
import org.robolectric.util.ReflectionHelpers;
import javax.annotation.Nullable;
/* Robolectric shadow for the androidx alert dialog. */
@Implements(AlertDialog.class)
public class ShadowAlertDialogCompat extends ShadowDialog {
@SuppressLint("StaticFieldLeak")
@Nullable
private static ShadowAlertDialogCompat sLatestSupportAlertDialog;
@RealObject
private AlertDialog mRealAlertDialog;
@Implementation
public void show() {
super.show();
sLatestSupportAlertDialog = this;
}
public CharSequence getMessage() {
final Object alertController = ReflectionHelpers.getField(mRealAlertDialog, "mAlert");
return ReflectionHelpers.getField(alertController, "mMessage");
}
public CharSequence getTitle() {
final Object alertController = ReflectionHelpers.getField(mRealAlertDialog, "mAlert");
return ReflectionHelpers.getField(alertController, "mTitle");
}
public View getView() {
final Object alertController = ReflectionHelpers.getField(mRealAlertDialog, "mAlert");
return ReflectionHelpers.getField(alertController, "mView");
}
@Nullable
public static AlertDialog getLatestAlertDialog() {
return sLatestSupportAlertDialog == null
? null : sLatestSupportAlertDialog.mRealAlertDialog;
}
@Resetter
public static void reset() {
sLatestSupportAlertDialog = null;
}
public static ShadowAlertDialogCompat shadowOf(AlertDialog alertDialog) {
return (ShadowAlertDialogCompat) Shadow.extract(alertDialog);
}
public void clickOnItem(int index) {
Shadows.shadowOf(mRealAlertDialog.getListView()).performItemClick(index);
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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.testutils.shadow;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import java.util.ArrayList;
import java.util.List;
@Implements(value = BluetoothAdapter.class)
public class ShadowBluetoothAdapter extends org.robolectric.shadows.ShadowBluetoothAdapter {
private int mState;
private List<Integer> mSupportedProfiles = new ArrayList<>();
private List<BluetoothDevice> mMostRecentlyConnectedDevices = new ArrayList<>();
@Implementation
protected List<Integer> getSupportedProfiles() {
return mSupportedProfiles;
}
public void addSupportedProfiles(int profile) {
mSupportedProfiles.add(profile);
}
public void clearSupportedProfiles() {
mSupportedProfiles.clear();
}
@Implementation
protected int getConnectionState() {
return mState;
}
public void setConnectionState(int state) {
mState = state;
}
@Implementation
protected boolean factoryReset() {
return true;
}
@Implementation
protected List<BluetoothDevice> getMostRecentlyConnectedDevices() {
return mMostRecentlyConnectedDevices;
}
public void setMostRecentlyConnectedDevices(List<BluetoothDevice> list) {
mMostRecentlyConnectedDevices = list;
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.testutils.shadow;
import android.net.ConnectivityManager;
import android.util.SparseBooleanArray;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
@Implements(value = ConnectivityManager.class)
public class ShadowConnectivityManager extends org.robolectric.shadows.ShadowConnectivityManager {
private final SparseBooleanArray mSupportedNetworkTypes = new SparseBooleanArray();
private boolean mTetheringSupported = false;
public void setNetworkSupported(int networkType, boolean supported) {
mSupportedNetworkTypes.put(networkType, supported);
}
@Implementation
protected boolean isNetworkSupported(int networkType) {
return mSupportedNetworkTypes.get(networkType);
}
public void setTetheringSupported(boolean supported) {
mTetheringSupported = supported;
}
@Implementation
protected boolean isTetheringSupported() {
return mTetheringSupported;
}
public static ShadowConnectivityManager getShadow() {
return Shadow.extract(
RuntimeEnvironment.application.getSystemService(ConnectivityManager.class));
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.testutils.shadow;
import com.android.settings.datausage.DataSaverBackend;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@Implements(DataSaverBackend.class)
public class ShadowDataSaverBackend {
private static boolean sIsEnabled = true;
@Implementation
protected boolean isDataSaverEnabled() {
return sIsEnabled;
}
@Implementation
protected void setDataSaverEnabled(boolean enabled) {
sIsEnabled = enabled;
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.testutils.shadow;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@Implements(value = Fragment.class)
public class ShadowFragment {
private Fragment mTargetFragment;
@Implementation
public void onCreate(Bundle icicle) {
// do nothing
}
@Implementation
protected void setTargetFragment(Fragment fragment, int requestCode) {
mTargetFragment = fragment;
}
@Implementation
protected Fragment getTargetFragment() {
return mTargetFragment;
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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.testutils.shadow;
import static org.mockito.Mockito.mock;
import com.android.internal.jank.InteractionJankMonitor;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
/**
* @deprecated use {@link com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor}
*/
@Deprecated
@Implements(InteractionJankMonitor.class)
public class ShadowInteractionJankMonitor {
@Implementation
public static InteractionJankMonitor getInstance() {
return mock(InteractionJankMonitor.class);
}
}

View File

@@ -0,0 +1,240 @@
/*
* 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.testutils.shadow;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
import android.app.admin.PasswordMetrics;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Implements(LockPatternUtils.class)
public class ShadowLockPatternUtils {
private static boolean sDeviceEncryptionEnabled;
private static Map<Integer, Integer> sUserToActivePasswordQualityMap = new HashMap<>();
private static Map<Integer, Integer> sUserToComplexityMap = new HashMap<>();
private static Map<Integer, Integer> sUserToProfileComplexityMap = new HashMap<>();
private static Map<Integer, PasswordMetrics> sUserToMetricsMap = new HashMap<>();
private static Map<Integer, PasswordMetrics> sUserToProfileMetricsMap = new HashMap<>();
private static Map<Integer, Boolean> sUserToIsSecureMap = new HashMap<>();
private static Map<Integer, Boolean> sUserToVisiblePatternEnabledMap = new HashMap<>();
private static Map<Integer, Boolean> sUserToBiometricAllowedMap = new HashMap<>();
private static Map<Integer, Boolean> sUserToLockPatternEnabledMap = new HashMap<>();
private static boolean sIsUserOwnsFrpCredential;
@Resetter
public static void reset() {
sUserToActivePasswordQualityMap.clear();
sUserToComplexityMap.clear();
sUserToProfileComplexityMap.clear();
sUserToMetricsMap.clear();
sUserToProfileMetricsMap.clear();
sUserToIsSecureMap.clear();
sUserToVisiblePatternEnabledMap.clear();
sUserToBiometricAllowedMap.clear();
sUserToLockPatternEnabledMap.clear();
sDeviceEncryptionEnabled = false;
sIsUserOwnsFrpCredential = false;
}
@Implementation
protected boolean hasSecureLockScreen() {
return true;
}
@Implementation
protected boolean isSecure(int userId) {
Boolean isSecure = sUserToIsSecureMap.get(userId);
if (isSecure == null) {
return true;
}
return isSecure;
}
public static void setIsSecure(int userId, boolean isSecure) {
sUserToIsSecureMap.put(userId, isSecure);
}
@Implementation
protected int getActivePasswordQuality(int userId) {
final Integer activePasswordQuality = sUserToActivePasswordQualityMap.get(userId);
if (activePasswordQuality == null) {
return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
}
return activePasswordQuality;
}
@Implementation
protected int getKeyguardStoredPasswordQuality(int userHandle) {
return 1;
}
@Implementation
protected static boolean isDeviceEncryptionEnabled() {
return sDeviceEncryptionEnabled;
}
@Implementation
protected List<ComponentName> getEnabledTrustAgents(int userId) {
return null;
}
public static void setDeviceEncryptionEnabled(boolean deviceEncryptionEnabled) {
sDeviceEncryptionEnabled = deviceEncryptionEnabled;
}
@Implementation
protected byte[] getPasswordHistoryHashFactor(
LockscreenCredential currentPassword, int userId) {
return null;
}
@Implementation
protected boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) {
return false;
}
@Implementation
public @DevicePolicyManager.PasswordComplexity int getRequestedPasswordComplexity(int userId) {
return getRequestedPasswordComplexity(userId, false);
}
@Implementation
@DevicePolicyManager.PasswordComplexity
public int getRequestedPasswordComplexity(int userId, boolean deviceWideOnly) {
int complexity = sUserToComplexityMap.getOrDefault(userId,
DevicePolicyManager.PASSWORD_COMPLEXITY_NONE);
if (!deviceWideOnly) {
complexity = Math.max(complexity, sUserToProfileComplexityMap.getOrDefault(userId,
DevicePolicyManager.PASSWORD_COMPLEXITY_NONE));
}
return complexity;
}
@Implementation
public static boolean userOwnsFrpCredential(Context context, UserInfo info) {
return sIsUserOwnsFrpCredential;
}
public static void setUserOwnsFrpCredential(boolean isUserOwnsFrpCredential) {
sIsUserOwnsFrpCredential = isUserOwnsFrpCredential;
}
@Implementation
public boolean isVisiblePatternEnabled(int userId) {
return sUserToVisiblePatternEnabledMap.getOrDefault(userId, false);
}
public static void setIsVisiblePatternEnabled(int userId, boolean isVisiblePatternEnabled) {
sUserToVisiblePatternEnabledMap.put(userId, isVisiblePatternEnabled);
}
@Implementation
public boolean isBiometricAllowedForUser(int userId) {
return sUserToBiometricAllowedMap.getOrDefault(userId, false);
}
public static void setIsBiometricAllowedForUser(int userId, boolean isBiometricAllowed) {
sUserToBiometricAllowedMap.put(userId, isBiometricAllowed);
}
@Implementation
public boolean isLockPatternEnabled(int userId) {
return sUserToBiometricAllowedMap.getOrDefault(userId, false);
}
public static void setIsLockPatternEnabled(int userId, boolean isLockPatternEnabled) {
sUserToLockPatternEnabledMap.put(userId, isLockPatternEnabled);
}
@Implementation
public boolean setLockCredential(
@NonNull LockscreenCredential newCredential,
@NonNull LockscreenCredential savedCredential, int userHandle) {
setIsSecure(userHandle, true);
return true;
}
@Implementation
public boolean checkCredential(
@NonNull LockscreenCredential credential, int userId,
@Nullable LockPatternUtils.CheckCredentialProgressCallback progressCallback)
throws LockPatternUtils.RequestThrottledException {
return true;
}
public static void setRequiredPasswordComplexity(int userHandle, int complexity) {
sUserToComplexityMap.put(userHandle, complexity);
}
public static void setRequiredPasswordComplexity(int complexity) {
sUserToComplexityMap.put(UserHandle.myUserId(), complexity);
}
public static void setRequiredProfilePasswordComplexity(int complexity) {
sUserToProfileComplexityMap.put(UserHandle.myUserId(), complexity);
}
@Implementation
public PasswordMetrics getRequestedPasswordMetrics(int userId, boolean deviceWideOnly) {
PasswordMetrics metrics = sUserToMetricsMap.getOrDefault(userId,
new PasswordMetrics(LockPatternUtils.CREDENTIAL_TYPE_NONE));
if (!deviceWideOnly) {
metrics.maxWith(sUserToProfileMetricsMap.getOrDefault(userId,
new PasswordMetrics(LockPatternUtils.CREDENTIAL_TYPE_NONE)));
}
return metrics;
}
public static void setRequestedPasswordMetrics(PasswordMetrics metrics) {
sUserToMetricsMap.put(UserHandle.myUserId(), metrics);
}
public static void setRequestedProfilePasswordMetrics(PasswordMetrics metrics) {
sUserToProfileMetricsMap.put(UserHandle.myUserId(), metrics);
}
public static void setActivePasswordQuality(int quality) {
sUserToActivePasswordQualityMap.put(UserHandle.myUserId(), quality);
}
@Implementation
public boolean isLockScreenDisabled(int userId) {
return false;
}
@Implementation
public boolean isSeparateProfileChallengeEnabled(int userHandle) {
return false;
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.testutils.shadow;
import com.android.settingslib.utils.ThreadUtils;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
@Implements(ThreadUtils.class)
public class ShadowThreadUtils {
private static boolean sIsMainThread = true;
private static final String TAG = "ShadowThreadUtils";
@Resetter
public static void reset() {
sIsMainThread = true;
}
@Implementation
protected static void postOnBackgroundThread(Runnable runnable) {
runnable.run();
}
@Implementation
protected static void postOnMainThread(Runnable runnable) {
runnable.run();
}
@Implementation
protected static boolean isMainThread() {
return sIsMainThread;
}
public static void setIsMainThread(boolean isMainThread) {
sIsMainThread = isMainThread;
}
}

View File

@@ -0,0 +1,283 @@
/*
* 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.testutils.shadow;
import android.annotation.UserIdInt;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager.EnforcingUser;
import com.google.android.collect.Maps;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Implements(value = UserManager.class)
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
private static boolean sIsSupportsMultipleUsers;
private static final int PRIMARY_USER_ID = 0;
private final List<String> mBaseRestrictions = new ArrayList<>();
private final Map<String, List<EnforcingUser>> mRestrictionSources = new HashMap<>();
private final List<UserInfo> mUserProfileInfos = new ArrayList<>();
private final Set<Integer> mManagedProfiles = new HashSet<>();
private final Set<String> mEnabledTypes = new HashSet<>();
private boolean mIsQuietModeEnabled = false;
private int[] mProfileIdsForUser = new int[0];
private boolean mUserSwitchEnabled;
private Bundle mDefaultGuestUserRestriction = new Bundle();
private boolean mIsGuestUser = false;
private @UserManager.UserSwitchabilityResult int mSwitchabilityStatus =
UserManager.SWITCHABILITY_STATUS_OK;
private final Map<Integer, Integer> mSameProfileGroupIds = Maps.newHashMap();
public void addProfile(UserInfo userInfo) {
mUserProfileInfos.add(userInfo);
}
@Resetter
public static void reset() {
sIsSupportsMultipleUsers = false;
}
@Implementation
protected List<UserInfo> getProfiles(@UserIdInt int userHandle) {
return mUserProfileInfos;
}
@Implementation
protected int[] getProfileIds(@UserIdInt int userHandle, boolean enabledOnly) {
int[] ids = new int[mUserProfileInfos.size()];
for (int i = 0; i < mUserProfileInfos.size(); i++) {
ids[i] = mUserProfileInfos.get(i).id;
}
return ids;
}
@Implementation
protected int getCredentialOwnerProfile(@UserIdInt int userHandle) {
return userHandle;
}
@Implementation
protected boolean hasBaseUserRestriction(String restrictionKey, UserHandle userHandle) {
return mBaseRestrictions.contains(restrictionKey);
}
public void addBaseUserRestriction(String restriction) {
mBaseRestrictions.add(restriction);
}
@Implementation
protected Bundle getDefaultGuestRestrictions() {
return mDefaultGuestUserRestriction;
}
@Implementation
protected void setDefaultGuestRestrictions(Bundle restrictions) {
mDefaultGuestUserRestriction = restrictions;
}
public void addGuestUserRestriction(String restriction) {
mDefaultGuestUserRestriction.putBoolean(restriction, true);
}
public boolean hasGuestUserRestriction(String restriction, boolean expectedValue) {
return mDefaultGuestUserRestriction.containsKey(restriction)
&& mDefaultGuestUserRestriction.getBoolean(restriction) == expectedValue;
}
@Implementation
protected boolean hasUserRestriction(String restrictionKey) {
return hasUserRestriction(restrictionKey, UserHandle.of(UserHandle.myUserId()));
}
public static ShadowUserManager getShadow() {
return (ShadowUserManager) Shadow.extract(
RuntimeEnvironment.application.getSystemService(UserManager.class));
}
@Implementation
protected List<EnforcingUser> getUserRestrictionSources(
String restrictionKey, UserHandle userHandle) {
// Return empty list when there is no enforcing user, otherwise might trigger
// NullPointer Exception in RestrictedLockUtils.checkIfRestrictionEnforced.
List<EnforcingUser> enforcingUsers =
mRestrictionSources.get(restrictionKey + userHandle.getIdentifier());
return enforcingUsers == null ? Collections.emptyList() : enforcingUsers;
}
public void setUserRestrictionSources(
String restrictionKey, UserHandle userHandle, List<EnforcingUser> enforcers) {
mRestrictionSources.put(restrictionKey + userHandle.getIdentifier(), enforcers);
}
@Implementation
protected boolean isQuietModeEnabled(UserHandle userHandle) {
return mIsQuietModeEnabled;
}
public void setQuietModeEnabled(boolean enabled) {
mIsQuietModeEnabled = enabled;
}
@Implementation
protected int[] getProfileIdsWithDisabled(@UserIdInt int userId) {
return mProfileIdsForUser;
}
public void setProfileIdsWithDisabled(int[] profileIds) {
mProfileIdsForUser = profileIds;
}
@Implementation
protected boolean isUserSwitcherEnabled() {
return mUserSwitchEnabled;
}
@Implementation
protected boolean isManagedProfile(int userId) {
return mManagedProfiles.contains(userId);
}
public void setManagedProfiles(Set<Integer> profileIds) {
mManagedProfiles.clear();
mManagedProfiles.addAll(profileIds);
}
public void setUserSwitcherEnabled(boolean userSwitchEnabled) {
mUserSwitchEnabled = userSwitchEnabled;
}
@Implementation
protected static boolean supportsMultipleUsers() {
return sIsSupportsMultipleUsers;
}
@Implementation
protected boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) {
return mSameProfileGroupIds.containsKey(userId)
&& mSameProfileGroupIds.get(userId) == otherUserId
|| mSameProfileGroupIds.containsKey(otherUserId)
&& mSameProfileGroupIds.get(otherUserId) == userId;
}
public Map<Integer, Integer> getSameProfileGroupIds() {
return mSameProfileGroupIds;
}
public void setSupportsMultipleUsers(boolean supports) {
sIsSupportsMultipleUsers = supports;
}
@Implementation
protected UserInfo getUserInfo(@UserIdInt int userId) {
return mUserProfileInfos.stream()
.filter(userInfo -> userInfo.id == userId)
.findFirst()
.orElse(super.getUserInfo(userId));
}
@Implementation
protected @UserManager.UserSwitchabilityResult int getUserSwitchability() {
return mSwitchabilityStatus;
}
public void setSwitchabilityStatus(@UserManager.UserSwitchabilityResult int newStatus) {
mSwitchabilityStatus = newStatus;
}
@Implementation
protected boolean isUserTypeEnabled(String userType) {
return mEnabledTypes.contains(userType);
}
public void setUserTypeEnabled(String type, boolean enabled) {
if (enabled) {
mEnabledTypes.add(type);
} else {
mEnabledTypes.remove(type);
}
}
@Implementation
protected UserInfo getPrimaryUser() {
return new UserInfo(PRIMARY_USER_ID, null, null,
UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
}
protected boolean setUserEphemeral(@UserIdInt int userId, boolean enableEphemeral) {
UserInfo userInfo = mUserProfileInfos.stream()
.filter(user -> user.id == userId)
.findFirst()
.orElse(super.getUserInfo(userId));
boolean isSuccess = false;
boolean isEphemeralUser =
(userInfo.flags & UserInfo.FLAG_EPHEMERAL) != 0;
boolean isEphemeralOnCreateUser =
(userInfo.flags & UserInfo.FLAG_EPHEMERAL_ON_CREATE)
!= 0;
// when user is created in ephemeral mode via FLAG_EPHEMERAL
// its state cannot be changed.
// FLAG_EPHEMERAL_ON_CREATE is used to keep track of this state
if (!isEphemeralOnCreateUser) {
isSuccess = true;
if (isEphemeralUser != enableEphemeral) {
if (enableEphemeral) {
userInfo.flags |= UserInfo.FLAG_EPHEMERAL;
} else {
userInfo.flags &= ~UserInfo.FLAG_EPHEMERAL;
}
}
}
return isSuccess;
}
@Implementation
protected void setUserAdmin(@UserIdInt int userId) {
for (int i = 0; i < mUserProfileInfos.size(); i++) {
mUserProfileInfos.get(i).flags |= UserInfo.FLAG_ADMIN;
}
}
@Implementation
protected boolean isGuestUser() {
return mIsGuestUser;
}
public void setGuestUser(boolean isGuestUser) {
mIsGuestUser = isGuestUser;
}
}

View File

@@ -0,0 +1,191 @@
/*
* 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.testutils.shadow;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArraySet;
import com.android.settings.Utils;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import java.util.HashMap;
import java.util.Map;
@Implements(Utils.class)
public class ShadowUtils {
private static FingerprintManager sFingerprintManager = null;
private static FaceManager sFaceManager = null;
private static boolean sIsUserAMonkey;
private static boolean sIsDemoUser;
private static ComponentName sDeviceOwnerComponentName;
private static Map<String, String> sAppNameMap;
private static boolean sIsSystemAlertWindowEnabled;
private static boolean sIsVoiceCapable;
private static ArraySet<String> sResultLinks = new ArraySet<>();
private static boolean sIsBatteryPresent;
private static boolean sIsMultipleBiometricsSupported;
@Implementation
protected static int enforceSameOwner(Context context, int userId) {
return userId;
}
@Implementation
protected static FingerprintManager getFingerprintManagerOrNull(Context context) {
return sFingerprintManager;
}
public static void setFingerprintManager(FingerprintManager fingerprintManager) {
sFingerprintManager = fingerprintManager;
}
@Implementation
protected static FaceManager getFaceManagerOrNull(Context context) {
return sFaceManager;
}
public static void setFaceManager(FaceManager faceManager) {
sFaceManager = faceManager;
}
public static void reset() {
sFingerprintManager = null;
sIsUserAMonkey = false;
sIsDemoUser = false;
sIsVoiceCapable = false;
sResultLinks = new ArraySet<>();
sIsBatteryPresent = true;
sIsMultipleBiometricsSupported = false;
}
public static void setIsDemoUser(boolean isDemoUser) {
sIsDemoUser = isDemoUser;
}
@Implementation
public static boolean isDemoUser(Context context) {
return sIsDemoUser;
}
public static void setIsUserAMonkey(boolean isUserAMonkey) {
sIsUserAMonkey = isUserAMonkey;
}
/**
* Returns true if Monkey is running.
*/
@Implementation
protected static boolean isMonkeyRunning() {
return sIsUserAMonkey;
}
public static void setDeviceOwnerComponent(ComponentName componentName) {
sDeviceOwnerComponentName = componentName;
}
@Implementation
protected static ComponentName getDeviceOwnerComponent(Context context) {
return sDeviceOwnerComponentName;
}
@Implementation
protected static int getManagedProfileId(UserManager um, int parentUserId) {
return UserHandle.USER_NULL;
}
@Implementation
protected static CharSequence getApplicationLabel(Context context, String packageName) {
if (sAppNameMap != null) {
return sAppNameMap.get(packageName);
}
return null;
}
@Implementation
protected static boolean isPackageEnabled(Context context, String packageName) {
return true;
}
public static void setApplicationLabel(String packageName, String appLabel) {
if (sAppNameMap == null) {
sAppNameMap = new HashMap<>();
}
sAppNameMap.put(packageName, appLabel);
}
@Implementation
protected static boolean isSystemAlertWindowEnabled(Context context) {
return sIsSystemAlertWindowEnabled;
}
public static void setIsSystemAlertWindowEnabled(boolean enabled) {
sIsSystemAlertWindowEnabled = enabled;
}
@Implementation
protected static boolean isVoiceCapable(Context context) {
return sIsVoiceCapable;
}
public static void setIsVoiceCapable(boolean isVoiceCapable) {
sIsVoiceCapable = isVoiceCapable;
}
@Implementation
protected static ArraySet<String> getHandledDomains(PackageManager pm, String packageName) {
return sResultLinks;
}
@Implementation
protected static Drawable getBadgedIcon(Context context, ApplicationInfo appInfo) {
return new ColorDrawable(0);
}
public static void setHandledDomains(ArraySet<String> links) {
sResultLinks = links;
}
@Implementation
protected static boolean isBatteryPresent(Context context) {
return sIsBatteryPresent;
}
public static void setIsBatteryPresent(boolean isBatteryPresent) {
sIsBatteryPresent = isBatteryPresent;
}
@Implementation
protected static boolean isMultipleBiometricsSupported(Context context) {
return sIsMultipleBiometricsSupported;
}
public static void setIsMultipleBiometricsSupported(boolean isMultipleBiometricsSupported) {
sIsMultipleBiometricsSupported = isMultipleBiometricsSupported;
}
}