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