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