BridgeContext.java revision efa199f016985b0a9d0471e42c803ee9f7941f0e
147d431f63a66505a645f282416659a9758a91f1cBrett Chabot/*
247d431f63a66505a645f282416659a9758a91f1cBrett Chabot * Copyright (C) 2008 The Android Open Source Project
347d431f63a66505a645f282416659a9758a91f1cBrett Chabot *
447d431f63a66505a645f282416659a9758a91f1cBrett Chabot * Licensed under the Apache License, Version 2.0 (the "License");
547d431f63a66505a645f282416659a9758a91f1cBrett Chabot * you may not use this file except in compliance with the License.
647d431f63a66505a645f282416659a9758a91f1cBrett Chabot * You may obtain a copy of the License at
747d431f63a66505a645f282416659a9758a91f1cBrett Chabot *
847d431f63a66505a645f282416659a9758a91f1cBrett Chabot *      http://www.apache.org/licenses/LICENSE-2.0
947d431f63a66505a645f282416659a9758a91f1cBrett Chabot *
1047d431f63a66505a645f282416659a9758a91f1cBrett Chabot * Unless required by applicable law or agreed to in writing, software
1147d431f63a66505a645f282416659a9758a91f1cBrett Chabot * distributed under the License is distributed on an "AS IS" BASIS,
1247d431f63a66505a645f282416659a9758a91f1cBrett Chabot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1347d431f63a66505a645f282416659a9758a91f1cBrett Chabot * See the License for the specific language governing permissions and
1447d431f63a66505a645f282416659a9758a91f1cBrett Chabot * limitations under the License.
1547d431f63a66505a645f282416659a9758a91f1cBrett Chabot */
1647d431f63a66505a645f282416659a9758a91f1cBrett Chabot
1747d431f63a66505a645f282416659a9758a91f1cBrett Chabotpackage com.android.layoutlib.bridge;
1847d431f63a66505a645f282416659a9758a91f1cBrett Chabot
1947d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport com.android.layoutlib.api.ILayoutLog;
2047d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport com.android.layoutlib.api.IProjectCallback;
2147d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport com.android.layoutlib.api.IResourceValue;
2247d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport com.android.layoutlib.api.IStyleResourceValue;
2347d431f63a66505a645f282416659a9758a91f1cBrett Chabot
2447d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.BroadcastReceiver;
2547d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.ComponentName;
2647d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.ContentResolver;
2747d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.Context;
2847d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.Intent;
2947d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.IntentFilter;
3047d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.IntentSender;
3147d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.ServiceConnection;
3247d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.SharedPreferences;
3347d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.pm.ApplicationInfo;
3447d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.pm.PackageManager;
3547d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.res.AssetManager;
3647d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.res.Configuration;
3747d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.res.Resources;
3847d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.res.TypedArray;
3947d431f63a66505a645f282416659a9758a91f1cBrett Chabotimport android.content.res.Resources.Theme;
40import android.database.sqlite.SQLiteDatabase;
41import android.database.sqlite.SQLiteDatabase.CursorFactory;
42import android.graphics.Bitmap;
43import android.graphics.drawable.Drawable;
44import android.net.Uri;
45import android.os.Bundle;
46import android.os.Handler;
47import android.os.Looper;
48import android.util.AttributeSet;
49import android.util.DisplayMetrics;
50import android.view.BridgeInflater;
51import android.view.View;
52
53import java.io.File;
54import java.io.FileInputStream;
55import java.io.FileNotFoundException;
56import java.io.FileOutputStream;
57import java.io.IOException;
58import java.io.InputStream;
59import java.util.HashMap;
60import java.util.Map;
61import java.util.TreeMap;
62import java.util.Map.Entry;
63
64/**
65 * Custom implementation of Context to handle non compiled resources.
66 */
67public final class BridgeContext extends Context {
68
69    private Resources mResources;
70    private Theme mTheme;
71    private HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
72    private IStyleResourceValue mThemeValues;
73    private final Object mProjectKey;
74    private Map<String, Map<String, IResourceValue>> mProjectResources;
75    private Map<String, Map<String, IResourceValue>> mFrameworkResources;
76    private Map<IStyleResourceValue, IStyleResourceValue> mStyleInheritanceMap;
77
78    // maps for dynamically generated id representing style objects (IStyleResourceValue)
79    private Map<Integer, IStyleResourceValue> mDynamicIdToStyleMap;
80    private Map<IStyleResourceValue, Integer> mStyleToDynamicIdMap;
81    private int mDynamicIdGenerator = 0x01030000; // Base id for framework R.style
82
83    // cache for TypedArray generated from IStyleResourceValue object
84    private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
85    private BridgeInflater mInflater;
86
87    private final IProjectCallback mProjectCallback;
88    private final ILayoutLog mLogger;
89    private BridgeContentResolver mContentResolver;
90
91    /**
92     * @param projectKey An Object identifying the project. This is used for the cache mechanism.
93     * @param metrics the {@link DisplayMetrics}.
94     * @param themeName The name of the theme to use.
95     * @param projectResources the resources of the project. The map contains (String, map) pairs
96     * where the string is the type of the resource reference used in the layout file, and the
97     * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
98     * and the value is the resource value.
99     * @param frameworkResources the framework resources. The map contains (String, map) pairs
100     * where the string is the type of the resource reference used in the layout file, and the map
101     * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
102     * value is the resource value.
103     * @param styleInheritanceMap
104     * @param customViewLoader
105     */
106    public BridgeContext(Object projectKey, DisplayMetrics metrics,
107            IStyleResourceValue currentTheme,
108            Map<String, Map<String, IResourceValue>> projectResources,
109            Map<String, Map<String, IResourceValue>> frameworkResources,
110            Map<IStyleResourceValue, IStyleResourceValue> styleInheritanceMap,
111            IProjectCallback customViewLoader, ILayoutLog logger) {
112        mProjectKey = projectKey;
113        mProjectCallback = customViewLoader;
114        mLogger = logger;
115        Configuration config = new Configuration();
116
117        AssetManager assetManager = BridgeAssetManager.initSystem();
118        mResources = BridgeResources.initSystem(
119                this,
120                assetManager,
121                metrics,
122                config,
123                customViewLoader);
124
125        mTheme = mResources.newTheme();
126
127        mThemeValues = currentTheme;
128        mProjectResources = projectResources;
129        mFrameworkResources = frameworkResources;
130        mStyleInheritanceMap = styleInheritanceMap;
131    }
132
133    public void setBridgeInflater(BridgeInflater inflater) {
134        mInflater = inflater;
135    }
136
137    public void addViewKey(View view, Object viewKey) {
138        mViewKeyMap.put(view, viewKey);
139    }
140
141    public Object getViewKey(View view) {
142        return mViewKeyMap.get(view);
143    }
144
145    public Object getProjectKey() {
146        return mProjectKey;
147    }
148
149    public IProjectCallback getProjectCallback() {
150        return mProjectCallback;
151    }
152
153    public ILayoutLog getLogger() {
154        return mLogger;
155    }
156
157    // ------------ Context methods
158
159    @Override
160    public Resources getResources() {
161        return mResources;
162    }
163
164    @Override
165    public Theme getTheme() {
166        return mTheme;
167    }
168
169    @Override
170    public ClassLoader getClassLoader() {
171        return this.getClass().getClassLoader();
172    }
173
174    @Override
175    public Object getSystemService(String service) {
176        if (LAYOUT_INFLATER_SERVICE.equals(service)) {
177            return mInflater;
178        }
179
180        // AutoCompleteTextView and MultiAutoCompleteTextView want a window
181        // service. We don't have any but it's not worth an exception.
182        if (WINDOW_SERVICE.equals(service)) {
183            return null;
184        }
185
186        throw new UnsupportedOperationException("Unsupported Service: " + service);
187    }
188
189
190    @Override
191    public final TypedArray obtainStyledAttributes(int[] attrs) {
192        return createStyleBasedTypedArray(mThemeValues, attrs);
193    }
194
195    @Override
196    public final TypedArray obtainStyledAttributes(int resid, int[] attrs)
197            throws Resources.NotFoundException {
198        // get the IStyleResourceValue based on the resId;
199        IStyleResourceValue style = getStyleByDynamicId(resid);
200
201        if (style == null) {
202            throw new Resources.NotFoundException();
203        }
204
205        if (mTypedArrayCache == null) {
206            mTypedArrayCache = new HashMap<int[], Map<Integer,TypedArray>>();
207
208            Map<Integer, TypedArray> map = new HashMap<Integer, TypedArray>();
209            mTypedArrayCache.put(attrs, map);
210
211            BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs);
212            map.put(resid, ta);
213
214            return ta;
215        }
216
217        // get the 2nd map
218        Map<Integer, TypedArray> map = mTypedArrayCache.get(attrs);
219        if (map == null) {
220            map = new HashMap<Integer, TypedArray>();
221            mTypedArrayCache.put(attrs, map);
222        }
223
224        // get the array from the 2nd map
225        TypedArray ta = map.get(resid);
226
227        if (ta == null) {
228            ta = createStyleBasedTypedArray(style, attrs);
229            map.put(resid, ta);
230        }
231
232        return ta;
233    }
234
235    @Override
236    public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) {
237        return obtainStyledAttributes(set, attrs, 0, 0);
238    }
239
240    @Override
241    public TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
242            int defStyleAttr, int defStyleRes) {
243
244        // Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
245        BridgeXmlBlockParser parser = null;
246        if (set instanceof BridgeXmlBlockParser) {
247            parser = (BridgeXmlBlockParser)set;
248        } else {
249            // reall this should not be happening since its instantiated in Bridge
250            mLogger.error("Parser is not a BridgeXmlBlockParser!");
251            return null;
252        }
253
254        boolean[] frameworkAttributes = new boolean[1];
255        TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes);
256
257        BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
258                parser.isPlatformFile());
259
260        // resolve the defStyleAttr value into a IStyleResourceValue
261        IStyleResourceValue defStyleValues = null;
262        if (defStyleAttr != 0) {
263            // get the name from the int.
264            String defStyleName = searchAttr(defStyleAttr);
265
266            // look for the style in the current theme, and its parent:
267            if (mThemeValues != null) {
268                IResourceValue item = findItemInStyle(mThemeValues, defStyleName);
269
270                if (item != null) {
271                    // item is a reference to a style entry. Search for it.
272                    item = findResValue(item.getValue());
273
274                    if (item instanceof IStyleResourceValue) {
275                        defStyleValues = (IStyleResourceValue)item;
276                    }
277                } else {
278                    // TODO: log the error properly
279                    System.out.println("Failed to find defStyle: " + defStyleName);
280                }
281            }
282        }
283
284        if (defStyleRes != 0) {
285            // FIXME: See what we need to do with this.
286            throw new UnsupportedOperationException();
287        }
288
289        String namespace = BridgeConstants.NS_RESOURCES;
290        if (frameworkAttributes[0] == false) {
291            // need to use the application namespace
292            namespace = mProjectCallback.getNamespace();
293        }
294
295        if (styleNameMap != null) {
296            for (Entry<Integer, String> styleAttribute : styleNameMap.entrySet()) {
297                int index = styleAttribute.getKey().intValue();
298
299                String name = styleAttribute.getValue();
300                String value = parser.getAttributeValue(namespace, name);
301
302                // if there's no direct value for this attribute in the XML, we look for default
303                // values in the widget defStyle, and then in the theme.
304                if (value == null) {
305                    IResourceValue resValue = null;
306
307                    // look for the value in the defStyle first (and its parent if needed)
308                    if (defStyleValues != null) {
309                        resValue = findItemInStyle(defStyleValues, name);
310                    }
311
312                    // if the item is not present in the defStyle, we look in the main theme (and
313                    // its parent themes)
314                    if (resValue == null && mThemeValues != null) {
315                        resValue = findItemInStyle(mThemeValues, name);
316                    }
317
318                    // if we found a value, we make sure this doesn't reference another value.
319                    // So we resolve it.
320                    if (resValue != null) {
321                        resValue = resolveResValue(resValue);
322                    }
323
324                    ta.bridgeSetValue(index, name, resValue);
325                } else {
326                    // there is a value in the XML, but we need to resolve it in case it's
327                    // referencing another resource or a theme value.
328                    ta.bridgeSetValue(index, name, resolveValue(null, name, value));
329                }
330            }
331        }
332
333        ta.sealArray();
334
335        return ta;
336    }
337
338    @Override
339    public Looper getMainLooper() {
340        return Looper.myLooper();
341    }
342
343
344    // ------------- private new methods
345
346    /**
347     * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
348     * values found in the given style.
349     * @see #obtainStyledAttributes(int, int[])
350     */
351    private BridgeTypedArray createStyleBasedTypedArray(IStyleResourceValue style, int[] attrs)
352            throws Resources.NotFoundException {
353        TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, null);
354
355        BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
356                false /* platformResourceFlag */);
357
358        // loop through all the values in the style map, and init the TypedArray with
359        // the style we got from the dynamic id
360        for (Entry<Integer, String> styleAttribute : styleNameMap.entrySet()) {
361            int index = styleAttribute.getKey().intValue();
362
363            String name = styleAttribute.getValue();
364
365            // get the value from the style, or its parent styles.
366            IResourceValue resValue = findItemInStyle(style, name);
367
368            // resolve it to make sure there are no references left.
369            ta.bridgeSetValue(index, name, resolveResValue(resValue));
370        }
371
372        ta.sealArray();
373
374        return ta;
375    }
376
377
378    /**
379     * Resolves the value of a resource, if the value references a theme or resource value.
380     * <p/>
381     * This method ensures that it returns a {@link IResourceValue} object that does not
382     * reference another resource.
383     * If the resource cannot be resolved, it returns <code>null</code>.
384     * <p/>
385     * If a value that does not need to be resolved is given, the method will return a new
386     * instance of IResourceValue that contains the input value.
387     *
388     * @param type the type of the resource
389     * @param name the name of the attribute containing this value.
390     * @param value the resource value, or reference to resolve
391     * @return the resolved resource value or <code>null</code> if it failed to resolve it.
392     */
393    private IResourceValue resolveValue(String type, String name, String value) {
394        if (value == null) {
395            return null;
396        }
397
398        // get the IResourceValue referenced by this value
399        IResourceValue resValue = findResValue(value);
400
401        // if resValue is null, but value is not null, this means it was not a reference.
402        // we return the name/value wrapper in a IResourceValue
403        if (resValue == null) {
404            return new ResourceValue(type, name, value);
405        }
406
407        // we resolved a first reference, but we need to make sure this isn't a reference also.
408        return resolveResValue(resValue);
409    }
410
411    /**
412     * Returns the {@link IResourceValue} referenced by the value of <var>value</var>.
413     * <p/>
414     * This method ensures that it returns a {@link IResourceValue} object that does not
415     * reference another resource.
416     * If the resource cannot be resolved, it returns <code>null</code>.
417     * <p/>
418     * If a value that does not need to be resolved is given, the method will return the input
419     * value.
420     *
421     * @param value the value containing the reference to resolve.
422     * @return a {@link IResourceValue} object or <code>null</code>
423     */
424    IResourceValue resolveResValue(IResourceValue value) {
425        if (value == null) {
426            return null;
427        }
428
429        // if the resource value is a style, we simply return it.
430        if (value instanceof IStyleResourceValue) {
431            return value;
432        }
433
434        // else attempt to find another IResourceValue referenced by this one.
435        IResourceValue resolvedValue = findResValue(value.getValue());
436
437        // if the value did not reference anything, then we simply return the input value
438        if (resolvedValue == null) {
439            return value;
440        }
441
442        // otherwise, we attempt to resolve this new value as well
443        return resolveResValue(resolvedValue);
444    }
445
446    /**
447     * Searches for, and returns a {@link IResourceValue} by its reference.
448     * <p/>
449     * The reference format can be:
450     * <pre>@resType/resName</pre>
451     * <pre>@android:resType/resName</pre>
452     * <pre>@resType/android:resName</pre>
453     * <pre>?resType/resName</pre>
454     * <pre>?android:resType/resName</pre>
455     * <pre>?resType/android:resName</pre>
456     * Any other string format will return <code>null</code>.
457     * <p/>
458     * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
459     * only support the android namespace.
460     *
461     * @param reference the resource reference to search for.
462     * @return a {@link IResourceValue} or <code>null</code>.
463     */
464    IResourceValue findResValue(String reference) {
465        if (reference == null) {
466            return null;
467        }
468        if (reference.startsWith(BridgeConstants.PREFIX_THEME_REF)) {
469            // no theme? no need to go further!
470            if (mThemeValues == null) {
471                return null;
472            }
473
474            boolean frameworkOnly = false;
475
476            // eleminate the prefix from the string
477            if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_THEME_REF)) {
478                frameworkOnly = true;
479                reference = reference.substring(BridgeConstants.PREFIX_ANDROID_THEME_REF.length());
480            } else {
481                reference = reference.substring(BridgeConstants.PREFIX_THEME_REF.length());
482            }
483
484            // at this point, value can contain type/name (drawable/foo for instance).
485            // split it to make sure.
486            String[] segments = reference.split("\\/");
487
488            // we look for the referenced item name.
489            String referenceName = null;
490
491            if (segments.length == 2) {
492                // there was a resType in the reference. If it's attr, we ignore it
493                // else, we assert for now.
494                if (BridgeConstants.RES_ATTR.equals(segments[0])) {
495                    referenceName = segments[1];
496                } else {
497                    // At this time, no support for ?type/name where type is not "attr"
498                    return null;
499                }
500            } else {
501                // it's just an item name.
502                referenceName = segments[0];
503            }
504
505            // now we look for android: in the referenceName in order to support format
506            // such as: ?attr/android:name
507            if (referenceName.startsWith(BridgeConstants.PREFIX_ANDROID)) {
508                frameworkOnly = true;
509                referenceName = referenceName.substring(BridgeConstants.PREFIX_ANDROID.length());
510            }
511
512            // Now look for the item in the theme, starting with the current one.
513            if (frameworkOnly) {
514                // FIXME for now we do the same as if it didn't specify android:
515                return findItemInStyle(mThemeValues, referenceName);
516            }
517
518            return findItemInStyle(mThemeValues, referenceName);
519        } else if (reference.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
520            boolean frameworkOnly = false;
521
522            // check for the specific null reference value.
523            if (BridgeConstants.REFERENCE_NULL.equals(reference)) {
524                return null;
525            }
526
527            // Eliminate the prefix from the string.
528            if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_RESOURCE_REF)) {
529                frameworkOnly = true;
530                reference = reference.substring(
531                        BridgeConstants.PREFIX_ANDROID_RESOURCE_REF.length());
532            } else {
533                reference = reference.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
534            }
535
536            // at this point, value contains type/[android:]name (drawable/foo for instance)
537            String[] segments = reference.split("\\/");
538
539            // now we look for android: in the resource name in order to support format
540            // such as: @drawable/android:name
541            if (segments[1].startsWith(BridgeConstants.PREFIX_ANDROID)) {
542                frameworkOnly = true;
543                segments[1] = segments[1].substring(BridgeConstants.PREFIX_ANDROID.length());
544            }
545
546            return findResValue(segments[0], segments[1], frameworkOnly);
547        }
548
549        // Looks like the value didn't reference anything. Return null.
550        return null;
551    }
552
553    /**
554     * Searches for, and returns a {@link IResourceValue} by its name, and type.
555     * @param resType the type of the resource
556     * @param resName  the name of the resource
557     * @param frameworkOnly if <code>true</code>, the method does not search in the
558     * project resources
559     */
560    private IResourceValue findResValue(String resType, String resName, boolean frameworkOnly) {
561        // map of IResouceValue for the given type
562        Map<String, IResourceValue> typeMap;
563
564        // if allowed, search in the project resources first.
565        if (frameworkOnly == false) {
566            typeMap = mProjectResources.get(resType);
567            if (typeMap != null) {
568                IResourceValue item = typeMap.get(resName);
569                if (item != null) {
570                    return item;
571                }
572            }
573        }
574
575        // now search in the framework resources.
576        typeMap = mFrameworkResources.get(resType);
577        if (typeMap != null) {
578            IResourceValue item = typeMap.get(resName);
579            if (item != null) {
580                return item;
581            }
582        }
583
584        // didn't find the resource anywhere.
585        return null;
586    }
587
588    /**
589     * Returns a framework resource by type and name. The returned resource is resolved.
590     * @param resourceType the type of the resource
591     * @param resourceName the name of the resource
592     */
593    public IResourceValue getFrameworkResource(String resourceType, String resourceName) {
594        return getResource(resourceType, resourceName, mFrameworkResources);
595    }
596
597    /**
598     * Returns a project resource by type and name. The returned resource is resolved.
599     * @param resourceType the type of the resource
600     * @param resourceName the name of the resource
601     */
602    public IResourceValue getProjectResource(String resourceType, String resourceName) {
603        return getResource(resourceType, resourceName, mProjectResources);
604    }
605
606    IResourceValue getResource(String resourceType, String resourceName,
607            Map<String, Map<String, IResourceValue>> resourceRepository) {
608        Map<String, IResourceValue> typeMap = resourceRepository.get(resourceType);
609        if (typeMap != null) {
610            IResourceValue item = typeMap.get(resourceName);
611            if (item != null) {
612                item = resolveResValue(item);
613                return item;
614            }
615        }
616
617        // didn't find the resource anywhere.
618        return null;
619
620    }
621
622    /**
623     * Returns the {@link IResourceValue} matching a given name in a given style. If the
624     * item is not directly available in the style, the method looks in its parent style.
625     * @param style the style to search in
626     * @param itemName the name of the item to search for.
627     * @return the {@link IResourceValue} object or <code>null</code>
628     */
629    IResourceValue findItemInStyle(IStyleResourceValue style, String itemName) {
630        IResourceValue item = style.findItem(itemName);
631
632        // if we didn't find it, we look in the parent style (if applicable)
633        if (item == null && mStyleInheritanceMap != null) {
634            IStyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
635            if (parentStyle != null) {
636                return findItemInStyle(parentStyle, itemName);
637            }
638        }
639
640        return item;
641    }
642
643    /**
644     * The input int[] attrs is one of com.android.internal.R.styleable fields where the name
645     * of the field is the style being referenced and the array contains one index per attribute.
646     * <p/>
647     * searchAttrs() finds all the names of the attributes referenced so for example if
648     * attrs == com.android.internal.R.styleable.View, this returns the list of the "xyz" where
649     * there's a field com.android.internal.R.styleable.View_xyz and the field value is the index
650     * that is used to reference the attribute later in the TypedArray.
651     *
652     * @param attrs An attribute array reference given to obtainStyledAttributes.
653     * @return A sorted map Attribute-Value to Attribute-Name for all attributes declared by the
654     *         attribute array. Returns null if nothing is found.
655     */
656    private TreeMap<Integer,String> searchAttrs(int[] attrs, boolean[] outFrameworkFlag) {
657        // get the name of the array from the framework resources
658        String arrayName = Bridge.resolveResourceValue(attrs);
659        if (arrayName != null) {
660            // if we found it, get the name of each of the int in the array.
661            TreeMap<Integer,String> attributes = new TreeMap<Integer, String>();
662            for (int i = 0 ; i < attrs.length ; i++) {
663                String[] info = Bridge.resolveResourceValue(attrs[i]);
664                if (info != null) {
665                    attributes.put(i, info[0]);
666                } else {
667                    // FIXME Not sure what we should be doing here...
668                    attributes.put(i, null);
669                }
670            }
671
672            if (outFrameworkFlag != null) {
673                outFrameworkFlag[0] = true;
674            }
675
676            return attributes;
677        }
678
679        // if the name was not found in the framework resources, look in the project
680        // resources
681        arrayName = mProjectCallback.resolveResourceValue(attrs);
682        if (arrayName != null) {
683            TreeMap<Integer,String> attributes = new TreeMap<Integer, String>();
684            for (int i = 0 ; i < attrs.length ; i++) {
685                String[] info = mProjectCallback.resolveResourceValue(attrs[i]);
686                if (info != null) {
687                    attributes.put(i, info[0]);
688                } else {
689                    // FIXME Not sure what we should be doing here...
690                    attributes.put(i, null);
691                }
692            }
693
694            if (outFrameworkFlag != null) {
695                outFrameworkFlag[0] = false;
696            }
697
698            return attributes;
699        }
700
701        return null;
702    }
703
704    /**
705     * Searches for the attribute referenced by its internal id.
706     *
707     * @param attr An attribute reference given to obtainStyledAttributes such as defStyle.
708     * @return The unique name of the attribute, if found, e.g. "buttonStyle". Returns null
709     *         if nothing is found.
710     */
711    public String searchAttr(int attr) {
712        String[] info = Bridge.resolveResourceValue(attr);
713        if (info != null) {
714            return info[0];
715        }
716
717        info = mProjectCallback.resolveResourceValue(attr);
718        if (info != null) {
719            return info[0];
720        }
721
722        return null;
723    }
724
725    int getDynamicIdByStyle(IStyleResourceValue resValue) {
726        if (mDynamicIdToStyleMap == null) {
727            // create the maps.
728            mDynamicIdToStyleMap = new HashMap<Integer, IStyleResourceValue>();
729            mStyleToDynamicIdMap = new HashMap<IStyleResourceValue, Integer>();
730        }
731
732        // look for an existing id
733        Integer id = mStyleToDynamicIdMap.get(resValue);
734
735        if (id == null) {
736            // generate a new id
737            id = Integer.valueOf(++mDynamicIdGenerator);
738
739            // and add it to the maps.
740            mDynamicIdToStyleMap.put(id, resValue);
741            mStyleToDynamicIdMap.put(resValue, id);
742        }
743
744        return id;
745    }
746
747    private IStyleResourceValue getStyleByDynamicId(int i) {
748        if (mDynamicIdToStyleMap != null) {
749            return mDynamicIdToStyleMap.get(i);
750        }
751
752        return null;
753    }
754
755    int getFrameworkIdValue(String idName, int defValue) {
756        Integer value = Bridge.getResourceValue(BridgeConstants.RES_ID, idName);
757        if (value != null) {
758            return value.intValue();
759        }
760
761        return defValue;
762    }
763
764    int getProjectIdValue(String idName, int defValue) {
765        if (mProjectCallback != null) {
766            Integer value = mProjectCallback.getResourceValue(BridgeConstants.RES_ID, idName);
767            if (value != null) {
768                return value.intValue();
769            }
770        }
771
772        return defValue;
773    }
774
775    //------------ NOT OVERRIDEN --------------------
776
777    @Override
778    public boolean bindService(Intent arg0, ServiceConnection arg1, int arg2) {
779        // TODO Auto-generated method stub
780        return false;
781    }
782
783    @Override
784    public int checkCallingOrSelfPermission(String arg0) {
785        // TODO Auto-generated method stub
786        return 0;
787    }
788
789    @Override
790    public int checkCallingOrSelfUriPermission(Uri arg0, int arg1) {
791        // TODO Auto-generated method stub
792        return 0;
793    }
794
795    @Override
796    public int checkCallingPermission(String arg0) {
797        // TODO Auto-generated method stub
798        return 0;
799    }
800
801    @Override
802    public int checkCallingUriPermission(Uri arg0, int arg1) {
803        // TODO Auto-generated method stub
804        return 0;
805    }
806
807    @Override
808    public int checkPermission(String arg0, int arg1, int arg2) {
809        // TODO Auto-generated method stub
810        return 0;
811    }
812
813    @Override
814    public int checkUriPermission(Uri arg0, int arg1, int arg2, int arg3) {
815        // TODO Auto-generated method stub
816        return 0;
817    }
818
819    @Override
820    public int checkUriPermission(Uri arg0, String arg1, String arg2, int arg3,
821            int arg4, int arg5) {
822        // TODO Auto-generated method stub
823        return 0;
824    }
825
826    @Override
827    public void clearWallpaper() {
828        // TODO Auto-generated method stub
829
830    }
831
832    @Override
833    public Context createPackageContext(String arg0, int arg1) {
834        // TODO Auto-generated method stub
835        return null;
836    }
837
838    @Override
839    public String[] databaseList() {
840        // TODO Auto-generated method stub
841        return null;
842    }
843
844    @Override
845    public boolean deleteDatabase(String arg0) {
846        // TODO Auto-generated method stub
847        return false;
848    }
849
850    @Override
851    public boolean deleteFile(String arg0) {
852        // TODO Auto-generated method stub
853        return false;
854    }
855
856    @Override
857    public void enforceCallingOrSelfPermission(String arg0, String arg1) {
858        // TODO Auto-generated method stub
859
860    }
861
862    @Override
863    public void enforceCallingOrSelfUriPermission(Uri arg0, int arg1,
864            String arg2) {
865        // TODO Auto-generated method stub
866
867    }
868
869    @Override
870    public void enforceCallingPermission(String arg0, String arg1) {
871        // TODO Auto-generated method stub
872
873    }
874
875    @Override
876    public void enforceCallingUriPermission(Uri arg0, int arg1, String arg2) {
877        // TODO Auto-generated method stub
878
879    }
880
881    @Override
882    public void enforcePermission(String arg0, int arg1, int arg2, String arg3) {
883        // TODO Auto-generated method stub
884
885    }
886
887    @Override
888    public void enforceUriPermission(Uri arg0, int arg1, int arg2, int arg3,
889            String arg4) {
890        // TODO Auto-generated method stub
891
892    }
893
894    @Override
895    public void enforceUriPermission(Uri arg0, String arg1, String arg2,
896            int arg3, int arg4, int arg5, String arg6) {
897        // TODO Auto-generated method stub
898
899    }
900
901    @Override
902    public String[] fileList() {
903        // TODO Auto-generated method stub
904        return null;
905    }
906
907    @Override
908    public AssetManager getAssets() {
909        // TODO Auto-generated method stub
910        return null;
911    }
912
913    @Override
914    public File getCacheDir() {
915        // TODO Auto-generated method stub
916        return null;
917    }
918
919    @Override
920    public ContentResolver getContentResolver() {
921        if (mContentResolver == null) {
922            mContentResolver = new BridgeContentResolver(this);
923        }
924        return mContentResolver;
925    }
926
927    @Override
928    public File getDatabasePath(String arg0) {
929        // TODO Auto-generated method stub
930        return null;
931    }
932
933    @Override
934    public File getDir(String arg0, int arg1) {
935        // TODO Auto-generated method stub
936        return null;
937    }
938
939    @Override
940    public File getFileStreamPath(String arg0) {
941        // TODO Auto-generated method stub
942        return null;
943    }
944
945    @Override
946    public File getFilesDir() {
947        // TODO Auto-generated method stub
948        return null;
949    }
950
951    @Override
952    public String getPackageCodePath() {
953        // TODO Auto-generated method stub
954        return null;
955    }
956
957    @Override
958    public PackageManager getPackageManager() {
959        // TODO Auto-generated method stub
960        return null;
961    }
962
963    @Override
964    public String getPackageName() {
965        // TODO Auto-generated method stub
966        return null;
967    }
968
969    @Override
970    public ApplicationInfo getApplicationInfo() {
971        // TODO Auto-generated method stub
972        return null;
973    }
974
975    @Override
976    public String getPackageResourcePath() {
977        // TODO Auto-generated method stub
978        return null;
979    }
980
981    @Override
982    public File getSharedPrefsFile(String name) {
983        // TODO Auto-generated method stub
984        return null;
985    }
986
987    @Override
988    public SharedPreferences getSharedPreferences(String arg0, int arg1) {
989        // TODO Auto-generated method stub
990        return null;
991    }
992
993    @Override
994    public Drawable getWallpaper() {
995        // TODO Auto-generated method stub
996        return null;
997    }
998
999    @Override
1000    public int getWallpaperDesiredMinimumWidth() {
1001        return -1;
1002    }
1003
1004    @Override
1005    public int getWallpaperDesiredMinimumHeight() {
1006        return -1;
1007    }
1008
1009    @Override
1010    public void grantUriPermission(String arg0, Uri arg1, int arg2) {
1011        // TODO Auto-generated method stub
1012
1013    }
1014
1015    @SuppressWarnings("unused")
1016    @Override
1017    public FileInputStream openFileInput(String arg0)
1018            throws FileNotFoundException {
1019        // TODO Auto-generated method stub
1020        return null;
1021    }
1022
1023    @SuppressWarnings("unused")
1024    @Override
1025    public FileOutputStream openFileOutput(String arg0, int arg1)
1026            throws FileNotFoundException {
1027        // TODO Auto-generated method stub
1028        return null;
1029    }
1030
1031    @Override
1032    public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
1033            CursorFactory arg2) {
1034        // TODO Auto-generated method stub
1035        return null;
1036    }
1037
1038    @Override
1039    public Drawable peekWallpaper() {
1040        // TODO Auto-generated method stub
1041        return null;
1042    }
1043
1044    @Override
1045    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1) {
1046        // TODO Auto-generated method stub
1047        return null;
1048    }
1049
1050    @Override
1051    public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
1052            String arg2, Handler arg3) {
1053        // TODO Auto-generated method stub
1054        return null;
1055    }
1056
1057    @Override
1058    public void removeStickyBroadcast(Intent arg0) {
1059        // TODO Auto-generated method stub
1060
1061    }
1062
1063    @Override
1064    public void revokeUriPermission(Uri arg0, int arg1) {
1065        // TODO Auto-generated method stub
1066
1067    }
1068
1069    @Override
1070    public void sendBroadcast(Intent arg0) {
1071        // TODO Auto-generated method stub
1072
1073    }
1074
1075    @Override
1076    public void sendBroadcast(Intent arg0, String arg1) {
1077        // TODO Auto-generated method stub
1078
1079    }
1080
1081    @Override
1082    public void sendOrderedBroadcast(Intent arg0, String arg1) {
1083        // TODO Auto-generated method stub
1084
1085    }
1086
1087    @Override
1088    public void sendOrderedBroadcast(Intent arg0, String arg1,
1089            BroadcastReceiver arg2, Handler arg3, int arg4, String arg5,
1090            Bundle arg6) {
1091        // TODO Auto-generated method stub
1092
1093    }
1094
1095    @Override
1096    public void sendStickyBroadcast(Intent arg0) {
1097        // TODO Auto-generated method stub
1098
1099    }
1100
1101    @Override
1102    public void sendStickyOrderedBroadcast(Intent intent,
1103            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
1104           Bundle initialExtras) {
1105        // TODO Auto-generated method stub
1106    }
1107
1108    @Override
1109    public void setTheme(int arg0) {
1110        // TODO Auto-generated method stub
1111
1112    }
1113
1114    @SuppressWarnings("unused")
1115    @Override
1116    public void setWallpaper(Bitmap arg0) throws IOException {
1117        // TODO Auto-generated method stub
1118
1119    }
1120
1121    @SuppressWarnings("unused")
1122    @Override
1123    public void setWallpaper(InputStream arg0) throws IOException {
1124        // TODO Auto-generated method stub
1125
1126    }
1127
1128    @Override
1129    public void startActivity(Intent arg0) {
1130        // TODO Auto-generated method stub
1131
1132    }
1133
1134    @Override
1135    public void startIntentSender(IntentSender intent,
1136            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
1137            throws IntentSender.SendIntentException {
1138        // TODO Auto-generated method stub
1139    }
1140
1141    @Override
1142    public boolean startInstrumentation(ComponentName arg0, String arg1,
1143            Bundle arg2) {
1144        // TODO Auto-generated method stub
1145        return false;
1146    }
1147
1148    @Override
1149    public ComponentName startService(Intent arg0) {
1150        // TODO Auto-generated method stub
1151        return null;
1152    }
1153
1154    @Override
1155    public boolean stopService(Intent arg0) {
1156        // TODO Auto-generated method stub
1157        return false;
1158    }
1159
1160    @Override
1161    public void unbindService(ServiceConnection arg0) {
1162        // TODO Auto-generated method stub
1163
1164    }
1165
1166    @Override
1167    public void unregisterReceiver(BroadcastReceiver arg0) {
1168        // TODO Auto-generated method stub
1169
1170    }
1171
1172    @Override
1173    public Context getApplicationContext() {
1174        throw new UnsupportedOperationException();
1175    }
1176}
1177