Merge "Add Asset management support for fonts." into lmp-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ad879adb65
@@ -16,12 +16,13 @@
|
||||
|
||||
package android.content.res;
|
||||
|
||||
import com.android.ide.common.rendering.api.AssetRepository;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
|
||||
public class BridgeAssetManager extends AssetManager {
|
||||
|
||||
private AssetRepository mAssetRepository;
|
||||
|
||||
/**
|
||||
* This initializes the static field {@link AssetManager#sSystem} which is used
|
||||
* by methods who get a global asset manager using {@link AssetManager#getSystem()}.
|
||||
@@ -48,6 +49,14 @@ public class BridgeAssetManager extends AssetManager {
|
||||
AssetManager.sSystem = null;
|
||||
}
|
||||
|
||||
private BridgeAssetManager() {
|
||||
public void setAssetRepository(AssetRepository assetRepository) {
|
||||
mAssetRepository = assetRepository;
|
||||
}
|
||||
|
||||
public AssetRepository getAssetRepository() {
|
||||
return mAssetRepository;
|
||||
}
|
||||
|
||||
public BridgeAssetManager() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,21 +18,28 @@ package android.graphics;
|
||||
|
||||
import com.android.annotations.NonNull;
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.ide.common.rendering.api.AssetRepository;
|
||||
import com.android.ide.common.rendering.api.LayoutLog;
|
||||
import com.android.layoutlib.bridge.Bridge;
|
||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.BridgeAssetManager;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -56,10 +63,28 @@ public class FontFamily_Delegate {
|
||||
public static final int BOLD_FONT_WEIGHT_DELTA = 300;
|
||||
public static final int BOLD_FONT_WEIGHT = 700;
|
||||
|
||||
// FONT_SUFFIX_ITALIC will always match FONT_SUFFIX_BOLDITALIC and hence it must be checked
|
||||
// separately.
|
||||
private static final String FONT_SUFFIX_ITALIC = "Italic.ttf";
|
||||
private static final String FN_ALL_FONTS_LIST = "fontsInSdk.txt";
|
||||
private static final String EXTENSION_OTF = ".otf";
|
||||
|
||||
private static final int CACHE_SIZE = 10;
|
||||
// The cache has a drawback that if the font file changed after the font object was created,
|
||||
// we will not update it.
|
||||
private static final Map<String, FontInfo> sCache =
|
||||
new LinkedHashMap<String, FontInfo>(CACHE_SIZE) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Entry<String, FontInfo> eldest) {
|
||||
return size() > CACHE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontInfo put(String key, FontInfo value) {
|
||||
// renew this entry.
|
||||
FontInfo removed = remove(key);
|
||||
super.put(key, value);
|
||||
return removed;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class associating {@link Font} with its metadata.
|
||||
@@ -194,7 +219,7 @@ public class FontFamily_Delegate {
|
||||
try {
|
||||
return Font.createFont(Font.TRUETYPE_FONT, f);
|
||||
} catch (Exception e) {
|
||||
if (path.endsWith(".otf") && e instanceof FontFormatException) {
|
||||
if (path.endsWith(EXTENSION_OTF) && e instanceof FontFormatException) {
|
||||
// If we aren't able to load an Open Type font, don't log a warning just yet.
|
||||
// We wait for a case where font is being used. Only then we try to log the
|
||||
// warning.
|
||||
@@ -281,8 +306,74 @@ public class FontFamily_Delegate {
|
||||
|
||||
@LayoutlibDelegate
|
||||
/*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) {
|
||||
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
|
||||
"Typeface.createFromAsset is not supported.", null, null);
|
||||
FontFamily_Delegate ffd = sManager.getDelegate(nativeFamily);
|
||||
ffd.mValid = true;
|
||||
if (mgr == null) {
|
||||
return false;
|
||||
}
|
||||
if (mgr instanceof BridgeAssetManager) {
|
||||
InputStream fontStream = null;
|
||||
try {
|
||||
AssetRepository assetRepository = ((BridgeAssetManager) mgr).getAssetRepository();
|
||||
if (assetRepository == null) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Asset not found: " + path,
|
||||
null);
|
||||
return false;
|
||||
}
|
||||
if (!assetRepository.isSupported()) {
|
||||
// Don't log any warnings on unsupported IDEs.
|
||||
return false;
|
||||
}
|
||||
// Check cache
|
||||
FontInfo fontInfo = sCache.get(path);
|
||||
if (fontInfo != null) {
|
||||
// renew the font's lease.
|
||||
sCache.put(path, fontInfo);
|
||||
ffd.addFont(fontInfo);
|
||||
return true;
|
||||
}
|
||||
fontStream = assetRepository.openAsset(path, AssetManager.ACCESS_STREAMING);
|
||||
if (fontStream == null) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Asset not found: " + path,
|
||||
path);
|
||||
return false;
|
||||
}
|
||||
Font font = Font.createFont(Font.TRUETYPE_FONT, fontStream);
|
||||
fontInfo = new FontInfo();
|
||||
fontInfo.mFont = font;
|
||||
fontInfo.mWeight = font.isBold() ? BOLD_FONT_WEIGHT : DEFAULT_FONT_WEIGHT;
|
||||
fontInfo.mIsItalic = font.isItalic();
|
||||
ffd.addFont(fontInfo);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Unable to load font " + path, e,
|
||||
path);
|
||||
} catch (FontFormatException e) {
|
||||
if (path.endsWith(EXTENSION_OTF)) {
|
||||
// otf fonts are not supported on the user's config (JRE version + OS)
|
||||
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
|
||||
"OpenType fonts are not supported yet: " + path, null, path);
|
||||
} else {
|
||||
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
|
||||
"Unable to load font " + path, e, path);
|
||||
}
|
||||
} finally {
|
||||
if (fontStream != null) {
|
||||
try {
|
||||
fontStream.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// This should never happen. AssetManager is a final class (from user's perspective), and
|
||||
// we've replaced every creation of AssetManager with our implementation. We create an
|
||||
// exception and log it, but continue with rest of the rendering, without loading this font.
|
||||
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
|
||||
"You have found a bug in the rendering library. Please file a bug at b.android.com.",
|
||||
new RuntimeException("Asset Manager is not an instance of BridgeAssetManager"),
|
||||
null);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.layoutlib.bridge.android;
|
||||
|
||||
import com.android.annotations.Nullable;
|
||||
import com.android.ide.common.rendering.api.AssetRepository;
|
||||
import com.android.ide.common.rendering.api.ILayoutPullParser;
|
||||
import com.android.ide.common.rendering.api.IProjectCallback;
|
||||
import com.android.ide.common.rendering.api.LayoutLog;
|
||||
@@ -47,6 +48,7 @@ import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.BridgeAssetManager;
|
||||
import android.content.res.BridgeResources;
|
||||
import android.content.res.BridgeTypedArray;
|
||||
import android.content.res.Configuration;
|
||||
@@ -101,6 +103,7 @@ public final class BridgeContext extends Context {
|
||||
* used to populate the mViewKeyMap.
|
||||
*/
|
||||
private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<Object, Object>();
|
||||
private final BridgeAssetManager mAssets;
|
||||
private Resources mSystemResources;
|
||||
private final Object mProjectKey;
|
||||
private final DisplayMetrics mMetrics;
|
||||
@@ -140,6 +143,7 @@ public final class BridgeContext extends Context {
|
||||
*/
|
||||
public BridgeContext(Object projectKey, DisplayMetrics metrics,
|
||||
RenderResources renderResources,
|
||||
AssetRepository assets,
|
||||
IProjectCallback projectCallback,
|
||||
Configuration config,
|
||||
int targetSdkVersion,
|
||||
@@ -150,6 +154,8 @@ public final class BridgeContext extends Context {
|
||||
|
||||
mRenderResources = renderResources;
|
||||
mConfig = config;
|
||||
mAssets = new BridgeAssetManager();
|
||||
mAssets.setAssetRepository(assets);
|
||||
|
||||
mApplicationInfo = new ApplicationInfo();
|
||||
mApplicationInfo.targetSdkVersion = targetSdkVersion;
|
||||
@@ -1075,9 +1081,8 @@ public final class BridgeContext extends Context {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetManager getAssets() {
|
||||
// pass
|
||||
return null;
|
||||
public BridgeAssetManager getAssets() {
|
||||
return mAssets;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -35,7 +35,6 @@ import com.android.resources.ScreenSize;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.HandlerThread_Delegate;
|
||||
import android.os.Looper;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.ViewConfiguration_Accessor;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
@@ -71,7 +70,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
||||
/**
|
||||
* Creates a renderAction.
|
||||
* <p>
|
||||
* This <b>must</b> be followed by a call to {@link RenderAction#init()}, which act as a
|
||||
* This <b>must</b> be followed by a call to {@link RenderAction#init(long)}, which act as a
|
||||
* call to {@link RenderAction#acquire(long)}
|
||||
*
|
||||
* @param params the RenderParams. This must be a copy that the action can keep
|
||||
@@ -121,8 +120,8 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
||||
|
||||
// build the context
|
||||
mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
|
||||
mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion(),
|
||||
mParams.isRtlSupported());
|
||||
mParams.getAssets(), mParams.getProjectCallback(), getConfiguration(),
|
||||
mParams.getTargetSdkVersion(), mParams.isRtlSupported());
|
||||
|
||||
setUp();
|
||||
|
||||
@@ -139,7 +138,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
||||
* The preparation can fail if another rendering took too long and the timeout was elapsed.
|
||||
*
|
||||
* More than one call to this from the same thread will have no effect and will return
|
||||
* {@link Result#SUCCESS}.
|
||||
* {@link Result.Status#SUCCESS}.
|
||||
*
|
||||
* After scene actions have taken place, only one call to {@link #release()} must be
|
||||
* done.
|
||||
@@ -173,7 +172,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
||||
* Acquire the lock so that the scene can be acted upon.
|
||||
* <p>
|
||||
* This returns null if the lock was just acquired, otherwise it returns
|
||||
* {@link Result#SUCCESS} if the lock already belonged to that thread, or another
|
||||
* {@link Result.Status#SUCCESS} if the lock already belonged to that thread, or another
|
||||
* instance (see {@link Result#getStatus()}) if an error occurred.
|
||||
*
|
||||
* @param timeout the time to wait if another rendering is happening.
|
||||
@@ -184,11 +183,11 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
||||
*/
|
||||
private Result acquireLock(long timeout) {
|
||||
ReentrantLock lock = Bridge.getLock();
|
||||
if (lock.isHeldByCurrentThread() == false) {
|
||||
if (!lock.isHeldByCurrentThread()) {
|
||||
try {
|
||||
boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
|
||||
|
||||
if (acquired == false) {
|
||||
if (!acquired) {
|
||||
return ERROR_TIMEOUT.createResult();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
@@ -308,7 +307,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
||||
*/
|
||||
protected void checkLock() {
|
||||
ReentrantLock lock = Bridge.getLock();
|
||||
if (lock.isHeldByCurrentThread() == false) {
|
||||
if (!lock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
|
||||
}
|
||||
if (sCurrentContext != mContext) {
|
||||
@@ -347,6 +346,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
||||
config.screenWidthDp = hardwareConfig.getScreenWidth() / density.getDpiValue();
|
||||
config.screenHeightDp = hardwareConfig.getScreenHeight() / density.getDpiValue();
|
||||
if (config.screenHeightDp < config.screenWidthDp) {
|
||||
//noinspection SuspiciousNameCombination
|
||||
config.smallestScreenWidthDp = config.screenHeightDp;
|
||||
} else {
|
||||
config.smallestScreenWidthDp = config.screenWidthDp;
|
||||
@@ -367,6 +367,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
||||
config.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||
break;
|
||||
case SQUARE:
|
||||
//noinspection deprecation
|
||||
config.orientation = Configuration.ORIENTATION_SQUARE;
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user