Adding the 'non client decor view' to free floating windows

This patch adds a new free floating window non client decor view which
has:
- Two buttons (maximize and close) as it meets our current UX design
- A Shadow which changes size with focus
- It's own view as preparation for the thread distributed drawing and
  user interaction handling (resize handles, etc)

Missing is at this point:
- The button functionality itself.
- Changing/removing decors based on window type (once the needed
  patches land.

bug: 21738666
bug: 21739152
Change-Id: I6e41f2a7470256cee7bae35029d7e8c43fb235dd
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 2b39528..0bd8d85 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -72,6 +72,7 @@
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.DecorContentParent;
 import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.NonClientDecorView;
 import com.android.internal.widget.SwipeDismissLayout;
 
 import android.app.ActivityManager;
@@ -1270,7 +1271,7 @@
      * @param st The panel being initialized.
      */
     protected boolean initializePanelDecor(PanelFeatureState st) {
-        st.decorView = new DecorView(getContext(), st.featureId);
+        st.decorView = generateDecor(st.featureId);
         st.gravity = Gravity.CENTER | Gravity.BOTTOM;
         st.setStyle(getContext());
         TypedArray a = getContext().obtainStyledAttributes(null,
@@ -2204,6 +2205,9 @@
 
         private final Rect mFrameOffsets = new Rect();
 
+        // True if a non client area decor exists.
+        private boolean mHasNonClientDecor = false;
+
         private boolean mChanging;
 
         private Drawable mMenuBackground;
@@ -3148,53 +3152,59 @@
                 return;
             }
 
-            setPadding(mFramePadding.left + mBackgroundPadding.left, mFramePadding.top
-                    + mBackgroundPadding.top, mFramePadding.right + mBackgroundPadding.right,
+            setPadding(mFramePadding.left + mBackgroundPadding.left,
+                    mFramePadding.top + mBackgroundPadding.top,
+                    mFramePadding.right + mBackgroundPadding.right,
                     mFramePadding.bottom + mBackgroundPadding.bottom);
             requestLayout();
             invalidate();
 
             int opacity = PixelFormat.OPAQUE;
-            // Note: if there is no background, we will assume opaque. The
-            // common case seems to be that an application sets there to be
-            // no background so it can draw everything itself. For that,
-            // we would like to assume OPAQUE and let the app force it to
-            // the slower TRANSLUCENT mode if that is really what it wants.
-            Drawable bg = getBackground();
-            Drawable fg = getForeground();
-            if (bg != null) {
-                if (fg == null) {
-                    opacity = bg.getOpacity();
-                } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0
-                        && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {
-                    // If the frame padding is zero, then we can be opaque
-                    // if either the frame -or- the background is opaque.
-                    int fop = fg.getOpacity();
-                    int bop = bg.getOpacity();
-                    if (false)
-                        Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
-                    if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
-                        opacity = PixelFormat.OPAQUE;
-                    } else if (fop == PixelFormat.UNKNOWN) {
-                        opacity = bop;
-                    } else if (bop == PixelFormat.UNKNOWN) {
-                        opacity = fop;
+            if (windowHasShadow()) {
+                // If the window has a shadow, it must be translucent.
+                opacity = PixelFormat.TRANSLUCENT;
+            } else{
+                // Note: If there is no background, we will assume opaque. The
+                // common case seems to be that an application sets there to be
+                // no background so it can draw everything itself. For that,
+                // we would like to assume OPAQUE and let the app force it to
+                // the slower TRANSLUCENT mode if that is really what it wants.
+                Drawable bg = getBackground();
+                Drawable fg = getForeground();
+                if (bg != null) {
+                    if (fg == null) {
+                        opacity = bg.getOpacity();
+                    } else if (mFramePadding.left <= 0 && mFramePadding.top <= 0
+                            && mFramePadding.right <= 0 && mFramePadding.bottom <= 0) {
+                        // If the frame padding is zero, then we can be opaque
+                        // if either the frame -or- the background is opaque.
+                        int fop = fg.getOpacity();
+                        int bop = bg.getOpacity();
+                        if (false)
+                            Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
+                        if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
+                            opacity = PixelFormat.OPAQUE;
+                        } else if (fop == PixelFormat.UNKNOWN) {
+                            opacity = bop;
+                        } else if (bop == PixelFormat.UNKNOWN) {
+                            opacity = fop;
+                        } else {
+                            opacity = Drawable.resolveOpacity(fop, bop);
+                        }
                     } else {
-                        opacity = Drawable.resolveOpacity(fop, bop);
+                        // For now we have to assume translucent if there is a
+                        // frame with padding... there is no way to tell if the
+                        // frame and background together will draw all pixels.
+                        if (false)
+                            Log.v(TAG, "Padding: " + mFramePadding);
+                        opacity = PixelFormat.TRANSLUCENT;
                     }
-                } else {
-                    // For now we have to assume translucent if there is a
-                    // frame with padding... there is no way to tell if the
-                    // frame and background together will draw all pixels.
-                    if (false)
-                        Log.v(TAG, "Padding: " + mFramePadding);
-                    opacity = PixelFormat.TRANSLUCENT;
                 }
+                if (false)
+                    Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
             }
 
             if (false)
-                Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
-            if (false)
                 Log.v(TAG, "Selected default opacity: " + opacity);
 
             mDefaultOpacity = opacity;
@@ -3401,8 +3411,7 @@
                         }
                     };
                 } else {
-                    ViewStub stub = (ViewStub) findViewById(
-                            R.id.action_mode_bar_stub);
+                    ViewStub stub = (ViewStub) findViewById(R.id.action_mode_bar_stub);
                     if (stub != null) {
                         mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
                     }
@@ -3490,6 +3499,28 @@
                 .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
         }
 
+        // Set when the window is free floating and a non client decor frame was added.
+        void enableNonClientDecor(boolean enable) {
+            if (mHasNonClientDecor != enable) {
+                mHasNonClientDecor = enable;
+                if (getForeground() != null) {
+                    drawableChanged();
+                }
+            }
+        }
+
+        // Returns true if the window has a non client decor.
+        private boolean windowHasNonClientDecor() {
+            return mHasNonClientDecor;
+        }
+
+        // Returns true if the Window is free floating and has a shadow. Note that non overlapping
+        // windows do not have a shadow since it could not be seen anyways (a small screen / tablet
+        // "tiles" the windows side by side but does not overlap them).
+        private boolean windowHasShadow() {
+            return windowHasNonClientDecor() && getElevation() > 0;
+        }
+
         /**
          * Clears out internal references when the action mode is destroyed.
          */
@@ -3599,8 +3630,8 @@
         }
     }
 
