CustomBar.java revision 02d2b5a4031c80bfe1012ce2f4f7b3695762abd9
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.ResourceHelper;
26import com.android.resources.Density;
27import com.android.resources.ResourceType;
28
29import org.kxml2.io.KXmlParser;
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, String layoutPath)
64            throws XmlPullParserException {
65        super(context);
66        setOrientation(LinearLayout.HORIZONTAL);
67        setGravity(Gravity.CENTER_VERTICAL);
68
69        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
70                Context.LAYOUT_INFLATER_SERVICE);
71
72        KXmlParser parser = new KXmlParser();
73        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
74        parser.setInput(
75                getClass().getResourceAsStream(layoutPath),
76                "UTF8");
77
78        BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
79                parser, (BridgeContext) context, false /*platformFile*/);
80
81        try {
82            inflater.inflate(bridgeParser, this, true);
83        } finally {
84            bridgeParser.ensurePopped();
85        }
86    }
87
88    private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut,
89            boolean tryOtherDensities) {
90        // current density
91        Density density = densityInOut[0];
92
93        // bitmap url relative to this class
94        pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
95
96        InputStream stream = getClass().getResourceAsStream(pathOut[0]);
97        if (stream == null && tryOtherDensities) {
98            for (Density d : Density.values()) {
99                if (d != density) {
100                    densityInOut[0] = d;
101                    stream = getIcon(iconName, densityInOut, pathOut, false /*tryOtherDensities*/);
102                    if (stream != null) {
103                        return stream;
104                    }
105                }
106            }
107        }
108
109        return stream;
110    }
111
112    protected void loadIcon(int index, String iconName, Density density) {
113        View child = getChildAt(index);
114        if (child instanceof ImageView) {
115            ImageView imageView = (ImageView) child;
116
117            String[] pathOut = new String[1];
118            Density[] densityInOut = new Density[] { density };
119            InputStream stream = getIcon(iconName, densityInOut, pathOut,
120                    true /*tryOtherDensities*/);
121            density = densityInOut[0];
122
123            if (stream != null) {
124                // look for a cached bitmap
125                Bitmap bitmap = Bridge.getCachedBitmap(pathOut[0], true /*isFramework*/);
126                if (bitmap == null) {
127                    try {
128                        bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
129                        Bridge.setCachedBitmap(pathOut[0], bitmap, true /*isFramework*/);
130                    } catch (IOException e) {
131                        return;
132                    }
133                }
134
135                if (bitmap != null) {
136                    BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(),
137                            bitmap);
138                    imageView.setBackgroundDrawable(drawable);
139                }
140            }
141        }
142    }
143
144    protected void loadIcon(int index, String iconReference) {
145        ResourceValue value = getResourceValue(iconReference);
146        if (value != null) {
147            loadIcon(index, value);
148        }
149    }
150
151    protected Drawable loadIcon(int index, ResourceType type, String name) {
152        BridgeContext bridgeContext = (BridgeContext) mContext;
153        RenderResources res = bridgeContext.getRenderResources();
154
155        // find the resource
156        ResourceValue value = res.getFrameworkResource(type, name);
157
158        // resolve it if needed
159        value = res.resolveResValue(value);
160        return loadIcon(index, value);
161    }
162
163    private Drawable loadIcon(int index, ResourceValue value) {
164        View child = getChildAt(index);
165        if (child instanceof ImageView) {
166            ImageView imageView = (ImageView) child;
167
168            Drawable drawable = ResourceHelper.getDrawable(
169                    value, (BridgeContext) mContext);
170            if (drawable != null) {
171                imageView.setBackgroundDrawable(drawable);
172            }
173
174            return drawable;
175        }
176
177        return null;
178    }
179
180    protected TextView setText(int index, String stringReference) {
181        View child = getChildAt(index);
182        if (child instanceof TextView) {
183            TextView textView = (TextView) child;
184            ResourceValue value = getResourceValue(stringReference);
185            if (value != null) {
186                textView.setText(value.getValue());
187            } else {
188                textView.setText(stringReference);
189            }
190            return textView;
191        }
192
193        return null;
194    }
195
196    protected void setStyle(String themeEntryName) {
197
198        BridgeContext bridgeContext = (BridgeContext) mContext;
199        RenderResources res = bridgeContext.getRenderResources();
200
201        ResourceValue value = res.findItemInTheme(themeEntryName);
202        value = res.resolveResValue(value);
203
204        if (value instanceof StyleResourceValue == false) {
205            return;
206        }
207
208        StyleResourceValue style = (StyleResourceValue) value;
209
210        // get the background
211        ResourceValue backgroundValue = res.findItemInStyle(style, "background");
212        backgroundValue = res.resolveResValue(backgroundValue);
213        if (backgroundValue != null) {
214            Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext);
215            if (d != null) {
216                setBackgroundDrawable(d);
217            }
218        }
219
220        TextView textView = getStyleableTextView();
221        if (textView != null) {
222            // get the text style
223            ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle");
224            textStyleValue = res.resolveResValue(textStyleValue);
225            if (textStyleValue instanceof StyleResourceValue) {
226                StyleResourceValue textStyle = (StyleResourceValue) textStyleValue;
227
228                ResourceValue textSize = res.findItemInStyle(textStyle, "textSize");
229                textSize = res.resolveResValue(textSize);
230
231                if (textSize != null) {
232                    TypedValue out = new TypedValue();
233                    if (ResourceHelper.stringToFloat(textSize.getValue(), out)) {
234                        textView.setTextSize(
235                                out.getDimension(bridgeContext.getResources().mMetrics));
236                    }
237                }
238
239
240                ResourceValue textColor = res.findItemInStyle(textStyle, "textColor");
241                textColor = res.resolveResValue(textColor);
242                if (textColor != null) {
243                    ColorStateList stateList = ResourceHelper.getColorStateList(
244                            textColor, bridgeContext);
245                    if (stateList != null) {
246                        textView.setTextColor(stateList);
247                    }
248                }
249            }
250        }
251    }
252
253    private ResourceValue getResourceValue(String reference) {
254        BridgeContext bridgeContext = (BridgeContext) mContext;
255        RenderResources res = bridgeContext.getRenderResources();
256
257        // find the resource
258        ResourceValue value = res.findResValue(reference, false /*isFramework*/);
259
260        // resolve it if needed
261        return res.resolveResValue(value);
262    }
263}
264