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