OSDN Git Service

LayoutLib: translucent sys ui bars
authorDeepanshu Gupta <deepanshu@google.com>
Thu, 23 Jul 2015 18:35:25 +0000 (11:35 -0700)
committerDeepanshu Gupta <deepanshu@google.com>
Thu, 23 Jul 2015 22:54:26 +0000 (15:54 -0700)
Change-Id: I9c294329fc78418c505a5115bc9c07da29595af2

tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Layout.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java

index c95fd74..145a03a 100644 (file)
@@ -32,7 +32,6 @@ import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.annotation.NonNull;
-import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
@@ -78,8 +77,7 @@ abstract class CustomBar extends LinearLayout {
             setGravity(Gravity.CENTER_HORIZONTAL);
         }
 
-        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
+        LayoutInflater inflater = LayoutInflater.from(mContext);
 
         XmlPullParser parser;
         try {
@@ -159,7 +157,7 @@ abstract class CustomBar extends LinearLayout {
 
     protected void setStyle(String themeEntryName) {
 
-        BridgeContext bridgeContext = (BridgeContext) mContext;
+        BridgeContext bridgeContext = getContext();
         RenderResources res = bridgeContext.getRenderResources();
 
         ResourceValue value = res.findItemInTheme(themeEntryName, true /*isFrameworkAttr*/);
@@ -219,27 +217,47 @@ abstract class CustomBar extends LinearLayout {
         }
     }
 
+    @Override
+    public BridgeContext getContext() {
+        return (BridgeContext) mContext;
+    }
+
     /**
-     * Given a theme attribute name, get the color referenced by it. The theme attribute may be
-     * used in a layout like "?attr/foo".
+     * Find the background color for this bar from the theme attributes. Only relevant to StatusBar
+     * and NavigationBar.
      * <p/>
      * Returns 0 if not found.
      *
+     * @param colorAttrName the attribute name for the background color
+     * @param translucentAttrName the attribute name for the translucency property of the bar.
+     *
      * @throws NumberFormatException if color resolved to an invalid string.
      */
-    protected int getThemeAttrColor(@NonNull String attrName, boolean isFramework) {
+    protected int getBarColor(@NonNull String colorAttrName, @NonNull String translucentAttrName) {
         if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) {
             return 0;
         }
-        assert mContext instanceof BridgeContext;
-        BridgeContext context = ((BridgeContext) mContext);
-        RenderResources renderResources = context.getRenderResources();
-        // From ?attr/foo to @color/bar. This is most likely an ItemResourceValue.
-        ResourceValue resource = renderResources.findItemInTheme(attrName, isFramework);
-        if (resource != null) {
-            // Form @color/bar to the #AARRGGBB
-            resource = renderResources.resolveResValue(resource);
+        RenderResources renderResources = getContext().getRenderResources();
+        // First check if the bar is translucent.
+        boolean translucent = ResourceHelper.getBooleanThemeValue(renderResources,
+                translucentAttrName, true, false);
+        if (translucent) {
+            // Keep in sync with R.color.system_bar_background_semi_transparent from system ui.
+            return 0x66000000;  // 40% black.
+        }
+        boolean transparent = ResourceHelper.getBooleanThemeValue(renderResources,
+                "windowDrawsSystemBarBackgrounds", true, false);
+        if (transparent) {
+            return getColor(renderResources, colorAttrName);
         }
+        return 0;
+    }
+
+    private static int getColor(RenderResources renderResources, String attr) {
+        // From ?attr/foo to @color/bar. This is most likely an ItemResourceValue.
+        ResourceValue resource = renderResources.findItemInTheme(attr, true);
+        // Form @color/bar to the #AARRGGBB
+        resource = renderResources.resolveResValue(resource);
         if (resource != null && ResourceType.COLOR.equals(resource.getResourceType())) {
             return ResourceHelper.getColor(resource.getValue());
         }
@@ -247,8 +265,7 @@ abstract class CustomBar extends LinearLayout {
     }
 
     private ResourceValue getResourceValue(String reference) {
-        BridgeContext bridgeContext = (BridgeContext) mContext;
-        RenderResources res = bridgeContext.getRenderResources();
+        RenderResources res = getContext().getRenderResources();
 
         // find the resource
         ResourceValue value = res.findResValue(reference, false);
index 1190668..9c89bfe 100644 (file)
@@ -31,6 +31,8 @@ public class NavigationBar extends CustomBar {
 
     /** Navigation bar background color attribute name. */
     private static final String ATTR_COLOR = "navigationBarColor";
+    /** Attribute for translucency property. */
+    public static final String ATTR_TRANSLUCENT = "windowTranslucentNavigation";
     // These correspond to @dimen/navigation_side_padding in the system ui code.
     private static final int PADDING_WIDTH_DEFAULT = 36;
     private static final int PADDING_WIDTH_SW360 = 40;
@@ -63,7 +65,7 @@ public class NavigationBar extends CustomBar {
         super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
                 "navigation_bar.xml", simulatedPlatformVersion);
 
-        int color = getThemeAttrColor(ATTR_COLOR, true);
+        int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
         setBackgroundColor(color == 0 ? 0xFF000000 : color);
 
         // Cannot access the inside items through id because no R.id values have been
index b77f140..2dc7c65 100644 (file)
@@ -43,6 +43,8 @@ public class StatusBar extends CustomBar {
     private final int mSimulatedPlatformVersion;
     /** Status bar background color attribute name. */
     private static final String ATTR_COLOR = "statusBarColor";
+    /** Attribute for translucency property. */
+    public static final String ATTR_TRANSLUCENT = "windowTranslucentStatus";
 
     /**
      * Constructor to be used when creating the {@link StatusBar} as a regular control. This
@@ -69,7 +71,7 @@ public class StatusBar extends CustomBar {
         // FIXME: use FILL_H?
         setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
 
-        int color = getThemeAttrColor(ATTR_COLOR, true);
+        int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
         setBackgroundColor(color == 0 ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
 
         // Cannot access the inside items through id because no R.id values have been
index 0798716..89d8319 100644 (file)
@@ -21,7 +21,6 @@ import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.SessionParams;
 import com.android.ide.common.rendering.api.StyleResourceValue;
-import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.bars.AppCompatActionBar;
@@ -91,6 +90,8 @@ class Layout extends RelativeLayout {
     private static final String ATTR_ACTION_BAR_SIZE = "actionBarSize";
     private static final String ATTR_WINDOW_NO_TITLE = "windowNoTitle";
     private static final String ATTR_WINDOW_TITLE_SIZE = "windowTitleSize";
+    private static final String ATTR_WINDOW_TRANSLUCENT_STATUS = StatusBar.ATTR_TRANSLUCENT;
+    private static final String ATTR_WINDOW_TRANSLUCENT_NAV = NavigationBar.ATTR_TRANSLUCENT;
     private static final String PREFIX_THEME_APPCOMPAT = "Theme.AppCompat";
 
     // Default sizes
@@ -131,8 +132,7 @@ class Layout extends RelativeLayout {
         boolean isRtl = Bridge.isLocaleRtl(getParams().getLocale());
 
         NavigationBar navBar = null;
-        if (Config.showOnScreenNavBar(simulatedPlatformVersion) && mBuilder.hasSoftwareButtons() &&
-                builder.isNavBarVertical()) {
+        if (mBuilder.hasNavBar()) {
             navBar = createNavBar(getContext(), density, isRtl, getParams().isRtlSupported(),
                     simulatedPlatformVersion);
         }
@@ -163,26 +163,37 @@ class Layout extends RelativeLayout {
     @NonNull
     private FrameLayout createContentFrame() {
         FrameLayout contentRoot = new FrameLayout(getContext());
-        LayoutParams params =
-                new LayoutParams(MATCH_PARENT, MATCH_PARENT);
+        LayoutParams params = createLayoutParams(MATCH_PARENT, MATCH_PARENT);
         int rule = mBuilder.isNavBarVertical() ? START_OF : ABOVE;
-        if (mBuilder.mNavBarSize > 0) {
+        if (mBuilder.solidBars()) {
             params.addRule(rule, getId(ID_NAV_BAR));
         }
         int below = -1;
         if (mBuilder.mActionBarSize <= 0 && mBuilder.mTitleBarSize > 0) {
             below = getId(ID_TITLE_BAR);
-        } else if (mBuilder.mStatusBarSize > 0) {
+        } else if (mBuilder.solidBars()) {
             below = getId(ID_STATUS_BAR);
         }
         if (below != -1) {
             params.addRule(BELOW, below);
         }
-
+        contentRoot.setLayoutParams(params);
         return contentRoot;
     }
 
     @NonNull
+    private LayoutParams createLayoutParams(int width, int height) {
+        DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+        if (width > 0) {
+            width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, width, metrics);
+        }
+        if (height > 0) {
+            height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics);
+        }
+        return new LayoutParams(width, height);
+    }
+
+    @NonNull
     public FrameLayout getContentRoot() {
         return mContentRoot;
     }
@@ -208,7 +219,7 @@ class Layout extends RelativeLayout {
             boolean isRtlSupported, int simulatedPlatformVersion) {
         StatusBar statusBar =
                 new StatusBar(context, density, isRtl, isRtlSupported, simulatedPlatformVersion);
-        LayoutParams params = new LayoutParams(MATCH_PARENT, mBuilder.mStatusBarSize);
+        LayoutParams params = createLayoutParams(MATCH_PARENT, mBuilder.mStatusBarSize);
         if (mBuilder.isNavBarVertical()) {
             params.addRule(START_OF, getId(ID_NAV_BAR));
         }
@@ -225,12 +236,12 @@ class Layout extends RelativeLayout {
         } else {
             actionBar = new FrameworkActionBar(context, params);
         }
-        LayoutParams layoutParams = new LayoutParams(MATCH_PARENT, MATCH_PARENT);
+        LayoutParams layoutParams = createLayoutParams(MATCH_PARENT, MATCH_PARENT);
         int rule = mBuilder.isNavBarVertical() ? START_OF : ABOVE;
-        if (mBuilder.mNavBarSize > 0) {
+        if (mBuilder.solidBars()) {
             layoutParams.addRule(rule, getId(ID_NAV_BAR));
         }
-        if (mBuilder.mStatusBarSize > 0) {
+        if (mBuilder.solidBars()) {
             layoutParams.addRule(BELOW, getId(ID_STATUS_BAR));
         }
         actionBar.getRootView().setLayoutParams(layoutParams);
@@ -238,16 +249,15 @@ class Layout extends RelativeLayout {
         return actionBar;
     }
 
-
     @NonNull
     private TitleBar createTitleBar(BridgeContext context, String title,
             int simulatedPlatformVersion) {
         TitleBar titleBar = new TitleBar(context, title, simulatedPlatformVersion);
-        LayoutParams params = new LayoutParams(MATCH_PARENT, mBuilder.mTitleBarSize);
-        if (mBuilder.mStatusBarSize > 0) {
+        LayoutParams params = createLayoutParams(MATCH_PARENT, mBuilder.mTitleBarSize);
+        if (mBuilder.solidBars()) {
             params.addRule(BELOW, getId(ID_STATUS_BAR));
         }
-        if (mBuilder.isNavBarVertical()) {
+        if (mBuilder.isNavBarVertical() && mBuilder.solidBars()) {
             params.addRule(START_OF, getId(ID_NAV_BAR));
         }
         titleBar.setLayoutParams(params);
@@ -270,7 +280,7 @@ class Layout extends RelativeLayout {
         boolean isVertical = mBuilder.isNavBarVertical();
         int w = isVertical ? size : MATCH_PARENT;
         int h = isVertical ? MATCH_PARENT : size;
-        LayoutParams params = new LayoutParams(w, h);
+        LayoutParams params = createLayoutParams(w, h);
         params.addRule(isVertical ? ALIGN_PARENT_END : ALIGN_PARENT_BOTTOM);
         navBar.setLayoutParams(params);
         navBar.setId(getId(ID_NAV_BAR));
@@ -306,6 +316,8 @@ class Layout extends RelativeLayout {
         private int mNavBarOrientation;
         private int mActionBarSize;
         private int mTitleBarSize;
+        private boolean mTranslucentStatus;
+        private boolean mTranslucentNav;
 
         private Boolean mIsThemeAppCompat;
 
@@ -313,7 +325,7 @@ class Layout extends RelativeLayout {
             mParams = params;
             mContext = context;
             mResources = mParams.getResources();
-            mWindowIsFloating = getBooleanThemeValue(mResources, ATTR_WINDOW_FLOATING, true, true);
+            mWindowIsFloating = ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_FLOATING, true, true);
             
             findBackground();
             findStatusBar();
@@ -334,10 +346,12 @@ class Layout extends RelativeLayout {
 
         private void findStatusBar() {
             boolean windowFullScreen =
-                    getBooleanThemeValue(mResources, ATTR_WINDOW_FULL_SCREEN, true, false);
+                    ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_FULL_SCREEN, true, false);
             if (!windowFullScreen && !mWindowIsFloating) {
                 mStatusBarSize =
                         getDimension(ATTR_STATUS_BAR_HEIGHT, true, DEFAULT_STATUS_BAR_HEIGHT);
+                mTranslucentStatus = ResourceHelper.getBooleanThemeValue(mResources,
+                        ATTR_WINDOW_TRANSLUCENT_STATUS, true, false);
             }
         }
 
@@ -346,14 +360,14 @@ class Layout extends RelativeLayout {
                 return;
             }
             // Check if an actionbar is needed
-            boolean windowActionBar = getBooleanThemeValue(mResources, ATTR_WINDOW_ACTION_BAR,
-                    isThemeAppCompat(), true);
+            boolean windowActionBar = ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_ACTION_BAR,
+                    !isThemeAppCompat(), true);
             if (windowActionBar) {
                 mActionBarSize = getDimension(ATTR_ACTION_BAR_SIZE, true, DEFAULT_TITLE_BAR_HEIGHT);
             } else {
                 // Maybe the gingerbread era title bar is needed
                 boolean windowNoTitle =
-                        getBooleanThemeValue(mResources, ATTR_WINDOW_NO_TITLE, true, false);
+                        ResourceHelper.getBooleanThemeValue(mResources, ATTR_WINDOW_NO_TITLE, true, false);
                 if (!windowNoTitle) {
                     mTitleBarSize =
                             getDimension(ATTR_WINDOW_TITLE_SIZE, true, DEFAULT_TITLE_BAR_HEIGHT);
@@ -381,6 +395,8 @@ class Layout extends RelativeLayout {
                 mNavBarOrientation = barOnBottom ? LinearLayout.HORIZONTAL : VERTICAL;
                 mNavBarSize = getDimension(barOnBottom ? ATTR_NAV_BAR_HEIGHT : ATTR_NAV_BAR_WIDTH,
                         true, DEFAULT_NAV_BAR_SIZE);
+                mTranslucentNav = ResourceHelper.getBooleanThemeValue(mResources,
+                        ATTR_WINDOW_TRANSLUCENT_NAV, true, false);
             }
         }
 
@@ -396,25 +412,6 @@ class Layout extends RelativeLayout {
             return defaultValue;
         }
 
-        /**
-         * Looks for an attribute in the current theme.
-         *
-         * @param resources the render resources
-         * @param name the name of the attribute
-         * @param defaultValue the default value.
-         * @param isFrameworkAttr if the attribute is in android namespace
-         * @return the value of the attribute or the default one if not found.
-         */
-        static boolean getBooleanThemeValue(@NonNull RenderResources resources, String name,
-                boolean isFrameworkAttr, boolean defaultValue) {
-            ResourceValue value = resources.findItemInTheme(name, isFrameworkAttr);
-            value = resources.resolveResValue(value);
-            if (value == null) {
-                return defaultValue;
-            }
-            return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
-        }
-
         private boolean hasSoftwareButtons() {
             return mParams.getHardwareConfig().hasSoftwareButtons();
         }
@@ -445,5 +442,18 @@ class Layout extends RelativeLayout {
             mIsThemeAppCompat = isThemeAppCompat;
             return isThemeAppCompat;
         }
+
+        /**
+         * Return if both status bar and nav bar are solid (content doesn't overlap with these
+         * bars).
+         */
+        private boolean solidBars() {
+            return hasNavBar() && !mTranslucentNav && !mTranslucentStatus && mStatusBarSize > 0;
+        }
+
+        private boolean hasNavBar() {
+            return Config.showOnScreenNavBar(mParams.getSimulatedPlatformVersion()) &&
+                    hasSoftwareButtons() && mNavBarSize > 0;
+        }
     }
 }
index dbd9d09..8178136 100644 (file)
@@ -170,8 +170,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
         BridgeContext context = getContext();
 
         // use default of true in case it's not found to use alpha by default
-        mIsAlphaChannelImage = Layout.Builder.getBooleanThemeValue(params.getResources(),
-                        "windowIsFloating", true, true);
+        mIsAlphaChannelImage = ResourceHelper.getBooleanThemeValue(params.getResources(),
+                "windowIsFloating", true, true);
 
         mLayoutBuilder = new Layout.Builder(params, context);
 
index ca77193..c72eeb1 100644 (file)
@@ -21,6 +21,7 @@ import com.android.ide.common.rendering.api.DensityBasedResourceValue;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.internal.util.XmlUtils;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
@@ -327,6 +328,25 @@ public final class ResourceHelper {
         return null;
     }
 
+    /**
+     * Looks for an attribute in the current theme.
+     *
+     * @param resources the render resources
+     * @param name the name of the attribute
+     * @param defaultValue the default value.
+     * @param isFrameworkAttr if the attribute is in android namespace
+     * @return the value of the attribute or the default one if not found.
+     */
+    public static boolean getBooleanThemeValue(@NonNull RenderResources resources, String name,
+            boolean isFrameworkAttr, boolean defaultValue) {
+        ResourceValue value = resources.findItemInTheme(name, isFrameworkAttr);
+        value = resources.resolveResValue(value);
+        if (value == null) {
+            return defaultValue;
+        }
+        return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
+    }
+
     // ------- TypedValue stuff
     // This is taken from //device/libs/utils/ResourceTypes.cpp