CustomBar.java revision 91fa3ba4cc8acd4caeeb88f90ce39198b5fea414
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.LayoutLog; 20import com.android.ide.common.rendering.api.RenderResources; 21import com.android.ide.common.rendering.api.ResourceValue; 22import com.android.ide.common.rendering.api.StyleResourceValue; 23import com.android.layoutlib.bridge.Bridge; 24import com.android.layoutlib.bridge.android.BridgeContext; 25import com.android.layoutlib.bridge.android.BridgeXmlBlockParser; 26import com.android.layoutlib.bridge.impl.ParserFactory; 27import com.android.layoutlib.bridge.impl.ResourceHelper; 28import com.android.resources.Density; 29import com.android.resources.LayoutDirection; 30import com.android.resources.ResourceType; 31 32import org.xmlpull.v1.XmlPullParser; 33import org.xmlpull.v1.XmlPullParserException; 34 35import android.annotation.NonNull; 36import android.annotation.Nullable; 37import android.content.res.ColorStateList; 38import android.graphics.Bitmap; 39import android.graphics.Bitmap_Delegate; 40import android.graphics.drawable.BitmapDrawable; 41import android.graphics.drawable.Drawable; 42import android.util.TypedValue; 43import android.view.Gravity; 44import android.view.LayoutInflater; 45import android.view.View; 46import android.widget.ImageView; 47import android.widget.LinearLayout; 48import android.widget.TextView; 49 50import java.io.IOException; 51import java.io.InputStream; 52 53import static android.os.Build.VERSION_CODES.LOLLIPOP; 54 55/** 56 * Base "bar" class for the window decor around the the edited layout. 57 * This is basically an horizontal layout that loads a given layout on creation (it is read 58 * through {@link Class#getResourceAsStream(String)}). 59 * 60 * The given layout should be a merge layout so that all the children belong to this class directly. 61 * 62 * It also provides a few utility methods to configure the content of the layout. 63 */ 64abstract class CustomBar extends LinearLayout { 65 66 67 private final int mSimulatedPlatformVersion; 68 69 protected abstract TextView getStyleableTextView(); 70 71 protected CustomBar(BridgeContext context, int orientation, String layoutPath, 72 String name, int simulatedPlatformVersion) { 73 super(context); 74 mSimulatedPlatformVersion = simulatedPlatformVersion; 75 setOrientation(orientation); 76 if (orientation == LinearLayout.HORIZONTAL) { 77 setGravity(Gravity.CENTER_VERTICAL); 78 } else { 79 setGravity(Gravity.CENTER_HORIZONTAL); 80 } 81 82 LayoutInflater inflater = LayoutInflater.from(mContext); 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, Boolean.TRUE /*isFramework*/); 121 if (bitmap == null) { 122 try { 123 bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density); 124 Bridge.setCachedBitmap(path, bitmap, Boolean.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 = getContext(); 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 @Override 223 public BridgeContext getContext() { 224 return (BridgeContext) mContext; 225 } 226 227 /** 228 * Find the background color for this bar from the theme attributes. Only relevant to StatusBar 229 * and NavigationBar. 230 * <p/> 231 * Returns null if not found. 232 * 233 * @param colorAttrName the attribute name for the background color 234 * @param translucentAttrName the attribute name for the translucency property of the bar. 235 * 236 * @throws NumberFormatException if color resolved to an invalid string. 237 */ 238 @Nullable 239 protected Integer getBarColor(@NonNull String colorAttrName, 240 @NonNull String translucentAttrName) { 241 if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) { 242 return null; 243 } 244 RenderResources renderResources = getContext().getRenderResources(); 245 // First check if the bar is translucent. 246 boolean translucent = ResourceHelper.getBooleanThemeValue(renderResources, 247 translucentAttrName, true, false); 248 if (translucent) { 249 // Keep in sync with R.color.system_bar_background_semi_transparent from system ui. 250 return 0x66000000; // 40% black. 251 } 252 boolean transparent = ResourceHelper.getBooleanThemeValue(renderResources, 253 "windowDrawsSystemBarBackgrounds", true, false); 254 if (transparent) { 255 return getColor(renderResources, colorAttrName); 256 } 257 return null; 258 } 259 260 @Nullable 261 private static Integer getColor(RenderResources renderResources, String attr) { 262 // From ?attr/foo to @color/bar. This is most likely an ItemResourceValue. 263 ResourceValue resource = renderResources.findItemInTheme(attr, true); 264 // Form @color/bar to the #AARRGGBB 265 resource = renderResources.resolveResValue(resource); 266 if (resource != null) { 267 ResourceType type = resource.getResourceType(); 268 if (type == null || type == ResourceType.COLOR) { 269 // if no type is specified, the value may have been specified directly in the style 270 // file, rather than referencing a color resource value. 271 try { 272 return ResourceHelper.getColor(resource.getValue()); 273 } catch (NumberFormatException e) { 274 // Conversion failed. 275 Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT, 276 "Theme attribute @android:" + attr + 277 " does not reference a color, instead is '" + 278 resource.getValue() + "'.", resource); 279 } 280 } 281 } 282 return null; 283 } 284 285 private ResourceValue getResourceValue(String reference) { 286 RenderResources res = getContext().getRenderResources(); 287 288 // find the resource 289 ResourceValue value = res.findResValue(reference, false); 290 291 // resolve it if needed 292 return res.resolveResValue(value); 293 } 294} 295