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