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