1 package org.robolectric.shadows; 2 3 import static org.robolectric.shadow.api.Shadow.newInstanceOf; 4 import static org.robolectric.util.reflector.Reflector.reflector; 5 6 import android.app.Application; 7 import android.app.LoadedApk; 8 import android.content.pm.ApplicationInfo; 9 import android.content.pm.PackageManager.NameNotFoundException; 10 import android.content.res.Resources; 11 import android.os.Build.VERSION_CODES; 12 import org.robolectric.RuntimeEnvironment; 13 import org.robolectric.annotation.Implementation; 14 import org.robolectric.annotation.Implements; 15 import org.robolectric.annotation.RealObject; 16 import org.robolectric.util.reflector.Accessor; 17 import org.robolectric.util.reflector.ForType; 18 19 @Implements(value = LoadedApk.class, isInAndroidSdk = false) 20 public class ShadowLoadedApk { 21 @RealObject private LoadedApk realLoadedApk; 22 private boolean isClassLoaderInitialized = false; 23 private final Object classLoaderLock = new Object(); 24 25 @Implementation getClassLoader()26 public ClassLoader getClassLoader() { 27 // The AppComponentFactory was introduced from SDK 28. 28 if (RuntimeEnvironment.getApiLevel() >= VERSION_CODES.P) { 29 synchronized (classLoaderLock) { 30 if (!isClassLoaderInitialized) { 31 isClassLoaderInitialized = true; 32 tryInitAppComponentFactory(realLoadedApk); 33 } 34 } 35 } 36 return this.getClass().getClassLoader(); 37 } 38 39 @Implementation(minSdk = VERSION_CODES.O) getSplitClassLoader(String splitName)40 public ClassLoader getSplitClassLoader(String splitName) throws NameNotFoundException { 41 return this.getClass().getClassLoader(); 42 } 43 tryInitAppComponentFactory(LoadedApk realLoadedApk)44 private void tryInitAppComponentFactory(LoadedApk realLoadedApk) { 45 if (RuntimeEnvironment.getApiLevel() >= VERSION_CODES.P) { 46 ApplicationInfo applicationInfo = realLoadedApk.getApplicationInfo(); 47 if (applicationInfo == null || applicationInfo.appComponentFactory == null) { 48 return; 49 } 50 _LoadedApk_ loadedApkReflector = reflector(_LoadedApk_.class, realLoadedApk); 51 if (!loadedApkReflector.getIncludeCode()) { 52 return; 53 } 54 String fullQualifiedClassName = 55 calculateFullQualifiedClassName( 56 applicationInfo.appComponentFactory, applicationInfo.packageName); 57 android.app.AppComponentFactory factory = 58 (android.app.AppComponentFactory) newInstanceOf(fullQualifiedClassName); 59 if (factory == null) { 60 factory = new android.app.AppComponentFactory(); 61 } 62 loadedApkReflector.setAppFactory(factory); 63 } 64 } 65 calculateFullQualifiedClassName(String className, String packageName)66 private String calculateFullQualifiedClassName(String className, String packageName) { 67 if (packageName == null) { 68 return className; 69 } 70 return className.startsWith(".") ? packageName + className : className; 71 } 72 73 /** Accessor interface for {@link LoadedApk}'s internals. */ 74 @ForType(LoadedApk.class) 75 public interface _LoadedApk_ { 76 77 @Accessor("mApplication") setApplication(Application application)78 void setApplication(Application application); 79 80 @Accessor("mResources") setResources(Resources resources)81 void setResources(Resources resources); 82 83 @Accessor("mIncludeCode") getIncludeCode()84 boolean getIncludeCode(); 85 86 @Accessor("mAppComponentFactory") setAppFactory(Object appFactory)87 void setAppFactory(Object appFactory); 88 } 89 } 90