* commit '97c88368e0036665507c8cd84c71d26953784c85': Fix layout rendering for RTL locales
This commit is contained in:
@ -7,5 +7,6 @@
|
|||||||
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
|
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
|
||||||
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar"/>
|
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/ninepatch/ninepatch-prebuilt.jar"/>
|
||||||
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/>
|
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/tools-common/tools-common-prebuilt.jar"/>
|
||||||
|
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/icu4j/icu4j.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
@ -22,6 +22,7 @@ LOCAL_JAVA_RESOURCE_DIRS := resources
|
|||||||
|
|
||||||
LOCAL_JAVA_LIBRARIES := \
|
LOCAL_JAVA_LIBRARIES := \
|
||||||
kxml2-2.3.0 \
|
kxml2-2.3.0 \
|
||||||
|
icu4j \
|
||||||
layoutlib_api-prebuilt \
|
layoutlib_api-prebuilt \
|
||||||
tools-common-prebuilt
|
tools-common-prebuilt
|
||||||
|
|
||||||
|
Binary file not shown.
After Width: | Height: | Size: 904 B |
Binary file not shown.
After Width: | Height: | Size: 533 B |
Binary file not shown.
After Width: | Height: | Size: 617 B |
Binary file not shown.
After Width: | Height: | Size: 423 B |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 552 B |
@ -35,6 +35,7 @@ import com.android.resources.ResourceType;
|
|||||||
import com.android.tools.layoutlib.create.MethodAdapter;
|
import com.android.tools.layoutlib.create.MethodAdapter;
|
||||||
import com.android.tools.layoutlib.create.OverrideMethod;
|
import com.android.tools.layoutlib.create.OverrideMethod;
|
||||||
import com.android.util.Pair;
|
import com.android.util.Pair;
|
||||||
|
import com.ibm.icu.util.ULocale;
|
||||||
|
|
||||||
import android.content.res.BridgeAssetManager;
|
import android.content.res.BridgeAssetManager;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@ -64,6 +65,8 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
*/
|
*/
|
||||||
public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
|
public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
|
||||||
|
|
||||||
|
private static final String ICU_LOCALE_DIRECTION_RTL = "right-to-left";
|
||||||
|
|
||||||
public static class StaticMethodNotImplementedException extends RuntimeException {
|
public static class StaticMethodNotImplementedException extends RuntimeException {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@ -211,7 +214,8 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
|
|||||||
Capability.ANIMATED_VIEW_MANIPULATION,
|
Capability.ANIMATED_VIEW_MANIPULATION,
|
||||||
Capability.ADAPTER_BINDING,
|
Capability.ADAPTER_BINDING,
|
||||||
Capability.EXTENDED_VIEWINFO,
|
Capability.EXTENDED_VIEWINFO,
|
||||||
Capability.FIXED_SCALABLE_NINE_PATCH);
|
Capability.FIXED_SCALABLE_NINE_PATCH,
|
||||||
|
Capability.RTL);
|
||||||
|
|
||||||
|
|
||||||
BridgeAssetManager.initSystem();
|
BridgeAssetManager.initSystem();
|
||||||
@ -411,6 +415,20 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
|
|||||||
throw new IllegalArgumentException("viewObject is not a View");
|
throw new IllegalArgumentException("viewObject is not a View");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRtl(String locale) {
|
||||||
|
return isLocaleRtl(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLocaleRtl(String locale) {
|
||||||
|
if (locale == null) {
|
||||||
|
locale = "";
|
||||||
|
}
|
||||||
|
ULocale uLocale = new ULocale(locale);
|
||||||
|
return uLocale.getCharacterOrientation().equals(ICU_LOCALE_DIRECTION_RTL) ?
|
||||||
|
true : false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the lock for the bridge
|
* Returns the lock for the bridge
|
||||||
*/
|
*/
|
||||||
|
@ -132,7 +132,8 @@ public final class BridgeContext extends Context {
|
|||||||
RenderResources renderResources,
|
RenderResources renderResources,
|
||||||
IProjectCallback projectCallback,
|
IProjectCallback projectCallback,
|
||||||
Configuration config,
|
Configuration config,
|
||||||
int targetSdkVersion) {
|
int targetSdkVersion,
|
||||||
|
boolean hasRtlSupport) {
|
||||||
mProjectKey = projectKey;
|
mProjectKey = projectKey;
|
||||||
mMetrics = metrics;
|
mMetrics = metrics;
|
||||||
mProjectCallback = projectCallback;
|
mProjectCallback = projectCallback;
|
||||||
@ -142,6 +143,9 @@ public final class BridgeContext extends Context {
|
|||||||
|
|
||||||
mApplicationInfo = new ApplicationInfo();
|
mApplicationInfo = new ApplicationInfo();
|
||||||
mApplicationInfo.targetSdkVersion = targetSdkVersion;
|
mApplicationInfo.targetSdkVersion = targetSdkVersion;
|
||||||
|
if (hasRtlSupport) {
|
||||||
|
mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL;
|
||||||
|
}
|
||||||
|
|
||||||
mWindowManager = new WindowManagerImpl(mMetrics);
|
mWindowManager = new WindowManagerImpl(mMetrics);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
|
|||||||
import com.android.layoutlib.bridge.impl.ParserFactory;
|
import com.android.layoutlib.bridge.impl.ParserFactory;
|
||||||
import com.android.layoutlib.bridge.impl.ResourceHelper;
|
import com.android.layoutlib.bridge.impl.ResourceHelper;
|
||||||
import com.android.resources.Density;
|
import com.android.resources.Density;
|
||||||
|
import com.android.resources.LayoutDirection;
|
||||||
import com.android.resources.ResourceType;
|
import com.android.resources.ResourceType;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
@ -86,38 +87,53 @@ abstract class CustomBar extends LinearLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut,
|
private InputStream getIcon(String iconName, Density[] densityInOut, LayoutDirection direction,
|
||||||
boolean tryOtherDensities) {
|
String[] pathOut, boolean tryOtherDensities) {
|
||||||
// current density
|
// current density
|
||||||
Density density = densityInOut[0];
|
Density density = densityInOut[0];
|
||||||
|
|
||||||
// bitmap url relative to this class
|
// bitmap url relative to this class
|
||||||
pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
|
if (direction != null) {
|
||||||
|
pathOut[0] = "/bars/" + direction.getResourceValue() + "-" + density.getResourceValue()
|
||||||
|
+ "/" + iconName;
|
||||||
|
} else {
|
||||||
|
pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
|
||||||
|
}
|
||||||
|
|
||||||
InputStream stream = getClass().getResourceAsStream(pathOut[0]);
|
InputStream stream = getClass().getResourceAsStream(pathOut[0]);
|
||||||
if (stream == null && tryOtherDensities) {
|
if (stream == null && tryOtherDensities) {
|
||||||
for (Density d : Density.values()) {
|
for (Density d : Density.values()) {
|
||||||
if (d != density) {
|
if (d != density) {
|
||||||
densityInOut[0] = d;
|
densityInOut[0] = d;
|
||||||
stream = getIcon(iconName, densityInOut, pathOut, false /*tryOtherDensities*/);
|
stream = getIcon(iconName, densityInOut, direction, pathOut,
|
||||||
|
false /*tryOtherDensities*/);
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// couldn't find resource with direction qualifier. try without.
|
||||||
|
if (direction != null) {
|
||||||
|
return getIcon(iconName, densityInOut, null, pathOut, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadIcon(int index, String iconName, Density density) {
|
protected void loadIcon(int index, String iconName, Density density) {
|
||||||
|
loadIcon(index, iconName, density, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void loadIcon(int index, String iconName, Density density, boolean isRtl) {
|
||||||
View child = getChildAt(index);
|
View child = getChildAt(index);
|
||||||
if (child instanceof ImageView) {
|
if (child instanceof ImageView) {
|
||||||
ImageView imageView = (ImageView) child;
|
ImageView imageView = (ImageView) child;
|
||||||
|
|
||||||
String[] pathOut = new String[1];
|
String[] pathOut = new String[1];
|
||||||
Density[] densityInOut = new Density[] { density };
|
Density[] densityInOut = new Density[] { density };
|
||||||
InputStream stream = getIcon(iconName, densityInOut, pathOut,
|
LayoutDirection dir = isRtl ? LayoutDirection.RTL : LayoutDirection.LTR;
|
||||||
|
InputStream stream = getIcon(iconName, densityInOut, dir, pathOut,
|
||||||
true /*tryOtherDensities*/);
|
true /*tryOtherDensities*/);
|
||||||
density = densityInOut[0];
|
density = densityInOut[0];
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package com.android.layoutlib.bridge.bars;
|
package com.android.layoutlib.bridge.bars;
|
||||||
|
|
||||||
import com.android.resources.Density;
|
import com.android.resources.Density;
|
||||||
|
import com.android.layoutlib.bridge.Bridge;
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
@ -26,7 +27,8 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
public class NavigationBar extends CustomBar {
|
public class NavigationBar extends CustomBar {
|
||||||
|
|
||||||
public NavigationBar(Context context, Density density, int orientation) throws XmlPullParserException {
|
public NavigationBar(Context context, Density density, int orientation, boolean isRtl,
|
||||||
|
boolean rtlEnabled) throws XmlPullParserException {
|
||||||
super(context, density, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml");
|
super(context, density, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml");
|
||||||
|
|
||||||
setBackgroundColor(0xFF000000);
|
setBackgroundColor(0xFF000000);
|
||||||
@ -37,14 +39,15 @@ public class NavigationBar extends CustomBar {
|
|||||||
// 0 is a spacer.
|
// 0 is a spacer.
|
||||||
int back = 1;
|
int back = 1;
|
||||||
int recent = 3;
|
int recent = 3;
|
||||||
if (orientation == LinearLayout.VERTICAL) {
|
if (orientation == LinearLayout.VERTICAL || (isRtl && !rtlEnabled)) {
|
||||||
|
// If RTL is enabled, then layoutlib mirrors the layout for us.
|
||||||
back = 3;
|
back = 3;
|
||||||
recent = 1;
|
recent = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadIcon(back, "ic_sysbar_back.png", density);
|
loadIcon(back, "ic_sysbar_back.png", density, isRtl);
|
||||||
loadIcon(2, "ic_sysbar_home.png", density);
|
loadIcon(2, "ic_sysbar_home.png", density, isRtl);
|
||||||
loadIcon(recent, "ic_sysbar_recent.png", density);
|
loadIcon(recent, "ic_sysbar_recent.png", density, isRtl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -30,7 +30,10 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
public class StatusBar extends CustomBar {
|
public class StatusBar extends CustomBar {
|
||||||
|
|
||||||
public StatusBar(Context context, Density density) throws XmlPullParserException {
|
public StatusBar(Context context, Density density, int direction, boolean RtlEnabled)
|
||||||
|
throws XmlPullParserException {
|
||||||
|
// FIXME: if direction is RTL but it's not enabled in application manifest, mirror this bar.
|
||||||
|
|
||||||
super(context, density, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml");
|
super(context, density, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml");
|
||||||
|
|
||||||
// FIXME: use FILL_H?
|
// FIXME: use FILL_H?
|
||||||
|
@ -121,7 +121,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.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion(),
|
||||||
|
mParams.isRtlSupported());
|
||||||
|
|
||||||
setUp();
|
setUp();
|
||||||
|
|
||||||
|
@ -224,13 +224,15 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
|||||||
SessionParams params = getParams();
|
SessionParams params = getParams();
|
||||||
HardwareConfig hardwareConfig = params.getHardwareConfig();
|
HardwareConfig hardwareConfig = params.getHardwareConfig();
|
||||||
BridgeContext context = getContext();
|
BridgeContext context = getContext();
|
||||||
|
boolean isRtl = Bridge.isLocaleRtl(params.getLocale());
|
||||||
|
int direction = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
|
||||||
|
|
||||||
// the view group that receives the window background.
|
// the view group that receives the window background.
|
||||||
ViewGroup backgroundView = null;
|
ViewGroup backgroundView = null;
|
||||||
|
|
||||||
if (mWindowIsFloating || params.isForceNoDecor()) {
|
if (mWindowIsFloating || params.isForceNoDecor()) {
|
||||||
backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
|
backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
|
||||||
|
mViewRoot.setLayoutDirection(direction);
|
||||||
} else {
|
} else {
|
||||||
if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
|
if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
|
||||||
/*
|
/*
|
||||||
@ -252,12 +254,14 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
|||||||
the bottom
|
the bottom
|
||||||
*/
|
*/
|
||||||
LinearLayout topLayout = new LinearLayout(context);
|
LinearLayout topLayout = new LinearLayout(context);
|
||||||
|
topLayout.setLayoutDirection(direction);
|
||||||
mViewRoot = topLayout;
|
mViewRoot = topLayout;
|
||||||
topLayout.setOrientation(LinearLayout.HORIZONTAL);
|
topLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
NavigationBar navigationBar = new NavigationBar(context,
|
NavigationBar navigationBar = new NavigationBar(context,
|
||||||
hardwareConfig.getDensity(), LinearLayout.VERTICAL);
|
hardwareConfig.getDensity(), LinearLayout.VERTICAL, isRtl,
|
||||||
|
params.isRtlSupported());
|
||||||
navigationBar.setLayoutParams(
|
navigationBar.setLayoutParams(
|
||||||
new LinearLayout.LayoutParams(
|
new LinearLayout.LayoutParams(
|
||||||
mNavigationBarSize,
|
mNavigationBarSize,
|
||||||
@ -289,6 +293,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
|||||||
|
|
||||||
LinearLayout topLayout = new LinearLayout(context);
|
LinearLayout topLayout = new LinearLayout(context);
|
||||||
topLayout.setOrientation(LinearLayout.VERTICAL);
|
topLayout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
topLayout.setLayoutDirection(direction);
|
||||||
// if we don't already have a view root this is it
|
// if we don't already have a view root this is it
|
||||||
if (mViewRoot == null) {
|
if (mViewRoot == null) {
|
||||||
mViewRoot = topLayout;
|
mViewRoot = topLayout;
|
||||||
@ -300,13 +305,22 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
|||||||
|
|
||||||
// this is the case of soft buttons + vertical bar.
|
// this is the case of soft buttons + vertical bar.
|
||||||
// this top layout is the first layout in the horizontal layout. see above)
|
// this top layout is the first layout in the horizontal layout. see above)
|
||||||
mViewRoot.addView(topLayout, 0);
|
if (isRtl && params.isRtlSupported()) {
|
||||||
|
// If RTL is enabled, layoutlib will mirror the layouts. So, add the
|
||||||
|
// topLayout to the right of Navigation Bar and layoutlib will draw it
|
||||||
|
// to the left.
|
||||||
|
mViewRoot.addView(topLayout);
|
||||||
|
} else {
|
||||||
|
// Add the top layout to the left of the Navigation Bar.
|
||||||
|
mViewRoot.addView(topLayout, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mStatusBarSize > 0) {
|
if (mStatusBarSize > 0) {
|
||||||
// system bar
|
// system bar
|
||||||
try {
|
try {
|
||||||
StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity());
|
StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity(),
|
||||||
|
direction, params.isRtlSupported());
|
||||||
systemBar.setLayoutParams(
|
systemBar.setLayoutParams(
|
||||||
new LinearLayout.LayoutParams(
|
new LinearLayout.LayoutParams(
|
||||||
LayoutParams.MATCH_PARENT, mStatusBarSize));
|
LayoutParams.MATCH_PARENT, mStatusBarSize));
|
||||||
@ -365,7 +379,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
|
|||||||
// system bar
|
// system bar
|
||||||
try {
|
try {
|
||||||
NavigationBar navigationBar = new NavigationBar(context,
|
NavigationBar navigationBar = new NavigationBar(context,
|
||||||
hardwareConfig.getDensity(), LinearLayout.HORIZONTAL);
|
hardwareConfig.getDensity(), LinearLayout.HORIZONTAL, isRtl,
|
||||||
|
params.isRtlSupported());
|
||||||
navigationBar.setLayoutParams(
|
navigationBar.setLayoutParams(
|
||||||
new LinearLayout.LayoutParams(
|
new LinearLayout.LayoutParams(
|
||||||
LayoutParams.MATCH_PARENT, mNavigationBarSize));
|
LayoutParams.MATCH_PARENT, mNavigationBarSize));
|
||||||
|
Reference in New Issue
Block a user