blob: 33ed35fc97e4a8b21b73801966cd58ba08896964 [file] [log] [blame]
/*
* 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;
}
}