diff options
15 files changed, 81 insertions, 19 deletions
| diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath index 3c124d90aaae..2e4274da5afd 100644 --- a/tools/layoutlib/bridge/.classpath +++ b/tools/layoutlib/bridge/.classpath @@ -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/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/icu4j/icu4j.jar"/>  	<classpathentry kind="output" path="bin"/>  </classpath> diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk index 687a91feeb6f..e3d48fca5eb2 100644 --- a/tools/layoutlib/bridge/Android.mk +++ b/tools/layoutlib/bridge/Android.mk @@ -22,6 +22,7 @@ LOCAL_JAVA_RESOURCE_DIRS := resources  LOCAL_JAVA_LIBRARIES := \  	kxml2-2.3.0 \ +	icu4j \  	layoutlib_api-prebuilt \  	tools-common-prebuilt diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.pngBinary files differ new file mode 100644 index 000000000000..782ebfe3f2ba --- /dev/null +++ b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_back.png diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.pngBinary files differ new file mode 100644 index 000000000000..677b47137a3f --- /dev/null +++ b/tools/layoutlib/bridge/resources/bars/ldrtl-hdpi/ic_sysbar_recent.png diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.pngBinary files differ new file mode 100644 index 000000000000..a1b806266959 --- /dev/null +++ b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_back.png diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.pngBinary files differ new file mode 100644 index 000000000000..fcdbefe9f506 --- /dev/null +++ b/tools/layoutlib/bridge/resources/bars/ldrtl-mdpi/ic_sysbar_recent.png diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.pngBinary files differ new file mode 100644 index 000000000000..633d86482938 --- /dev/null +++ b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_back.png diff --git a/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.pngBinary files differ new file mode 100644 index 000000000000..4665e2a6fef9 --- /dev/null +++ b/tools/layoutlib/bridge/resources/bars/ldrtl-xhdpi/ic_sysbar_recent.png diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 42257c560a7f..ab4be7132967 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -35,6 +35,7 @@ import com.android.resources.ResourceType;  import com.android.tools.layoutlib.create.MethodAdapter;  import com.android.tools.layoutlib.create.OverrideMethod;  import com.android.util.Pair; +import com.ibm.icu.util.ULocale;  import android.content.res.BridgeAssetManager;  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 { +    private static final String ICU_LOCALE_DIRECTION_RTL = "right-to-left"; +      public static class StaticMethodNotImplementedException extends RuntimeException {          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.ADAPTER_BINDING,                  Capability.EXTENDED_VIEWINFO, -                Capability.FIXED_SCALABLE_NINE_PATCH); +                Capability.FIXED_SCALABLE_NINE_PATCH, +                Capability.RTL);          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");      } +    @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       */ diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 21bef1c22515..99aa22811196 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -132,7 +132,8 @@ public final class BridgeContext extends Context {              RenderResources renderResources,              IProjectCallback projectCallback,              Configuration config, -            int targetSdkVersion) { +            int targetSdkVersion, +            boolean hasRtlSupport) {          mProjectKey = projectKey;          mMetrics = metrics;          mProjectCallback = projectCallback; @@ -142,6 +143,9 @@ public final class BridgeContext extends Context {          mApplicationInfo = new ApplicationInfo();          mApplicationInfo.targetSdkVersion = targetSdkVersion; +        if (hasRtlSupport) { +            mApplicationInfo.flags = mApplicationInfo.flags | ApplicationInfo.FLAG_SUPPORTS_RTL; +        }          mWindowManager = new WindowManagerImpl(mMetrics);      } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java index ea9d8d929bc8..17b0eb641efa 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java @@ -25,6 +25,7 @@ import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;  import com.android.layoutlib.bridge.impl.ParserFactory;  import com.android.layoutlib.bridge.impl.ResourceHelper;  import com.android.resources.Density; +import com.android.resources.LayoutDirection;  import com.android.resources.ResourceType;  import org.xmlpull.v1.XmlPullParser; @@ -86,38 +87,53 @@ abstract class CustomBar extends LinearLayout {          }      } -    private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut, -            boolean tryOtherDensities) { +    private InputStream getIcon(String iconName, Density[] densityInOut, LayoutDirection direction,  +            String[] pathOut, boolean tryOtherDensities) {          // current density          Density density = densityInOut[0];          // 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]);          if (stream == null && tryOtherDensities) {              for (Density d : Density.values()) {                  if (d != density) {                      densityInOut[0] = d; -                    stream = getIcon(iconName, densityInOut, pathOut, false /*tryOtherDensities*/); +                    stream = getIcon(iconName, densityInOut, direction, pathOut, +                            false /*tryOtherDensities*/);                      if (stream != null) {                          return stream;                      }                  }              } +            // couldn't find resource with direction qualifier. try without. +            if (direction != null) { +                return getIcon(iconName, densityInOut, null, pathOut, true); +            }          }          return stream;      }      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);          if (child instanceof ImageView) {              ImageView imageView = (ImageView) child;              String[] pathOut = new String[1];              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*/);              density = densityInOut[0]; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java index cc90d6b33abe..84e676ed4bbd 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java @@ -17,6 +17,7 @@  package com.android.layoutlib.bridge.bars;  import com.android.resources.Density; +import com.android.layoutlib.bridge.Bridge;  import org.xmlpull.v1.XmlPullParserException; @@ -26,7 +27,8 @@ import android.widget.TextView;  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");          setBackgroundColor(0xFF000000); @@ -37,14 +39,15 @@ public class NavigationBar extends CustomBar {          // 0 is a spacer.          int back = 1;          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;              recent = 1;          } -        loadIcon(back,   "ic_sysbar_back.png", density); -        loadIcon(2,      "ic_sysbar_home.png", density); -        loadIcon(recent, "ic_sysbar_recent.png", density); +        loadIcon(back,   "ic_sysbar_back.png",   density, isRtl); +        loadIcon(2,      "ic_sysbar_home.png",   density, isRtl); +        loadIcon(recent, "ic_sysbar_recent.png", density, isRtl);      }      @Override diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java index 5c084121d123..baa956d976d0 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java @@ -30,7 +30,10 @@ import android.widget.TextView;  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");          // FIXME: use FILL_H? diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java index b909bec6299e..87047b34371e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java @@ -121,7 +121,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.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion(), +                mParams.isRtlSupported());          setUp(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index c14af4add019..9ddbbf140df4 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -225,13 +225,15 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {              SessionParams params = getParams();              HardwareConfig hardwareConfig = params.getHardwareConfig();              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.              ViewGroup backgroundView = null;              if (mWindowIsFloating || params.isForceNoDecor()) {                  backgroundView = mViewRoot = mContentRoot = new FrameLayout(context); +                mViewRoot.setLayoutDirection(direction);              } else {                  if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {                      /* @@ -253,12 +255,14 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {                         the bottom                       */                      LinearLayout topLayout = new LinearLayout(context); +                    topLayout.setLayoutDirection(direction);                      mViewRoot = topLayout;                      topLayout.setOrientation(LinearLayout.HORIZONTAL);                      try {                          NavigationBar navigationBar = new NavigationBar(context, -                                hardwareConfig.getDensity(), LinearLayout.VERTICAL); +                                hardwareConfig.getDensity(), LinearLayout.VERTICAL, isRtl, +                                params.isRtlSupported());                          navigationBar.setLayoutParams(                                  new LinearLayout.LayoutParams(                                          mNavigationBarSize, @@ -290,6 +294,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {                  LinearLayout topLayout = new LinearLayout(context);                  topLayout.setOrientation(LinearLayout.VERTICAL); +                topLayout.setLayoutDirection(direction);                  // if we don't already have a view root this is it                  if (mViewRoot == null) {                      mViewRoot = topLayout; @@ -301,13 +306,22 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {                      // this is the case of soft buttons + vertical bar.                      // 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) {                      // system bar                      try { -                        StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity()); +                        StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity(), +                                direction, params.isRtlSupported());                          systemBar.setLayoutParams(                                  new LinearLayout.LayoutParams(                                          LayoutParams.MATCH_PARENT, mStatusBarSize)); @@ -366,7 +380,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {                      // system bar                      try {                          NavigationBar navigationBar = new NavigationBar(context, -                                hardwareConfig.getDensity(), LinearLayout.HORIZONTAL); +                                hardwareConfig.getDensity(), LinearLayout.HORIZONTAL, isRtl, +                                params.isRtlSupported());                          navigationBar.setLayoutParams(                                  new LinearLayout.LayoutParams(                                          LayoutParams.MATCH_PARENT, mNavigationBarSize)); |