CustomBar.java revision 1076be31f1c14f39295cc2ce7a747ee9ad96ee73
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 50import static com.android.layoutlib.bridge.bars.Config.DEFAULT_RESOURCE_DIR; 51 52/** 53 * Base "bar" class for the window decor around the the edited layout. 54 * This is basically an horizontal layout that loads a given layout on creation (it is read 55 * through {@link Class#getResourceAsStream(String)}). 56 * 57 * The given layout should be a merge layout so that all the children belong to this class directly. 58 * 59 * It also provides a few utility methods to configure the content of the layout. 60 */ 61abstract class CustomBar extends LinearLayout { 62 63 // An upper-bound on the length of the path to the directory to find the icon in. 64 // This assumes that resource directory name for different api levels have same length. 65 private static final int ICON_PATH_LENGTH = DEFAULT_RESOURCE_DIR.length() 66 + LayoutDirection.RTL.getResourceValue().length() + 9; // 9 = "-xxxhdpi/".length 67 68 69 private final int mSimulatedPlatformVersion; 70 71 protected abstract TextView getStyleableTextView(); 72 73 protected CustomBar(Context context, int orientation, String layoutPath, 74 String name, int simulatedPlatformVersion) throws XmlPullParserException { 75 super(context); 76 mSimulatedPlatformVersion = simulatedPlatformVersion; 77 setOrientation(orientation); 78 if (orientation == LinearLayout.HORIZONTAL) { 79 setGravity(Gravity.CENTER_VERTICAL); 80 } else { 81 setGravity(Gravity.CENTER_HORIZONTAL); 82 } 83 84 LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 85 Context.LAYOUT_INFLATER_SERVICE); 86 87 XmlPullParser parser = ParserFactory.create(getClass().getResourceAsStream(layoutPath), 88 name); 89 90 BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser( 91 parser, (BridgeContext) context, false /*platformFile*/); 92 93 try { 94 inflater.inflate(bridgeParser, this, true); 95 } finally { 96 bridgeParser.ensurePopped(); 97 } 98 } 99 100 private InputStream getIcon(String iconName, Density[] densityInOut, LayoutDirection direction, 101 StringBuilder[] pathOut, boolean tryOtherDensities) { 102 pathOut[0] = new StringBuilder(ICON_PATH_LENGTH + iconName.length()); 103 104 if (Config.usesCustomResourceDir(mSimulatedPlatformVersion)) { 105 // current density. 106 Density density = densityInOut[0]; 107 InputStream stream = getIcon(iconName, Config.getResourceDir(mSimulatedPlatformVersion), 108 densityInOut, direction, pathOut, tryOtherDensities); 109 if (stream != null) { 110 return stream; 111 } 112 // reset the density. 113 densityInOut[0] = density; 114 } 115 return getIcon(iconName, DEFAULT_RESOURCE_DIR, densityInOut, direction, pathOut, 116 tryOtherDensities); 117 118 } 119 120 private InputStream getIcon(String iconName, String dir, Density[] densityInOut, 121 LayoutDirection direction, StringBuilder[] pathOut, boolean tryOtherDensities) { 122 // current density 123 Density density = densityInOut[0]; 124 125 pathOut[0].setLength(0); 126 127 // bitmap url relative to this class 128 if (direction == LayoutDirection.RTL) { 129 pathOut[0].append(dir) 130 .append(direction.getResourceValue()) 131 .append('-') 132 .append(density.getResourceValue()) 133 .append('/') 134 .append(iconName); 135 } else { 136 // Since we do not have any ldltr resource, skip the check. 137 pathOut[0].append(dir) 138 .append(density.getResourceValue()) 139 .append('/') 140 .append(iconName); 141 } 142 143 InputStream stream = getClass().getResourceAsStream(pathOut[0].toString()); 144 if (stream == null && tryOtherDensities) { 145 for (Density d : Density.values()) { 146 if (d != density) { 147 densityInOut[0] = d; 148 stream = getIcon(iconName, dir, densityInOut, direction, pathOut, 149 false /*tryOtherDensities*/); 150 if (stream != null) { 151 return stream; 152 } 153 } 154 } 155 // couldn't find resource with direction qualifier, try without. 156 if (direction == LayoutDirection.RTL) { 157 densityInOut[0] = density; 158 stream = getIcon(iconName, dir, densityInOut, null, pathOut, 159 true /*tryOtherDensities*/); 160 } 161 } 162 163 return stream; 164 } 165 166 protected void loadIcon(int index, String iconName, Density density) { 167 loadIcon(index, iconName, density, false); 168 } 169 170 protected void loadIcon(int index, String iconName, Density density, boolean isRtl) { 171 View child = getChildAt(index); 172 if (child instanceof ImageView) { 173 ImageView imageView = (ImageView) child; 174 175 StringBuilder[] pathOut = new StringBuilder[1]; 176 Density[] densityInOut = new Density[]{density}; 177 LayoutDirection dir = isRtl ? LayoutDirection.RTL : null; 178 InputStream stream = getIcon(iconName, densityInOut, dir, pathOut, 179 true /*tryOtherDensities*/); 180 density = densityInOut[0]; 181 String path = pathOut[0].toString(); 182 183 if (stream != null) { 184 // look for a cached bitmap 185 Bitmap bitmap = Bridge.getCachedBitmap(path, true /*isFramework*/); 186 if (bitmap == null) { 187 try { 188 bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density); 189 Bridge.setCachedBitmap(path, bitmap, true /*isFramework*/); 190 } catch (IOException e) { 191 return; 192 } 193 } 194 195 if (bitmap != null) { 196 BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(), 197 bitmap); 198 imageView.setImageDrawable(drawable); 199 } 200 } 201 } 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 private void setText(TextView textView, String stringReference) { 216 ResourceValue value = getResourceValue(stringReference); 217 if (value != null) { 218 textView.setText(value.getValue()); 219 } else { 220 textView.setText(stringReference); 221 } 222 } 223 224 protected void setStyle(String themeEntryName) { 225 226 BridgeContext bridgeContext = (BridgeContext) mContext; 227 RenderResources res = bridgeContext.getRenderResources(); 228 229 ResourceValue value = res.findItemInTheme(themeEntryName, true /*isFrameworkAttr*/); 230 value = res.resolveResValue(value); 231 232 if (!(value instanceof StyleResourceValue)) { 233 return; 234 } 235 236 StyleResourceValue style = (StyleResourceValue) value; 237 238 // get the background 239 ResourceValue backgroundValue = res.findItemInStyle(style, "background", 240 true /*isFrameworkAttr*/); 241 backgroundValue = res.resolveResValue(backgroundValue); 242 if (backgroundValue != null) { 243 Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext); 244 if (d != null) { 245 setBackground(d); 246 } 247 } 248 249 TextView textView = getStyleableTextView(); 250 if (textView != null) { 251 // get the text style 252 ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle", 253 true /*isFrameworkAttr*/); 254 textStyleValue = res.resolveResValue(textStyleValue); 255 if (textStyleValue instanceof StyleResourceValue) { 256 StyleResourceValue textStyle = (StyleResourceValue) textStyleValue; 257 258 ResourceValue textSize = res.findItemInStyle(textStyle, "textSize", 259 true /*isFrameworkAttr*/); 260 textSize = res.resolveResValue(textSize); 261 262 if (textSize != null) { 263 TypedValue out = new TypedValue(); 264 if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out, 265 true /*requireUnit*/)) { 266 textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 267 out.getDimension(bridgeContext.getResources().getDisplayMetrics())); 268 } 269 } 270 271 272 ResourceValue textColor = res.findItemInStyle(textStyle, "textColor", 273 true /*isFrameworkAttr*/); 274 textColor = res.resolveResValue(textColor); 275 if (textColor != null) { 276 ColorStateList stateList = ResourceHelper.getColorStateList( 277 textColor, bridgeContext); 278 if (stateList != null) { 279 textView.setTextColor(stateList); 280 } 281 } 282 } 283 } 284 } 285 286 private ResourceValue getResourceValue(String reference) { 287 BridgeContext bridgeContext = (BridgeContext) mContext; 288 RenderResources res = bridgeContext.getRenderResources(); 289 290 // find the resource 291 ResourceValue value = res.findResValue(reference, false /*isFramework*/); 292 293 // resolve it if needed 294 return res.resolveResValue(value); 295 } 296} 297