CustomBar.java revision b1484862e2367d87d3ccbd0fd0a6d2598ed5918a
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; 29import com.android.resources.ResourceType; 30 31import org.xmlpull.v1.XmlPullParser; 32import org.xmlpull.v1.XmlPullParserException; 33 34import android.annotation.NonNull; 35import android.content.Context; 36import android.content.res.ColorStateList; 37import android.graphics.Bitmap; 38import android.graphics.Bitmap_Delegate; 39import android.graphics.drawable.BitmapDrawable; 40import android.graphics.drawable.Drawable; 41import android.util.TypedValue; 42import android.view.Gravity; 43import android.view.LayoutInflater; 44import android.view.View; 45import android.widget.ImageView; 46import android.widget.LinearLayout; 47import android.widget.TextView; 48 49import java.io.IOException; 50import java.io.InputStream; 51 52import static android.os.Build.VERSION_CODES.LOLLIPOP; 53 54/** 55 * Base "bar" class for the window decor around the the edited layout. 56 * This is basically an horizontal layout that loads a given layout on creation (it is read 57 * through {@link Class#getResourceAsStream(String)}). 58 * 59 * The given layout should be a merge layout so that all the children belong to this class directly. 60 * 61 * It also provides a few utility methods to configure the content of the layout. 62 */ 63abstract class CustomBar extends LinearLayout { 64 65 66 private final int mSimulatedPlatformVersion; 67 68 protected abstract TextView getStyleableTextView(); 69 70 protected CustomBar(BridgeContext context, int orientation, String layoutPath, 71 String name, int simulatedPlatformVersion) { 72 super(context); 73 mSimulatedPlatformVersion = simulatedPlatformVersion; 74 setOrientation(orientation); 75 if (orientation == LinearLayout.HORIZONTAL) { 76 setGravity(Gravity.CENTER_VERTICAL); 77 } else { 78 setGravity(Gravity.CENTER_HORIZONTAL); 79 } 80 81 LayoutInflater inflater = (LayoutInflater) getContext().getSystemService( 82 Context.LAYOUT_INFLATER_SERVICE); 83 84 XmlPullParser parser; 85 try { 86 parser = ParserFactory.create(getClass().getResourceAsStream(layoutPath), name); 87 } catch (XmlPullParserException e) { 88 // Should not happen as the resource is bundled with the jar, and ParserFactory should 89 // have been initialized. 90 throw new AssertionError(e); 91 } 92 93 BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(parser, context, false); 94 95 try { 96 inflater.inflate(bridgeParser, this, true); 97 } finally { 98 bridgeParser.ensurePopped(); 99 } 100 } 101 102 protected void loadIcon(int index, String iconName, Density density) { 103 loadIcon(index, iconName, density, false); 104 } 105 106 protected void loadIcon(int index, String iconName, Density density, boolean isRtl) { 107 View child = getChildAt(index); 108 if (child instanceof ImageView) { 109 ImageView imageView = (ImageView) child; 110 111 LayoutDirection dir = isRtl ? LayoutDirection.RTL : null; 112 IconLoader iconLoader = new IconLoader(iconName, density, mSimulatedPlatformVersion, 113 dir); 114 InputStream stream = iconLoader.getIcon(); 115 116 if (stream != null) { 117 density = iconLoader.getDensity(); 118 String path = iconLoader.getPath(); 119 // look for a cached bitmap 120 Bitmap bitmap = Bridge.getCachedBitmap(path, true /*isFramework*/); 121 if (bitmap == null) { 122 try { 123 bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density); 124 Bridge.setCachedBitmap(path, bitmap, true /*isFramework*/); 125 } catch (IOException e) { 126 return; 127 } 128 } 129 130 if (bitmap != null) { 131 BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(), 132 bitmap); 133 imageView.setImageDrawable(drawable); 134 } 135 } 136 } 137 } 138 139 protected TextView setText(int index, String string, boolean reference) { 140 View child = getChildAt(index); 141 if (child instanceof TextView) { 142 TextView textView = (TextView) child; 143 setText(textView, string, reference); 144 return textView; 145 } 146 147 return null; 148 } 149 150 private void setText(TextView textView, String string, boolean reference) { 151 if (reference) { 152 ResourceValue value = getResourceValue(string); 153 if (value != null) { 154 string = value.getValue(); 155 } 156 } 157 textView.setText(string); 158 } 159 160 protected void setStyle(String themeEntryName) { 161 162 BridgeContext bridgeContext = (BridgeContext) mContext; 163 RenderResources res = bridgeContext.getRenderResources(); 164 165 ResourceValue value = res.findItemInTheme(themeEntryName, true /*isFrameworkAttr*/); 166 value = res.resolveResValue(value); 167 168 if (!(value instanceof StyleResourceValue)) { 169 return; 170 } 171 172 StyleResourceValue style = (StyleResourceValue) value; 173 174 // get the background 175 ResourceValue backgroundValue = res.findItemInStyle(style, "background", 176 true /*isFrameworkAttr*/); 177 backgroundValue = res.resolveResValue(backgroundValue); 178 if (backgroundValue != null) { 179 Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext); 180 if (d != null) { 181 setBackground(d); 182 } 183 } 184 185 TextView textView = getStyleableTextView(); 186 if (textView != null) { 187 // get the text style 188 ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle", 189 true /*isFrameworkAttr*/); 190 textStyleValue = res.resolveResValue(textStyleValue); 191 if (textStyleValue instanceof StyleResourceValue) { 192 StyleResourceValue textStyle = (StyleResourceValue) textStyleValue; 193 194 ResourceValue textSize = res.findItemInStyle(textStyle, "textSize", 195 true /*isFrameworkAttr*/); 196 textSize = res.resolveResValue(textSize); 197 198 if (textSize != null) { 199 TypedValue out = new TypedValue(); 200 if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out, 201 true /*requireUnit*/)) { 202 textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 203 out.getDimension(bridgeContext.getResources().getDisplayMetrics())); 204 } 205 } 206 207 208 ResourceValue textColor = res.findItemInStyle(textStyle, "textColor", 209 true); 210 textColor = res.resolveResValue(textColor); 211 if (textColor != null) { 212 ColorStateList stateList = ResourceHelper.getColorStateList( 213 textColor, bridgeContext); 214 if (stateList != null) { 215 textView.setTextColor(stateList); 216 } 217 } 218 } 219 } 220 } 221 222 /** 223 * Given a theme attribute name, get the color referenced by it. The theme attribute may be 224 * used in a layout like "?attr/foo". 225 * <p/> 226 * Returns 0 if not found. 227 * 228 * @throws NumberFormatException if color resolved to an invalid string. 229 */ 230 protected int getThemeAttrColor(@NonNull String attrName, boolean isFramework) { 231 if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) { 232 return 0; 233 } 234 assert mContext instanceof BridgeContext; 235 BridgeContext context = ((BridgeContext) mContext); 236 RenderResources renderResources = context.getRenderResources(); 237 // From ?attr/foo to @color/bar. This is most likely an ItemResourceValue. 238 ResourceValue resource = renderResources.findItemInTheme(attrName, isFramework); 239 if (resource != null) { 240 // Form @color/bar to the #AARRGGBB 241 resource = renderResources.resolveResValue(resource); 242 } 243 if (resource != null && ResourceType.COLOR.equals(resource.getResourceType())) { 244 return ResourceHelper.getColor(resource.getValue()); 245 } 246 return 0; 247 } 248 249 private ResourceValue getResourceValue(String reference) { 250 BridgeContext bridgeContext = (BridgeContext) mContext; 251 RenderResources res = bridgeContext.getRenderResources(); 252 253 // find the resource 254 ResourceValue value = res.findResValue(reference, false); 255 256 // resolve it if needed 257 return res.resolveResValue(value); 258 } 259} 260