• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.example.android.render;
18 
19 import com.android.ide.common.rendering.LayoutLibrary;
20 import com.android.ide.common.rendering.api.DrawableParams;
21 import com.android.ide.common.rendering.api.IImageFactory;
22 import com.android.ide.common.rendering.api.ILayoutPullParser;
23 import com.android.ide.common.rendering.api.IProjectCallback;
24 import com.android.ide.common.rendering.api.LayoutLog;
25 import com.android.ide.common.rendering.api.RenderSession;
26 import com.android.ide.common.rendering.api.ResourceValue;
27 import com.android.ide.common.rendering.api.Result;
28 import com.android.ide.common.rendering.api.SessionParams;
29 import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
30 import com.android.ide.common.resources.ResourceResolver;
31 import com.android.ide.common.resources.configuration.FolderConfiguration;
32 import com.android.resources.ResourceType;
33 import com.android.resources.ScreenOrientation;
34 
35 import org.xmlpull.v1.XmlPullParser;
36 import org.xmlpull.v1.XmlPullParserException;
37 
38 import java.awt.image.BufferedImage;
39 import java.io.File;
40 import java.io.FileInputStream;
41 import java.io.FileNotFoundException;
42 
43 
44 /**
45  * The {@link RenderService} provides rendering service and easy config.
46  */
47 public class RenderService {
48 
49     // The following fields are set through the constructor and are required.
50 
51     private final IProjectCallback mProjectCallback;
52     private final ResourceResolver mResourceResolver;
53     private final LayoutLibrary mLayoutLib;
54     private final FolderConfiguration mConfig;
55 
56     // The following fields are optional or configurable using the various chained
57     // setters:
58 
59     private int mWidth;
60     private int mHeight;
61     private int mMinSdkVersion = -1;
62     private int mTargetSdkVersion = -1;
63     private float mXdpi = -1;
64     private float mYdpi = -1;
65     private RenderingMode mRenderingMode = RenderingMode.NORMAL;
66     private LayoutLog mLogger;
67     private Integer mOverrideBgColor;
68     private boolean mShowDecorations = true;
69     private String mAppLabel;
70     private String mAppIconName;
71     private IImageFactory mImageFactory;
72 
73     /** Use the {@link RenderServiceFactory#create} factory instead */
RenderService(LayoutLibrary layoutLibrary, ResourceResolver resources, FolderConfiguration config, IProjectCallback projectCallback)74     RenderService(LayoutLibrary layoutLibrary,
75             ResourceResolver resources,
76             FolderConfiguration config,
77             IProjectCallback projectCallback) {
78         mLayoutLib = layoutLibrary;
79         mResourceResolver = resources;
80         mConfig = config;
81         mProjectCallback = projectCallback;
82     }
83 
84     /**
85      * Sets the {@link LayoutLog} to be used during rendering. If none is specified, a
86      * silent logger will be used.
87      *
88      * @param logger the log to be used
89      * @return this (such that chains of setters can be stringed together)
90      */
setLog(LayoutLog logger)91     public RenderService setLog(LayoutLog logger) {
92         mLogger = logger;
93         return this;
94     }
95 
96     /**
97      * Sets the {@link RenderingMode} to be used during rendering. If none is specified,
98      * the default is {@link RenderingMode#NORMAL}.
99      *
100      * @param renderingMode the rendering mode to be used
101      * @return this (such that chains of setters can be stringed together)
102      */
setRenderingMode(RenderingMode renderingMode)103     public RenderService setRenderingMode(RenderingMode renderingMode) {
104         mRenderingMode = renderingMode;
105         return this;
106     }
107 
108     /**
109      * Sets the overriding background color to be used, if any. The color should be a
110      * bitmask of AARRGGBB. The default is null.
111      *
112      * @param overrideBgColor the overriding background color to be used in the rendering,
113      *            in the form of a AARRGGBB bitmask, or null to use no custom background.
114      * @return this (such that chains of setters can be stringed together)
115      */
setOverrideBgColor(Integer overrideBgColor)116     public RenderService setOverrideBgColor(Integer overrideBgColor) {
117         mOverrideBgColor = overrideBgColor;
118         return this;
119     }
120 
121     /**
122      * Sets whether the rendering should include decorations such as a system bar, an
123      * application bar etc depending on the SDK target and theme. The default is true.
124      *
125      * @param showDecorations true if the rendering should include system bars etc.
126      * @return this (such that chains of setters can be stringed together)
127      */
setDecorations(boolean showDecorations)128     public RenderService setDecorations(boolean showDecorations) {
129         mShowDecorations = showDecorations;
130         return this;
131     }
132 
setAppInfo(String label, String icon)133     public RenderService setAppInfo(String label, String icon) {
134         mAppLabel = label;
135         mAppIconName = icon;
136         return this;
137     }
138 
setMinSdkVersion(int minSdkVersion)139     public RenderService setMinSdkVersion(int minSdkVersion) {
140         mMinSdkVersion = minSdkVersion;
141         return this;
142     }
143 
setTargetSdkVersion(int targetSdkVersion)144     public RenderService setTargetSdkVersion(int targetSdkVersion) {
145         mTargetSdkVersion = targetSdkVersion;
146         return this;
147     }
148 
setExactDeviceDpi(float xdpi, float ydpi)149     public RenderService setExactDeviceDpi(float xdpi, float ydpi) {
150         mXdpi = xdpi;
151         mYdpi = ydpi;
152         return this;
153     }
154 
setImageFactory(IImageFactory imageFactory)155     public RenderService setImageFactory(IImageFactory imageFactory) {
156         mImageFactory = imageFactory;
157         return this;
158     }
159 
160     /** Initializes any remaining optional fields after all setters have been called */
finishConfiguration()161     private void finishConfiguration() {
162         if (mLogger == null) {
163             // Silent logging
164             mLogger = new LayoutLog();
165         }
166     }
167 
168     /**
169      * Renders the model and returns the result as a {@link RenderSession}.
170      * @return the {@link RenderSession} resulting from rendering the current model
171      * @throws XmlPullParserException
172      * @throws FileNotFoundException
173      */
createRenderSession(String layoutName)174     public RenderSession createRenderSession(String layoutName) throws FileNotFoundException,
175             XmlPullParserException {
176         finishConfiguration();
177 
178         if (mResourceResolver == null) {
179             // Abort the rendering if the resources are not found.
180             return null;
181         }
182 
183         // find the layout to run
184         ResourceValue value = mResourceResolver.getProjectResource(ResourceType.LAYOUT, layoutName);
185         if (value == null || value.getValue() == null) {
186             throw new IllegalArgumentException("layout does not exist");
187         }
188 
189         File layoutFile = new File(value.getValue());
190 
191         ILayoutPullParser parser = null;
192         parser = new XmlParser();
193         parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
194         parser.setInput(new FileInputStream(layoutFile), "UTF-8"); //$NON-NLS-1$
195 
196         figureSomeValuesOut();
197 
198         SessionParams params = new SessionParams(
199                 parser,
200                 mRenderingMode,
201                 this /* projectKey */,
202                 mWidth, mHeight,
203                 mConfig.getDensityQualifier().getValue(),
204                 mXdpi, mYdpi,
205                 mResourceResolver,
206                 mProjectCallback,
207                 mMinSdkVersion,
208                 mTargetSdkVersion,
209                 mLogger);
210 
211         // Request margin and baseline information.
212         // TODO: Be smarter about setting this; start without it, and on the first request
213         // for an extended view info, re-render in the same session, and then set a flag
214         // which will cause this to create extended view info each time from then on in the
215         // same session
216         params.setExtendedViewInfoMode(true);
217 
218         if (!mShowDecorations) {
219             params.setForceNoDecor();
220         } else {
221             if (mAppLabel == null) {
222                 mAppLabel = "Random App";
223             }
224 
225             params.setAppLabel(mAppLabel);
226             params.setAppIcon(mAppIconName); // ok to be null
227         }
228 
229         params.setConfigScreenSize(mConfig.getScreenSizeQualifier().getValue());
230 
231         if (mOverrideBgColor != null) {
232             params.setOverrideBgColor(mOverrideBgColor.intValue());
233         }
234 
235         // set the Image Overlay as the image factory.
236         params.setImageFactory(mImageFactory);
237 
238         try {
239             return mLayoutLib.createSession(params);
240         } catch (RuntimeException t) {
241             // Exceptions from the bridge
242             mLogger.error(null, t.getLocalizedMessage(), t, null);
243             throw t;
244         }
245     }
246 
figureSomeValuesOut()247     private void figureSomeValuesOut() {
248         int size1 = mConfig.getScreenDimensionQualifier().getValue1();
249         int size2 = mConfig.getScreenDimensionQualifier().getValue2();
250         ScreenOrientation orientation = mConfig.getScreenOrientationQualifier().getValue();
251         switch (orientation) {
252             case LANDSCAPE:
253                 mWidth = size1 < size2 ? size2 : size1;
254                 mHeight = size1 < size2 ? size1 : size2;
255                 break;
256             case PORTRAIT:
257                 mWidth = size1 < size2 ? size1 : size2;
258                 mHeight = size1 < size2 ? size2 : size1;
259                 break;
260             case SQUARE:
261                 mWidth = mHeight = size1;
262                 break;
263         }
264 
265         if (mMinSdkVersion == -1) {
266             mMinSdkVersion = mConfig.getVersionQualifier().getVersion();
267         }
268 
269         if (mTargetSdkVersion == -1) {
270             mTargetSdkVersion = mConfig.getVersionQualifier().getVersion();
271         }
272 
273         if (mXdpi == -1) {
274             mXdpi = mConfig.getDensityQualifier().getValue().getDpiValue();
275         }
276 
277         if (mYdpi == -1) {
278             mYdpi = mConfig.getDensityQualifier().getValue().getDpiValue();
279         }
280     }
281 
282     /**
283      * Renders the given resource value (which should refer to a drawable) and returns it
284      * as an image
285      *
286      * @param drawableResourceValue the drawable resource value to be rendered, or null
287      * @return the image, or null if something went wrong
288      */
289     public BufferedImage renderDrawable(ResourceValue drawableResourceValue) {
290         if (drawableResourceValue == null) {
291             return null;
292         }
293 
294         finishConfiguration();
295 
296         figureSomeValuesOut();
297 
298         DrawableParams params = new DrawableParams(drawableResourceValue, this, mWidth, mHeight,
299                 mConfig.getDensityQualifier().getValue(),
300                 mXdpi, mYdpi, mResourceResolver, mProjectCallback, mMinSdkVersion,
301                 mTargetSdkVersion, mLogger);
302         params.setForceNoDecor();
303         Result result = mLayoutLib.renderDrawable(params);
304         if (result != null && result.isSuccess()) {
305             Object data = result.getData();
306             if (data instanceof BufferedImage) {
307                 return (BufferedImage) data;
308             }
309         }
310 
311         return null;
312     }
313 }
314