1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 4 import static android.os.Build.VERSION_CODES.KITKAT; 5 import static android.os.Build.VERSION_CODES.LOLLIPOP; 6 import static android.os.Build.VERSION_CODES.O; 7 import static org.robolectric.shadow.api.Shadow.directlyOn; 8 9 import android.app.ActivityManager; 10 import android.app.IActivityManager; 11 import android.content.Context; 12 import android.content.pm.ConfigurationInfo; 13 import android.os.Build.VERSION_CODES; 14 import android.os.Process; 15 import java.util.List; 16 import java.util.concurrent.CopyOnWriteArrayList; 17 import org.robolectric.RuntimeEnvironment; 18 import org.robolectric.annotation.HiddenApi; 19 import org.robolectric.annotation.Implementation; 20 import org.robolectric.annotation.Implements; 21 import org.robolectric.annotation.RealObject; 22 import org.robolectric.annotation.Resetter; 23 import org.robolectric.shadow.api.Shadow; 24 import org.robolectric.util.ReflectionHelpers; 25 26 @Implements(ActivityManager.class) 27 public class ShadowActivityManager { 28 private int memoryClass = 16; 29 private String backgroundPackage; 30 private ActivityManager.MemoryInfo memoryInfo; 31 private final List<ActivityManager.AppTask> appTasks = new CopyOnWriteArrayList<>(); 32 private final List<ActivityManager.RunningTaskInfo> tasks = new CopyOnWriteArrayList<>(); 33 private final List<ActivityManager.RunningServiceInfo> services = new CopyOnWriteArrayList<>(); 34 private static List<ActivityManager.RunningAppProcessInfo> processes = 35 new CopyOnWriteArrayList<>(); 36 @RealObject private ActivityManager realObject; 37 private Boolean isLowRamDeviceOverride = null; 38 private int lockTaskModeState = ActivityManager.LOCK_TASK_MODE_NONE; 39 ShadowActivityManager()40 public ShadowActivityManager() { 41 ActivityManager.RunningAppProcessInfo processInfo = new ActivityManager.RunningAppProcessInfo(); 42 fillInProcessInfo(processInfo); 43 processInfo.processName = RuntimeEnvironment.application.getPackageName(); 44 processInfo.pkgList = new String[] {RuntimeEnvironment.application.getPackageName()}; 45 processes.add(processInfo); 46 } 47 48 @Implementation getMemoryClass()49 protected int getMemoryClass() { 50 return memoryClass; 51 } 52 53 @Implementation isUserAMonkey()54 protected static boolean isUserAMonkey() { 55 return false; 56 } 57 58 @Implementation getRunningTasks(int maxNum)59 protected List<ActivityManager.RunningTaskInfo> getRunningTasks(int maxNum) { 60 return tasks; 61 } 62 63 /** 64 * For tests, returns the list of {@link android.app.ActivityManager.AppTask} set using {@link 65 * #setAppTasks(List)}. Returns empty list if nothing is set. 66 * 67 * @see #setAppTasks(List) 68 * @return List of current AppTask. 69 */ 70 @Implementation(minSdk = LOLLIPOP) getAppTasks()71 protected List<ActivityManager.AppTask> getAppTasks() { 72 return appTasks; 73 } 74 75 @Implementation getRunningServices(int maxNum)76 protected List<ActivityManager.RunningServiceInfo> getRunningServices(int maxNum) { 77 return services; 78 } 79 80 @Implementation getRunningAppProcesses()81 protected List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() { 82 // This method is explicitly documented not to return an empty list 83 if (processes.isEmpty()) { 84 return null; 85 } 86 return processes; 87 } 88 89 /** Returns information seeded by {@link #setProcesses}. */ 90 @Implementation getMyMemoryState(ActivityManager.RunningAppProcessInfo inState)91 protected static void getMyMemoryState(ActivityManager.RunningAppProcessInfo inState) { 92 fillInProcessInfo(inState); 93 for (ActivityManager.RunningAppProcessInfo info : processes) { 94 if (info.pid == Process.myPid()) { 95 inState.importance = info.importance; 96 inState.lru = info.lru; 97 inState.importanceReasonCode = info.importanceReasonCode; 98 inState.importanceReasonPid = info.importanceReasonPid; 99 inState.lastTrimLevel = info.lastTrimLevel; 100 inState.pkgList = info.pkgList; 101 inState.processName = info.processName; 102 } 103 } 104 } 105 fillInProcessInfo(ActivityManager.RunningAppProcessInfo processInfo)106 private static void fillInProcessInfo(ActivityManager.RunningAppProcessInfo processInfo) { 107 processInfo.pid = Process.myPid(); 108 processInfo.uid = Process.myUid(); 109 } 110 111 @HiddenApi 112 @Implementation(minSdk = JELLY_BEAN_MR1) switchUser(int userid)113 protected boolean switchUser(int userid) { 114 ShadowUserManager shadowUserManager = 115 Shadow.extract(RuntimeEnvironment.application.getSystemService(Context.USER_SERVICE)); 116 shadowUserManager.switchUser(userid); 117 return true; 118 } 119 120 @Implementation killBackgroundProcesses(String packageName)121 protected void killBackgroundProcesses(String packageName) { 122 backgroundPackage = packageName; 123 } 124 125 @Implementation getMemoryInfo(ActivityManager.MemoryInfo outInfo)126 protected void getMemoryInfo(ActivityManager.MemoryInfo outInfo) { 127 if (memoryInfo != null) { 128 outInfo.availMem = memoryInfo.availMem; 129 outInfo.lowMemory = memoryInfo.lowMemory; 130 outInfo.threshold = memoryInfo.threshold; 131 outInfo.totalMem = memoryInfo.totalMem; 132 } 133 } 134 135 @Implementation getDeviceConfigurationInfo()136 protected android.content.pm.ConfigurationInfo getDeviceConfigurationInfo() { 137 return new ConfigurationInfo(); 138 } 139 140 /** 141 * @param tasks List of running tasks. 142 */ setTasks(List<ActivityManager.RunningTaskInfo> tasks)143 public void setTasks(List<ActivityManager.RunningTaskInfo> tasks) { 144 this.tasks.clear(); 145 this.tasks.addAll(tasks); 146 } 147 148 /** 149 * Sets the values to be returned by {@link #getAppTasks()}. 150 * 151 * @see #getAppTasks() 152 * @param tasks List of app tasks. 153 */ setAppTasks(List<ActivityManager.AppTask> appTasks)154 public void setAppTasks(List<ActivityManager.AppTask> appTasks) { 155 this.appTasks.clear(); 156 this.appTasks.addAll(appTasks); 157 } 158 159 /** 160 * @param services List of running services. 161 */ setServices(List<ActivityManager.RunningServiceInfo> services)162 public void setServices(List<ActivityManager.RunningServiceInfo> services) { 163 this.services.clear(); 164 this.services.addAll(services); 165 } 166 167 /** 168 * @param processes List of running processes. 169 */ setProcesses(List<ActivityManager.RunningAppProcessInfo> processes)170 public void setProcesses(List<ActivityManager.RunningAppProcessInfo> processes) { 171 ShadowActivityManager.processes.clear(); 172 ShadowActivityManager.processes.addAll(processes); 173 } 174 175 /** 176 * @return Get the package name of the last background processes killed. 177 */ getBackgroundPackage()178 public String getBackgroundPackage() { 179 return backgroundPackage; 180 } 181 182 /** 183 * @param memoryClass Set the application's memory class. 184 */ setMemoryClass(int memoryClass)185 public void setMemoryClass(int memoryClass) { 186 this.memoryClass = memoryClass; 187 } 188 189 /** 190 * @param memoryInfo Set the application's memory info. 191 */ setMemoryInfo(ActivityManager.MemoryInfo memoryInfo)192 public void setMemoryInfo(ActivityManager.MemoryInfo memoryInfo) { 193 this.memoryInfo = memoryInfo; 194 } 195 196 @Implementation(minSdk = O) getService()197 protected static IActivityManager getService() { 198 return ReflectionHelpers.createNullProxy(IActivityManager.class); 199 } 200 201 @Implementation(minSdk = KITKAT) isLowRamDevice()202 protected boolean isLowRamDevice() { 203 if (isLowRamDeviceOverride != null) { 204 return isLowRamDeviceOverride; 205 } 206 return directlyOn(realObject, ActivityManager.class, "isLowRamDevice"); 207 } 208 209 /** 210 * Override the return value of isLowRamDevice(). 211 */ setIsLowRamDevice(boolean isLowRamDevice)212 public void setIsLowRamDevice(boolean isLowRamDevice) { 213 isLowRamDeviceOverride = isLowRamDevice; 214 } 215 216 @Implementation(minSdk = VERSION_CODES.M) getLockTaskModeState()217 protected int getLockTaskModeState() { 218 return lockTaskModeState; 219 } 220 221 @Implementation(minSdk = VERSION_CODES.LOLLIPOP) isInLockTaskMode()222 protected boolean isInLockTaskMode() { 223 return getLockTaskModeState() != ActivityManager.LOCK_TASK_MODE_NONE; 224 } 225 226 /** 227 * Sets lock task mode state to be reported by {@link ActivityManager#getLockTaskModeState}, but 228 * has no effect otherwise. 229 */ setLockTaskModeState(int lockTaskModeState)230 public void setLockTaskModeState(int lockTaskModeState) { 231 this.lockTaskModeState = lockTaskModeState; 232 } 233 234 @Resetter reset()235 public static void reset() { 236 processes.clear(); 237 } 238 } 239