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