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 com.android.layoutlib.bridge.bars;
18
19import com.android.ide.common.rendering.api.RenderResources;
20import com.android.ide.common.rendering.api.ResourceValue;
21import com.android.ide.common.rendering.api.StyleResourceValue;
22import com.android.layoutlib.bridge.Bridge;
23import com.android.layoutlib.bridge.android.BridgeContext;
24import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
25import com.android.layoutlib.bridge.impl.ParserFactory;
26import com.android.layoutlib.bridge.impl.ResourceHelper;
27import com.android.resources.Density;
28import com.android.resources.ResourceType;
29
30import org.xmlpull.v1.XmlPullParser;
31import org.xmlpull.v1.XmlPullParserException;
32
33import android.content.Context;
34import android.content.res.ColorStateList;
35import android.graphics.Bitmap;
36import android.graphics.Bitmap_Delegate;
37import android.graphics.drawable.BitmapDrawable;
38import android.graphics.drawable.Drawable;
39import android.util.TypedValue;
40import android.view.Gravity;
41import android.view.LayoutInflater;
42import android.view.View;
43import android.widget.ImageView;
44import android.widget.LinearLayout;
45import android.widget.TextView;
46
47import java.io.IOException;
48import java.io.InputStream;
49
50/**
51 * Base "bar" class for the window decor around the the edited layout.
52 * This is basically an horizontal layout that loads a given layout on creation (it is read
53 * through {@link Class#getResourceAsStream(String)}).
54 *
55 * The given layout should be a merge layout so that all the children belong to this class directly.
56 *
57 * It also provides a few utility methods to configure the content of the layout.
58 */
59abstract class CustomBar extends LinearLayout {
60
61    protected abstract TextView getStyleableTextView();
62
63    protected CustomBar(Context context, Density density, int orientation, String layoutPath,
64            String name) throws XmlPullParserException {
65        super(context);
66        setOrientation(orientation);
67        if (orientation == LinearLayout.HORIZONTAL) {
68            setGravity(Gravity.CENTER_VERTICAL);
69        } else {
70            setGravity(Gravity.CENTER_HORIZONTAL);
71        }
72
73        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
74                Context.LAYOUT_INFLATER_SERVICE);
75
76        XmlPullParser parser = ParserFactory.create(getClass().getResourceAsStream(layoutPath),
77                name);
78
79        BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
80                parser, (BridgeContext) context, false /*platformFile*/);
81
82        try {
83            inflater.inflate(bridgeParser, this, true);
84        } finally {
85            bridgeParser.ensurePopped();
86        }
87    }
88
89    private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut,
90            boolean tryOtherDensities) {
91        // current density
92        Density density = densityInOut[0];
93
94        // bitmap url relative to this class
95        pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
96
97        InputStream stream = getClass().getResourceAsStream(pathOut[0]);
98        if (stream == null && tryOtherDensities) {
99            for (Density d : Density.values()) {
100                if (d != density) {
101                    densityInOut[0] = d;
102                    stream = getIcon(iconName, densityInOut, pathOut, false /*tryOtherDensities*/);
103                    if (stream != null) {
104                        return stream;
105                    }
106                }
107            }
108        }
109
110        return stream;
111    }
112
113    protected void loadIcon(int index, String iconName, Density density) {
114        View child = getChildAt(index);
115        if (child instanceof ImageView) {
116            ImageView imageView = (ImageView) child;
117
118            String[] pathOut = new String[1];
119            Density[] densityInOut = new Density[] { density };
120            InputStream stream = getIcon(iconName, densityInOut, pathOut,
121                    true /*tryOtherDensities*/);
122            density = densityInOut[0];
123
124            if (stream != null) {
125                // look for a cached bitmap
126                Bitmap bitmap = Bridge.getCachedBitmap(pathOut[0], true /*isFramework*/);
127                if (bitmap == null) {
128                    try {
129                        bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
130                        Bridge.setCachedBitmap(pathOut[0], bitmap, true /*isFramework*/);
131                    } catch (IOException e) {
132                        return;
133                    }
134                }
135
136                if (bitmap != null) {
137                    BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(),
138                            bitmap);
139                    imageView.setImageDrawable(drawable);
140                }
141            }
142        }
143    }
144
145    protected void loadIcon(int index, String iconReference) {
146        ResourceValue value = getResourceValue(iconReference);
147        if (value != null) {
148            loadIcon(index, value);
149        }
150    }
151
152    protected void loadIconById(int id, String iconReference) {
153        ResourceValue value = getResourceValue(iconReference);
154        if (value != null) {
155            loadIconById(id, value);
156        }
157    }
158
159
160    protected Drawable loadIcon(int index, ResourceType type, String name) {
161        BridgeContext bridgeContext = (BridgeContext) mContext;
162        RenderResources res = bridgeContext.getRenderResources();
163
164        // find the resource
165        ResourceValue value = res.getFrameworkResource(type, name);
166
167        // resolve it if needed
168        value = res.resolveResValue(value);
169        return loadIcon(index, value);
170    }
171
172    private Drawable loadIcon(int index, ResourceValue value) {
173        View child = getChildAt(index);
174        if (child instanceof ImageView) {
175            ImageView imageView = (ImageView) child;
176
177            return loadIcon(imageView, value);
178        }
179
180        return null;
181    }
182
183    private Drawable loadIconById(int id, ResourceValue value) {
184        View child = findViewById(id);
185        if (child instanceof ImageView) {
186            ImageView imageView = (ImageView) child;
187
188            return loadIcon(imageView, value);
189        }
190
191        return null;
192    }
193
194
195    private Drawable loadIcon(ImageView imageView, ResourceValue value) {
196        Drawable drawable = ResourceHelper.getDrawable(value, (BridgeContext) mContext);
197        if (drawable != null) {
198            imageView.setImageDrawable(drawable);
199        }
200
201        return drawable;
202    }
203
204    protected TextView setText(int index, String stringReference) {
205        View child = getChildAt(index);
206        if (child instanceof TextView) {
207            TextView textView = (TextView) child;
208            setText(textView, stringReference);
209            return textView;
210        }
211
212        return null;
213    }
214
215    protected TextView setTextById(int id, String stringReference) {
216        View child = findViewById(id);
217        if (child instanceof TextView) {
218            TextView textView = (TextView) child;
219            setText(textView, stringReference);
220            return textView;
221        }
222
223        return null;
224    }
225
226    private void setText(TextView textView, String stringReference) {
227        ResourceValue value = getResourceValue(stringReference);
228        if (value != null) {
229            textView.setText(value.getValue());
230        } else {
231            textView.setText(stringReference);
232        }
233    }
234
235    protected void setStyle(String themeEntryName) {
236
237        BridgeContext bridgeContext = (BridgeContext) mContext;
238        RenderResources res = bridgeContext.getRenderResources();
239
240        ResourceValue value = res.findItemInTheme(themeEntryName, true /*isFrameworkAttr*/);
241        value = res.resolveResValue(value);
242
243        if (value instanceof StyleResourceValue == false) {
244            return;
245        }
246
247        StyleResourceValue style = (StyleResourceValue) value;
248
249        // get the background
250        ResourceValue backgroundValue = res.findItemInStyle(style, "background",
251                true /*isFrameworkAttr*/);
252        backgroundValue = res.resolveResValue(backgroundValue);
253        if (backgroundValue != null) {
254            Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext);
255            if (d != null) {
256                setBackground(d);
257            }
258        }
259
260        TextView textView = getStyleableTextView();
261        if (textView != null) {
262            // get the text style
263            ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle",
264                    true /*isFrameworkAttr*/);
265            textStyleValue = res.resolveResValue(textStyleValue);
266            if (textStyleValue instanceof StyleResourceValue) {
267                StyleResourceValue textStyle = (StyleResourceValue) textStyleValue;
268
269                ResourceValue textSize = res.findItemInStyle(textStyle, "textSize",
270                        true /*isFrameworkAttr*/);
271                textSize = res.resolveResValue(textSize);
272
273                if (textSize != null) {
274                    TypedValue out = new TypedValue();
275                    if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out,
276                            true /*requireUnit*/)) {
277                        textView.setTextSize(
278                                out.getDimension(bridgeContext.getResources().getDisplayMetrics()));
279                    }
280                }
281
282
283                ResourceValue textColor = res.findItemInStyle(textStyle, "textColor",
284                        true /*isFrameworkAttr*/);
285                textColor = res.resolveResValue(textColor);
286                if (textColor != null) {
287                    ColorStateList stateList = ResourceHelper.getColorStateList(
288                            textColor, bridgeContext);
289                    if (stateList != null) {
290                        textView.setTextColor(stateList);
291                    }
292                }
293            }
294        }
295    }
296
297    private ResourceValue getResourceValue(String reference) {
298        BridgeContext bridgeContext = (BridgeContext) mContext;
299        RenderResources res = bridgeContext.getRenderResources();
300
301        // find the resource
302        ResourceValue value = res.findResValue(reference, false /*isFramework*/);
303
304        // resolve it if needed
305        return res.resolveResValue(value);
306    }
307}
308