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