1/*
2 * Copyright (C) 2011 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
17package android.content.res;
18
19import com.android.ide.common.rendering.api.ResourceReference;
20import com.android.ide.common.rendering.api.StyleResourceValue;
21import com.android.layoutlib.bridge.android.BridgeContext;
22import com.android.layoutlib.bridge.impl.DelegateManager;
23import com.android.layoutlib.bridge.impl.RenderSessionImpl;
24import com.android.resources.ResourceType;
25import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
26
27import android.annotation.Nullable;
28import android.content.res.Resources.NotFoundException;
29import android.content.res.Resources.Theme;
30import android.content.res.Resources.ThemeKey;
31import android.util.AttributeSet;
32import android.util.TypedValue;
33
34/**
35 * Delegate used to provide new implementation of a select few methods of {@link Resources.Theme}
36 *
37 * Through the layoutlib_create tool, the original  methods of Theme have been replaced
38 * by calls to methods of the same name in this delegate class.
39 *
40 */
41public class Resources_Theme_Delegate {
42
43    // ---- delegate manager ----
44
45    private static final DelegateManager<Resources_Theme_Delegate> sManager =
46            new DelegateManager<Resources_Theme_Delegate>(Resources_Theme_Delegate.class);
47
48    public static DelegateManager<Resources_Theme_Delegate> getDelegateManager() {
49        return sManager;
50    }
51
52    // ---- delegate methods. ----
53
54    @LayoutlibDelegate
55    /*package*/ static TypedArray obtainStyledAttributes(
56            Resources thisResources, Theme thisTheme,
57            int[] attrs) {
58        boolean changed = setupResources(thisTheme);
59        BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
60        ta.setTheme(thisTheme);
61        restoreResources(changed);
62        return ta;
63    }
64
65    @LayoutlibDelegate
66    /*package*/ static TypedArray obtainStyledAttributes(
67            Resources thisResources, Theme thisTheme,
68            int resid, int[] attrs)
69            throws NotFoundException {
70        boolean changed = setupResources(thisTheme);
71        BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid,
72                attrs);
73        ta.setTheme(thisTheme);
74        restoreResources(changed);
75        return ta;
76    }
77
78    @LayoutlibDelegate
79    /*package*/ static TypedArray obtainStyledAttributes(
80            Resources thisResources, Theme thisTheme,
81            AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
82        boolean changed = setupResources(thisTheme);
83        BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(set,
84                attrs, defStyleAttr, defStyleRes);
85        ta.setTheme(thisTheme);
86        restoreResources(changed);
87        return ta;
88    }
89
90    @LayoutlibDelegate
91    /*package*/ static boolean resolveAttribute(
92            Resources thisResources, Theme thisTheme,
93            int resid, TypedValue outValue,
94            boolean resolveRefs) {
95        boolean changed = setupResources(thisTheme);
96        boolean found =  RenderSessionImpl.getCurrentContext().resolveThemeAttribute(resid,
97                outValue, resolveRefs);
98        restoreResources(changed);
99        return found;
100    }
101
102    @LayoutlibDelegate
103    /*package*/ static TypedArray resolveAttributes(Resources thisResources, Theme thisTheme,
104            int[] values, int[] attrs) {
105        // FIXME
106        return null;
107    }
108
109    // ---- private helper methods ----
110
111    private static boolean setupResources(Theme thisTheme) {
112        // Key is a space-separated list of theme ids applied that have been merged into the
113        // BridgeContext's theme to make thisTheme.
114        final ThemeKey key = thisTheme.getKey();
115        final int[] resId = key.mResId;
116        final boolean[] force = key.mForce;
117
118        boolean changed = false;
119        for (int i = 0, N = key.mCount; i < N; i++) {
120            StyleResourceValue style = resolveStyle(resId[i]);
121            if (style != null) {
122                RenderSessionImpl.getCurrentContext().getRenderResources().applyStyle(
123                        style, force[i]);
124                changed = true;
125            }
126
127        }
128        return changed;
129    }
130
131    private static void restoreResources(boolean changed) {
132        if (changed) {
133            RenderSessionImpl.getCurrentContext().getRenderResources().clearStyles();
134        }
135    }
136
137    @Nullable
138    private static StyleResourceValue resolveStyle(int nativeResid) {
139        if (nativeResid == 0) {
140            return null;
141        }
142        BridgeContext context = RenderSessionImpl.getCurrentContext();
143        ResourceReference theme = context.resolveId(nativeResid);
144        if (theme.isFramework()) {
145            return (StyleResourceValue) context.getRenderResources()
146                    .getFrameworkResource(ResourceType.STYLE, theme.getName());
147        } else {
148            return (StyleResourceValue) context.getRenderResources()
149                    .getProjectResource(ResourceType.STYLE, theme.getName());
150        }
151    }
152}
153