Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.layoutlib.bridge.android;
     18 
     19 import com.android.SdkConstants;
     20 import com.android.ide.common.rendering.api.AssetRepository;
     21 import com.android.ide.common.rendering.api.ILayoutPullParser;
     22 import com.android.ide.common.rendering.api.LayoutLog;
     23 import com.android.ide.common.rendering.api.LayoutlibCallback;
     24 import com.android.ide.common.rendering.api.RenderResources;
     25 import com.android.ide.common.rendering.api.ResourceNamespace;
     26 import com.android.ide.common.rendering.api.ResourceNamespace.Resolver;
     27 import com.android.ide.common.rendering.api.ResourceReference;
     28 import com.android.ide.common.rendering.api.ResourceValue;
     29 import com.android.ide.common.rendering.api.StyleResourceValue;
     30 import com.android.layoutlib.bridge.Bridge;
     31 import com.android.layoutlib.bridge.BridgeConstants;
     32 import com.android.layoutlib.bridge.android.view.WindowManagerImpl;
     33 import com.android.layoutlib.bridge.impl.ParserFactory;
     34 import com.android.layoutlib.bridge.impl.Stack;
     35 import com.android.resources.ResourceType;
     36 import com.android.util.Pair;
     37 import com.android.util.PropertiesMap;
     38 import com.android.util.PropertiesMap.Property;
     39 
     40 import org.xmlpull.v1.XmlPullParser;
     41 import org.xmlpull.v1.XmlPullParserException;
     42 
     43 import android.annotation.NonNull;
     44 import android.annotation.Nullable;
     45 import android.app.SystemServiceRegistry_Accessor;
     46 import android.content.BroadcastReceiver;
     47 import android.content.ComponentName;
     48 import android.content.ContentResolver;
     49 import android.content.Context;
     50 import android.content.ContextWrapper;
     51 import android.content.Intent;
     52 import android.content.IntentFilter;
     53 import android.content.IntentSender;
     54 import android.content.ServiceConnection;
     55 import android.content.SharedPreferences;
     56 import android.content.pm.ApplicationInfo;
     57 import android.content.pm.PackageManager;
     58 import android.content.res.AssetManager;
     59 import android.content.res.BridgeAssetManager;
     60 import android.content.res.BridgeTypedArray;
     61 import android.content.res.Configuration;
     62 import android.content.res.Resources;
     63 import android.content.res.Resources.Theme;
     64 import android.content.res.Resources_Delegate;
     65 import android.database.DatabaseErrorHandler;
     66 import android.database.sqlite.SQLiteDatabase;
     67 import android.database.sqlite.SQLiteDatabase.CursorFactory;
     68 import android.graphics.Bitmap;
     69 import android.graphics.Color;
     70 import android.graphics.drawable.Drawable;
     71 import android.hardware.display.DisplayManager;
     72 import android.net.Uri;
     73 import android.os.Bundle;
     74 import android.os.Handler;
     75 import android.os.IBinder;
     76 import android.os.IInterface;
     77 import android.os.Looper;
     78 import android.os.Parcel;
     79 import android.os.PowerManager;
     80 import android.os.RemoteException;
     81 import android.os.ResultReceiver;
     82 import android.os.ShellCallback;
     83 import android.os.UserHandle;
     84 import android.util.AttributeSet;
     85 import android.util.DisplayMetrics;
     86 import android.util.TypedValue;
     87 import android.view.BridgeInflater;
     88 import android.view.Display;
     89 import android.view.DisplayAdjustments;
     90 import android.view.View;
     91 import android.view.ViewGroup;
     92 import android.view.WindowManager;
     93 import android.view.accessibility.AccessibilityManager;
     94 import android.view.textservice.TextServicesManager;
     95 
     96 import java.io.File;
     97 import java.io.FileDescriptor;
     98 import java.io.FileInputStream;
     99 import java.io.FileNotFoundException;
    100 import java.io.FileOutputStream;
    101 import java.io.IOException;
    102 import java.io.InputStream;
    103 import java.util.ArrayList;
    104 import java.util.Collections;
    105 import java.util.HashMap;
    106 import java.util.IdentityHashMap;
    107 import java.util.List;
    108 import java.util.Map;
    109 
    110 import static android.os._Original_Build.VERSION_CODES.JELLY_BEAN_MR1;
    111 import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
    112 
    113 /**
    114  * Custom implementation of Context/Activity to handle non compiled resources.
    115  */
    116 @SuppressWarnings("deprecation")  // For use of Pair.
    117 public class BridgeContext extends Context {
    118     private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat";
    119 
    120     private static final Map<String, ResourceValue> FRAMEWORK_PATCHED_VALUES = new HashMap<>(2);
    121     private static final Map<String, ResourceValue> FRAMEWORK_REPLACE_VALUES = new HashMap<>(3);
    122 
    123     private static final Resolver LEGACY_NAMESPACE_RESOLVER =
    124             Collections.singletonMap(SdkConstants.TOOLS_PREFIX, SdkConstants.TOOLS_URI)::get;
    125 
    126     static {
    127         FRAMEWORK_PATCHED_VALUES.put("animateFirstView", new ResourceValue(
    128                 ResourceType.BOOL, "animateFirstView", "false", false));
    129         FRAMEWORK_PATCHED_VALUES.put("animateLayoutChanges",
    130                 new ResourceValue(ResourceType.BOOL, "animateLayoutChanges", "false", false));
    131 
    132 
    133         FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionItemLayout",
    134                 new ResourceValue(ResourceType.LAYOUT, "textEditSuggestionItemLayout",
    135                         "text_edit_suggestion_item", true));
    136         FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionContainerLayout",
    137                 new ResourceValue(ResourceType.LAYOUT, "textEditSuggestionContainerLayout",
    138                         "text_edit_suggestion_container", true));
    139         FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionHighlightStyle",
    140                 new ResourceValue(ResourceType.STYLE, "textEditSuggestionHighlightStyle",
    141                         "TextAppearance.Holo.SuggestionHighlight", true));
    142 
    143     }
    144 
    145     /** The map adds cookies to each view so that IDE can link xml tags to views. */
    146     private final HashMap<View, Object> mViewKeyMap = new HashMap<>();
    147     /**
    148      * In some cases, when inflating an xml, some objects are created. Then later, the objects are
    149      * converted to views. This map stores the mapping from objects to cookies which can then be
    150      * used to populate the mViewKeyMap.
    151      */
    152     private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<>();
    153     private final BridgeAssetManager mAssets;
    154     private Resources mSystemResources;
    155     private final Object mProjectKey;
    156     private final DisplayMetrics mMetrics;
    157     private final RenderResources mRenderResources;
    158     private final Configuration mConfig;
    159     private final ApplicationInfo mApplicationInfo;
    160     private final LayoutlibCallback mLayoutlibCallback;
    161     private final WindowManager mWindowManager;
    162     private final DisplayManager mDisplayManager;
    163     private final HashMap<View, Integer> mScrollYPos = new HashMap<>();
    164     private final HashMap<View, Integer> mScrollXPos = new HashMap<>();
    165 
    166     private Resources.Theme mTheme;
    167 
    168     private final Map<Object, PropertiesMap> mDefaultPropMaps = new IdentityHashMap<>();
    169 
    170     // maps for dynamically generated id representing style objects (StyleResourceValue)
    171     @Nullable
    172     private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
    173     private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
    174     private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
    175 
    176     // cache for TypedArray generated from StyleResourceValue object
    177     private TypedArrayCache mTypedArrayCache;
    178     private BridgeInflater mBridgeInflater;
    179 
    180     private BridgeContentResolver mContentResolver;
    181 
    182     private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<>();
    183     private SharedPreferences mSharedPreferences;
    184     private ClassLoader mClassLoader;
    185     private IBinder mBinder;
    186     private PackageManager mPackageManager;
    187     private Boolean mIsThemeAppCompat;
    188 
    189     /**
    190      * Some applications that target both pre API 17 and post API 17, set the newer attrs to
    191      * reference the older ones. For example, android:paddingStart will resolve to
    192      * android:paddingLeft. This way the apps need to only define paddingLeft at any other place.
    193      * This a map from value to attribute name. Warning for missing references shouldn't be logged
    194      * if value and attr name pair is the same as an entry in this map.
    195      */
    196     private static Map<String, String> RTL_ATTRS = new HashMap<>(10);
    197 
    198     static {
    199         RTL_ATTRS.put("?android:attr/paddingLeft", "paddingStart");
    200         RTL_ATTRS.put("?android:attr/paddingRight", "paddingEnd");
    201         RTL_ATTRS.put("?android:attr/layout_marginLeft", "layout_marginStart");
    202         RTL_ATTRS.put("?android:attr/layout_marginRight", "layout_marginEnd");
    203         RTL_ATTRS.put("?android:attr/layout_toLeftOf", "layout_toStartOf");
    204         RTL_ATTRS.put("?android:attr/layout_toRightOf", "layout_toEndOf");
    205         RTL_ATTRS.put("?android:attr/layout_alignParentLeft", "layout_alignParentStart");
    206         RTL_ATTRS.put("?android:attr/layout_alignParentRight", "layout_alignParentEnd");
    207         RTL_ATTRS.put("?android:attr/drawableLeft", "drawableStart");
    208         RTL_ATTRS.put("?android:attr/drawableRight", "drawableEnd");
    209     }
    210 
    211     /**
    212      * @param projectKey An Object identifying the project. This is used for the cache mechanism.
    213      * @param metrics the {@link DisplayMetrics}.
    214      * @param renderResources the configured resources (both framework and projects) for this
    215      * render.
    216      * @param config the Configuration object for this render.
    217      * @param targetSdkVersion the targetSdkVersion of the application.
    218      */
    219     public BridgeContext(Object projectKey, @NonNull DisplayMetrics metrics,
    220             @NonNull RenderResources renderResources,
    221             @NonNull AssetRepository assets,
    222             @NonNull LayoutlibCallback layoutlibCallback,
    223             @NonNull Configuration config,
    224             int targetSdkVersion,
    225             boolean hasRtlSupport) {
    226         mProjectKey = projectKey;
    227         mMetrics = metrics;
    228         mLayoutlibCallback = layoutlibCallback;
    229 
    230         mRenderResources = renderResources;
    231         mConfig = config;
    232         AssetManager systemAssetManager = AssetManager.getSystem();
    233         if (systemAssetManager instanceof BridgeAssetManager) {
    234             mAssets = (BridgeAssetManager) systemAssetManager;
    235         } else {
    236             throw new AssertionError("Creating BridgeContext without initializing Bridge");
    237         }
    238         mAssets.setAssetRepository(assets);
    239 
    240         mApplicationInfo = new ApplicationInfo();
    241         mApplicationInfo.targetSdkVersion = targetSdkVersion;
    242         if (hasRtlSupport) {
    243             mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL;
    244         }
    245 
    246         mWindowManager = new WindowManagerImpl(mMetrics);
    247         mDisplayManager = new DisplayManager(this);
    248     }
    249 
    250     /**
    251      * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its
    252      * {@link DisplayMetrics}, {@link Configuration}, and {@link LayoutlibCallback}.
    253      *
    254      * @see #disposeResources()
    255      */
    256     public void initResources() {
    257         AssetManager assetManager = AssetManager.getSystem();
    258 
    259         mSystemResources = Resources_Delegate.initSystem(
    260                 this,
    261                 assetManager,
    262                 mMetrics,
    263                 mConfig,
    264                 mLayoutlibCallback);
    265         mTheme = mSystemResources.newTheme();
    266     }
    267 
    268     /**
    269      * Disposes the {@link Resources} singleton.
    270      */
    271     public void disposeResources() {
    272         Resources_Delegate.disposeSystem();
    273     }
    274 
    275     public void setBridgeInflater(BridgeInflater inflater) {
    276         mBridgeInflater = inflater;
    277     }
    278 
    279     public void addViewKey(View view, Object viewKey) {
    280         mViewKeyMap.put(view, viewKey);
    281     }
    282 
    283     public Object getViewKey(View view) {
    284         return mViewKeyMap.get(view);
    285     }
    286 
    287     public void addCookie(Object o, Object cookie) {
    288         mViewKeyHelpMap.put(o, cookie);
    289     }
    290 
    291     public Object getCookie(Object o) {
    292         return mViewKeyHelpMap.get(o);
    293     }
    294 
    295     public Object getProjectKey() {
    296         return mProjectKey;
    297     }
    298 
    299     public DisplayMetrics getMetrics() {
    300         return mMetrics;
    301     }
    302 
    303     public LayoutlibCallback getLayoutlibCallback() {
    304         return mLayoutlibCallback;
    305     }
    306 
    307     public RenderResources getRenderResources() {
    308         return mRenderResources;
    309     }
    310 
    311     public Map<Object, PropertiesMap> getDefaultProperties() {
    312         return mDefaultPropMaps;
    313     }
    314 
    315     public Configuration getConfiguration() {
    316         return mConfig;
    317     }
    318 
    319     /**
    320      * Adds a parser to the stack.
    321      * @param parser the parser to add.
    322      */
    323     public void pushParser(BridgeXmlBlockParser parser) {
    324         if (ParserFactory.LOG_PARSER) {
    325             System.out.println("PUSH " + parser.getParser().toString());
    326         }
    327         mParserStack.push(parser);
    328     }
    329 
    330     /**
    331      * Removes the parser at the top of the stack
    332      */
    333     public void popParser() {
    334         BridgeXmlBlockParser parser = mParserStack.pop();
    335         if (ParserFactory.LOG_PARSER) {
    336             System.out.println("POPD " + parser.getParser().toString());
    337         }
    338     }
    339 
    340     /**
    341      * Returns the current parser at the top the of the stack.
    342      * @return a parser or null.
    343      */
    344     private BridgeXmlBlockParser getCurrentParser() {
    345         return mParserStack.peek();
    346     }
    347 
    348     /**
    349      * Returns the previous parser.
    350      * @return a parser or null if there isn't any previous parser
    351      */
    352     public BridgeXmlBlockParser getPreviousParser() {
    353         if (mParserStack.size() < 2) {
    354             return null;
    355         }
    356         return mParserStack.get(mParserStack.size() - 2);
    357     }
    358 
    359     public boolean resolveThemeAttribute(int resId, TypedValue outValue, boolean resolveRefs) {
    360         Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resId);
    361         boolean isFrameworkRes = true;
    362         if (resourceInfo == null) {
    363             resourceInfo = mLayoutlibCallback.resolveResourceId(resId);
    364             isFrameworkRes = false;
    365         }
    366 
    367         if (resourceInfo == null) {
    368             return false;
    369         }
    370 
    371         ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond(),
    372                 isFrameworkRes);
    373         if (resolveRefs) {
    374             value = mRenderResources.resolveResValue(value);
    375         }
    376 
    377         if (value == null) {
    378             // unable to find the attribute.
    379             return false;
    380         }
    381 
    382         // check if this is a style resource
    383         if (value instanceof StyleResourceValue) {
    384             // get the id that will represent this style.
    385             outValue.resourceId = getDynamicIdByStyle((StyleResourceValue) value);
    386             return true;
    387         }
    388 
    389         String stringValue = value.getValue();
    390         if (!stringValue.isEmpty()) {
    391             if (stringValue.charAt(0) == '#') {
    392                 outValue.type = TypedValue.TYPE_INT_COLOR_ARGB8;
    393                 outValue.data = Color.parseColor(value.getValue());
    394             }
    395             else if (stringValue.charAt(0) == '@') {
    396                 outValue.type = TypedValue.TYPE_REFERENCE;
    397             }
    398 
    399         }
    400 
    401         int a;
    402         // if this is a framework value.
    403         if (value.isFramework()) {
    404             // look for idName in the android R classes.
    405             // use 0 a default res value as it's not a valid id value.
    406             a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
    407         } else {
    408             // look for idName in the project R class.
    409             // use 0 a default res value as it's not a valid id value.
    410             a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
    411         }
    412 
    413         if (a != 0) {
    414             outValue.resourceId = a;
    415             return true;
    416         }
    417 
    418         // If the value is not a valid reference, fallback to pass the value as a string.
    419         outValue.string = stringValue;
    420         return true;
    421     }
    422 
    423 
    424     public ResourceReference resolveId(int id) {
    425         // first get the String related to this id in the framework
    426         Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
    427 
    428         if (resourceInfo != null) {
    429             return new ResourceReference(resourceInfo.getSecond(), true);
    430         }
    431 
    432         // didn't find a match in the framework? look in the project.
    433         if (mLayoutlibCallback != null) {
    434             resourceInfo = mLayoutlibCallback.resolveResourceId(id);
    435 
    436             if (resourceInfo != null) {
    437                 return new ResourceReference(resourceInfo.getSecond(), false);
    438             }
    439         }
    440 
    441         // The base value for R.style is 0x01030000 and the custom style is 0x02030000.
    442         // So, if the second byte is 03, it's probably a style.
    443         if ((id >> 16 & 0xFF) == 0x03) {
    444             return getStyleByDynamicId(id);
    445         }
    446         return null;
    447     }
    448 
    449     public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent,
    450             @SuppressWarnings("SameParameterValue") boolean attachToRoot,
    451             boolean skipCallbackParser) {
    452         boolean isPlatformLayout = resource.isFramework();
    453 
    454         if (!isPlatformLayout && !skipCallbackParser) {
    455             // check if the project callback can provide us with a custom parser.
    456             ILayoutPullParser parser = getParser(resource);
    457 
    458             if (parser != null) {
    459                 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
    460                         this, resource.isFramework());
    461                 try {
    462                     pushParser(blockParser);
    463                     return Pair.of(
    464                             mBridgeInflater.inflate(blockParser, parent, attachToRoot),
    465                             Boolean.TRUE);
    466                 } finally {
    467                     popParser();
    468                 }
    469             }
    470         }
    471 
    472         ResourceValue resValue;
    473         if (resource instanceof ResourceValue) {
    474             resValue = (ResourceValue) resource;
    475         } else {
    476             if (isPlatformLayout) {
    477                 resValue = mRenderResources.getFrameworkResource(ResourceType.LAYOUT,
    478                         resource.getName());
    479             } else {
    480                 resValue = mRenderResources.getProjectResource(ResourceType.LAYOUT,
    481                         resource.getName());
    482             }
    483         }
    484 
    485         if (resValue != null) {
    486 
    487             File xml = new File(resValue.getValue());
    488             if (xml.isFile()) {
    489                 // we need to create a pull parser around the layout XML file, and then
    490                 // give that to our XmlBlockParser
    491                 try {
    492                     XmlPullParser parser = ParserFactory.create(xml, true);
    493 
    494                     // set the resource ref to have correct view cookies
    495                     mBridgeInflater.setResourceReference(resource);
    496 
    497                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
    498                             this, resource.isFramework());
    499                     try {
    500                         pushParser(blockParser);
    501                         return Pair.of(
    502                                 mBridgeInflater.inflate(blockParser, parent, attachToRoot),
    503                                 Boolean.FALSE);
    504                     } finally {
    505                         popParser();
    506                     }
    507                 } catch (XmlPullParserException e) {
    508                     Bridge.getLog().error(LayoutLog.TAG_BROKEN,
    509                             "Failed to configure parser for " + xml, e, null /*data*/);
    510                     // we'll return null below.
    511                 } catch (FileNotFoundException e) {
    512                     // this shouldn't happen since we check above.
    513                 } finally {
    514                     mBridgeInflater.setResourceReference(null);
    515                 }
    516             } else {
    517                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
    518                         String.format("File %s is missing!", xml), null);
    519             }
    520         } else {
    521             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
    522                     String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "",
    523                             resource.getName()), null);
    524         }
    525 
    526         return Pair.of(null, Boolean.FALSE);
    527     }
    528 
    529     /**
    530      * Returns whether the current selected theme is based on AppCompat
    531      */
    532     public boolean isAppCompatTheme() {
    533         // If a cached value exists, return it.
    534         if (mIsThemeAppCompat != null) {
    535             return mIsThemeAppCompat;
    536         }
    537         // Ideally, we should check if the corresponding activity extends
    538         // android.support.v7.app.ActionBarActivity, and not care about the theme name at all.
    539         StyleResourceValue defaultTheme = mRenderResources.getDefaultTheme();
    540         // We can't simply check for parent using resources.themeIsParentOf() since the
    541         // inheritance structure isn't really what one would expect. The first common parent
    542         // between Theme.AppCompat.Light and Theme.AppCompat is Theme.Material (for v21).
    543         boolean isThemeAppCompat = false;
    544         for (int i = 0; i < 50; i++) {
    545             if (defaultTheme == null) {
    546                 break;
    547             }
    548             // for loop ensures that we don't run into cyclic theme inheritance.
    549             if (defaultTheme.getName().startsWith(PREFIX_THEME_APPCOMPAT)) {
    550                 isThemeAppCompat = true;
    551                 break;
    552             }
    553             defaultTheme = mRenderResources.getParent(defaultTheme);
    554         }
    555         mIsThemeAppCompat = isThemeAppCompat;
    556         return isThemeAppCompat;
    557     }
    558 
    559     @SuppressWarnings("deprecation")
    560     private ILayoutPullParser getParser(ResourceReference resource) {
    561         ILayoutPullParser parser;
    562         if (resource instanceof ResourceValue) {
    563             parser = mLayoutlibCallback.getParser((ResourceValue) resource);
    564         } else {
    565             parser = mLayoutlibCallback.getParser(resource.getName());
    566         }
    567         return parser;
    568     }
    569 
    570     // ------------ Context methods
    571 
    572     @Override
    573     public Resources getResources() {
    574         return mSystemResources;
    575     }
    576 
    577     @Override
    578     public Theme getTheme() {
    579         return mTheme;
    580     }
    581 
    582     @Override
    583     public ClassLoader getClassLoader() {
    584         // The documentation for this method states that it should return a class loader one can
    585         // use to retrieve classes in this package. However, when called by LayoutInflater, we do
    586         // not want the class loader to return app's custom views.
    587         // This is so that the IDE can instantiate the custom views and also generate proper error
    588         // messages in case of failure. This also enables the IDE to fallback to MockView in case
    589         // there's an exception thrown when trying to inflate the custom view.
    590         // To work around this issue, LayoutInflater is modified via LayoutLib Create tool to
    591         // replace invocations of this method to a new method: getFrameworkClassLoader(). Also,
    592         // the method is injected into Context. The implementation of getFrameworkClassLoader() is:
    593         // "return getClass().getClassLoader();". This means that when LayoutInflater asks for
    594         // the context ClassLoader, it gets only LayoutLib's ClassLoader which doesn't have
    595         // access to the apps's custom views.
    596         // This method can now return the right ClassLoader, which CustomViews can use to do the
    597         // right thing.
    598         if (mClassLoader == null) {
    599             mClassLoader = new ClassLoader(getClass().getClassLoader()) {
    600                 @Override
    601                 protected Class<?> findClass(String name) throws ClassNotFoundException {
    602                     for (String prefix : BridgeInflater.getClassPrefixList()) {
    603                         if (name.startsWith(prefix)) {
    604                             // These are framework classes and should not be loaded from the app.
    605                             throw new ClassNotFoundException(name + " not found");
    606                         }
    607                     }
    608                     return BridgeContext.this.mLayoutlibCallback.findClass(name);
    609                 }
    610             };
    611         }
    612         return mClassLoader;
    613     }
    614 
    615     @Override
    616     public Object getSystemService(String service) {
    617         switch (service) {
    618             case LAYOUT_INFLATER_SERVICE:
    619                 return mBridgeInflater;
    620 
    621             case TEXT_SERVICES_MANAGER_SERVICE:
    622                 // we need to return a valid service to avoid NPE
    623                 return TextServicesManager.getInstance();
    624 
    625             case WINDOW_SERVICE:
    626                 return mWindowManager;
    627 
    628             case POWER_SERVICE:
    629                 return new PowerManager(this, new BridgePowerManager(), new Handler());
    630 
    631             case DISPLAY_SERVICE:
    632                 return mDisplayManager;
    633 
    634             case ACCESSIBILITY_SERVICE:
    635                 return AccessibilityManager.getInstance(this);
    636 
    637             case INPUT_METHOD_SERVICE:  // needed by SearchView
    638             case AUTOFILL_MANAGER_SERVICE:
    639             case AUDIO_SERVICE:
    640             case TEXT_CLASSIFICATION_SERVICE:
    641                 return null;
    642             default:
    643                 assert false : "Unsupported Service: " + service;
    644         }
    645 
    646         return null;
    647     }
    648 
    649     @Override
    650     public String getSystemServiceName(Class<?> serviceClass) {
    651         return SystemServiceRegistry_Accessor.getSystemServiceName(serviceClass);
    652     }
    653 
    654 
    655     /**
    656      * Same as Context#obtainStyledAttributes. We do not override the base method to give the
    657      * original Context the chance to override the theme when needed.
    658      */
    659     @Nullable
    660     public final BridgeTypedArray internalObtainStyledAttributes(int resId, int[] attrs)
    661             throws Resources.NotFoundException {
    662         StyleResourceValue style = null;
    663         // get the StyleResourceValue based on the resId;
    664         if (resId != 0) {
    665             style = getStyleByDynamicId(resId);
    666 
    667             if (style == null) {
    668                 // In some cases, style may not be a dynamic id, so we do a full search.
    669                 ResourceReference ref = resolveId(resId);
    670                 if (ref != null) {
    671                     style = mRenderResources.getStyle(ref.getName(), ref.isFramework());
    672                 }
    673             }
    674 
    675             if (style == null) {
    676                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
    677                         "Failed to find style with " + resId, null);
    678                 return null;
    679             }
    680         }
    681 
    682         if (mTypedArrayCache == null) {
    683             mTypedArrayCache = new TypedArrayCache();
    684         }
    685 
    686         List<StyleResourceValue> currentThemes = mRenderResources.getAllThemes();
    687 
    688         Pair<BridgeTypedArray, PropertiesMap> typeArrayAndPropertiesPair =
    689                 mTypedArrayCache.get(attrs, currentThemes, resId);
    690 
    691         if (typeArrayAndPropertiesPair == null) {
    692             typeArrayAndPropertiesPair = createStyleBasedTypedArray(style, attrs);
    693             mTypedArrayCache.put(attrs, currentThemes, resId, typeArrayAndPropertiesPair);
    694         }
    695         // Add value to defaultPropsMap if needed
    696         if (typeArrayAndPropertiesPair.getSecond() != null) {
    697             BridgeXmlBlockParser parser = getCurrentParser();
    698             Object key = parser != null ? parser.getViewCookie() : null;
    699             if (key != null) {
    700                 PropertiesMap defaultPropMap = mDefaultPropMaps.get(key);
    701                 if (defaultPropMap == null) {
    702                     defaultPropMap = typeArrayAndPropertiesPair.getSecond();
    703                     mDefaultPropMaps.put(key, defaultPropMap);
    704                 } else {
    705                     defaultPropMap.putAll(typeArrayAndPropertiesPair.getSecond());
    706                 }
    707             }
    708         }
    709         return typeArrayAndPropertiesPair.getFirst();
    710     }
    711 
    712     /**
    713      * Same as Context#obtainStyledAttributes. We do not override the base method to give the
    714      * original Context the chance to override the theme when needed.
    715      */
    716     @Nullable
    717     public BridgeTypedArray internalObtainStyledAttributes(@Nullable AttributeSet set, int[] attrs,
    718             int defStyleAttr, int defStyleRes) {
    719 
    720         PropertiesMap defaultPropMap = null;
    721         boolean isPlatformFile = true;
    722 
    723         // TODO(namespaces): We need to figure out how to keep track of the namespace of the current
    724         // layout file.
    725         ResourceNamespace currentFileNamespace = ResourceNamespace.TODO;
    726 
    727         // TODO(namespaces): get this through the callback, only in non-namespaced projects.
    728         ResourceNamespace.Resolver resolver = LEGACY_NAMESPACE_RESOLVER;
    729 
    730         // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
    731         if (set instanceof BridgeXmlBlockParser) {
    732             BridgeXmlBlockParser parser;
    733             parser = (BridgeXmlBlockParser)set;
    734 
    735             isPlatformFile = parser.isPlatformFile();
    736 
    737             Object key = parser.getViewCookie();
    738             if (key != null) {
    739                 defaultPropMap = mDefaultPropMaps.computeIfAbsent(key, k -> new PropertiesMap());
    740             }
    741 
    742             resolver = parser::getNamespace;
    743             currentFileNamespace = ResourceNamespace.fromBoolean(parser.isPlatformFile());
    744         } else if (set instanceof BridgeLayoutParamsMapAttributes) {
    745             // this is only for temp layout params generated dynamically, so this is never
    746             // platform content.
    747             isPlatformFile = false;
    748         } else if (set != null) { // null parser is ok
    749             // really this should not be happening since its instantiated in Bridge
    750             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
    751                     "Parser is not a BridgeXmlBlockParser!", null);
    752             return null;
    753         }
    754 
    755         List<AttributeHolder> attributeList = searchAttrs(attrs);
    756 
    757         BridgeTypedArray ta =
    758                 Resources_Delegate.newTypeArray(mSystemResources, attrs.length, isPlatformFile);
    759 
    760         // look for a custom style.
    761         String customStyle = null;
    762         if (set != null) {
    763             customStyle = set.getAttributeValue(null, "style");
    764         }
    765 
    766         StyleResourceValue customStyleValues = null;
    767         if (customStyle != null) {
    768             ResourceValue item = mRenderResources.findResValue(customStyle,
    769                     isPlatformFile /*forceFrameworkOnly*/);
    770 
    771             // resolve it in case it links to something else
    772             item = mRenderResources.resolveResValue(item);
    773 
    774             if (item instanceof StyleResourceValue) {
    775                 customStyleValues = (StyleResourceValue)item;
    776             }
    777         }
    778 
    779         // resolve the defStyleAttr value into a IStyleResourceValue
    780         StyleResourceValue defStyleValues = null;
    781 
    782         if (defStyleAttr != 0) {
    783             // get the name from the int.
    784             Pair<String, Boolean> defStyleAttribute = searchAttr(defStyleAttr);
    785 
    786             if (defStyleAttribute == null) {
    787                 // This should be rare. Happens trying to map R.style.foo to @style/foo fails.
    788                 // This will happen if the user explicitly used a non existing int value for
    789                 // defStyleAttr or there's something wrong with the project structure/build.
    790                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
    791                         "Failed to find the style corresponding to the id " + defStyleAttr, null);
    792             } else {
    793                 String defStyleName = defStyleAttribute.getFirst();
    794 
    795                 // look for the style in the current theme, and its parent:
    796                 ResourceValue item = mRenderResources.findItemInTheme(defStyleName,
    797                         defStyleAttribute.getSecond());
    798 
    799                 if (item != null) {
    800                     // item is a reference to a style entry. Search for it.
    801                     item = mRenderResources.findResValue(item.getValue(), item.isFramework());
    802                     item = mRenderResources.resolveResValue(item);
    803                     if (item instanceof StyleResourceValue) {
    804                         defStyleValues = (StyleResourceValue) item;
    805                     }
    806                     if (defaultPropMap != null) {
    807                         if (defStyleAttribute.getSecond()) {
    808                             defStyleName = "android:" + defStyleName;
    809                         }
    810                         defaultPropMap.put("style", new Property(defStyleName, item.getValue()));
    811                     }
    812                 }
    813             }
    814         }
    815 
    816         if (defStyleValues == null && defStyleRes != 0) {
    817             StyleResourceValue item = getStyleByDynamicId(defStyleRes);
    818             if (item != null) {
    819                 defStyleValues = item;
    820             } else {
    821                 boolean isFrameworkRes = true;
    822                 Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
    823                 if (value == null) {
    824                     value = mLayoutlibCallback.resolveResourceId(defStyleRes);
    825                     isFrameworkRes = false;
    826                 }
    827 
    828                 if (value != null) {
    829                     if ((value.getFirst() == ResourceType.STYLE)) {
    830                         // look for the style in all resources:
    831                         item = mRenderResources.getStyle(value.getSecond(), isFrameworkRes);
    832                         if (item != null) {
    833                             if (defaultPropMap != null) {
    834                                 String name = item.getName();
    835                                 defaultPropMap.put("style", new Property(name, name));
    836                             }
    837 
    838                             defStyleValues = item;
    839                         } else {
    840                             Bridge.getLog().error(null,
    841                                     String.format(
    842                                             "Style with id 0x%x (resolved to '%s') does not exist.",
    843                                             defStyleRes, value.getSecond()),
    844                                     null);
    845                         }
    846                     } else {
    847                         Bridge.getLog().error(null,
    848                                 String.format(
    849                                         "Resource id 0x%x is not of type STYLE (instead %s)",
    850                                         defStyleRes, value.getFirst().toString()),
    851                                 null);
    852                     }
    853                 } else {
    854                     Bridge.getLog().error(null,
    855                             String.format(
    856                                     "Failed to find style with id 0x%x in current theme",
    857                                     defStyleRes),
    858                             null);
    859                 }
    860             }
    861         }
    862 
    863         String appNamespace = mLayoutlibCallback.getNamespace();
    864 
    865         if (attributeList != null) {
    866             for (int index = 0 ; index < attributeList.size() ; index++) {
    867                 AttributeHolder attributeHolder = attributeList.get(index);
    868 
    869                 if (attributeHolder == null) {
    870                     continue;
    871                 }
    872 
    873                 String attrName = attributeHolder.name;
    874                 boolean frameworkAttr = attributeHolder.isFramework;
    875                 String value = null;
    876                 if (set != null) {
    877                     value = set.getAttributeValue(
    878                             frameworkAttr ? BridgeConstants.NS_RESOURCES : appNamespace,
    879                                     attrName);
    880 
    881                     // if this is an app attribute, and the first get fails, try with the
    882                     // new res-auto namespace as well
    883                     if (!frameworkAttr && value == null) {
    884                         value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName);
    885                     }
    886                 }
    887 
    888                 // Calculate the default value from the Theme in two cases:
    889                 //   - If defaultPropMap is not null, get the default value to add it to the list
    890                 //   of default values of properties.
    891                 //   - If value is null, it means that the attribute is not directly set as an
    892                 //   attribute in the XML so try to get the default value.
    893                 ResourceValue defaultValue = null;
    894                 if (defaultPropMap != null || value == null) {
    895                     // look for the value in the custom style first (and its parent if needed)
    896                     if (customStyleValues != null) {
    897                         defaultValue = mRenderResources.findItemInStyle(customStyleValues, attrName,
    898                                 frameworkAttr);
    899                     }
    900 
    901                     // then look for the value in the default Style (and its parent if needed)
    902                     if (defaultValue == null && defStyleValues != null) {
    903                         defaultValue = mRenderResources.findItemInStyle(defStyleValues, attrName,
    904                                 frameworkAttr);
    905                     }
    906 
    907                     // if the item is not present in the defStyle, we look in the main theme (and
    908                     // its parent themes)
    909                     if (defaultValue == null) {
    910                         defaultValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
    911                     }
    912 
    913                     // if we found a value, we make sure this doesn't reference another value.
    914                     // So we resolve it.
    915                     if (defaultValue != null) {
    916                         String preResolve = defaultValue.getValue();
    917                         defaultValue = mRenderResources.resolveResValue(defaultValue);
    918 
    919                         if (defaultPropMap != null) {
    920                             defaultPropMap.put(
    921                                     frameworkAttr ? SdkConstants.PREFIX_ANDROID + attrName :
    922                                             attrName, new Property(preResolve, defaultValue.getValue()));
    923                         }
    924                     }
    925                 }
    926                 // Done calculating the defaultValue
    927 
    928                 // if there's no direct value for this attribute in the XML, we look for default
    929                 // values in the widget defStyle, and then in the theme.
    930                 if (value == null) {
    931                     if (frameworkAttr) {
    932                         // For some framework values, layoutlib patches the actual value in the
    933                         // theme when it helps to improve the final preview. In most cases
    934                         // we just disable animations.
    935                         ResourceValue patchedValue = FRAMEWORK_PATCHED_VALUES.get(attrName);
    936                         if (patchedValue != null) {
    937                             defaultValue = patchedValue;
    938                         }
    939                     }
    940 
    941                     // if we found a value, we make sure this doesn't reference another value.
    942                     // So we resolve it.
    943                     if (defaultValue != null) {
    944                         // If the value is a reference to another theme attribute that doesn't
    945                         // exist, we should log a warning and omit it.
    946                         String val = defaultValue.getValue();
    947                         if (val != null && val.startsWith(SdkConstants.PREFIX_THEME_REF)) {
    948                             // Because we always use the latest framework code, some resources might
    949                             // fail to resolve when using old themes (they haven't been backported).
    950                             // Since this is an artifact caused by us using always the latest
    951                             // code, we check for some of those values and replace them here.
    952                             defaultValue = FRAMEWORK_REPLACE_VALUES.get(attrName);
    953 
    954                             if (defaultValue == null &&
    955                                     (getApplicationInfo().targetSdkVersion < JELLY_BEAN_MR1 ||
    956                                     !attrName.equals(RTL_ATTRS.get(val)))) {
    957                                 // Only log a warning if the referenced value isn't one of the RTL
    958                                 // attributes, or the app targets old API.
    959                                 Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
    960                                         String.format("Failed to find '%s' in current theme.", val),
    961                                         val);
    962                             }
    963                         }
    964                     }
    965 
    966                     ta.bridgeSetValue(index, attrName, frameworkAttr, attributeHolder.resourceId,
    967                             defaultValue);
    968                 } else {
    969                     // There is a value in the XML, but we need to resolve it in case it's
    970                     // referencing another resource or a theme value.
    971                     ResourceValue dummy =
    972                             new ResourceValue(
    973                                     currentFileNamespace,
    974                                     null,
    975                                     attrName,
    976                                     value);
    977                     dummy.setNamespaceLookup(resolver);
    978 
    979                     ta.bridgeSetValue(
    980                             index, attrName, frameworkAttr, attributeHolder.resourceId,
    981                             mRenderResources.resolveResValue(dummy));
    982                 }
    983             }
    984         }
    985 
    986         ta.sealArray();
    987 
    988         return ta;
    989     }
    990 
    991     @Override
    992     public Looper getMainLooper() {
    993         return Looper.myLooper();
    994     }
    995 
    996 
    997     @Override
    998     public String getPackageName() {
    999         if (mApplicationInfo.packageName == null) {
   1000             mApplicationInfo.packageName = mLayoutlibCallback.getFlag(FLAG_KEY_APPLICATION_PACKAGE);
   1001         }
   1002         return mApplicationInfo.packageName;
   1003     }
   1004 
   1005     @Override
   1006     public PackageManager getPackageManager() {
   1007         if (mPackageManager == null) {
   1008             mPackageManager = new BridgePackageManager();
   1009         }
   1010         return mPackageManager;
   1011     }
   1012 
   1013     // ------------- private new methods
   1014 
   1015     /**
   1016      * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
   1017      * values found in the given style. If no style is specified, the default theme, along with the
   1018      * styles applied to it are used.
   1019      *
   1020      * @see #obtainStyledAttributes(int, int[])
   1021      */
   1022     private Pair<BridgeTypedArray, PropertiesMap> createStyleBasedTypedArray(
   1023             @Nullable StyleResourceValue style, int[] attrs) throws Resources.NotFoundException {
   1024         List<AttributeHolder> attributes = searchAttrs(attrs);
   1025 
   1026         BridgeTypedArray ta =
   1027                 Resources_Delegate.newTypeArray(mSystemResources, attrs.length, false);
   1028 
   1029         PropertiesMap defaultPropMap = new PropertiesMap();
   1030         // for each attribute, get its name so that we can search it in the style
   1031         for (int i = 0; i < attrs.length; i++) {
   1032             AttributeHolder attrHolder = attributes.get(i);
   1033 
   1034             if (attrHolder != null) {
   1035                 // look for the value in the given style
   1036                 ResourceValue resValue;
   1037                 String attrName = attrHolder.name;
   1038                 boolean frameworkAttr = attrHolder.isFramework;
   1039                 if (style != null) {
   1040                     resValue = mRenderResources.findItemInStyle(style, attrName, frameworkAttr);
   1041                 } else {
   1042                     resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
   1043                 }
   1044 
   1045                 if (resValue != null) {
   1046                     // Add it to defaultPropMap before resolving
   1047                     String preResolve = resValue.getValue();
   1048                     // resolve it to make sure there are no references left.
   1049                     resValue = mRenderResources.resolveResValue(resValue);
   1050                     ta.bridgeSetValue(i, attrName, frameworkAttr, attrHolder.resourceId,
   1051                             resValue);
   1052                     defaultPropMap.put(
   1053                             frameworkAttr ? SdkConstants.ANDROID_PREFIX + attrName : attrName,
   1054                             new Property(preResolve, resValue.getValue()));
   1055                 }
   1056             }
   1057         }
   1058 
   1059         ta.sealArray();
   1060 
   1061         return Pair.of(ta, defaultPropMap);
   1062     }
   1063 
   1064     /**
   1065      * The input int[] attributeIds is a list of attributes. The returns a list of information about
   1066      * each attributes. The information is (name, isFramework)
   1067      * <p/>
   1068      *
   1069      * @param attributeIds An attribute array reference given to obtainStyledAttributes.
   1070      * @return List of attribute information.
   1071      */
   1072     private List<AttributeHolder> searchAttrs(int[] attributeIds) {
   1073         List<AttributeHolder> results = new ArrayList<>(attributeIds.length);
   1074 
   1075         // for each attribute, get its name so that we can search it in the style
   1076         for (int id : attributeIds) {
   1077             Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(id);
   1078             boolean isFramework = false;
   1079             if (resolvedResource != null) {
   1080                 isFramework = true;
   1081             } else {
   1082                 resolvedResource = mLayoutlibCallback.resolveResourceId(id);
   1083             }
   1084 
   1085             if (resolvedResource != null) {
   1086                 results.add(new AttributeHolder(id, resolvedResource.getSecond(), isFramework));
   1087             } else {
   1088                 results.add(null);
   1089             }
   1090         }
   1091 
   1092         return results;
   1093     }
   1094 
   1095     /**
   1096      * Searches for the attribute referenced by its internal id.
   1097      *
   1098      * @param attr An attribute reference given to obtainStyledAttributes such as defStyle.
   1099      * @return A (name, isFramework) pair describing the attribute if found. Returns null
   1100      *         if nothing is found.
   1101      */
   1102     private Pair<String, Boolean> searchAttr(int attr) {
   1103         Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
   1104         if (info != null) {
   1105             return Pair.of(info.getSecond(), Boolean.TRUE);
   1106         }
   1107 
   1108         info = mLayoutlibCallback.resolveResourceId(attr);
   1109         if (info != null) {
   1110             return Pair.of(info.getSecond(), Boolean.FALSE);
   1111         }
   1112 
   1113         return null;
   1114     }
   1115 
   1116     public int getDynamicIdByStyle(StyleResourceValue resValue) {
   1117         if (mDynamicIdToStyleMap == null) {
   1118             // create the maps.
   1119             mDynamicIdToStyleMap = new HashMap<>();
   1120             mStyleToDynamicIdMap = new HashMap<>();
   1121         }
   1122 
   1123         // look for an existing id
   1124         Integer id = mStyleToDynamicIdMap.get(resValue);
   1125 
   1126         if (id == null) {
   1127             // generate a new id
   1128             id = ++mDynamicIdGenerator;
   1129 
   1130             // and add it to the maps.
   1131             mDynamicIdToStyleMap.put(id, resValue);
   1132             mStyleToDynamicIdMap.put(resValue, id);
   1133         }
   1134 
   1135         return id;
   1136     }
   1137 
   1138     private StyleResourceValue getStyleByDynamicId(int i) {
   1139         if (mDynamicIdToStyleMap != null) {
   1140             return mDynamicIdToStyleMap.get(i);
   1141         }
   1142 
   1143         return null;
   1144     }
   1145 
   1146     public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
   1147         if (getRenderResources().getFrameworkResource(resType, resName) != null) {
   1148             // Bridge.getResourceId creates a new resource id if an existing one isn't found. So,
   1149             // we check for the existence of the resource before calling it.
   1150             return Bridge.getResourceId(resType, resName);
   1151         }
   1152 
   1153         return defValue;
   1154     }
   1155 
   1156     public int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
   1157         // getResourceId creates a new resource id if an existing resource id isn't found. So, we
   1158         // check for the existence of the resource before calling it.
   1159         if (getRenderResources().getProjectResource(resType, resName) != null) {
   1160             if (mLayoutlibCallback != null) {
   1161                 Integer value = mLayoutlibCallback.getResourceId(resType, resName);
   1162                 if (value != null) {
   1163                     return value;
   1164                 }
   1165             }
   1166         }
   1167 
   1168         return defValue;
   1169     }
   1170 
   1171     public static Context getBaseContext(Context context) {
   1172         while (context instanceof ContextWrapper) {
   1173             context = ((ContextWrapper) context).getBaseContext();
   1174         }
   1175         return context;
   1176     }
   1177 
   1178     public IBinder getBinder() {
   1179         if (mBinder == null) {
   1180             // create a dummy binder. We only need it be not null.
   1181             mBinder = new IBinder() {
   1182                 @Override
   1183                 public String getInterfaceDescriptor() throws RemoteException {
   1184                     return null;
   1185                 }
   1186 
   1187                 @Override
   1188                 public boolean pingBinder() {
   1189                     return false;
   1190                 }
   1191 
   1192                 @Override
   1193                 public boolean isBinderAlive() {
   1194                     return false;
   1195                 }
   1196 
   1197                 @Override
   1198                 public IInterface queryLocalInterface(String descriptor) {
   1199                     return null;
   1200                 }
   1201 
   1202                 @Override
   1203                 public void dump(FileDescriptor fd, String[] args) throws RemoteException {
   1204 
   1205                 }
   1206 
   1207                 @Override
   1208                 public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
   1209 
   1210                 }
   1211 
   1212                 @Override
   1213                 public boolean transact(int code, Parcel data, Parcel reply, int flags)
   1214                         throws RemoteException {
   1215                     return false;
   1216                 }
   1217 
   1218                 @Override
   1219                 public void linkToDeath(DeathRecipient recipient, int flags)
   1220                         throws RemoteException {
   1221 
   1222                 }
   1223 
   1224                 @Override
   1225                 public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
   1226                     return false;
   1227                 }
   1228 
   1229                 @Override
   1230                 public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
   1231                   String[] args, ShellCallback shellCallback, ResultReceiver resultReceiver) {
   1232                 }
   1233             };
   1234         }
   1235         return mBinder;
   1236     }
   1237 
   1238     //------------ NOT OVERRIDEN --------------------
   1239 
   1240     @Override
   1241     public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) {
   1242         // pass
   1243         return false;
   1244     }
   1245 
   1246     @Override
   1247     public int checkCallingOrSelfPermission(String arg0) {
   1248         // pass
   1249         return 0;
   1250     }
   1251 
   1252     @Override
   1253     public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) {
   1254         // pass
   1255         return 0;
   1256     }
   1257 
   1258     @Override
   1259     public int checkCallingPermission(String arg0) {
   1260         // pass
   1261         return 0;
   1262     }
   1263 
   1264     @Override
   1265     public int checkCallingUriPermission(Uri arg0, int arg1) {
   1266         // pass
   1267         return 0;
   1268     }
   1269 
   1270     @Override
   1271     public int checkPermission(String arg0, int arg1, int arg2) {
   1272         // pass
   1273         return 0;
   1274     }
   1275 
   1276     @Override
   1277     public int checkSelfPermission(String arg0) {
   1278         // pass
   1279         return 0;
   1280     }
   1281 
   1282     @Override
   1283     public int checkPermission(String arg0, int arg1, int arg2, IBinder arg3) {
   1284         // pass
   1285         return 0;
   1286     }
   1287 
   1288     @Override
   1289     public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
   1290         // pass
   1291         return 0;
   1292     }
   1293 
   1294     @Override
   1295     public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3, IBinder arg4) {
   1296         // pass
   1297         return 0;
   1298     }
   1299 
   1300     @Override
   1301     public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
   1302             int arg4, int arg5) {
   1303         // pass
   1304         return 0;
   1305     }
   1306 
   1307     @Override
   1308     public void clearWallpaper() {
   1309         // pass
   1310 
   1311     }
   1312 
   1313     @Override
   1314     public Context createPackageContext(String arg0, int arg1) {
   1315         // pass
   1316         return null;
   1317     }
   1318 
   1319     @Override
   1320     public Context createPackageContextAsUser(String arg0, int arg1, UserHandle user) {
   1321         // pass
   1322         return null;
   1323     }
   1324 
   1325     @Override
   1326     public Context createConfigurationContext(Configuration overrideConfiguration) {
   1327         // pass
   1328         return null;
   1329     }
   1330 
   1331     @Override
   1332     public Context createDisplayContext(Display display) {
   1333         // pass
   1334         return null;
   1335     }
   1336 
   1337     @Override
   1338     public Context createContextForSplit(String splitName) {
   1339         // pass
   1340         return null;
   1341     }
   1342 
   1343     @Override
   1344     public String[] databaseList() {
   1345         // pass
   1346         return null;
   1347     }
   1348 
   1349     @Override
   1350     public Context createApplicationContext(ApplicationInfo application, int flags)
   1351             throws PackageManager.NameNotFoundException {
   1352         return null;
   1353     }
   1354 
   1355     @Override
   1356     public boolean moveDatabaseFrom(Context sourceContext, String name) {
   1357         // pass
   1358         return false;
   1359     }
   1360 
   1361     @Override
   1362     public boolean deleteDatabase(String arg0) {
   1363         // pass
   1364         return false;
   1365     }
   1366 
   1367     @Override
   1368     public boolean deleteFile(String arg0) {
   1369         // pass
   1370         return false;
   1371     }
   1372 
   1373     @Override
   1374     public void enforceCallingOrSelfPermission(String arg0, String arg1) {
   1375         // pass
   1376 
   1377     }
   1378 
   1379     @Override
   1380     public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1,
   1381             String arg2) {
   1382         // pass
   1383 
   1384     }
   1385 
   1386     @Override
   1387     public void enforceCallingPermission(String arg0, String arg1) {
   1388         // pass
   1389 
   1390     }
   1391 
   1392     @Override
   1393     public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) {
   1394         // pass
   1395 
   1396     }
   1397 
   1398     @Override
   1399     public void enforcePermission(String arg0, int arg1, int arg2, String arg3) {
   1400         // pass
   1401 
   1402     }
   1403 
   1404     @Override
   1405     public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3,
   1406             String arg4) {
   1407         // pass
   1408 
   1409     }
   1410 
   1411     @Override
   1412     public void enforceUriPermission(Uri arg0, String arg1, String arg2,
   1413             int arg3, int arg4, int arg5, String arg6) {
   1414         // pass
   1415 
   1416     }
   1417 
   1418     @Override
   1419     public String[] fileList() {
   1420         // pass
   1421         return null;
   1422     }
   1423 
   1424     @Override
   1425     public BridgeAssetManager getAssets() {
   1426         return mAssets;
   1427     }
   1428 
   1429     @Override
   1430     public File getCacheDir() {
   1431         // pass
   1432         return null;
   1433     }
   1434 
   1435     @Override
   1436     public File getCodeCacheDir() {
   1437         // pass
   1438         return null;
   1439     }
   1440 
   1441     @Override
   1442     public File getExternalCacheDir() {
   1443         // pass
   1444         return null;
   1445     }
   1446 
   1447     @Override
   1448     public File getPreloadsFileCache() {
   1449         // pass
   1450         return null;
   1451     }
   1452 
   1453     @Override
   1454     public ContentResolver getContentResolver() {
   1455         if (mContentResolver == null) {
   1456             mContentResolver = new BridgeContentResolver(this);
   1457         }
   1458         return mContentResolver;
   1459     }
   1460 
   1461     @Override
   1462     public File getDatabasePath(String arg0) {
   1463         // pass
   1464         return null;
   1465     }
   1466 
   1467     @Override
   1468     public File getDir(String arg0, int arg1) {
   1469         // pass
   1470         return null;
   1471     }
   1472 
   1473     @Override
   1474     public File getFileStreamPath(String arg0) {
   1475         // pass
   1476         return null;
   1477     }
   1478 
   1479     @Override
   1480     public File getSharedPreferencesPath(String name) {
   1481         // pass
   1482         return null;
   1483     }
   1484 
   1485     @Override
   1486     public File getDataDir() {
   1487         // pass
   1488         return null;
   1489     }
   1490 
   1491     @Override
   1492     public File getFilesDir() {
   1493         // pass
   1494         return null;
   1495     }
   1496 
   1497     @Override
   1498     public File getNoBackupFilesDir() {
   1499         // pass
   1500         return null;
   1501     }
   1502 
   1503     @Override
   1504     public File getExternalFilesDir(String type) {
   1505         // pass
   1506         return null;
   1507     }
   1508 
   1509     @Override
   1510     public String getPackageCodePath() {
   1511         // pass
   1512         return null;
   1513     }
   1514 
   1515     @Override
   1516     public String getBasePackageName() {
   1517         // pass
   1518         return null;
   1519     }
   1520 
   1521     @Override
   1522     public String getOpPackageName() {
   1523         // pass
   1524         return null;
   1525     }
   1526 
   1527     @Override
   1528     public ApplicationInfo getApplicationInfo() {
   1529         return mApplicationInfo;
   1530     }
   1531 
   1532     @Override
   1533     public String getPackageResourcePath() {
   1534         // pass
   1535         return null;
   1536     }
   1537 
   1538     @Override
   1539     public SharedPreferences getSharedPreferences(String arg0, int arg1) {
   1540         if (mSharedPreferences == null) {
   1541             mSharedPreferences = new BridgeSharedPreferences();
   1542         }
   1543         return mSharedPreferences;
   1544     }
   1545 
   1546     @Override
   1547     public SharedPreferences getSharedPreferences(File arg0, int arg1) {
   1548         if (mSharedPreferences == null) {
   1549             mSharedPreferences = new BridgeSharedPreferences();
   1550         }
   1551         return mSharedPreferences;
   1552     }
   1553 
   1554     @Override
   1555     public void reloadSharedPreferences() {
   1556         // intentional noop
   1557     }
   1558 
   1559     @Override
   1560     public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
   1561         // pass
   1562         return false;
   1563     }
   1564 
   1565     @Override
   1566     public boolean deleteSharedPreferences(String name) {
   1567         // pass
   1568         return false;
   1569     }
   1570 
   1571     @Override
   1572     public Drawable getWallpaper() {
   1573         // pass
   1574         return null;
   1575     }
   1576 
   1577     @Override
   1578     public int getWallpaperDesiredMinimumWidth() {
   1579         return -1;
   1580     }
   1581 
   1582     @Override
   1583     public int getWallpaperDesiredMinimumHeight() {
   1584         return -1;
   1585     }
   1586 
   1587     @Override
   1588     public void grantUriPermission(String arg0, Uri arg1, int arg2) {
   1589         // pass
   1590 
   1591     }
   1592 
   1593     @Override
   1594     public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
   1595         // pass
   1596         return null;
   1597     }
   1598 
   1599     @Override
   1600     public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
   1601         // pass
   1602         return null;
   1603     }
   1604 
   1605     @Override
   1606     public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
   1607         // pass
   1608         return null;
   1609     }
   1610 
   1611     @Override
   1612     public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
   1613             CursorFactory arg2, DatabaseErrorHandler arg3) {
   1614         // pass
   1615         return null;
   1616     }
   1617 
   1618     @Override
   1619     public Drawable peekWallpaper() {
   1620         // pass
   1621         return null;
   1622     }
   1623 
   1624     @Override
   1625     public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) {
   1626         // pass
   1627         return null;
   1628     }
   1629 
   1630     @Override
   1631     public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, int arg2) {
   1632         // pass
   1633         return null;
   1634     }
   1635 
   1636     @Override
   1637     public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
   1638             String arg2, Handler arg3) {
   1639         // pass
   1640         return null;
   1641     }
   1642 
   1643     @Override
   1644     public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
   1645             String arg2, Handler arg3, int arg4) {
   1646         // pass
   1647         return null;
   1648     }
   1649 
   1650     @Override
   1651     public Intent registerReceiverAsUser(BroadcastReceiver arg0, UserHandle arg0p5,
   1652             IntentFilter arg1, String arg2, Handler arg3) {
   1653         // pass
   1654         return null;
   1655     }
   1656 
   1657     @Override
   1658     public void removeStickyBroadcast(Intent arg0) {
   1659         // pass
   1660 
   1661     }
   1662 
   1663     @Override
   1664     public void revokeUriPermission(Uri arg0, int arg1) {
   1665         // pass
   1666 
   1667     }
   1668 
   1669     @Override
   1670     public void revokeUriPermission(String arg0, Uri arg1, int arg2) {
   1671         // pass
   1672 
   1673     }
   1674 
   1675     @Override
   1676     public void sendBroadcast(Intent arg0) {
   1677         // pass
   1678 
   1679     }
   1680 
   1681     @Override
   1682     public void sendBroadcast(Intent arg0, String arg1) {
   1683         // pass
   1684 
   1685     }
   1686 
   1687     @Override
   1688     public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
   1689         // pass
   1690 
   1691     }
   1692 
   1693     @Override
   1694     public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
   1695             String[] receiverPermissions) {
   1696         // pass
   1697 
   1698     }
   1699 
   1700     @Override
   1701     public void sendBroadcast(Intent arg0, String arg1, Bundle arg2) {
   1702         // pass
   1703 
   1704     }
   1705 
   1706     @Override
   1707     public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
   1708         // pass
   1709     }
   1710 
   1711     @Override
   1712     public void sendOrderedBroadcast(Intent arg0, String arg1) {
   1713         // pass
   1714 
   1715     }
   1716 
   1717     @Override
   1718     public void sendOrderedBroadcast(Intent arg0, String arg1,
   1719             BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
   1720             Bundle arg6) {
   1721         // pass
   1722 
   1723     }
   1724 
   1725     @Override
   1726     public void sendOrderedBroadcast(Intent arg0, String arg1,
   1727             Bundle arg7, BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
   1728             Bundle arg6) {
   1729         // pass
   1730 
   1731     }
   1732 
   1733     @Override
   1734     public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp,
   1735             BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
   1736             String initialData, Bundle initialExtras) {
   1737         // pass
   1738     }
   1739 
   1740     @Override
   1741     public void sendBroadcastAsUser(Intent intent, UserHandle user) {
   1742         // pass
   1743     }
   1744 
   1745     @Override
   1746     public void sendBroadcastAsUser(Intent intent, UserHandle user,
   1747             String receiverPermission) {
   1748         // pass
   1749     }
   1750 
   1751     @Override
   1752     public void sendBroadcastAsUser(Intent intent, UserHandle user,
   1753             String receiverPermission, Bundle options) {
   1754         // pass
   1755     }
   1756 
   1757     public void sendBroadcastAsUser(Intent intent, UserHandle user,
   1758             String receiverPermission, int appOp) {
   1759         // pass
   1760     }
   1761 
   1762     @Override
   1763     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
   1764             String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
   1765             int initialCode, String initialData, Bundle initialExtras) {
   1766         // pass
   1767     }
   1768 
   1769     @Override
   1770     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
   1771             String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
   1772             Handler scheduler,
   1773             int initialCode, String initialData, Bundle initialExtras) {
   1774         // pass
   1775     }
   1776 
   1777     @Override
   1778     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
   1779             String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
   1780             Handler scheduler,
   1781             int initialCode, String initialData, Bundle initialExtras) {
   1782         // pass
   1783     }
   1784 
   1785     @Override
   1786     public void sendStickyBroadcast(Intent arg0) {
   1787         // pass
   1788 
   1789     }
   1790 
   1791     @Override
   1792     public void sendStickyOrderedBroadcast(Intent intent,
   1793             BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
   1794            Bundle initialExtras) {
   1795         // pass
   1796     }
   1797 
   1798     @Override
   1799     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
   1800         // pass
   1801     }
   1802 
   1803     @Override
   1804     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
   1805         // pass
   1806     }
   1807 
   1808     @Override
   1809     public void sendStickyOrderedBroadcastAsUser(Intent intent,
   1810             UserHandle user, BroadcastReceiver resultReceiver,
   1811             Handler scheduler, int initialCode, String initialData,
   1812             Bundle initialExtras) {
   1813         // pass
   1814     }
   1815 
   1816     @Override
   1817     public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
   1818         // pass
   1819     }
   1820 
   1821     @Override
   1822     public void setTheme(int arg0) {
   1823         // pass
   1824 
   1825     }
   1826 
   1827     @Override
   1828     public void setWallpaper(Bitmap arg0) throws IOException {
   1829         // pass
   1830 
   1831     }
   1832 
   1833     @Override
   1834     public void setWallpaper(InputStream arg0) throws IOException {
   1835         // pass
   1836 
   1837     }
   1838 
   1839     @Override
   1840     public void startActivity(Intent arg0) {
   1841         // pass
   1842     }
   1843 
   1844     @Override
   1845     public void startActivity(Intent arg0, Bundle arg1) {
   1846         // pass
   1847     }
   1848 
   1849     @Override
   1850     public void startIntentSender(IntentSender intent,
   1851             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
   1852             throws IntentSender.SendIntentException {
   1853         // pass
   1854     }
   1855 
   1856     @Override
   1857     public void startIntentSender(IntentSender intent,
   1858             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
   1859             Bundle options) throws IntentSender.SendIntentException {
   1860         // pass
   1861     }
   1862 
   1863     @Override
   1864     public boolean startInstrumentation(ComponentName arg0, String arg1,
   1865             Bundle arg2) {
   1866         // pass
   1867         return false;
   1868     }
   1869 
   1870     @Override
   1871     public ComponentName startService(Intent arg0) {
   1872         // pass
   1873         return null;
   1874     }
   1875 
   1876     @Override
   1877     public ComponentName startForegroundService(Intent service) {
   1878         // pass
   1879         return null;
   1880     }
   1881 
   1882     @Override
   1883     public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
   1884         // pass
   1885         return null;
   1886     }
   1887 
   1888     @Override
   1889     public boolean stopService(Intent arg0) {
   1890         // pass
   1891         return false;
   1892     }
   1893 
   1894     @Override
   1895     public ComponentName startServiceAsUser(Intent arg0, UserHandle arg1) {
   1896         // pass
   1897         return null;
   1898     }
   1899 
   1900     @Override
   1901     public boolean stopServiceAsUser(Intent arg0, UserHandle arg1) {
   1902         // pass
   1903         return false;
   1904     }
   1905 
   1906     @Override
   1907     public void unbindService(ServiceConnection arg0) {
   1908         // pass
   1909 
   1910     }
   1911 
   1912     @Override
   1913     public void unregisterReceiver(BroadcastReceiver arg0) {
   1914         // pass
   1915 
   1916     }
   1917 
   1918     @Override
   1919     public Context getApplicationContext() {
   1920         return this;
   1921     }
   1922 
   1923     @Override
   1924     public void startActivities(Intent[] arg0) {
   1925         // pass
   1926 
   1927     }
   1928 
   1929     @Override
   1930     public void startActivities(Intent[] arg0, Bundle arg1) {
   1931         // pass
   1932 
   1933     }
   1934 
   1935     @Override
   1936     public boolean isRestricted() {
   1937         return false;
   1938     }
   1939 
   1940     @Override
   1941     public File getObbDir() {
   1942         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
   1943         return null;
   1944     }
   1945 
   1946     @Override
   1947     public DisplayAdjustments getDisplayAdjustments(int displayId) {
   1948         // pass
   1949         return null;
   1950     }
   1951 
   1952     @Override
   1953     public Display getDisplay() {
   1954         // pass
   1955         return null;
   1956     }
   1957 
   1958     @Override
   1959     public void updateDisplay(int displayId) {
   1960         // pass
   1961     }
   1962 
   1963     @Override
   1964     public int getUserId() {
   1965         return 0; // not used
   1966     }
   1967 
   1968     @Override
   1969     public File[] getExternalFilesDirs(String type) {
   1970         // pass
   1971         return new File[0];
   1972     }
   1973 
   1974     @Override
   1975     public File[] getObbDirs() {
   1976         // pass
   1977         return new File[0];
   1978     }
   1979 
   1980     @Override
   1981     public File[] getExternalCacheDirs() {
   1982         // pass
   1983         return new File[0];
   1984     }
   1985 
   1986     @Override
   1987     public File[] getExternalMediaDirs() {
   1988         // pass
   1989         return new File[0];
   1990     }
   1991 
   1992     public void setScrollYPos(@NonNull View view, int scrollPos) {
   1993         mScrollYPos.put(view, scrollPos);
   1994     }
   1995 
   1996     public int getScrollYPos(@NonNull View view) {
   1997         Integer pos = mScrollYPos.get(view);
   1998         return pos != null ? pos : 0;
   1999     }
   2000 
   2001     public void setScrollXPos(@NonNull View view, int scrollPos) {
   2002         mScrollXPos.put(view, scrollPos);
   2003     }
   2004 
   2005     public int getScrollXPos(@NonNull View view) {
   2006         Integer pos = mScrollXPos.get(view);
   2007         return pos != null ? pos : 0;
   2008     }
   2009 
   2010     @Override
   2011     public Context createDeviceProtectedStorageContext() {
   2012         // pass
   2013         return null;
   2014     }
   2015 
   2016     @Override
   2017     public Context createCredentialProtectedStorageContext() {
   2018         // pass
   2019         return null;
   2020     }
   2021 
   2022     @Override
   2023     public boolean isDeviceProtectedStorage() {
   2024         return false;
   2025     }
   2026 
   2027     @Override
   2028     public boolean isCredentialProtectedStorage() {
   2029         return false;
   2030     }
   2031 
   2032     @Override
   2033     public boolean canLoadUnsafeResources() {
   2034         return true;
   2035     }
   2036 
   2037     private class AttributeHolder {
   2038         private int resourceId;
   2039         private String name;
   2040         private boolean isFramework;
   2041 
   2042         private AttributeHolder(int resourceId, String name, boolean isFramework) {
   2043             this.resourceId = resourceId;
   2044             this.name = name;
   2045             this.isFramework = isFramework;
   2046         }
   2047     }
   2048 
   2049     /**
   2050      * The cached value depends on
   2051      * <ol>
   2052      * <li>{@code int[]}: the attributes for which TypedArray is created </li>
   2053      * <li>{@code List<StyleResourceValue>}: the themes set on the context at the time of
   2054      * creation of the TypedArray</li>
   2055      * <li>{@code Integer}: the default style used at the time of creation</li>
   2056      * </ol>
   2057      *
   2058      * The class is created by using nested maps resolving one dependency at a time.
   2059      * <p/>
   2060      * The final value of the nested maps is a pair of the typed array and a map of properties
   2061      * that should be added to {@link #mDefaultPropMaps}, if needed.
   2062      */
   2063     private static class TypedArrayCache {
   2064 
   2065         private Map<int[],
   2066                 Map<List<StyleResourceValue>,
   2067                         Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>> mCache;
   2068 
   2069         private TypedArrayCache() {
   2070             mCache = new IdentityHashMap<>();
   2071         }
   2072 
   2073         public Pair<BridgeTypedArray, PropertiesMap> get(int[] attrs,
   2074                 List<StyleResourceValue> themes, int resId) {
   2075             Map<List<StyleResourceValue>, Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>
   2076                     cacheFromThemes = mCache.get(attrs);
   2077             if (cacheFromThemes != null) {
   2078                 Map<Integer, Pair<BridgeTypedArray, PropertiesMap>> cacheFromResId =
   2079                         cacheFromThemes.get(themes);
   2080                 if (cacheFromResId != null) {
   2081                     return cacheFromResId.get(resId);
   2082                 }
   2083             }
   2084             return null;
   2085         }
   2086 
   2087         public void put(int[] attrs, List<StyleResourceValue> themes, int resId,
   2088                 Pair<BridgeTypedArray, PropertiesMap> value) {
   2089             Map<List<StyleResourceValue>, Map<Integer, Pair<BridgeTypedArray, PropertiesMap>>>
   2090                     cacheFromThemes = mCache.computeIfAbsent(attrs, k -> new HashMap<>());
   2091             Map<Integer, Pair<BridgeTypedArray, PropertiesMap>> cacheFromResId =
   2092                     cacheFromThemes.computeIfAbsent(themes, k -> new HashMap<>());
   2093             cacheFromResId.put(resId, value);
   2094         }
   2095 
   2096     }
   2097 }
   2098