am 0a300b89: am ad879adb: Merge "Add Asset management support for fonts." into lmp-dev automerge: 0684991
* commit '0a300b897711bfa39e0d30e2fa61664f01fb58d8': Add Asset management support for fonts.
This commit is contained in:
@@ -16,12 +16,13 @@
|
|||||||
|
|
||||||
package android.content.res;
|
package android.content.res;
|
||||||
|
|
||||||
|
import com.android.ide.common.rendering.api.AssetRepository;
|
||||||
import com.android.layoutlib.bridge.Bridge;
|
import com.android.layoutlib.bridge.Bridge;
|
||||||
|
|
||||||
import android.content.res.AssetManager;
|
|
||||||
|
|
||||||
public class BridgeAssetManager extends AssetManager {
|
public class BridgeAssetManager extends AssetManager {
|
||||||
|
|
||||||
|
private AssetRepository mAssetRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This initializes the static field {@link AssetManager#sSystem} which is used
|
* This initializes the static field {@link AssetManager#sSystem} which is used
|
||||||
* by methods who get a global asset manager using {@link AssetManager#getSystem()}.
|
* by methods who get a global asset manager using {@link AssetManager#getSystem()}.
|
||||||
@@ -48,6 +49,14 @@ public class BridgeAssetManager extends AssetManager {
|
|||||||
AssetManager.sSystem = null;
|
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.NonNull;
|
||||||
import com.android.annotations.Nullable;
|
import com.android.annotations.Nullable;
|
||||||
|
import com.android.ide.common.rendering.api.AssetRepository;
|
||||||
import com.android.ide.common.rendering.api.LayoutLog;
|
import com.android.ide.common.rendering.api.LayoutLog;
|
||||||
import com.android.layoutlib.bridge.Bridge;
|
import com.android.layoutlib.bridge.Bridge;
|
||||||
import com.android.layoutlib.bridge.impl.DelegateManager;
|
import com.android.layoutlib.bridge.impl.DelegateManager;
|
||||||
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
|
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
|
||||||
|
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
|
import android.content.res.BridgeAssetManager;
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.FontFormatException;
|
import java.awt.FontFormatException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.Set;
|
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_DELTA = 300;
|
||||||
public static final int BOLD_FONT_WEIGHT = 700;
|
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 FONT_SUFFIX_ITALIC = "Italic.ttf";
|
||||||
private static final String FN_ALL_FONTS_LIST = "fontsInSdk.txt";
|
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.
|
* A class associating {@link Font} with its metadata.
|
||||||
@@ -194,7 +219,7 @@ public class FontFamily_Delegate {
|
|||||||
try {
|
try {
|
||||||
return Font.createFont(Font.TRUETYPE_FONT, f);
|
return Font.createFont(Font.TRUETYPE_FONT, f);
|
||||||
} catch (Exception e) {
|
} 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.
|
// 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
|
// We wait for a case where font is being used. Only then we try to log the
|
||||||
// warning.
|
// warning.
|
||||||
@@ -281,8 +306,74 @@ public class FontFamily_Delegate {
|
|||||||
|
|
||||||
@LayoutlibDelegate
|
@LayoutlibDelegate
|
||||||
/*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) {
|
/*package*/ static boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, String path) {
|
||||||
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
|
FontFamily_Delegate ffd = sManager.getDelegate(nativeFamily);
|
||||||
"Typeface.createFromAsset is not supported.", null, null);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.layoutlib.bridge.android;
|
|||||||
|
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import com.android.annotations.Nullable;
|
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.ILayoutPullParser;
|
||||||
import com.android.ide.common.rendering.api.IProjectCallback;
|
import com.android.ide.common.rendering.api.IProjectCallback;
|
||||||
import com.android.ide.common.rendering.api.LayoutLog;
|
import com.android.ide.common.rendering.api.LayoutLog;
|
||||||
@@ -48,6 +49,7 @@ import android.content.SharedPreferences;
|
|||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
|
import android.content.res.BridgeAssetManager;
|
||||||
import android.content.res.BridgeResources;
|
import android.content.res.BridgeResources;
|
||||||
import android.content.res.BridgeTypedArray;
|
import android.content.res.BridgeTypedArray;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
@@ -102,6 +104,7 @@ public final class BridgeContext extends Context {
|
|||||||
* used to populate the mViewKeyMap.
|
* used to populate the mViewKeyMap.
|
||||||
*/
|
*/
|
||||||
private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<Object, Object>();
|
private final HashMap<Object, Object> mViewKeyHelpMap = new HashMap<Object, Object>();
|
||||||
|
private final BridgeAssetManager mAssets;
|
||||||
private Resources mSystemResources;
|
private Resources mSystemResources;
|
||||||
private final Object mProjectKey;
|
private final Object mProjectKey;
|
||||||
private final DisplayMetrics mMetrics;
|
private final DisplayMetrics mMetrics;
|
||||||
@@ -141,6 +144,7 @@ public final class BridgeContext extends Context {
|
|||||||
*/
|
*/
|
||||||
public BridgeContext(Object projectKey, DisplayMetrics metrics,
|
public BridgeContext(Object projectKey, DisplayMetrics metrics,
|
||||||
RenderResources renderResources,
|
RenderResources renderResources,
|
||||||
|
AssetRepository assets,
|
||||||
IProjectCallback projectCallback,
|
IProjectCallback projectCallback,
|
||||||
Configuration config,
|
Configuration config,
|
||||||
int targetSdkVersion,
|
int targetSdkVersion,
|
||||||
@@ -151,6 +155,8 @@ public final class BridgeContext extends Context {
|
|||||||
|
|
||||||
mRenderResources = renderResources;
|
mRenderResources = renderResources;
|
||||||
mConfig = config;
|
mConfig = config;
|
||||||
|
mAssets = new BridgeAssetManager();
|
||||||
|
mAssets.setAssetRepository(assets);
|
||||||
|
|
||||||
mApplicationInfo = new ApplicationInfo();
|
mApplicationInfo = new ApplicationInfo();
|
||||||
mApplicationInfo.targetSdkVersion = targetSdkVersion;
|
mApplicationInfo.targetSdkVersion = targetSdkVersion;
|
||||||
@@ -1088,9 +1094,8 @@ public final class BridgeContext extends Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AssetManager getAssets() {
|
public BridgeAssetManager getAssets() {
|
||||||
// pass
|
return mAssets;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import com.android.resources.ScreenSize;
|
|||||||
|
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.HandlerThread_Delegate;
|
import android.os.HandlerThread_Delegate;
|
||||||
import android.os.Looper;
|
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.view.ViewConfiguration_Accessor;
|
import android.view.ViewConfiguration_Accessor;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
@@ -71,7 +70,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
|||||||
/**
|
/**
|
||||||
* Creates a renderAction.
|
* Creates a renderAction.
|
||||||
* <p>
|
* <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)}
|
* call to {@link RenderAction#acquire(long)}
|
||||||
*
|
*
|
||||||
* @param params the RenderParams. This must be a copy that the action can keep
|
* @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
|
// build the context
|
||||||
mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
|
mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
|
||||||
mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion(),
|
mParams.getAssets(), mParams.getProjectCallback(), getConfiguration(),
|
||||||
mParams.isRtlSupported());
|
mParams.getTargetSdkVersion(), mParams.isRtlSupported());
|
||||||
|
|
||||||
setUp();
|
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.
|
* 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
|
* 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
|
* After scene actions have taken place, only one call to {@link #release()} must be
|
||||||
* done.
|
* 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.
|
* Acquire the lock so that the scene can be acted upon.
|
||||||
* <p>
|
* <p>
|
||||||
* This returns null if the lock was just acquired, otherwise it returns
|
* 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.
|
* instance (see {@link Result#getStatus()}) if an error occurred.
|
||||||
*
|
*
|
||||||
* @param timeout the time to wait if another rendering is happening.
|
* @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) {
|
private Result acquireLock(long timeout) {
|
||||||
ReentrantLock lock = Bridge.getLock();
|
ReentrantLock lock = Bridge.getLock();
|
||||||
if (lock.isHeldByCurrentThread() == false) {
|
if (!lock.isHeldByCurrentThread()) {
|
||||||
try {
|
try {
|
||||||
boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
|
boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
if (acquired == false) {
|
if (!acquired) {
|
||||||
return ERROR_TIMEOUT.createResult();
|
return ERROR_TIMEOUT.createResult();
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@@ -308,7 +307,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
|||||||
*/
|
*/
|
||||||
protected void checkLock() {
|
protected void checkLock() {
|
||||||
ReentrantLock lock = Bridge.getLock();
|
ReentrantLock lock = Bridge.getLock();
|
||||||
if (lock.isHeldByCurrentThread() == false) {
|
if (!lock.isHeldByCurrentThread()) {
|
||||||
throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
|
throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
|
||||||
}
|
}
|
||||||
if (sCurrentContext != mContext) {
|
if (sCurrentContext != mContext) {
|
||||||
@@ -347,6 +346,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
|||||||
config.screenWidthDp = hardwareConfig.getScreenWidth() / density.getDpiValue();
|
config.screenWidthDp = hardwareConfig.getScreenWidth() / density.getDpiValue();
|
||||||
config.screenHeightDp = hardwareConfig.getScreenHeight() / density.getDpiValue();
|
config.screenHeightDp = hardwareConfig.getScreenHeight() / density.getDpiValue();
|
||||||
if (config.screenHeightDp < config.screenWidthDp) {
|
if (config.screenHeightDp < config.screenWidthDp) {
|
||||||
|
//noinspection SuspiciousNameCombination
|
||||||
config.smallestScreenWidthDp = config.screenHeightDp;
|
config.smallestScreenWidthDp = config.screenHeightDp;
|
||||||
} else {
|
} else {
|
||||||
config.smallestScreenWidthDp = config.screenWidthDp;
|
config.smallestScreenWidthDp = config.screenWidthDp;
|
||||||
@@ -367,6 +367,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
|||||||
config.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
config.orientation = Configuration.ORIENTATION_LANDSCAPE;
|
||||||
break;
|
break;
|
||||||
case SQUARE:
|
case SQUARE:
|
||||||
|
//noinspection deprecation
|
||||||
config.orientation = Configuration.ORIENTATION_SQUARE;
|
config.orientation = Configuration.ORIENTATION_SQUARE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user