am 97c88368: am c78d173b: am 68411471: Merge "Fix layout rendering for RTL locales" into jb-mr2-dev

* commit '97c88368e0036665507c8cd84c71d26953784c85':
  Fix layout rendering for RTL locales
This commit is contained in:
Deepanshu Gupta
2013-09-05 12:00:54 -07:00
committed by Android Git Automerger
15 changed files with 81 additions and 19 deletions

View File

@ -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>

View File

@ -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

View File

@ -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
*/ */

View File

@ -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);
} }

View File

@ -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];

View File

@ -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

View File

@ -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?

View File

@ -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();

View File

@ -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));