blob: 0633b7dda7a27a57b14ad5690e2aba1bbf1f8623 [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.log.ILogger;
import com.android.ide.common.rendering.LayoutLibrary;
import com.android.ide.common.rendering.api.AttrResourceValue;
import com.android.ide.common.rendering.api.DeclareStyleableResourceValue;
import com.android.ide.common.rendering.api.IProjectCallback;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.resources.FrameworkResources;
import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.common.resources.ResourceResolver;
import com.android.ide.common.resources.configuration.DensityQualifier;
import com.android.ide.common.resources.configuration.FolderConfiguration;
import com.android.ide.common.resources.configuration.KeyboardStateQualifier;
import com.android.ide.common.resources.configuration.NavigationMethodQualifier;
import com.android.ide.common.resources.configuration.NavigationStateQualifier;
import com.android.ide.common.resources.configuration.ScreenDimensionQualifier;
import com.android.ide.common.resources.configuration.ScreenHeightQualifier;
import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
import com.android.ide.common.resources.configuration.ScreenRatioQualifier;
import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
import com.android.ide.common.resources.configuration.ScreenWidthQualifier;
import com.android.ide.common.resources.configuration.SmallestScreenWidthQualifier;
import com.android.ide.common.resources.configuration.TextInputMethodQualifier;
import com.android.ide.common.resources.configuration.TouchScreenQualifier;
import com.android.ide.common.resources.configuration.VersionQualifier;
import com.android.ide.common.sdk.LoadStatus;
import com.android.io.FileWrapper;
import com.android.io.FolderWrapper;
import com.android.resources.Density;
import com.android.resources.Keyboard;
import com.android.resources.KeyboardState;
import com.android.resources.Navigation;
import com.android.resources.NavigationState;
import com.android.resources.ResourceType;
import com.android.resources.ScreenOrientation;
import com.android.resources.ScreenRatio;
import com.android.resources.ScreenSize;
import com.android.resources.TouchScreen;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.internal.project.ProjectProperties;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* RenderService Factory. This is initialized for a given platform from the SDK.
*
* Also contains some utility method to create {@link FolderConfiguration} and
* {@link ResourceResolver}
*
*/
public class RenderServiceFactory {
private LayoutLibrary mLibrary;
private FrameworkResources mResources;
public static RenderServiceFactory create(File platformFolder) {
// create the factory
RenderServiceFactory factory = new RenderServiceFactory();
if (factory.loadLibrary(platformFolder)) {
return factory;
}
return null;
}
/**
* Creates a config. This must be a valid config like a device would return. This is to
* prevent issues where some resources don't exist in all cases and not in the default
* (for instance only available in hdpi and mdpi but not in default).
*
* @param size1
* @param size2
* @param screenSize
* @param screenRatio
* @param orientation
* @param density
* @param touchScreen
* @param keyboardState
* @param keyboard
* @param navigationState
* @param navigation
* @param apiLevel
* @return
*/
public static FolderConfiguration createConfig(
int size1,
int size2,
ScreenSize screenSize,
ScreenRatio screenRatio,
ScreenOrientation orientation,
Density density,
TouchScreen touchScreen,
KeyboardState keyboardState,
Keyboard keyboard,
NavigationState navigationState,
Navigation navigation,
int apiLevel) {
FolderConfiguration config = new FolderConfiguration();
int width = size1, height = size2;
switch (orientation) {
case LANDSCAPE:
width = size1 < size2 ? size2 : size1;
height = size1 < size2 ? size1 : size2;
break;
case PORTRAIT:
width = size1 < size2 ? size1 : size2;
height = size1 < size2 ? size2 : size1;
break;
case SQUARE:
width = height = size1;
break;
}
int wdp = (width * Density.DEFAULT_DENSITY) / density.getDpiValue();
int hdp = (height * Density.DEFAULT_DENSITY) / density.getDpiValue();
config.addQualifier(new SmallestScreenWidthQualifier(wdp < hdp ? wdp : hdp));
config.addQualifier(new ScreenWidthQualifier(wdp));
config.addQualifier(new ScreenHeightQualifier(hdp));
config.addQualifier(new ScreenSizeQualifier(screenSize));
config.addQualifier(new ScreenRatioQualifier(screenRatio));
config.addQualifier(new ScreenOrientationQualifier(orientation));
config.addQualifier(new DensityQualifier(density));
config.addQualifier(new TouchScreenQualifier(touchScreen));
config.addQualifier(new KeyboardStateQualifier(keyboardState));
config.addQualifier(new TextInputMethodQualifier(keyboard));
config.addQualifier(new NavigationStateQualifier(navigationState));
config.addQualifier(new NavigationMethodQualifier(navigation));
config.addQualifier(width > height ? new ScreenDimensionQualifier(width, height) :
new ScreenDimensionQualifier(height, width));
config.addQualifier(new VersionQualifier(apiLevel));
config.updateScreenWidthAndHeight();
return config;
}
/**
* Returns a {@link ResourceResolver} for a given config and project resource.
*
* @param config
* @param projectResources
* @param themeName
* @param isProjectTheme
* @return
*/
public ResourceResolver createResourceResolver(
FolderConfiguration config,
ResourceRepository projectResources,
String themeName,
boolean isProjectTheme) {
Map<ResourceType, Map<String, ResourceValue>> configedProjectRes =
projectResources.getConfiguredResources(config);
Map<ResourceType, Map<String, ResourceValue>> configedFrameworkRes =
mResources.getConfiguredResources(config);
return ResourceResolver.create(configedProjectRes, configedFrameworkRes,
themeName, isProjectTheme);
}
/**
* Creates a RenderService
*
* @param resources
* @param config
* @param projectCallback
* @return
*/
public RenderService createService(
ResourceResolver resources,
FolderConfiguration config,
IProjectCallback projectCallback) {
RenderService renderService = new RenderService(
mLibrary, resources, config, projectCallback);
return renderService;
}
/**
* Creates a RenderService. This is less efficient than
* {@link #createService(ResourceResolver, FolderConfiguration, IProjectCallback)} since the
* {@link ResourceResolver} object is not cached by the caller.
*
* @param projectResources
* @param themeName
* @param isProjectTheme
* @param config
* @param projectCallback
* @return
*/
public RenderService createService(
ResourceRepository projectResources,
String themeName,
boolean isProjectTheme,
FolderConfiguration config,
IProjectCallback projectCallback) {
ResourceResolver resources = createResourceResolver(
config, projectResources, themeName, isProjectTheme);
RenderService renderService = new RenderService(
mLibrary, resources, config, projectCallback);
return renderService;
}
private RenderServiceFactory() {
}
private boolean loadLibrary(File platformFolder) {
if (platformFolder.isDirectory() == false) {
throw new IllegalArgumentException("platform folder does not exist.");
}
File dataFolder = new File(platformFolder, "data");
if (dataFolder.isDirectory() == false) {
throw new IllegalArgumentException("platform data folder does not exist.");
}
File layoutLibJar = new File(dataFolder, "layoutlib.jar");
if (layoutLibJar.isFile() == false) {
throw new IllegalArgumentException("platform layoutlib.jar does not exist.");
}
File resFolder = new File(dataFolder, "res");
if (resFolder.isDirectory() == false) {
throw new IllegalArgumentException("platform res folder does not exist.");
}
File fontFolder = new File(dataFolder, "fonts");
if (fontFolder.isDirectory() == false) {
throw new IllegalArgumentException("platform font folder does not exist.");
}
FileWrapper buildProp = new FileWrapper(platformFolder, SdkConstants.FN_BUILD_PROP);
if (buildProp.isFile() == false) {
throw new IllegalArgumentException("platform build.prop does not exist.");
}
StdOutLogger log = new StdOutLogger();
mLibrary = LayoutLibrary.load(layoutLibJar.getAbsolutePath(), log,
"LayoutLibRenderer");
if (mLibrary.getStatus() != LoadStatus.LOADED) {
throw new IllegalArgumentException(mLibrary.getLoadMessage());
}
// load the framework resources
mResources = loadResources(resFolder, log);
// get all the attr values.
HashMap<String, Map<String, Integer>> enumMap = new HashMap<String, Map<String, Integer>>();
FolderConfiguration config = new FolderConfiguration();
Map<ResourceType, Map<String, ResourceValue>> res =
mResources.getConfiguredResources(config);
// get the ATTR values
Map<String, ResourceValue> attrItems = res.get(ResourceType.ATTR);
for (ResourceValue value : attrItems.values()) {
if (value instanceof AttrResourceValue) {
AttrResourceValue attr = (AttrResourceValue) value;
Map<String, Integer> values = attr.getAttributeValues();
if (values != null) {
enumMap.put(attr.getName(), values);
}
}
}
// get the declare-styleable values
Map<String, ResourceValue> styleableItems = res.get(ResourceType.DECLARE_STYLEABLE);
// get the attr from the styleable
for (ResourceValue value : styleableItems.values()) {
if (value instanceof DeclareStyleableResourceValue) {
DeclareStyleableResourceValue dsrc = (DeclareStyleableResourceValue) value;
Map<String, AttrResourceValue> attrs = dsrc.getAllAttributes();
if (attrs != null && attrs.size() > 0) {
for (AttrResourceValue attr : attrs.values()) {
Map<String, Integer> values = attr.getAttributeValues();
if (values != null) {
enumMap.put(attr.getName(), values);
}
}
}
}
}
// we need to parse the build.prop for this
Map<String, String> buildPropMap = ProjectProperties.parsePropertyFile(buildProp, log);
return mLibrary.init(buildPropMap, fontFolder, enumMap, log);
}
private FrameworkResources loadResources(File resFolder, ILogger log) {
FrameworkResources resources = new FrameworkResources();
try {
FolderWrapper path = new FolderWrapper(resFolder);
resources.loadResources(path);
resources.loadPublicResources(path, log);
return resources;
} catch (IOException e) {
// since we test that folders are folders, and files are files, this shouldn't
// happen. We can ignore it.
}
return null;
}
}