RenderDrawable.java revision 681c7d142a6d25d3215d5f879074cd4359c6f106
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.impl; 18 19import com.android.ide.common.rendering.api.DrawableParams; 20import com.android.ide.common.rendering.api.HardwareConfig; 21import com.android.ide.common.rendering.api.ResourceValue; 22import com.android.ide.common.rendering.api.Result; 23import com.android.ide.common.rendering.api.Result.Status; 24import com.android.layoutlib.bridge.android.BridgeContext; 25import com.android.layoutlib.bridge.android.RenderParamsFlags; 26import com.android.resources.ResourceType; 27 28import android.graphics.Bitmap; 29import android.graphics.Bitmap_Delegate; 30import android.graphics.Canvas; 31import android.graphics.drawable.Drawable; 32import android.graphics.drawable.StateListDrawable; 33import android.view.AttachInfo_Accessor; 34import android.view.View.MeasureSpec; 35import android.widget.FrameLayout; 36 37import java.awt.AlphaComposite; 38import java.awt.Color; 39import java.awt.Graphics2D; 40import java.awt.image.BufferedImage; 41 42import java.util.ArrayList; 43import java.util.Collections; 44import java.util.List; 45 46/** 47 * Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}. 48 * 49 * The class only provides a simple {@link #render()} method, but the full life-cycle of the 50 * action must be respected. 51 * 52 * @see RenderAction 53 * 54 */ 55public class RenderDrawable extends RenderAction<DrawableParams> { 56 57 public RenderDrawable(DrawableParams params) { 58 super(new DrawableParams(params)); 59 } 60 61 public Result render() { 62 checkLock(); 63 // get the drawable resource value 64 DrawableParams params = getParams(); 65 HardwareConfig hardwareConfig = params.getHardwareConfig(); 66 ResourceValue drawableResource = params.getDrawable(); 67 68 // resolve it 69 BridgeContext context = getContext(); 70 drawableResource = context.getRenderResources().resolveResValue(drawableResource); 71 72 if (drawableResource == null || 73 drawableResource.getResourceType() != ResourceType.DRAWABLE) { 74 return Status.ERROR_NOT_A_DRAWABLE.createResult(); 75 } 76 77 Drawable d = ResourceHelper.getDrawable(drawableResource, context); 78 79 final Boolean allStates = 80 params.getFlag(RenderParamsFlags.FLAG_KEY_RENDER_ALL_DRAWABLE_STATES); 81 if (allStates == Boolean.TRUE) { 82 final List<BufferedImage> result; 83 84 if (d instanceof StateListDrawable) { 85 result = new ArrayList<BufferedImage>(); 86 final StateListDrawable stateList = (StateListDrawable) d; 87 for (int i = 0; i < stateList.getStateCount(); i++) { 88 final Drawable stateDrawable = stateList.getStateDrawable(i); 89 result.add(renderImage(hardwareConfig, stateDrawable, context)); 90 } 91 } else { 92 result = Collections.singletonList(renderImage(hardwareConfig, d, context)); 93 } 94 95 return Status.SUCCESS.createResult(result); 96 } else { 97 BufferedImage image = renderImage(hardwareConfig, d, context); 98 return Status.SUCCESS.createResult(image); 99 } 100 } 101 102 private BufferedImage renderImage(HardwareConfig hardwareConfig, Drawable d, 103 BridgeContext context) { 104 // create a simple FrameLayout 105 FrameLayout content = new FrameLayout(context); 106 107 // get the actual Drawable object to draw 108 content.setBackground(d); 109 110 // set the AttachInfo on the root view. 111 AttachInfo_Accessor.setAttachInfo(content); 112 113 114 // measure 115 int w = d.getIntrinsicWidth(); 116 int h = d.getIntrinsicHeight(); 117 118 final int screenWidth = hardwareConfig.getScreenWidth(); 119 final int screenHeight = hardwareConfig.getScreenHeight(); 120 121 if (w == -1 || h == -1) { 122 // Use screen size when either intrinsic width or height isn't available 123 w = screenWidth; 124 h = screenHeight; 125 } else if (w > screenWidth || h > screenHeight) { 126 // If image wouldn't fit to the screen, resize it to avoid cropping. 127 128 // We need to find scale such that scale * w <= screenWidth, scale * h <= screenHeight 129 double scale = Math.min((double) screenWidth / w, (double) screenHeight / h); 130 131 // scale * w / scale * h = w / h, so, proportions are preserved. 132 w = (int) Math.floor(scale * w); 133 h = (int) Math.floor(scale * h); 134 } 135 136 int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY); 137 int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY); 138 content.measure(w_spec, h_spec); 139 140 // now do the layout. 141 content.layout(0, 0, w, h); 142 143 // preDraw setup 144 AttachInfo_Accessor.dispatchOnPreDraw(content); 145 146 // draw into a new image 147 BufferedImage image = getImage(w, h); 148 149 // create an Android bitmap around the BufferedImage 150 Bitmap bitmap = Bitmap_Delegate.createBitmap(image, 151 true /*isMutable*/, hardwareConfig.getDensity()); 152 153 // create a Canvas around the Android bitmap 154 Canvas canvas = new Canvas(bitmap); 155 canvas.setDensity(hardwareConfig.getDensity().getDpiValue()); 156 157 // and draw 158 content.draw(canvas); 159 return image; 160 } 161 162 protected BufferedImage getImage(int w, int h) { 163 BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 164 Graphics2D gc = image.createGraphics(); 165 gc.setComposite(AlphaComposite.Src); 166 167 gc.setColor(new Color(0x00000000, true)); 168 gc.fillRect(0, 0, w, h); 169 170 // done 171 gc.dispose(); 172 173 return image; 174 } 175 176} 177