diff --git a/res/layout/design_drawer_item.xml b/res/layout/design_drawer_item.xml
new file mode 100644
index 000000000..c1eb1cef6
--- /dev/null
+++ b/res/layout/design_drawer_item.xml
@@ -0,0 +1,26 @@
+
+
+
diff --git a/res/layout/design_drawer_menu.xml b/res/layout/design_drawer_menu.xml
new file mode 100644
index 000000000..e28eaf07b
--- /dev/null
+++ b/res/layout/design_drawer_menu.xml
@@ -0,0 +1,22 @@
+
+
+
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index a6096ceb1..5102d1894 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -14,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
@@ -36,4 +35,15 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d16bb77d1..903399914 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -14,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
8dp
@@ -23,4 +22,9 @@
56dp
40dp
-
\ No newline at end of file
+ 320dp
+ 12dp
+ 32dp
+ 24dp
+
+
diff --git a/res/values/styles.xml b/res/values/styles.xml
index ad42108a8..0cb5ead5f 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -14,7 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-
\ No newline at end of file
+
+
+
+
+
diff --git a/src/android/support/design/internal/NavigationMenuItemView.java b/src/android/support/design/internal/NavigationMenuItemView.java
new file mode 100644
index 000000000..531372289
--- /dev/null
+++ b/src/android/support/design/internal/NavigationMenuItemView.java
@@ -0,0 +1,99 @@
+/*
+ * 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 android.support.design.internal;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.design.R;
+import android.support.v4.widget.TextViewCompat;
+import android.support.v7.internal.view.menu.MenuItemImpl;
+import android.support.v7.internal.view.menu.MenuView;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * @hide
+ */
+public class NavigationMenuItemView extends TextView implements MenuView.ItemView {
+
+ private MenuItemImpl mItemData;
+
+ private int mIconSize;
+
+ public NavigationMenuItemView(Context context) {
+ this(context, null);
+ }
+
+ public NavigationMenuItemView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mIconSize = context.getResources().getDimensionPixelSize(R.dimen.drawer_icon_size);
+ }
+
+ @Override
+ public void initialize(MenuItemImpl itemData, int menuType) {
+ mItemData = itemData;
+
+ setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
+
+ setTitle(itemData.getTitle());
+ setCheckable(itemData.isCheckable());
+ setIcon(itemData.getIcon());
+ setEnabled(itemData.isEnabled());
+ }
+
+ @Override
+ public MenuItemImpl getItemData() {
+ return mItemData;
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ setText(title);
+ }
+
+ @Override
+ public void setCheckable(boolean checkable) {
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ }
+
+ @Override
+ public void setShortcut(boolean showShortcut, char shortcutKey) {
+ }
+
+ @Override
+ public void setIcon(Drawable icon) {
+ if (icon != null) {
+ icon.setBounds(0, 0, mIconSize, mIconSize);
+ }
+ TextViewCompat.setCompoundDrawablesRelative(this, icon, null, null, null);
+ }
+
+ @Override
+ public boolean prefersCondensedTitle() {
+ return false;
+ }
+
+ @Override
+ public boolean showsIcon() {
+ return true;
+ }
+
+}
diff --git a/src/android/support/design/internal/NavigationMenuPresenter.java b/src/android/support/design/internal/NavigationMenuPresenter.java
new file mode 100644
index 000000000..b4c891e69
--- /dev/null
+++ b/src/android/support/design/internal/NavigationMenuPresenter.java
@@ -0,0 +1,160 @@
+/*
+ * 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 android.support.design.internal;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.support.design.R;
+import android.support.v7.internal.view.menu.MenuBuilder;
+import android.support.v7.internal.view.menu.MenuItemImpl;
+import android.support.v7.internal.view.menu.MenuPresenter;
+import android.support.v7.internal.view.menu.MenuView;
+import android.support.v7.internal.view.menu.SubMenuBuilder;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+
+/**
+ * @hide
+ */
+public class NavigationMenuPresenter implements MenuPresenter, AdapterView.OnItemClickListener {
+
+ private NavigationMenuView mMenuView;
+
+ private Callback mCallback;
+
+ private MenuBuilder mMenu;
+
+ private int mId;
+
+ private NavigationMenuAdapter mAdapter;
+
+ private LayoutInflater mLayoutInflater;
+
+ @Override
+ public void initForMenu(Context context, MenuBuilder menu) {
+ mLayoutInflater = LayoutInflater.from(context);
+ mMenu = menu;
+ }
+
+ @Override
+ public MenuView getMenuView(ViewGroup root) {
+ if (mMenuView == null) {
+ mMenuView = (NavigationMenuView) mLayoutInflater.inflate(
+ R.layout.design_drawer_menu, root, false);
+ if (mAdapter == null) {
+ mAdapter = new NavigationMenuAdapter();
+ }
+ mMenuView.setAdapter(mAdapter);
+ mMenuView.setOnItemClickListener(this);
+ }
+ return mMenuView;
+ }
+
+ @Override
+ public void updateMenuView(boolean cleared) {
+ if (mAdapter != null) {
+ mAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void setCallback(Callback cb) {
+ mCallback = cb;
+ }
+
+ @Override
+ public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+ return false;
+ }
+
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ if (mCallback != null) {
+ mCallback.onCloseMenu(menu, allMenusAreClosing);
+ }
+ }
+
+ @Override
+ public boolean flagActionItems() {
+ return false;
+ }
+
+ @Override
+ public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ return false;
+ }
+
+ @Override
+ public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+ return false;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+
+ public void setId(int id) {
+ mId = id;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ return null;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ }
+
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ mMenu.performItemAction(mAdapter.getItem(position), this, 0);
+ }
+
+ private class NavigationMenuAdapter extends BaseAdapter {
+
+ @Override
+ public int getCount() {
+ return mMenu.size();
+ }
+
+ @Override
+ public MenuItemImpl getItem(int position) {
+ return (MenuItemImpl) mMenu.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mLayoutInflater.inflate(R.layout.design_drawer_item, parent, false);
+ }
+ MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+ itemView.initialize(getItem(position), 0);
+ return convertView;
+ }
+ }
+
+}
diff --git a/src/android/support/design/internal/NavigationMenuView.java b/src/android/support/design/internal/NavigationMenuView.java
new file mode 100644
index 000000000..054b800c7
--- /dev/null
+++ b/src/android/support/design/internal/NavigationMenuView.java
@@ -0,0 +1,52 @@
+/*
+ * 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 android.support.design.internal;
+
+import android.content.Context;
+import android.support.v7.internal.view.menu.MenuBuilder;
+import android.support.v7.internal.view.menu.MenuView;
+import android.util.AttributeSet;
+import android.widget.ListView;
+
+/**
+ * @hide
+ */
+public class NavigationMenuView extends ListView implements MenuView {
+
+ public NavigationMenuView(Context context) {
+ this(context, null);
+ }
+
+ public NavigationMenuView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NavigationMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public void initialize(MenuBuilder menu) {
+
+ }
+
+ @Override
+ public int getWindowAnimations() {
+ return 0;
+ }
+
+}
diff --git a/src/android/support/design/internal/ScrimInsetsFrameLayout.java b/src/android/support/design/internal/ScrimInsetsFrameLayout.java
new file mode 100644
index 000000000..246d5b322
--- /dev/null
+++ b/src/android/support/design/internal/ScrimInsetsFrameLayout.java
@@ -0,0 +1,130 @@
+/*
+ * 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 android.support.design.internal;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.design.R;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.WindowInsetsCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+/**
+ * @hide
+ */
+public class ScrimInsetsFrameLayout extends FrameLayout {
+
+ private Drawable mInsetForeground;
+
+ private Rect mInsets;
+
+ private Rect mTempRect = new Rect();
+
+ public ScrimInsetsFrameLayout(Context context) {
+ this(context, null);
+ }
+
+ public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.ScrimInsetsFrameLayout, defStyleAttr,
+ R.style.Widget_Design_ScrimInsetsFrameLayout);
+ mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsFrameLayout_insetForeground);
+ a.recycle();
+ setWillNotDraw(true); // No need to draw until the insets are adjusted
+
+ ViewCompat.setOnApplyWindowInsetsListener(this,
+ new android.support.v4.view.OnApplyWindowInsetsListener() {
+ @Override
+ public WindowInsetsCompat onApplyWindowInsets(View v,
+ WindowInsetsCompat insets) {
+ if (null == mInsets) {
+ mInsets = new Rect();
+ }
+ mInsets.set(insets.getSystemWindowInsetLeft(),
+ insets.getSystemWindowInsetTop(),
+ insets.getSystemWindowInsetRight(),
+ insets.getSystemWindowInsetBottom());
+ setWillNotDraw(mInsets.isEmpty() || mInsetForeground == null);
+ ViewCompat.postInvalidateOnAnimation(ScrimInsetsFrameLayout.this);
+ return insets.consumeSystemWindowInsets();
+ }
+ });
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ super.draw(canvas);
+
+ int width = getWidth();
+ int height = getHeight();
+ if (mInsets != null && mInsetForeground != null) {
+ int sc = canvas.save();
+ canvas.translate(getScrollX(), getScrollY());
+
+ // Top
+ mTempRect.set(0, 0, width, mInsets.top);
+ mInsetForeground.setBounds(mTempRect);
+ mInsetForeground.draw(canvas);
+
+ // Bottom
+ mTempRect.set(0, height - mInsets.bottom, width, height);
+ mInsetForeground.setBounds(mTempRect);
+ mInsetForeground.draw(canvas);
+
+ // Left
+ mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
+ mInsetForeground.setBounds(mTempRect);
+ mInsetForeground.draw(canvas);
+
+ // Right
+ mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
+ mInsetForeground.setBounds(mTempRect);
+ mInsetForeground.draw(canvas);
+
+ canvas.restoreToCount(sc);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mInsetForeground != null) {
+ mInsetForeground.setCallback(this);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mInsetForeground != null) {
+ mInsetForeground.setCallback(null);
+ }
+ }
+
+}
diff --git a/src/android/support/design/widget/NavigationDrawerView.java b/src/android/support/design/widget/NavigationDrawerView.java
new file mode 100644
index 000000000..98505dd5a
--- /dev/null
+++ b/src/android/support/design/widget/NavigationDrawerView.java
@@ -0,0 +1,154 @@
+/*
+ * 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 android.support.design.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.design.R;
+import android.support.design.internal.NavigationMenuPresenter;
+import android.support.design.internal.ScrimInsetsFrameLayout;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.internal.view.menu.MenuBuilder;
+import android.util.AttributeSet;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * Represents a standard navigation drawer for application. The drawer contents can be populated by
+ * a menu resource
+ * file.
+ *
NavigationDrawer needs to be placed inside a {@link android.support.v4.widget.DrawerLayout}.
+ *
+ *
+ * <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ * xmlns:app="http://schemas.android.com/apk/res-auto"
+ * android:id="@+id/drawer_layout"
+ * android:layout_width="match_parent"
+ * android:layout_height="match_parent"
+ * android:fitsSystemWindows="true">
+ *
+ * <!-- Your contents -->
+ *
+ * <android.support.design.widget.NavigationDrawerView
+ * android:id="@+id/navigation_drawer"
+ * android:layout_width="wrap_content"
+ * android:layout_height="match_parent"
+ * android:layout_gravity="start" />
+ * </android.support.v4.widget.DrawerLayout>
+ *
+ */
+public class NavigationDrawerView extends ScrimInsetsFrameLayout {
+
+ private OnNavigationItemSelectedListener mListener;
+
+ private MenuBuilder mMenu;
+
+ private int mMaxWidth;
+
+ public NavigationDrawerView(Context context) {
+ this(context, null);
+ }
+
+ public NavigationDrawerView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NavigationDrawerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ // Custom attributes
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.NavigationDrawerView, defStyleAttr,
+ R.style.Widget_Design_NavigationDrawerView);
+
+ //noinspection deprecation
+ setBackgroundDrawable(a.getDrawable(R.styleable.NavigationDrawerView_android_background));
+ ViewCompat.setElevation(this,
+ a.getDimensionPixelSize(R.styleable.NavigationDrawerView_android_elevation, 0));
+ ViewCompat.setFitsSystemWindows(this,
+ a.getBoolean(R.styleable.NavigationDrawerView_android_fitsSystemWindows, false));
+ mMaxWidth = a.getDimensionPixelSize(R.styleable.NavigationDrawerView_android_maxWidth, 0);
+ a.recycle();
+
+ // Set up the menu
+ mMenu = new MenuBuilder(context);
+ MenuBuilder.Callback menuCallback = new MenuBuilder.Callback() {
+ @Override
+ public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+ return mListener != null && mListener.onNavigationItemSelected(item);
+ }
+
+ @Override
+ public void onMenuModeChange(MenuBuilder menu) {
+
+ }
+ };
+ mMenu.setCallback(menuCallback);
+ NavigationMenuPresenter presenter = new NavigationMenuPresenter();
+ presenter.initForMenu(context, mMenu);
+ addView((View) presenter.getMenuView(this));
+ }
+
+ /**
+ * Set a listener that will be notified when a menu item is clicked.
+ *
+ * @param listener The listener to notify
+ */
+ public void setNavigationItemSelectedListener(OnNavigationItemSelectedListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ switch (MeasureSpec.getMode(widthSpec)) {
+ case MeasureSpec.EXACTLY:
+ // Nothing to do
+ break;
+ case MeasureSpec.AT_MOST:
+ widthSpec = MeasureSpec.makeMeasureSpec(
+ Math.min(MeasureSpec.getSize(widthSpec), mMaxWidth), MeasureSpec.EXACTLY);
+ break;
+ case MeasureSpec.UNSPECIFIED:
+ widthSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, MeasureSpec.EXACTLY);
+ break;
+ }
+ // Let super sort out the height
+ super.onMeasure(widthSpec, heightSpec);
+ }
+
+ /**
+ * @return The {@link Menu} associated with this NavigationDrawerView.
+ */
+ public Menu getMenu() {
+ return mMenu;
+ }
+
+ /**
+ * Listener for handling events on navigation drawer items.
+ */
+ public interface OnNavigationItemSelectedListener {
+
+ /**
+ * Called when an item in the navigation drawer is selected.
+ *
+ * @param item The selected item
+ */
+ public boolean onNavigationItemSelected(MenuItem item);
+ }
+
+}