| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.example.android.render; |
| |
| import com.android.ide.common.rendering.LayoutLibrary; |
| import com.android.ide.common.rendering.api.DrawableParams; |
| import com.android.ide.common.rendering.api.IImageFactory; |
| import com.android.ide.common.rendering.api.ILayoutPullParser; |
| import com.android.ide.common.rendering.api.IProjectCallback; |
| import com.android.ide.common.rendering.api.LayoutLog; |
| import com.android.ide.common.rendering.api.RenderSession; |
| import com.android.ide.common.rendering.api.ResourceValue; |
| import com.android.ide.common.rendering.api.Result; |
| import com.android.ide.common.rendering.api.SessionParams; |
| import com.android.ide.common.rendering.api.SessionParams.RenderingMode; |
| import com.android.ide.common.resources.ResourceResolver; |
| import com.android.ide.common.resources.configuration.FolderConfiguration; |
| import com.android.resources.ResourceType; |
| import com.android.resources.ScreenOrientation; |
| |
| import org.xmlpull.v1.XmlPullParser; |
| import org.xmlpull.v1.XmlPullParserException; |
| |
| import java.awt.image.BufferedImage; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| |
| |
| /** |
| * The {@link RenderService} provides rendering service and easy config. |
| */ |
| public class RenderService { |
| |
| // The following fields are set through the constructor and are required. |
| |
| private final IProjectCallback mProjectCallback; |
| private final ResourceResolver mResourceResolver; |
| private final LayoutLibrary mLayoutLib; |
| private final FolderConfiguration mConfig; |
| |
| // The following fields are optional or configurable using the various chained |
| // setters: |
| |
| private int mWidth; |
| private int mHeight; |
| private int mMinSdkVersion = -1; |
| private int mTargetSdkVersion = -1; |
| private float mXdpi = -1; |
| private float mYdpi = -1; |
| private RenderingMode mRenderingMode = RenderingMode.NORMAL; |
| private LayoutLog mLogger; |
| private Integer mOverrideBgColor; |
| private boolean mShowDecorations = true; |
| private String mAppLabel; |
| private String mAppIconName; |
| private IImageFactory mImageFactory; |
| |
| /** Use the {@link RenderServiceFactory#create} factory instead */ |
| RenderService(LayoutLibrary layoutLibrary, |
| ResourceResolver resources, |
| FolderConfiguration config, |
| IProjectCallback projectCallback) { |
| mLayoutLib = layoutLibrary; |
| mResourceResolver = resources; |
| mConfig = config; |
| mProjectCallback = projectCallback; |
| } |
| |
| /** |
| * Sets the {@link LayoutLog} to be used during rendering. If none is specified, a |
| * silent logger will be used. |
| * |
| * @param logger the log to be used |
| * @return this (such that chains of setters can be stringed together) |
| */ |
| public RenderService setLog(LayoutLog logger) { |
| mLogger = logger; |
| return this; |
| } |
| |
| /** |
| * Sets the {@link RenderingMode} to be used during rendering. If none is specified, |
| * the default is {@link RenderingMode#NORMAL}. |
| * |
| * @param renderingMode the rendering mode to be used |
| * @return this (such that chains of setters can be stringed together) |
| */ |
| public RenderService setRenderingMode(RenderingMode renderingMode) { |
| mRenderingMode = renderingMode; |
| return this; |
| } |
| |
| /** |
| * Sets the overriding background color to be used, if any. The color should be a |
| * bitmask of AARRGGBB. The default is null. |
| * |
| * @param overrideBgColor the overriding background color to be used in the rendering, |
| * in the form of a AARRGGBB bitmask, or null to use no custom background. |
| * @return this (such that chains of setters can be stringed together) |
| */ |
| public RenderService setOverrideBgColor(Integer overrideBgColor) { |
| mOverrideBgColor = overrideBgColor; |
| return this; |
| } |
| |
| /** |
| * Sets whether the rendering should include decorations such as a system bar, an |
| * application bar etc depending on the SDK target and theme. The default is true. |
| * |
| * @param showDecorations true if the rendering should include system bars etc. |
| * @return this (such that chains of setters can be stringed together) |
| */ |
| public RenderService setDecorations(boolean showDecorations) { |
| mShowDecorations = showDecorations; |
| return this; |
| } |
| |
| public RenderService setAppInfo(String label, String icon) { |
| mAppLabel = label; |
| mAppIconName = icon; |
| return this; |
| } |
| |
| public RenderService setMinSdkVersion(int minSdkVersion) { |
| mMinSdkVersion = minSdkVersion; |
| return this; |
| } |
| |
| public RenderService setTargetSdkVersion(int targetSdkVersion) { |
| mTargetSdkVersion = targetSdkVersion; |
| return this; |
| } |
| |
| public RenderService setExactDeviceDpi(float xdpi, float ydpi) { |
| mXdpi = xdpi; |
| mYdpi = ydpi; |
| return this; |
| } |
| |
| public RenderService setImageFactory(IImageFactory imageFactory) { |
| mImageFactory = imageFactory; |
| return this; |
| } |
| |
| /** Initializes any remaining optional fields after all setters have been called */ |
| private void finishConfiguration() { |
| if (mLogger == null) { |
| // Silent logging |
| mLogger = new LayoutLog(); |
| } |
| } |
| |
| /** |
| * Renders the model and returns the result as a {@link RenderSession}. |
| * @return the {@link RenderSession} resulting from rendering the current model |
| * @throws XmlPullParserException |
| * @throws FileNotFoundException |
| */ |
| public RenderSession createRenderSession(String layoutName) throws FileNotFoundException, |
| XmlPullParserException { |
| finishConfiguration(); |
| |
| if (mResourceResolver == null) { |
| // Abort the rendering if the resources are not found. |
| return null; |
| } |
| |
| // find the layout to run |
| ResourceValue value = mResourceResolver.getProjectResource(ResourceType.LAYOUT, layoutName); |
| if (value == null || value.getValue() == null) { |
| throw new IllegalArgumentException("layout does not exist"); |
| } |
| |
| File layoutFile = new File(value.getValue()); |
| |
| ILayoutPullParser parser = null; |
| parser = new XmlParser(); |
| parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); |
| parser.setInput(new FileInputStream(layoutFile), "UTF-8"); //$NON-NLS-1$ |
| |
| figureSomeValuesOut(); |
| |
| SessionParams params = new SessionParams( |
| parser, |
| mRenderingMode, |
| this /* projectKey */, |
| mWidth, mHeight, |
| mConfig.getDensityQualifier().getValue(), |
| mXdpi, mYdpi, |
| mResourceResolver, |
| mProjectCallback, |
| mMinSdkVersion, |
| mTargetSdkVersion, |
| mLogger); |
| |
| // Request margin and baseline information. |
| // TODO: Be smarter about setting this; start without it, and on the first request |
| // for an extended view info, re-render in the same session, and then set a flag |
| // which will cause this to create extended view info each time from then on in the |
| // same session |
| params.setExtendedViewInfoMode(true); |
| |
| if (!mShowDecorations) { |
| params.setForceNoDecor(); |
| } else { |
| if (mAppLabel == null) { |
| mAppLabel = "Random App"; |
| } |
| |
| params.setAppLabel(mAppLabel); |
| params.setAppIcon(mAppIconName); // ok to be null |
| } |
| |
| params.setConfigScreenSize(mConfig.getScreenSizeQualifier().getValue()); |
| |
| if (mOverrideBgColor != null) { |
| params.setOverrideBgColor(mOverrideBgColor.intValue()); |
| } |
| |
| // set the Image Overlay as the image factory. |
| params.setImageFactory(mImageFactory); |
| |
| try { |
| return mLayoutLib.createSession(params); |
| } catch (RuntimeException t) { |
| // Exceptions from the bridge |
| mLogger.error(null, t.getLocalizedMessage(), t, null); |
| throw t; |
| } |
| } |
| |
| private void figureSomeValuesOut() { |
| int size1 = mConfig.getScreenDimensionQualifier().getValue1(); |
| int size2 = mConfig.getScreenDimensionQualifier().getValue2(); |
| ScreenOrientation orientation = mConfig.getScreenOrientationQualifier().getValue(); |
| switch (orientation) { |
| case LANDSCAPE: |
| mWidth = size1 < size2 ? size2 : size1; |
| mHeight = size1 < size2 ? size1 : size2; |
| break; |
| case PORTRAIT: |
| mWidth = size1 < size2 ? size1 : size2; |
| mHeight = size1 < size2 ? size2 : size1; |
| break; |
| case SQUARE: |
| mWidth = mHeight = size1; |
| break; |
| } |
| |
| if (mMinSdkVersion == -1) { |
| mMinSdkVersion = mConfig.getVersionQualifier().getVersion(); |
| } |
| |
| if (mTargetSdkVersion == -1) { |
| mTargetSdkVersion = mConfig.getVersionQualifier().getVersion(); |
| } |
| |
| if (mXdpi == -1) { |
| mXdpi = mConfig.getDensityQualifier().getValue().getDpiValue(); |
| } |
| |
| if (mYdpi == -1) { |
| mYdpi = mConfig.getDensityQualifier().getValue().getDpiValue(); |
| } |
| } |
| |
| /** |
| * Renders the given resource value (which should refer to a drawable) and returns it |
| * as an image |
| * |
| * @param drawableResourceValue the drawable resource value to be rendered, or null |
| * @return the image, or null if something went wrong |
| */ |
| public BufferedImage renderDrawable(ResourceValue drawableResourceValue) { |
| if (drawableResourceValue == null) { |
| return null; |
| } |
| |
| finishConfiguration(); |
| |
| figureSomeValuesOut(); |
| |
| DrawableParams params = new DrawableParams(drawableResourceValue, this, mWidth, mHeight, |
| mConfig.getDensityQualifier().getValue(), |
| mXdpi, mYdpi, mResourceResolver, mProjectCallback, mMinSdkVersion, |
| mTargetSdkVersion, mLogger); |
| params.setForceNoDecor(); |
| Result result = mLayoutLib.renderDrawable(params); |
| if (result != null && result.isSuccess()) { |
| Object data = result.getData(); |
| if (data instanceof BufferedImage) { |
| return (BufferedImage) data; |
| } |
| } |
| |
| return null; |
| } |
| } |