• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ide.common.rendering.api.ILayoutPullParser;
20 import com.android.ide.common.rendering.api.IProjectCallback;
21 import com.android.ide.common.rendering.api.LayoutLog;
22 import com.android.ide.common.rendering.api.RenderResources;
23 import com.android.ide.common.rendering.api.ResourceReference;
24 import com.android.ide.common.rendering.api.ResourceValue;
25 import com.android.ide.common.rendering.api.StyleResourceValue;
26 import com.android.layoutlib.bridge.Bridge;
27 import com.android.layoutlib.bridge.BridgeConstants;
28 import com.android.layoutlib.bridge.impl.ParserFactory;
29 import com.android.layoutlib.bridge.impl.Stack;
30 import com.android.resources.ResourceType;
31 import com.android.util.Pair;
32 
33 import org.xmlpull.v1.XmlPullParser;
34 import org.xmlpull.v1.XmlPullParserException;
35 
36 import android.content.BroadcastReceiver;
37 import android.content.ComponentName;
38 import android.content.ContentResolver;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.IntentFilter;
42 import android.content.IntentSender;
43 import android.content.ServiceConnection;
44 import android.content.SharedPreferences;
45 import android.content.pm.ApplicationInfo;
46 import android.content.pm.PackageManager;
47 import android.content.res.AssetManager;
48 import android.content.res.BridgeResources;
49 import android.content.res.BridgeTypedArray;
50 import android.content.res.Configuration;
51 import android.content.res.Resources;
52 import android.content.res.Resources.Theme;
53 import android.content.res.TypedArray;
54 import android.database.DatabaseErrorHandler;
55 import android.database.sqlite.SQLiteDatabase;
56 import android.database.sqlite.SQLiteDatabase.CursorFactory;
57 import android.graphics.Bitmap;
58 import android.graphics.drawable.Drawable;
59 import android.net.Uri;
60 import android.os.Bundle;
61 import android.os.Handler;
62 import android.os.Looper;
63 import android.os.PowerManager;
64 import android.util.AttributeSet;
65 import android.util.DisplayMetrics;
66 import android.util.TypedValue;
67 import android.view.BridgeInflater;
68 import android.view.Surface;
69 import android.view.View;
70 import android.view.ViewGroup;
71 import android.view.textservice.TextServicesManager;
72 
73 import java.io.File;
74 import java.io.FileInputStream;
75 import java.io.FileNotFoundException;
76 import java.io.FileOutputStream;
77 import java.io.IOException;
78 import java.io.InputStream;
79 import java.util.ArrayList;
80 import java.util.HashMap;
81 import java.util.IdentityHashMap;
82 import java.util.List;
83 import java.util.Map;
84 
85 /**
86  * Custom implementation of Context/Activity to handle non compiled resources.
87  */
88 public final class BridgeContext extends Context {
89 
90     private Resources mSystemResources;
91     private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
92     private final Object mProjectKey;
93     private final DisplayMetrics mMetrics;
94     private final RenderResources mRenderResources;
95     private final Configuration mConfig;
96     private final ApplicationInfo mApplicationInfo;
97     private final IProjectCallback mProjectCallback;
98     private final BridgeWindowManager mIWindowManager;
99 
100     private Resources.Theme mTheme;
101 
102     private final Map<Object, Map<String, String>> mDefaultPropMaps =
103         new IdentityHashMap<Object, Map<String,String>>();
104 
105     // maps for dynamically generated id representing style objects (StyleResourceValue)
106     private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
107     private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
108     private int mDynamicIdGenerator = 0x01030000; // Base id for framework R.style
109 
110     // cache for TypedArray generated from IStyleResourceValue object
111     private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
112     private BridgeInflater mBridgeInflater;
113 
114     private BridgeContentResolver mContentResolver;
115 
116     private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
117 
118     /**
119      * @param projectKey An Object identifying the project. This is used for the cache mechanism.
120      * @param metrics the {@link DisplayMetrics}.
121      * @param renderResources the configured resources (both framework and projects) for this
122      * render.
123      * @param projectCallback
124      * @param config the Configuration object for this render.
125      * @param targetSdkVersion the targetSdkVersion of the application.
126      */
BridgeContext(Object projectKey, DisplayMetrics metrics, RenderResources renderResources, IProjectCallback projectCallback, Configuration config, int targetSdkVersion)127     public BridgeContext(Object projectKey, DisplayMetrics metrics,
128             RenderResources renderResources,
129             IProjectCallback projectCallback,
130             Configuration config,
131             int targetSdkVersion) {
132         mProjectKey = projectKey;
133         mMetrics = metrics;
134         mProjectCallback = projectCallback;
135 
136         mRenderResources = renderResources;
137         mConfig = config;
138 
139         mIWindowManager = new BridgeWindowManager(mConfig, metrics, Surface.ROTATION_0);
140 
141         mApplicationInfo = new ApplicationInfo();
142         mApplicationInfo.targetSdkVersion = targetSdkVersion;
143     }
144 
145     /**
146      * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its
147      * {@link DisplayMetrics}, {@link Configuration}, and {@link IProjectCallback}.
148      *
149      * @see #disposeResources()
150      */
initResources()151     public void initResources() {
152         AssetManager assetManager = AssetManager.getSystem();
153 
154         mSystemResources = BridgeResources.initSystem(
155                 this,
156                 assetManager,
157                 mMetrics,
158                 mConfig,
159                 mProjectCallback);
160         mTheme = mSystemResources.newTheme();
161     }
162 
163     /**
164      * Disposes the {@link Resources} singleton.
165      */
disposeResources()166     public void disposeResources() {
167         BridgeResources.disposeSystem();
168     }
169 
setBridgeInflater(BridgeInflater inflater)170     public void setBridgeInflater(BridgeInflater inflater) {
171         mBridgeInflater = inflater;
172     }
173 
addViewKey(View view, Object viewKey)174     public void addViewKey(View view, Object viewKey) {
175         mViewKeyMap.put(view, viewKey);
176     }
177 
getViewKey(View view)178     public Object getViewKey(View view) {
179         return mViewKeyMap.get(view);
180     }
181 
getProjectKey()182     public Object getProjectKey() {
183         return mProjectKey;
184     }
185 
getMetrics()186     public DisplayMetrics getMetrics() {
187         return mMetrics;
188     }
189 
getProjectCallback()190     public IProjectCallback getProjectCallback() {
191         return mProjectCallback;
192     }
193 
getRenderResources()194     public RenderResources getRenderResources() {
195         return mRenderResources;
196     }
197 
getIWindowManager()198     public BridgeWindowManager getIWindowManager() {
199         return mIWindowManager;
200     }
201 
getDefaultPropMap(Object key)202     public Map<String, String> getDefaultPropMap(Object key) {
203         return mDefaultPropMaps.get(key);
204     }
205 
206     /**
207      * Adds a parser to the stack.
208      * @param parser the parser to add.
209      */
pushParser(BridgeXmlBlockParser parser)210     public void pushParser(BridgeXmlBlockParser parser) {
211         if (ParserFactory.LOG_PARSER) {
212             System.out.println("PUSH " + parser.getParser().toString());
213         }
214         mParserStack.push(parser);
215     }
216 
217     /**
218      * Removes the parser at the top of the stack
219      */
popParser()220     public void popParser() {
221         BridgeXmlBlockParser parser = mParserStack.pop();
222         if (ParserFactory.LOG_PARSER) {
223             System.out.println("POPD " + parser.getParser().toString());
224         }
225     }
226 
227     /**
228      * Returns the current parser at the top the of the stack.
229      * @return a parser or null.
230      */
getCurrentParser()231     public BridgeXmlBlockParser getCurrentParser() {
232         return mParserStack.peek();
233     }
234 
235     /**
236      * Returns the previous parser.
237      * @return a parser or null if there isn't any previous parser
238      */
getPreviousParser()239     public BridgeXmlBlockParser getPreviousParser() {
240         if (mParserStack.size() < 2) {
241             return null;
242         }
243         return mParserStack.get(mParserStack.size() - 2);
244     }
245 
resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs)246     public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
247         Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid);
248         boolean isFrameworkRes = true;
249         if (resourceInfo == null) {
250             resourceInfo = mProjectCallback.resolveResourceId(resid);
251             isFrameworkRes = false;
252         }
253 
254         if (resourceInfo == null) {
255             return false;
256         }
257 
258         ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond(),
259                 isFrameworkRes);
260         if (resolveRefs) {
261             value = mRenderResources.resolveResValue(value);
262         }
263 
264         // check if this is a style resource
265         if (value instanceof StyleResourceValue) {
266             // get the id that will represent this style.
267             outValue.resourceId = getDynamicIdByStyle((StyleResourceValue)value);
268             return true;
269         }
270 
271 
272         int a;
273         // if this is a framework value.
274         if (value.isFramework()) {
275             // look for idName in the android R classes.
276             // use 0 a default res value as it's not a valid id value.
277             a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
278         } else {
279             // look for idName in the project R class.
280             // use 0 a default res value as it's not a valid id value.
281             a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
282         }
283 
284         if (a != 0) {
285             outValue.resourceId = a;
286             return true;
287         }
288 
289         return false;
290     }
291 
292 
resolveId(int id)293     public ResourceReference resolveId(int id) {
294         // first get the String related to this id in the framework
295         Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
296 
297         if (resourceInfo != null) {
298             return new ResourceReference(resourceInfo.getSecond(), true);
299         }
300 
301         // didn't find a match in the framework? look in the project.
302         if (mProjectCallback != null) {
303             resourceInfo = mProjectCallback.resolveResourceId(id);
304 
305             if (resourceInfo != null) {
306                 return new ResourceReference(resourceInfo.getSecond(), false);
307             }
308         }
309 
310         return null;
311     }
312 
inflateView(ResourceReference resource, ViewGroup parent, boolean attachToRoot, boolean skipCallbackParser)313     public Pair<View, Boolean> inflateView(ResourceReference resource, ViewGroup parent,
314             boolean attachToRoot, boolean skipCallbackParser) {
315         boolean isPlatformLayout = resource.isFramework();
316 
317         if (isPlatformLayout == false && skipCallbackParser == false) {
318             // check if the project callback can provide us with a custom parser.
319             ILayoutPullParser parser = getParser(resource);
320 
321             if (parser != null) {
322                 BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
323                         this, resource.isFramework());
324                 try {
325                     pushParser(blockParser);
326                     return Pair.of(
327                             mBridgeInflater.inflate(blockParser, parent, attachToRoot),
328                             true);
329                 } finally {
330                     popParser();
331                 }
332             }
333         }
334 
335         ResourceValue resValue;
336         if (resource instanceof ResourceValue) {
337             resValue = (ResourceValue) resource;
338         } else {
339             if (isPlatformLayout) {
340                 resValue = mRenderResources.getFrameworkResource(ResourceType.LAYOUT,
341                         resource.getName());
342             } else {
343                 resValue = mRenderResources.getProjectResource(ResourceType.LAYOUT,
344                         resource.getName());
345             }
346         }
347 
348         if (resValue != null) {
349 
350             File xml = new File(resValue.getValue());
351             if (xml.isFile()) {
352                 // we need to create a pull parser around the layout XML file, and then
353                 // give that to our XmlBlockParser
354                 try {
355                     XmlPullParser parser = ParserFactory.create(xml);
356 
357                     // set the resource ref to have correct view cookies
358                     mBridgeInflater.setResourceReference(resource);
359 
360                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(parser,
361                             this, resource.isFramework());
362                     try {
363                         pushParser(blockParser);
364                         return Pair.of(
365                                 mBridgeInflater.inflate(blockParser, parent, attachToRoot),
366                                 false);
367                     } finally {
368                         popParser();
369                     }
370                 } catch (XmlPullParserException e) {
371                     Bridge.getLog().error(LayoutLog.TAG_BROKEN,
372                             "Failed to configure parser for " + xml, e, null /*data*/);
373                     // we'll return null below.
374                 } catch (FileNotFoundException e) {
375                     // this shouldn't happen since we check above.
376                 } finally {
377                     mBridgeInflater.setResourceReference(null);
378                 }
379             } else {
380                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
381                         String.format("File %s is missing!", xml), null);
382             }
383         } else {
384             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
385                     String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "",
386                             resource.getName()), null);
387         }
388 
389         return Pair.of(null, false);
390     }
391 
392     @SuppressWarnings("deprecation")
getParser(ResourceReference resource)393     private ILayoutPullParser getParser(ResourceReference resource) {
394         ILayoutPullParser parser;
395         if (resource instanceof ResourceValue) {
396             parser = mProjectCallback.getParser((ResourceValue) resource);
397         } else {
398             parser = mProjectCallback.getParser(resource.getName());
399         }
400         return parser;
401     }
402 
403     // ------------ Context methods
404 
405     @Override
getResources()406     public Resources getResources() {
407         return mSystemResources;
408     }
409 
410     @Override
getTheme()411     public Theme getTheme() {
412         return mTheme;
413     }
414 
415     @Override
getClassLoader()416     public ClassLoader getClassLoader() {
417         return this.getClass().getClassLoader();
418     }
419 
420     @Override
getSystemService(String service)421     public Object getSystemService(String service) {
422         if (LAYOUT_INFLATER_SERVICE.equals(service)) {
423             return mBridgeInflater;
424         }
425 
426         if (TEXT_SERVICES_MANAGER_SERVICE.equals(service)) {
427             // we need to return a valid service to avoid NPE
428             return TextServicesManager.getInstance();
429         }
430 
431         // AutoCompleteTextView and MultiAutoCompleteTextView want a window
432         // service. We don't have any but it's not worth an exception.
433         if (WINDOW_SERVICE.equals(service)) {
434             return null;
435         }
436 
437         // needed by SearchView
438         if (INPUT_METHOD_SERVICE.equals(service)) {
439             return null;
440         }
441 
442         if (POWER_SERVICE.equals(service)) {
443             return new PowerManager(new BridgePowerManager(), new Handler());
444         }
445 
446         throw new UnsupportedOperationException("Unsupported Service: " + service);
447     }
448 
449 
450     @Override
obtainStyledAttributes(int[] attrs)451     public final TypedArray obtainStyledAttributes(int[] attrs) {
452         return createStyleBasedTypedArray(mRenderResources.getCurrentTheme(), attrs);
453     }
454 
455     @Override
obtainStyledAttributes(int resid, int[] attrs)456     public final TypedArray obtainStyledAttributes(int resid, int[] attrs)
457             throws Resources.NotFoundException {
458         // get the StyleResourceValue based on the resId;
459         StyleResourceValue style = getStyleByDynamicId(resid);
460 
461         if (style == null) {
462             throw new Resources.NotFoundException();
463         }
464 
465         if (mTypedArrayCache == null) {
466             mTypedArrayCache = new HashMap<int[], Map<Integer,TypedArray>>();
467 
468             Map<Integer, TypedArray> map = new HashMap<Integer, TypedArray>();
469             mTypedArrayCache.put(attrs, map);
470 
471             BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs);
472             map.put(resid, ta);
473 
474             return ta;
475         }
476 
477         // get the 2nd map
478         Map<Integer, TypedArray> map = mTypedArrayCache.get(attrs);
479         if (map == null) {
480             map = new HashMap<Integer, TypedArray>();
481             mTypedArrayCache.put(attrs, map);
482         }
483 
484         // get the array from the 2nd map
485         TypedArray ta = map.get(resid);
486 
487         if (ta == null) {
488             ta = createStyleBasedTypedArray(style, attrs);
489             map.put(resid, ta);
490         }
491 
492         return ta;
493     }
494 
495     @Override
obtainStyledAttributes(AttributeSet set, int[] attrs)496     public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) {
497         return obtainStyledAttributes(set, attrs, 0, 0);
498     }
499 
500     @Override
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)501     public TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
502             int defStyleAttr, int defStyleRes) {
503 
504         Map<String, String> defaultPropMap = null;
505         boolean isPlatformFile = true;
506 
507         // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
508         if (set instanceof BridgeXmlBlockParser) {
509             BridgeXmlBlockParser parser = null;
510             parser = (BridgeXmlBlockParser)set;
511 
512             isPlatformFile = parser.isPlatformFile();
513 
514             Object key = parser.getViewCookie();
515             if (key != null) {
516                 defaultPropMap = mDefaultPropMaps.get(key);
517                 if (defaultPropMap == null) {
518                     defaultPropMap = new HashMap<String, String>();
519                     mDefaultPropMaps.put(key, defaultPropMap);
520                 }
521             }
522 
523         } else if (set instanceof BridgeLayoutParamsMapAttributes) {
524             // this is only for temp layout params generated dynamically, so this is never
525             // platform content.
526             isPlatformFile = false;
527         } else if (set != null) { // null parser is ok
528             // really this should not be happening since its instantiated in Bridge
529             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
530                     "Parser is not a BridgeXmlBlockParser!", null /*data*/);
531             return null;
532         }
533 
534         List<Pair<String, Boolean>> attributeList = searchAttrs(attrs);
535 
536         BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
537                 isPlatformFile);
538 
539         // look for a custom style.
540         String customStyle = null;
541         if (set != null) {
542             customStyle = set.getAttributeValue(null /* namespace*/, "style");
543         }
544 
545         StyleResourceValue customStyleValues = null;
546         if (customStyle != null) {
547             ResourceValue item = mRenderResources.findResValue(customStyle,
548                     false /*forceFrameworkOnly*/);
549 
550             // resolve it in case it links to something else
551             item = mRenderResources.resolveResValue(item);
552 
553             if (item instanceof StyleResourceValue) {
554                 customStyleValues = (StyleResourceValue)item;
555             }
556         }
557 
558         // resolve the defStyleAttr value into a IStyleResourceValue
559         StyleResourceValue defStyleValues = null;
560 
561         if (defStyleAttr != 0) {
562             // get the name from the int.
563             Pair<String, Boolean> defStyleAttribute = searchAttr(defStyleAttr);
564 
565             if (defaultPropMap != null) {
566                 String defStyleName = defStyleAttribute.getFirst();
567                 if (defStyleAttribute.getSecond()) {
568                     defStyleName = "android:" + defStyleName;
569                 }
570                 defaultPropMap.put("style", defStyleName);
571             }
572 
573             // look for the style in the current theme, and its parent:
574             ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute.getFirst(),
575                     defStyleAttribute.getSecond());
576 
577             if (item != null) {
578                 // item is a reference to a style entry. Search for it.
579                 item = mRenderResources.findResValue(item.getValue(),
580                         false /*forceFrameworkOnly*/);
581 
582                 if (item instanceof StyleResourceValue) {
583                     defStyleValues = (StyleResourceValue)item;
584                 }
585             } else {
586                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
587                         String.format(
588                                 "Failed to find style '%s' in current theme",
589                                 defStyleAttribute.getFirst()),
590                         null /*data*/);
591             }
592         } else if (defStyleRes != 0) {
593             boolean isFrameworkRes = true;
594             Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
595             if (value == null) {
596                 value = mProjectCallback.resolveResourceId(defStyleRes);
597                 isFrameworkRes = false;
598             }
599 
600             if (value != null) {
601                 if (value.getFirst() == ResourceType.STYLE) {
602                     // look for the style in the current theme, and its parent:
603                     ResourceValue item = mRenderResources.findItemInTheme(value.getSecond(),
604                             isFrameworkRes);
605                     if (item != null) {
606                         if (item instanceof StyleResourceValue) {
607                             if (defaultPropMap != null) {
608                                 defaultPropMap.put("style", item.getName());
609                             }
610 
611                             defStyleValues = (StyleResourceValue)item;
612                         }
613                     } else {
614                         Bridge.getLog().error(null,
615                                 String.format(
616                                         "Style with id 0x%x (resolved to '%s') does not exist.",
617                                         defStyleRes, value.getSecond()),
618                                 null /*data*/);
619                     }
620                 } else {
621                     Bridge.getLog().error(null,
622                             String.format(
623                                     "Resouce id 0x%x is not of type STYLE (instead %s)",
624                                     defStyleRes, value.getFirst().toString()),
625                             null /*data*/);
626                 }
627             } else {
628                 Bridge.getLog().error(null,
629                         String.format(
630                                 "Failed to find style with id 0x%x in current theme",
631                                 defStyleRes),
632                         null /*data*/);
633             }
634         }
635 
636         String appNamespace = mProjectCallback.getNamespace();
637 
638         if (attributeList != null) {
639             for (int index = 0 ; index < attributeList.size() ; index++) {
640                 Pair<String, Boolean> attribute = attributeList.get(index);
641 
642                 if (attribute == null) {
643                     continue;
644                 }
645 
646                 String attrName = attribute.getFirst();
647                 boolean frameworkAttr = attribute.getSecond().booleanValue();
648                 String value = null;
649                 if (set != null) {
650                     value = set.getAttributeValue(
651                             frameworkAttr ? BridgeConstants.NS_RESOURCES : appNamespace,
652                                     attrName);
653 
654                     // if this is an app attribute, and the first get fails, try with the
655                     // new res-auto namespace as well
656                     if (frameworkAttr == false && value == null) {
657                         value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName);
658                     }
659                 }
660 
661                 // if there's no direct value for this attribute in the XML, we look for default
662                 // values in the widget defStyle, and then in the theme.
663                 if (value == null) {
664                     ResourceValue resValue = null;
665 
666                     // look for the value in the custom style first (and its parent if needed)
667                     if (customStyleValues != null) {
668                         resValue = mRenderResources.findItemInStyle(customStyleValues,
669                                 attrName, frameworkAttr);
670                     }
671 
672                     // then look for the value in the default Style (and its parent if needed)
673                     if (resValue == null && defStyleValues != null) {
674                         resValue = mRenderResources.findItemInStyle(defStyleValues,
675                                 attrName, frameworkAttr);
676                     }
677 
678                     // if the item is not present in the defStyle, we look in the main theme (and
679                     // its parent themes)
680                     if (resValue == null) {
681                         resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
682                     }
683 
684                     // if we found a value, we make sure this doesn't reference another value.
685                     // So we resolve it.
686                     if (resValue != null) {
687                         // put the first default value, before the resolution.
688                         if (defaultPropMap != null) {
689                             defaultPropMap.put(attrName, resValue.getValue());
690                         }
691 
692                         resValue = mRenderResources.resolveResValue(resValue);
693                     }
694 
695                     ta.bridgeSetValue(index, attrName, frameworkAttr, resValue);
696                 } else {
697                     // there is a value in the XML, but we need to resolve it in case it's
698                     // referencing another resource or a theme value.
699                     ta.bridgeSetValue(index, attrName, frameworkAttr,
700                             mRenderResources.resolveValue(null, attrName, value, isPlatformFile));
701                 }
702             }
703         }
704 
705         ta.sealArray();
706 
707         return ta;
708     }
709 
710     @Override
getMainLooper()711     public Looper getMainLooper() {
712         return Looper.myLooper();
713     }
714 
715 
716     // ------------- private new methods
717 
718     /**
719      * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
720      * values found in the given style.
721      * @see #obtainStyledAttributes(int, int[])
722      */
createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)723     private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
724             throws Resources.NotFoundException {
725 
726         List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
727 
728         BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
729                 false);
730 
731         // for each attribute, get its name so that we can search it in the style
732         for (int i = 0 ; i < attrs.length ; i++) {
733             Pair<String, Boolean> attribute = attributes.get(i);
734 
735             // look for the value in the given style
736             ResourceValue resValue = mRenderResources.findItemInStyle(style, attribute.getFirst(),
737                     attribute.getSecond());
738 
739             if (resValue != null) {
740                 // resolve it to make sure there are no references left.
741                 ta.bridgeSetValue(i, attribute.getFirst(), attribute.getSecond(),
742                         mRenderResources.resolveResValue(resValue));
743             }
744         }
745 
746         ta.sealArray();
747 
748         return ta;
749     }
750 
751 
752     /**
753      * The input int[] attrs is a list of attributes. The returns a list of information about
754      * each attributes. The information is (name, isFramework)
755      * <p/>
756      *
757      * @param attrs An attribute array reference given to obtainStyledAttributes.
758      * @return List of attribute information.
759      */
searchAttrs(int[] attrs)760     private List<Pair<String, Boolean>> searchAttrs(int[] attrs) {
761         List<Pair<String, Boolean>> results = new ArrayList<Pair<String, Boolean>>(attrs.length);
762 
763         // for each attribute, get its name so that we can search it in the style
764         for (int i = 0 ; i < attrs.length ; i++) {
765             Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attrs[i]);
766             boolean isFramework = false;
767             if (resolvedResource != null) {
768                 isFramework = true;
769             } else {
770                 resolvedResource = mProjectCallback.resolveResourceId(attrs[i]);
771             }
772 
773             if (resolvedResource != null) {
774                 results.add(Pair.of(resolvedResource.getSecond(), isFramework));
775             } else {
776                 results.add(null);
777             }
778         }
779 
780         return results;
781     }
782 
783     /**
784      * Searches for the attribute referenced by its internal id.
785      *
786      * @param attr An attribute reference given to obtainStyledAttributes such as defStyle.
787      * @return A (name, isFramework) pair describing the attribute if found. Returns null
788      *         if nothing is found.
789      */
searchAttr(int attr)790     public Pair<String, Boolean> searchAttr(int attr) {
791         Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
792         if (info != null) {
793             return Pair.of(info.getSecond(), Boolean.TRUE);
794         }
795 
796         info = mProjectCallback.resolveResourceId(attr);
797         if (info != null) {
798             return Pair.of(info.getSecond(), Boolean.FALSE);
799         }
800 
801         return null;
802     }
803 
getDynamicIdByStyle(StyleResourceValue resValue)804     public int getDynamicIdByStyle(StyleResourceValue resValue) {
805         if (mDynamicIdToStyleMap == null) {
806             // create the maps.
807             mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>();
808             mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>();
809         }
810 
811         // look for an existing id
812         Integer id = mStyleToDynamicIdMap.get(resValue);
813 
814         if (id == null) {
815             // generate a new id
816             id = Integer.valueOf(++mDynamicIdGenerator);
817 
818             // and add it to the maps.
819             mDynamicIdToStyleMap.put(id, resValue);
820             mStyleToDynamicIdMap.put(resValue, id);
821         }
822 
823         return id;
824     }
825 
getStyleByDynamicId(int i)826     private StyleResourceValue getStyleByDynamicId(int i) {
827         if (mDynamicIdToStyleMap != null) {
828             return mDynamicIdToStyleMap.get(i);
829         }
830 
831         return null;
832     }
833 
getFrameworkResourceValue(ResourceType resType, String resName, int defValue)834     public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
835         Integer value = Bridge.getResourceId(resType, resName);
836         if (value != null) {
837             return value.intValue();
838         }
839 
840         return defValue;
841     }
842 
getProjectResourceValue(ResourceType resType, String resName, int defValue)843     public int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
844         if (mProjectCallback != null) {
845             Integer value = mProjectCallback.getResourceId(resType, resName);
846             if (value != null) {
847                 return value.intValue();
848             }
849         }
850 
851         return defValue;
852     }
853 
854     //------------ NOT OVERRIDEN --------------------
855 
856     @Override
bindService(Intent arg0, ServiceConnection arg1, int arg2)857     public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) {
858         // pass
859         return false;
860     }
861 
862     @Override
checkCallingOrSelfPermission(String arg0)863     public int checkCallingOrSelfPermission(String arg0) {
864         // pass
865         return 0;
866     }
867 
868     @Override
checkCallingOrSelfUriPermission(Uri arg0, int arg1)869     public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) {
870         // pass
871         return 0;
872     }
873 
874     @Override
checkCallingPermission(String arg0)875     public int checkCallingPermission(String arg0) {
876         // pass
877         return 0;
878     }
879 
880     @Override
checkCallingUriPermission(Uri arg0, int arg1)881     public int checkCallingUriPermission(Uri arg0, int arg1) {
882         // pass
883         return 0;
884     }
885 
886     @Override
checkPermission(String arg0, int arg1, int arg2)887     public int checkPermission(String arg0, int arg1, int arg2) {
888         // pass
889         return 0;
890     }
891 
892     @Override
checkUriPermission(Uri arg0, int arg1, int arg2, int arg3)893     public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
894         // pass
895         return 0;
896     }
897 
898     @Override
checkUriPermission(Uri arg0, String arg1, String arg2, int arg3, int arg4, int arg5)899     public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
900             int arg4, int arg5) {
901         // pass
902         return 0;
903     }
904 
905     @Override
clearWallpaper()906     public void clearWallpaper() {
907         // pass
908 
909     }
910 
911     @Override
createPackageContext(String arg0, int arg1)912     public Context createPackageContext(String arg0, int arg1) {
913         // pass
914         return null;
915     }
916 
917     @Override
databaseList()918     public String[] databaseList() {
919         // pass
920         return null;
921     }
922 
923     @Override
deleteDatabase(String arg0)924     public boolean deleteDatabase(String arg0) {
925         // pass
926         return false;
927     }
928 
929     @Override
deleteFile(String arg0)930     public boolean deleteFile(String arg0) {
931         // pass
932         return false;
933     }
934 
935     @Override
enforceCallingOrSelfPermission(String arg0, String arg1)936     public void enforceCallingOrSelfPermission(String arg0, String arg1) {
937         // pass
938 
939     }
940 
941     @Override
enforceCallingOrSelfUriPermission(Uri arg0, int arg1, String arg2)942     public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1,
943             String arg2) {
944         // pass
945 
946     }
947 
948     @Override
enforceCallingPermission(String arg0, String arg1)949     public void enforceCallingPermission(String arg0, String arg1) {
950         // pass
951 
952     }
953 
954     @Override
enforceCallingUriPermission(Uri arg0, int arg1, String arg2)955     public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) {
956         // pass
957 
958     }
959 
960     @Override
enforcePermission(String arg0, int arg1, int arg2, String arg3)961     public void enforcePermission(String arg0, int arg1, int arg2, String arg3) {
962         // pass
963 
964     }
965 
966     @Override
enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3, String arg4)967     public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3,
968             String arg4) {
969         // pass
970 
971     }
972 
973     @Override
enforceUriPermission(Uri arg0, String arg1, String arg2, int arg3, int arg4, int arg5, String arg6)974     public void enforceUriPermission(Uri arg0, String arg1, String arg2,
975             int arg3, int arg4, int arg5, String arg6) {
976         // pass
977 
978     }
979 
980     @Override
fileList()981     public String[] fileList() {
982         // pass
983         return null;
984     }
985 
986     @Override
getAssets()987     public AssetManager getAssets() {
988         // pass
989         return null;
990     }
991 
992     @Override
getCacheDir()993     public File getCacheDir() {
994         // pass
995         return null;
996     }
997 
998     @Override
getExternalCacheDir()999     public File getExternalCacheDir() {
1000         // pass
1001         return null;
1002     }
1003 
1004     @Override
getContentResolver()1005     public ContentResolver getContentResolver() {
1006         if (mContentResolver == null) {
1007             mContentResolver = new BridgeContentResolver(this);
1008         }
1009         return mContentResolver;
1010     }
1011 
1012     @Override
getDatabasePath(String arg0)1013     public File getDatabasePath(String arg0) {
1014         // pass
1015         return null;
1016     }
1017 
1018     @Override
getDir(String arg0, int arg1)1019     public File getDir(String arg0, int arg1) {
1020         // pass
1021         return null;
1022     }
1023 
1024     @Override
getFileStreamPath(String arg0)1025     public File getFileStreamPath(String arg0) {
1026         // pass
1027         return null;
1028     }
1029 
1030     @Override
getFilesDir()1031     public File getFilesDir() {
1032         // pass
1033         return null;
1034     }
1035 
1036     @Override
getExternalFilesDir(String type)1037     public File getExternalFilesDir(String type) {
1038         // pass
1039         return null;
1040     }
1041 
1042     @Override
getPackageCodePath()1043     public String getPackageCodePath() {
1044         // pass
1045         return null;
1046     }
1047 
1048     @Override
getPackageManager()1049     public PackageManager getPackageManager() {
1050         // pass
1051         return null;
1052     }
1053 
1054     @Override
getPackageName()1055     public String getPackageName() {
1056         // pass
1057         return null;
1058     }
1059 
1060     @Override
getApplicationInfo()1061     public ApplicationInfo getApplicationInfo() {
1062         return mApplicationInfo;
1063     }
1064 
1065     @Override
getPackageResourcePath()1066     public String getPackageResourcePath() {
1067         // pass
1068         return null;
1069     }
1070 
1071     @Override
getSharedPrefsFile(String name)1072     public File getSharedPrefsFile(String name) {
1073         // pass
1074         return null;
1075     }
1076 
1077     @Override
getSharedPreferences(String arg0, int arg1)1078     public SharedPreferences getSharedPreferences(String arg0, int arg1) {
1079         // pass
1080         return null;
1081     }
1082 
1083     @Override
getWallpaper()1084     public Drawable getWallpaper() {
1085         // pass
1086         return null;
1087     }
1088 
1089     @Override
getWallpaperDesiredMinimumWidth()1090     public int getWallpaperDesiredMinimumWidth() {
1091         return -1;
1092     }
1093 
1094     @Override
getWallpaperDesiredMinimumHeight()1095     public int getWallpaperDesiredMinimumHeight() {
1096         return -1;
1097     }
1098 
1099     @Override
grantUriPermission(String arg0, Uri arg1, int arg2)1100     public void grantUriPermission(String arg0, Uri arg1, int arg2) {
1101         // pass
1102 
1103     }
1104 
1105     @Override
openFileInput(String arg0)1106     public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
1107         // pass
1108         return null;
1109     }
1110 
1111     @Override
openFileOutput(String arg0, int arg1)1112     public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
1113         // pass
1114         return null;
1115     }
1116 
1117     @Override
openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2)1118     public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
1119         // pass
1120         return null;
1121     }
1122 
1123     @Override
openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2, DatabaseErrorHandler arg3)1124     public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
1125             CursorFactory arg2, DatabaseErrorHandler arg3) {
1126         // pass
1127         return null;
1128     }
1129 
1130     @Override
peekWallpaper()1131     public Drawable peekWallpaper() {
1132         // pass
1133         return null;
1134     }
1135 
1136     @Override
registerReceiver(BroadcastReceiver arg0, IntentFilter arg1)1137     public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) {
1138         // pass
1139         return null;
1140     }
1141 
1142     @Override
registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, String arg2, Handler arg3)1143     public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
1144             String arg2, Handler arg3) {
1145         // pass
1146         return null;
1147     }
1148 
1149     @Override
removeStickyBroadcast(Intent arg0)1150     public void removeStickyBroadcast(Intent arg0) {
1151         // pass
1152 
1153     }
1154 
1155     @Override
revokeUriPermission(Uri arg0, int arg1)1156     public void revokeUriPermission(Uri arg0, int arg1) {
1157         // pass
1158 
1159     }
1160 
1161     @Override
sendBroadcast(Intent arg0)1162     public void sendBroadcast(Intent arg0) {
1163         // pass
1164 
1165     }
1166 
1167     @Override
sendBroadcast(Intent arg0, String arg1)1168     public void sendBroadcast(Intent arg0, String arg1) {
1169         // pass
1170 
1171     }
1172 
1173     @Override
sendOrderedBroadcast(Intent arg0, String arg1)1174     public void sendOrderedBroadcast(Intent arg0, String arg1) {
1175         // pass
1176 
1177     }
1178 
1179     @Override
sendOrderedBroadcast(Intent arg0, String arg1, BroadcastReceiver arg2, Handler arg3, int arg4, String arg5, Bundle arg6)1180     public void sendOrderedBroadcast(Intent arg0, String arg1,
1181             BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
1182             Bundle arg6) {
1183         // pass
1184 
1185     }
1186 
1187     @Override
sendStickyBroadcast(Intent arg0)1188     public void sendStickyBroadcast(Intent arg0) {
1189         // pass
1190 
1191     }
1192 
1193     @Override
sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)1194     public void sendStickyOrderedBroadcast(Intent intent,
1195             BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
1196            Bundle initialExtras) {
1197         // pass
1198     }
1199 
1200     @Override
setTheme(int arg0)1201     public void setTheme(int arg0) {
1202         // pass
1203 
1204     }
1205 
1206     @Override
setWallpaper(Bitmap arg0)1207     public void setWallpaper(Bitmap arg0) throws IOException {
1208         // pass
1209 
1210     }
1211 
1212     @Override
setWallpaper(InputStream arg0)1213     public void setWallpaper(InputStream arg0) throws IOException {
1214         // pass
1215 
1216     }
1217 
1218     @Override
startActivity(Intent arg0)1219     public void startActivity(Intent arg0) {
1220         // pass
1221     }
1222 
1223     @Override
startActivity(Intent arg0, Bundle arg1)1224     public void startActivity(Intent arg0, Bundle arg1) {
1225         // pass
1226     }
1227 
1228     @Override
startIntentSender(IntentSender intent, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)1229     public void startIntentSender(IntentSender intent,
1230             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
1231             throws IntentSender.SendIntentException {
1232         // pass
1233     }
1234 
1235     @Override
startIntentSender(IntentSender intent, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options)1236     public void startIntentSender(IntentSender intent,
1237             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
1238             Bundle options) throws IntentSender.SendIntentException {
1239         // pass
1240     }
1241 
1242     @Override
startInstrumentation(ComponentName arg0, String arg1, Bundle arg2)1243     public boolean startInstrumentation(ComponentName arg0, String arg1,
1244             Bundle arg2) {
1245         // pass
1246         return false;
1247     }
1248 
1249     @Override
startService(Intent arg0)1250     public ComponentName startService(Intent arg0) {
1251         // pass
1252         return null;
1253     }
1254 
1255     @Override
stopService(Intent arg0)1256     public boolean stopService(Intent arg0) {
1257         // pass
1258         return false;
1259     }
1260 
1261     @Override
unbindService(ServiceConnection arg0)1262     public void unbindService(ServiceConnection arg0) {
1263         // pass
1264 
1265     }
1266 
1267     @Override
unregisterReceiver(BroadcastReceiver arg0)1268     public void unregisterReceiver(BroadcastReceiver arg0) {
1269         // pass
1270 
1271     }
1272 
1273     @Override
getApplicationContext()1274     public Context getApplicationContext() {
1275         return this;
1276     }
1277 
1278     @Override
startActivities(Intent[] arg0)1279     public void startActivities(Intent[] arg0) {
1280         // pass
1281 
1282     }
1283 
1284     @Override
startActivities(Intent[] arg0, Bundle arg1)1285     public void startActivities(Intent[] arg0, Bundle arg1) {
1286         // pass
1287 
1288     }
1289 
1290     @Override
isRestricted()1291     public boolean isRestricted() {
1292         return false;
1293     }
1294 
1295     @Override
getObbDir()1296     public File getObbDir() {
1297         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
1298         return null;
1299     }
1300 }
1301