-    protected DecorView generateDecor() {
-        return new DecorView(getContext(), -1);
+    protected DecorView generateDecor(int featureId) {
+        return new DecorView(getContext(), featureId);
     }
 
     protected void setFeatureFromAttrs(int featureId, TypedArray attrs,
@@ -3879,8 +3910,15 @@
 
         mDecor.startChanging();
 
+        NonClientDecorView nonClientDecorView = createNonClientDecorView();
         View in = mLayoutInflater.inflate(layoutResource, null);
-        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        if (nonClientDecorView != null) {
+            decor.addView(nonClientDecorView,
+                    new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            nonClientDecorView.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        } else {
+            decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        }
         mContentRoot = (ViewGroup) in;
 
         ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
@@ -3936,6 +3974,54 @@
         return contentParent;
     }
 
+    // Free floating overlapping windows require a non client decor with a caption and shadow..
+    private NonClientDecorView createNonClientDecorView() {
+        boolean needsDecor = true;
+        NonClientDecorView nonClientDecorView = null;
+
+        final WindowManager.LayoutParams attrs = getAttributes();
+        // TODO(skuhne): Use the associated stack to figure out if the window is on the free style
+        // desktop, the side by side desktop or the full screen desktop. With that informations the
+        // choice is fairly easy to decide.
+        // => This is only a kludge for now to suppress fullscreen windows, recents, launcher, etc..
+        boolean isFullscreen =
+                0 != ((mDecor.getWindowSystemUiVisibility() | mDecor.getSystemUiVisibility()) &
+                        (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION));
+        boolean isApplication = attrs.type != TYPE_BASE_APPLICATION &&
+                attrs.type != TYPE_APPLICATION;
+
+        // We do not show the non client decor if...
+        // - this is a floating dialog (which is not a real window, e.g. it cannot be maximized).
+        // - it is not an application (special windows have special functions, e.g text selector).
+        // - the application is full screen, drawing everything (since the decor would be out of the
+        //   screen in that case and could not be seen).
+        if (isFloating() || isFullscreen || isApplication) {
+            needsDecor = false;
+        }
+
+        if (needsDecor) {
+            // TODO(skuhne): If running in side by side mode on a device - turn off the shadow.
+            boolean windowHasShadow = true;
+            // Dependent on the brightness of the used title we either use the
+            // dark or the light button frame.
+            TypedValue value = new TypedValue();
+            getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+            if (Color.brightness(value.data) < 0.5) {
+                nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
+                        R.layout.non_client_decor_dark, null);
+            } else {
+                nonClientDecorView = (NonClientDecorView) mLayoutInflater.inflate(
+                        R.layout.non_client_decor_light, null);
+            }
+            nonClientDecorView.setPhoneWindow(this, windowHasShadow);
+        }
+
+        // Tell the Decor if it has a non client decor.
+        mDecor.enableNonClientDecor(needsDecor);
+
+        return nonClientDecorView;
+    }
+
     /** @hide */
     public void alwaysReadCloseOnTouchAttr() {
         mAlwaysReadCloseOnTouchAttr = true;
@@ -3943,7 +4029,7 @@
 
     private void installDecor() {
         if (mDecor == null) {
-            mDecor = generateDecor();
+            mDecor = generateDecor(-1);
             mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
             mDecor.setIsRootNamespace(true);
             if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
new file mode 100644
index 0000000..57039b7
--- /dev/null
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.util.Log;
+import android.util.TypedValue;
+
+import android.view.ViewOutlineProvider;
+import android.view.WindowInsets;
+import com.android.internal.R;
+import com.android.internal.policy.PhoneWindow;
+
+import java.util.List;
+
+/**
+ * This class represents the special screen elements to control a window on free form
+ * environment. All thse screen elements are added in the "non client area" which is the area of
+ * the window which is handled by the OS and not the application.
+ * As such this class handles the following things:
+ * <ul>
+ * <li>The caption, containing the system buttons like maximize, close and such as well as
+ * allowing the user to drag the window around.</li>
+ * <li>The shadow - which is changing dependent on the window focus.</li>
+ * <li>The border around the client area (if there is one).</li>
+ * <li>The resize handles which allow to resize the window.</li>
+ * </ul>
+ * After creating the view, the function
+ * {@link #setPhoneWindow(PhoneWindow owner, boolean windowHasShadow)} needs to be called to make
+ * the connection to it's owning PhoneWindow.
+ * Note: At this time the application can change various attributes of the DecorView which
+ * will break things (in settle/unexpected ways):
+ * <ul>
+ * <li>setElevation</li>
+ * <li>setOutlineProvider</li>
+ * <li>setSurfaceFormat</li>
+ * <li>..</li>
+ * </ul>
+ * This will be mitigated once b/22527834 will be addressed.
+ */
+public class NonClientDecorView extends ViewGroup implements View.OnClickListener {
+    private final static String TAG = "NonClientDecorView";
+    // The height of a window which has focus in DIP.
+    private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
+    // The height of a window which has not in DIP.
+    private final int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
+
+    private PhoneWindow mOwner = null;
+    boolean mWindowHasShadow = false;
+
+    // The current focus state of the window for updating the window elevation.
+    boolean mWindowHasFocus = true;
+
+    // Cludge to address b/22668382: Set the shadow size to the maximum so that the layer
+    // size calculation takes the shadow size into account. We set the elevation currently
+    // to max until the first layout command has been executed.
+    boolean mAllowUpdateElevation = false;
+
+    public NonClientDecorView(Context context) {
+        super(context);
+    }
+
+    public NonClientDecorView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public NonClientDecorView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setPhoneWindow(PhoneWindow owner, boolean windowHasShadow) {
+        mOwner = owner;
+        mWindowHasShadow = windowHasShadow;
+        if (mWindowHasShadow) {
+            // TODO(skuhne): Call setMaxElevation here as soon as b/22668382 got fixed.
+            updateElevation();
+        }
+        // By changing the outline provider to BOUNDS, the window can remove its
+        // background without removing the shadow.
+        mOwner.getDecorView().setOutlineProvider(ViewOutlineProvider.BOUNDS);
+        findViewById(R.id.maximize_window).setOnClickListener(this);
+        findViewById(R.id.close_window).setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (view.getId() == R.id.maximize_window) {
+            // TODO(skuhne): Add code to maximize window.
+        } else if (view.getId() == R.id.close_window) {
+            // TODO(skuhne): This is not the right way to kill an app and we should add a high level
+            // function for it.
+            final ActivityManager m =
+                    (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
+            List<RunningTaskInfo> runningTaskInfoList =  m.getRunningTasks(1);
+            if (!runningTaskInfoList.isEmpty()) {
+                try {
+                    ActivityManagerNative.getDefault().removeTask(runningTaskInfoList.get(0).id);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Couldn't close task with the close button.");
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        mWindowHasFocus = hasWindowFocus;
+        updateElevation();
+        super.onWindowFocusChanged(hasWindowFocus);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        measureChildren(widthMeasureSpec, heightMeasureSpec);
+        final int width = MeasureSpec.getSize(widthMeasureSpec);
+        final int height = MeasureSpec.getSize(heightMeasureSpec);
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        // The system inset needs only to be applied to the caption. The client area of
+        // the window will automatically be adjusted by the the DecorView.
+        WindowInsets insets = getRootWindowInsets();
+        int systemMargin = insets.getSystemWindowInsetTop();
+
+        final int leftPos = getPaddingLeft();
+        final int rightPos = right - left - getPaddingRight();
+        final int topPos = getPaddingTop();
+        final int bottomPos = bottom - top - getPaddingBottom();
+
+        // On top we have the caption which has to fill left to right with a fixed height.
+        final int width = rightPos - leftPos;
+        final View caption = getChildAt(0);
+
+        // If the application changed its SystemUI metrics, we might also have to adapt
+        // our shadow elevation.
+        updateElevation();
+        mAllowUpdateElevation = true;
+
+        // Remove the decor temporarily if the window entered a full screen/immersive mode.
+        final int captionHeight = isFillingScreen() ? 0 : caption.getMeasuredHeight();
+        caption.layout(leftPos, topPos + systemMargin, leftPos + width,
+                topPos + systemMargin + captionHeight);
+
+        // Note: We should never have more then 1 additional item in here.
+        if (getChildCount() > 1) {
+            getChildAt(1).layout(leftPos, topPos + captionHeight, leftPos + width, bottomPos);
+        }
+    }
+
+    // Make sure that we never get more then one client area in our view.
+    @Override
+    public void addView(View child, int index, LayoutParams params) {
+        if (index >= 2 || getChildCount() >= 2) {
+            throw new IllegalStateException("NonClientDecorView can only handle 1 client view");
+        }
+        super.addView(child, index, params);
+    }
+
+    // Returns true when the window is filling the entire screen and the non client area
+    // should not be shown.
+    private boolean isFillingScreen() {
+        return (0 != ((getWindowSystemUiVisibility() | getSystemUiVisibility()) &
+                (View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+                        View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_LOW_PROFILE)));
+    }
+
+    // The shadow height gets controlled by the focus to visualize highlighted windows.
+    // Note: This will overwrite application elevation properties.
+    // Note: Windows which have (temporarily) changed their attributes to cover the SystemUI
+    //       will get no shadow as they are expected to be "full screen".
+    private void updateElevation() {
+        float elevation = 0;
+        if (mWindowHasShadow) {
+            boolean fill = isFillingScreen();
+            elevation = fill ? 0 :
+                    (mWindowHasFocus ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP :
+                            DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP);
+            if (!mAllowUpdateElevation && !fill) {
+                // TODO(skuhne): Change this to setMaxElevation as soon as b/22668382 got fixed
+                // and remove this cludge.
+                elevation = DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
+            }
+            // Convert the DP elevation into physical pixels.
+            elevation = dipToPx(elevation);
+        }
+        // Don't change the elevation if it didn't change since it can require some time.
+        if (mOwner.getDecorView().getElevation() != elevation) {
+            mOwner.setElevation(elevation);
+        }
+    }
+
+    private float dipToPx(float dip) {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
+                getResources().getDisplayMetrics());
+    }
+}
diff --git a/core/res/res/drawable/decor_close_button_dark.xml b/core/res/res/drawable/decor_close_button_dark.xml
new file mode 100644
index 0000000..e5ea1f3
--- /dev/null
+++ b/core/res/res/drawable/decor_close_button_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/ic_decor_close_button_dark_focused" />
+    <item android:drawable="@drawable/ic_decor_close_button_dark_unfocused" />
+</selector>
+
diff --git a/core/res/res/drawable/decor_close_button_light.xml b/core/res/res/drawable/decor_close_button_light.xml
new file mode 100644
index 0000000..b77b2bd
--- /dev/null
+++ b/core/res/res/drawable/decor_close_button_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/ic_decor_close_button_light_focused" />
+    <item android:drawable="@drawable/ic_decor_close_button_light_unfocused" />
+</selector>
+
diff --git a/core/res/res/drawable/decor_maximize_button_dark.xml b/core/res/res/drawable/decor_maximize_button_dark.xml
new file mode 100644
index 0000000..5ea372b
--- /dev/null
+++ b/core/res/res/drawable/decor_maximize_button_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/ic_decor_maximize_button_dark_focused" />
+    <item android:drawable="@drawable/ic_decor_maximize_button_dark_unfocused" />
+</selector>
+
diff --git a/core/res/res/drawable/decor_maximize_button_light.xml b/core/res/res/drawable/decor_maximize_button_light.xml
new file mode 100644
index 0000000..5bda131
--- /dev/null
+++ b/core/res/res/drawable/decor_maximize_button_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/ic_decor_maximize_button_light_focused" />
+    <item android:drawable="@drawable/ic_decor_maximize_button_light_unfocused" />
+</selector>
+
diff --git a/core/res/res/drawable/ic_decor_close_button_dark_focused.xml b/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
new file mode 100644
index 0000000..d7b167dd
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml b/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
new file mode 100644
index 0000000..e2e81b9
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#33FFFFFF"
+            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_light_focused.xml b/core/res/res/drawable/ic_decor_close_button_light_focused.xml
new file mode 100644
index 0000000..0794ed3
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_close_button_light_focused.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#ff000000"
+            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml b/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
new file mode 100644
index 0000000..bd1db51
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
@@ -0,0 +1,29 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#33000000"
+            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml b/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
new file mode 100644
index 0000000..73d808b
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
@@ -0,0 +1,32 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
+        <path
+            android:fillColor="#B2FFFFFF"
+            android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml b/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
new file mode 100644
index 0000000..dc79e10
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
@@ -0,0 +1,32 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#33FFFFFF"
+            android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
+        <path
+            android:fillColor="#33FFFFFF"
+            android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml b/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
new file mode 100644
index 0000000..c23390e
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
@@ -0,0 +1,32 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#FF000000"
+            android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
+        <path
+            android:fillColor="#B2000000"
+            android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml b/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
new file mode 100644
index 0000000..a194a39
--- /dev/null
+++ b/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
@@ -0,0 +1,32 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="#33000000"
+            android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
+        <path
+            android:fillColor="#33000000"
+            android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/non_client_decor_title.xml b/core/res/res/drawable/non_client_decor_title.xml
new file mode 100644
index 0000000..e50daea
--- /dev/null
+++ b/core/res/res/drawable/non_client_decor_title.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_window_focused="true"
+          android:drawable="@drawable/non_client_decor_title_focused" />
+    <item android:drawable="@drawable/non_client_decor_title_unfocused" />
+</selector>
diff --git a/core/res/res/drawable/non_client_decor_title_focused.xml b/core/res/res/drawable/non_client_decor_title_focused.xml
new file mode 100644
index 0000000..7d1c230
--- /dev/null
+++ b/core/res/res/drawable/non_client_decor_title_focused.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape android:shape="rectangle"
+       android:tintMode="multiply"
+       android:tint="#D8D8D8"
+       xmlns:android="http://schemas.android.com/apk/res/android">
+     <!-- Fading the primary color to 85% blackness -->
+     <solid android:color="?android:attr/colorPrimary" />
+</shape>
diff --git a/core/res/res/drawable/non_client_decor_title_unfocused.xml b/core/res/res/drawable/non_client_decor_title_unfocused.xml
new file mode 100644
index 0000000..2846d8ca
--- /dev/null
+++ b/core/res/res/drawable/non_client_decor_title_unfocused.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape android:shape="rectangle"
+       android:tintMode="multiply"
+       android:tint="#F2F2F2"
+       xmlns:android="http://schemas.android.com/apk/res/android">
+     <!-- Fading the primary color to 95% blackness -->
+     <solid android:color="?android:attr/colorPrimary"/>
+</shape>
diff --git a/core/res/res/layout/non_client_decor_dark.xml b/core/res/res/layout/non_client_decor_dark.xml
new file mode 100644
index 0000000..00b4255
--- /dev/null
+++ b/core/res/res/layout/non_client_decor_dark.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.internal.widget.NonClientDecorView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top|start"
+    android:descendantFocusability="beforeDescendants" >
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_gravity="end"
+        android:layout_height="wrap_content"
+        android:background="@drawable/non_client_decor_title" >
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+        <Button
+            android:id="@+id/maximize_window"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_margin="5dp"
+            android:padding="4dp"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/maximize_button_text"
+            android:background="@drawable/decor_maximize_button_dark" />
+         <Button
+            android:id="@+id/close_window"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_margin="5dp"
+            android:padding="4dp"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/close_button_text"
+            android:background="@drawable/decor_close_button_dark" />
+    </LinearLayout>
+</com.android.internal.widget.NonClientDecorView>
diff --git a/core/res/res/layout/non_client_decor_light.xml b/core/res/res/layout/non_client_decor_light.xml
new file mode 100644
index 0000000..0ce8fa7
--- /dev/null
+++ b/core/res/res/layout/non_client_decor_light.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.internal.widget.NonClientDecorView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top|start"
+    android:descendantFocusability="beforeDescendants" >
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_gravity="end"
+        android:layout_height="wrap_content"
+        android:background="@drawable/non_client_decor_title" >
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+        <Button
+            android:id="@+id/maximize_window"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_margin="5dp"
+            android:padding="4dp"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/maximize_button_text"
+            android:background="@drawable/decor_maximize_button_light" />
+         <Button
+            android:id="@+id/close_window"
+            android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:layout_margin="5dp"
+            android:padding="4dp"
+            android:layout_gravity="center_vertical|end"
+            android:contentDescription="@string/close_button_text"
+            android:background="@drawable/decor_close_button_light" />
+    </LinearLayout>
+</com.android.internal.widget.NonClientDecorView>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7cdad4b..ac6204d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4056,6 +4056,12 @@
     <!-- Content description for the button that closes the floating toolbar overflow. [CHAR LIMIT=NONE] -->
     <string name="floating_toolbar_close_overflow_description">Close overflow</string>
 
+    <!-- Free style window strings -->
+    <!-- Accessibility text for the maximize window button -->
+    <string name="maximize_button_text">Maximize</string>
+    <!-- Accessibility text for the close window button -->
+    <string name="close_button_text">Close</string>
+
     <!-- Ellipsis character to appear in notification templates, e.g.
          notification_template_material_inbox.xml.
          DO NOT TRANSLATE -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5303d5f..a45d907 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1939,6 +1939,10 @@
 
   <!-- From Phone -->
   <java-symbol type="bool" name="config_built_in_sip_phone" />
+  <java-symbol type="id" name="maximize_window" />
+  <java-symbol type="id" name="close_window" />
+  <java-symbol type="layout" name="non_client_decor_light" />
+  <java-symbol type="layout" name="non_client_decor_dark" />
 
   <!-- From TelephonyProvider -->
   <java-symbol type="xml" name="apns" />