Setup external/robolectric for SettingsRoboTests

Current failing tests: ab/I64100010182936387
Had to Ignore some of com.android.settings.accessibility tests, which will be fixed separately

Bug: 261728063
Test: atest SettingsRoboTests -- --test-arg com.android.tradefed.testtype.IsolatedHostTest:java-flags:-XX:CompressedClassSpaceSize=3g

Change-Id: I4a0cb992db924936826e0c9808accc78dddb5f30
This commit is contained in:
Rex Hoffman
2023-06-07 20:20:58 +00:00
committed by Kevin Liu
parent 4f510190b3
commit 3c961e1c0e
180 changed files with 1339 additions and 157 deletions

View File

@@ -23,7 +23,7 @@ import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@Implements(ActivityManager.class)
public class ShadowActivityManager {
public class ShadowActivityManager extends org.robolectric.shadows.ShadowActivityManager {
private static int sCurrentUserId = 0;
private static IActivityManager sService = null;

View File

@@ -0,0 +1,52 @@
/*
* 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 android.app.ApplicationPackageManager;
import android.content.pm.PackageInfo;
import org.robolectric.annotation.Implements;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Implements(ApplicationPackageManager.class)
public class ShadowApplicationPackageManager
extends org.robolectric.shadows.ShadowApplicationPackageManager {
static final Map<Integer, List<String>> packagesForUserId = new HashMap<>();
public void setInstalledPackagesForUserId(int userId, List<String> packages) {
packagesForUserId.put(userId, packages);
for (String packageName : packages) {
addPackage(packageName);
}
}
protected List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
List<PackageInfo> packages = new ArrayList<>();
for (String packageName : packagesForUserId.getOrDefault(userId, new ArrayList<>())) {
try {
packages.add(getPackageInfo(packageName, flags));
} catch (Exception e) {
// ignore
}
}
return packages;
}
}

View File

@@ -31,12 +31,12 @@ import android.media.AudioDeviceCallback;
import android.media.AudioManager;
import android.os.Handler;
import java.util.List;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
import java.util.ArrayList;
import java.util.List;
@Implements(value = AudioManager.class)
public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManager {
@@ -46,7 +46,7 @@ public class ShadowAudioManager extends org.robolectric.shadows.ShadowAudioManag
private List<AudioDeviceCallback> mDeviceCallbacks = new ArrayList<>();
@Implementation
private int getRingerModeInternal() {
protected int getRingerModeInternal() {
return mRingerMode;
}

View File

@@ -33,6 +33,7 @@ public class ShadowAuthenticationHelper {
static final String[] LABELS = {"LABEL1", "LABEL2", "LABEL3", "LABEL4"};
private static String[] sEnabledAccount = TYPES;
@Implementation
protected void __constructor__(Context context, UserHandle userHandle,
AuthenticatorHelper.OnAccountsUpdateListener listener) {
}

View File

@@ -0,0 +1,69 @@
/*
* 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 android.Manifest;
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.CrossProfileApps;
import android.content.pm.ICrossProfileApps;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@Implements(CrossProfileApps.class)
public class ShadowCrossProfileApps extends org.robolectric.shadows.ShadowCrossProfileApps {
private static final Set<String> configurableInteractAcrossProfilePackages = new HashSet<>();
private Context mContext;
private PackageManager mPackageManager;
@Implementation
protected void __constructor__(Context context, ICrossProfileApps service) {
super.__constructor__(context, service);
this.mContext = context;
this.mPackageManager = context.getPackageManager();
}
public void addCrossProfilePackage(String packageName) {
configurableInteractAcrossProfilePackages.add(packageName);
}
@Implementation
protected boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) {
return configurableInteractAcrossProfilePackages.contains(packageName);
}
@Implementation
protected boolean canUserAttemptToConfigureInteractAcrossProfiles(@NonNull String packageName) {
PackageInfo packageInfo;
try {
packageInfo = mPackageManager.getPackageInfo(packageName, /* flags= */ 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
if (packageInfo == null || packageInfo.requestedPermissions == null) {
return false;
}
return Arrays.asList(packageInfo.requestedPermissions).contains(
Manifest.permission.INTERACT_ACROSS_PROFILES);
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.content.Context;
import android.text.format.DateFormat;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import java.util.Locale;
@Implements(DateFormat.class)
public class ShadowDateFormat {
@Implementation
protected static java.text.DateFormat getDateFormat(Context context) {
return new java.text.SimpleDateFormat("MMM-dd-yyyy", Locale.ROOT);
}
@Implementation
protected static java.text.DateFormat getLongDateFormat(Context context) {
return new java.text.SimpleDateFormat("MMMM dd, yyyy", Locale.ROOT);
}
@Implementation
protected static java.text.DateFormat getTimeFormat(Context context) {
return new java.text.SimpleDateFormat("HH:mm:ss", Locale.ROOT);
}
}

View File

@@ -1,8 +1,25 @@
/*
* 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 android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Build.VERSION_CODES.Q;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -22,10 +39,12 @@ import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@Implements(DevicePolicyManager.class)
public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDevicePolicyManager {
@@ -34,12 +53,14 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev
private final Map<String, Integer> mDeviceOwnerTypes = new HashMap<>();
private Map<Integer, CharSequence> mSupportMessagesMap = new HashMap<>();
private boolean mIsAdminActiveAsUser = false;
private ComponentName mProfileOwner;
private ComponentName mDeviceOwnerComponentName;
private ManagedSubscriptionsPolicy mManagedSubscriptionsPolicy;
private int mDeviceOwnerUserId = -1;
private int mPasswordMinQuality = PASSWORD_QUALITY_UNSPECIFIED;
private int mPasswordMinLength = 0;
private int mPasswordMinSymbols = 0;
private Set<String> mCrossProfileCalendarPackages = Collections.emptySet();
private List<String> mPermittedAccessibilityServices = null;
@@ -149,4 +170,32 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev
ApplicationProvider.getApplicationContext()
.getSystemService(DevicePolicyManager.class));
}
// BEGIN-INTERNAL
@Implementation(minSdk = Q)
protected Set<String> getCrossProfileCalendarPackages() {
return mCrossProfileCalendarPackages;
}
@Implementation(minSdk = Q)
public void setCrossProfileCalendarPackages(ComponentName admin, Set<String> packageNames) {
enforceProfileOwner(admin);
mCrossProfileCalendarPackages = packageNames;
}
/**
* Sets the admin as active admin and profile owner.
*
* @see DevicePolicyManager#getProfileOwner()
*/
public void setProfileOwner(ComponentName admin) {
setActiveAdmin(admin);
mProfileOwner = admin;
}
private void enforceProfileOwner(ComponentName admin) {
if (!admin.equals(mProfileOwner)) {
throw new SecurityException("[" + admin + "] is not a profile owner");
}
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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 org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@Implements(ShadowDrawable.class)
public class ShadowDrawable extends org.robolectric.shadows.ShadowDrawable {
private static int sDefaultIntrinsicWidth = -1;
private int mIntrinsicWidth = sDefaultIntrinsicWidth;
@Implementation
public int getIntrinsicWidth() {
return mIntrinsicWidth;
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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 static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManager;
import android.os.Handler;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
/**
* Shadow for {@link InputManager} that has accessors for registered
* {@link InputManager.InputDeviceListener}s.
*/
@Implements(value = InputManager.class, callThroughByDefault = false)
public class ShadowInputManager extends org.robolectric.shadows.ShadowInputManager {
private List<InputManager.InputDeviceListener> mInputDeviceListeners;
@Implementation
protected void __constructor__(IInputManager service) {
mInputDeviceListeners = new ArrayList<>();
}
@Implementation
protected static InputManager getInstance() {
return ReflectionHelpers.callConstructor(
InputManager.class,
from(IInputManager.class, null));
}
@Implementation
protected void registerInputDeviceListener(InputManager.InputDeviceListener listener,
Handler handler) {
// TODO: Use handler.
if (!mInputDeviceListeners.contains(listener)) {
mInputDeviceListeners.add(listener);
}
}
@Implementation
protected void unregisterInputDeviceListener(InputManager.InputDeviceListener listener) {
mInputDeviceListeners.remove(listener);
}
}

View File

@@ -28,7 +28,7 @@ public class ShadowKeyStore {
private static boolean sIsHardwareBacked;
@Resetter
public void reset() {
public static void reset() {
sIsHardwareBacked = false;
}

View File

@@ -0,0 +1,42 @@
/*
* 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 android.service.persistentdata.PersistentDataBlockManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
@Implements(PersistentDataBlockManager.class)
public class ShadowPersistentDataBlockManager {
private static int sDataBlockSize = 0;
@Resetter
public static void reset() {
sDataBlockSize = 0;
}
@Implementation
protected int getDataBlockSize() {
return sDataBlockSize;
}
public static void setDataBlockSize(int dataBlockSize) {
sDataBlockSize = dataBlockSize;
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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 android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import android.content.ContentResolver;
import android.provider.Settings;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.shadows.ShadowSettings;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
@Implements(value = Settings.System.class)
public class ShadowSystemSettings extends ShadowSettings.ShadowSystem {
private static final Map<ContentResolver, Map<String, String>> sDataMap = new WeakHashMap<>();
@Resetter
public static void reset() {
sDataMap.clear();
}
@Implementation(minSdk = JELLY_BEAN_MR1)
protected static boolean putStringForUser(ContentResolver cr, String name, String value,
int userHandle) {
return putString(cr, name, value);
}
@Implementation(minSdk = JELLY_BEAN_MR1)
protected static String getStringForUser(ContentResolver cr, String name, int userHandle) {
return getString(cr, name);
}
@Implementation
protected static boolean putString(ContentResolver cr, String name, String value) {
get(cr).put(name, value);
return true;
}
@Implementation
protected static String getString(ContentResolver cr, String name) {
return get(cr).get(name);
}
private static Map<String, String> get(ContentResolver cr) {
Map<String, String> map = sDataMap.get(cr);
if (map == null) {
map = new HashMap<>();
sDataMap.put(cr, map);
}
return map;
}
}