Home | History | Annotate | Download | only in render
      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 */
     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      */
     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      */
    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      */
    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      */
    128     public RenderService setDecorations(boolean showDecorations) {
    129         mShowDecorations = showDecorations;
    130         return this;
    131     }
    132 
    133     public RenderService setAppInfo(String label, String icon) {
    134         mAppLabel = label;
    135         mAppIconName = icon;
    136         return this;
    137     }
    138 
    139     public RenderService setMinSdkVersion(int minSdkVersion) {
    140         mMinSdkVersion = minSdkVersion;
    141         return this;
    142     }
    143 
    144     public RenderService setTargetSdkVersion(int targetSdkVersion) {
    145         mTargetSdkVersion = targetSdkVersion;
    146         return this;
    147     }
    148 
    149     public RenderService setExactDeviceDpi(float xdpi, float ydpi) {
    150         mXdpi = xdpi;
    151         mYdpi = ydpi;
    152         return this;
    153     }
    154 
    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 */
    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      */
    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 
    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