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