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