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