1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2011 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License.
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License.
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage com.android.layoutlib.bridge.impl;
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.DrawableParams;
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.HardwareConfig;
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.ResourceValue;
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.Result;
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.Result.Status;
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.android.BridgeContext;
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.ResourceType;
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Bitmap;
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Bitmap_Delegate;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.Canvas;
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.graphics.drawable.Drawable;
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.view.AttachInfo_Accessor;
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.view.View.MeasureSpec;
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.widget.FrameLayout;
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.awt.AlphaComposite;
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.awt.Color;
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.awt.Graphics2D;
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.awt.image.BufferedImage;
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.io.IOException;
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/**
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The class only provides a simple {@link #render()} method, but the full life-cycle of the
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * action must be respected.
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @see RenderAction
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic class RenderDrawable extends RenderAction<DrawableParams> {
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public RenderDrawable(DrawableParams params) {
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        super(new DrawableParams(params));
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Result render() {
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        checkLock();
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        try {
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // get the drawable resource value
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            DrawableParams params = getParams();
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            HardwareConfig hardwareConfig = params.getHardwareConfig();
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            ResourceValue drawableResource = params.getDrawable();
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // resolve it
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            BridgeContext context = getContext();
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            drawableResource = context.getRenderResources().resolveResValue(drawableResource);
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (drawableResource == null ||
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    drawableResource.getResourceType() != ResourceType.DRAWABLE) {
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return Status.ERROR_NOT_A_DRAWABLE.createResult();
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // create a simple FrameLayout
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            FrameLayout content = new FrameLayout(context);
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // get the actual Drawable object to draw
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Drawable d = ResourceHelper.getDrawable(drawableResource, context);
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            content.setBackground(d);
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // set the AttachInfo on the root view.
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AttachInfo_Accessor.setAttachInfo(content);
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // measure
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int w = hardwareConfig.getScreenWidth();
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int h = hardwareConfig.getScreenHeight();
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            content.measure(w_spec, h_spec);
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // now do the layout.
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            content.layout(0, 0, w, h);
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // preDraw setup
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            AttachInfo_Accessor.dispatchOnPreDraw(content);
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // draw into a new image
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            BufferedImage image = getImage(w, h);
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // create an Android bitmap around the BufferedImage
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Bitmap bitmap = Bitmap_Delegate.createBitmap(image,
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    true /*isMutable*/, hardwareConfig.getDensity());
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // create a Canvas around the Android bitmap
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            Canvas canvas = new Canvas(bitmap);
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            canvas.setDensity(hardwareConfig.getDensity().getDpiValue());
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // and draw
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            content.draw(canvas);
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return Status.SUCCESS.createResult(image);
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } catch (IOException e) {
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return ERROR_UNKNOWN.createResult(e.getMessage(), e);
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected BufferedImage getImage(int w, int h) {
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Graphics2D gc = image.createGraphics();
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        gc.setComposite(AlphaComposite.Src);
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        gc.setColor(new Color(0x00000000, true));
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        gc.fillRect(0, 0, w, h);
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // done
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        gc.dispose();
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return image;
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
134