blob: d6a35e3eff8cf2c4821283450e60456f90026c08 [file] [log] [blame]
/*
* Copyright (C) 2013 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.android.tools.idea.rendering;
import com.android.ide.common.rendering.api.*;
import com.android.tools.idea.rendering.imagepool.ImagePool;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.psi.PsiFile;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class RenderResult {
private static Logger LOG = Logger.getInstance(RenderResult.class);
@NotNull private final PsiFile myFile;
@NotNull private final RenderLogger myLogger;
@NotNull private final ImmutableList<ViewInfo> myRootViews;
@NotNull private final ImmutableList<ViewInfo> mySystemRootViews;
@NotNull private final ImagePool.Image myImage;
@Nullable private final RenderTask myRenderTask;
@NotNull private final Result myRenderResult;
@NotNull private final Map<Object, Map<ResourceReference, ResourceValue>> myDefaultProperties;
@NotNull private final Map<Object, String> myDefaultStyles;
@NotNull private final Module myModule;
private final ReadWriteLock myDisposeLock = new ReentrantReadWriteLock();
@Nullable private final Object myValidatorResult;
private boolean isDisposed;
protected RenderResult(@NotNull PsiFile file,
@NotNull Module module,
@NotNull RenderLogger logger,
@Nullable RenderTask renderTask,
@NotNull Result renderResult,
@NotNull ImmutableList<ViewInfo> rootViews,
@NotNull ImmutableList<ViewInfo> systemRootViews,
@NotNull ImagePool.Image image,
@NotNull Map<Object, Map<ResourceReference, ResourceValue>> defaultProperties,
@NotNull Map<Object, String> defaultStyles,
@Nullable Object validatorResult) {
myRenderTask = renderTask;
myModule = module;
myFile = file;
myLogger = logger;
myRenderResult = renderResult;
myRootViews = rootViews;
mySystemRootViews = systemRootViews;
myImage = image;
myDefaultProperties = defaultProperties;
myDefaultStyles = defaultStyles;
myValidatorResult = validatorResult;
}
public void dispose() {
myDisposeLock.writeLock().lock();
try {
isDisposed = true;
myImage.dispose();
} finally {
myDisposeLock.writeLock().unlock();
}
}
/**
* Creates a new {@link RenderResult} from a given RenderTask and RenderSession
*/
@NotNull
public static RenderResult create(@NotNull RenderTask renderTask,
@NotNull RenderSession session,
@NotNull PsiFile file,
@NotNull RenderLogger logger,
@NotNull ImagePool.Image image) {
List<ViewInfo> rootViews = session.getRootViews();
List<ViewInfo> systemRootViews = session.getSystemRootViews();
Map<Object, Map<ResourceReference, ResourceValue>> defaultProperties = session.getDefaultNamespacedProperties();
Map<Object, String> defaultStyles = session.getDefaultStyles();
RenderResult result = new RenderResult(
file,
renderTask.getContext().getModule(),
logger,
renderTask,
session.getResult(),
rootViews != null ? ImmutableList.copyOf(rootViews) : ImmutableList.of(),
systemRootViews != null ? ImmutableList.copyOf(systemRootViews) : ImmutableList.of(),
image, // image might be ImagePool.NULL_POOL_IMAGE if there is no rendered image (as in layout())
defaultProperties != null ? ImmutableMap.copyOf(defaultProperties) : ImmutableMap.of(),
defaultStyles != null ? ImmutableMap.copyOf(defaultStyles) : ImmutableMap.of(),
session.getValidationData());
if (LOG.isDebugEnabled()) {
LOG.debug(result.toString());
}
return result;
}
/**
* Creates a new session initialization error {@link RenderResult} from a given RenderTask
*/
@NotNull
public static RenderResult createSessionInitializationError(@NotNull RenderTask renderTask,
@NotNull PsiFile file,
@NotNull RenderLogger logger,
@Nullable Throwable throwable) {
Module module = logger.getModule();
assert module != null;
RenderResult result = new RenderResult(
file,
module, // do not use renderTask.getModule as a disposed renderTask could be the reason we are here
logger,
renderTask,
Result.Status.ERROR_UNKNOWN.createResult("Failed to initialize session", throwable),
ImmutableList.of(),
ImmutableList.of(),
ImagePool.NULL_POOLED_IMAGE,
ImmutableMap.of(),
ImmutableMap.of(),
null);
if (LOG.isDebugEnabled()) {
LOG.debug(result.toString());
}
return result;
}
/**
* Creates a new blank {@link RenderResult}
*
* @param file the PSI file the render result corresponds to
* @return a blank render result
*/
@NotNull
public static RenderResult createBlank(@NotNull PsiFile file) {
return createErrorResult(file, Result.Status.ERROR_UNKNOWN.createResult(""), null);
}
/**
* Creates a blank {@link RenderResult} to report render task creation errors
*
* @param file the PSI file the render result corresponds to
* @param logger the logger containing the errors to surface to the user
*/
@NotNull
public static RenderResult createRenderTaskErrorResult(@NotNull PsiFile file, @NotNull RenderLogger logger) {
return createErrorResult(file, Result.Status.ERROR_RENDER_TASK.createResult(), logger);
}
@NotNull
private static RenderResult createErrorResult(@NotNull PsiFile file, @NotNull Result errorResult, @Nullable RenderLogger logger) {
Module module = ModuleUtilCore.findModuleForPsiElement(file);
assert module != null;
RenderResult result = new RenderResult(
file,
module,
logger != null ? logger : new RenderLogger(null, module),
null,
errorResult,
ImmutableList.of(),
ImmutableList.of(),
ImagePool.NULL_POOLED_IMAGE,
ImmutableMap.of(),
ImmutableMap.of(),
null);
if (LOG.isDebugEnabled()) {
LOG.debug(result.toString());
}
return result;
}
@NotNull
public Result getRenderResult() {
return myRenderResult;
}
@NotNull
public RenderLogger getLogger() {
return myLogger;
}
@NotNull
public ImagePool.Image getRenderedImage() {
myDisposeLock.readLock().lock();
try {
return !isDisposed ? myImage : ImagePool.NULL_POOLED_IMAGE;
} finally {
myDisposeLock.readLock().unlock();
}
}
@NotNull
public PsiFile getFile() {
return myFile;
}
@Nullable
public RenderTask getRenderTask() {
return myRenderTask;
}
@NotNull
public Module getModule() {
return myModule;
}
@NotNull
public ImmutableList<ViewInfo> getRootViews() {
return myRootViews;
}
@NotNull
public ImmutableList<ViewInfo> getSystemRootViews() {
return mySystemRootViews;
}
@Nullable
public Object getValidatorResult() {
return myValidatorResult;
}
/**
* Returns the default properties map. This map contains a list of the widgets default values for every attribute as returned by layoutlib.
* The map is index by view cookie.
*/
@NotNull
public Map<Object, Map<ResourceReference, ResourceValue>> getDefaultProperties() {
return myDefaultProperties;
}
/**
* Returns the default style map. This map contains the default style of the widgets as returned by layoutlib.
* The map is index by view cookie.
*/
@NotNull
public Map<Object, String> getDefaultStyles() {
return myDefaultStyles;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("renderResult", myRenderResult)
.add("psiFile", myFile)
.add("rootViews", myRootViews)
.add("systemViews", mySystemRootViews)
.toString();
}
}