1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v7.app;
18
19import android.content.res.Configuration;
20import android.content.res.Resources;
21import android.content.res.TypedArray;
22import android.os.Bundle;
23import android.support.v4.view.GravityCompat;
24import android.support.v4.widget.DrawerLayout;
25import android.support.v7.appcompat.test.R;
26import android.support.v7.testutils.BaseTestActivity;
27import android.support.v7.testutils.Shakespeare;
28import android.support.v7.widget.Toolbar;
29import android.view.MenuItem;
30import android.view.View;
31import android.view.ViewTreeObserver;
32import android.widget.AdapterView;
33import android.widget.ArrayAdapter;
34import android.widget.ListView;
35import android.widget.TextView;
36
37/**
38 * Test activity for testing various APIs and interactions for DrawerLayout. It follows
39 * a common usage of the DrawerLayout widget combined with Toolbar in the Android support library
40 * that respect the
41 * <a href="https://www.google.com/design/spec/patterns/navigation-drawer.html">Material design
42 * guidelines</a> for the drawer component.
43 */
44public class DrawerLayoutActivity extends BaseTestActivity {
45    private DrawerLayout mDrawerLayout;
46    private ListView mDrawer;
47    private TextView mContent;
48
49    private ActionBarDrawerToggle mDrawerToggle;
50    private Toolbar mToolbar;
51
52    @Override
53    protected int getContentViewLayoutResId() {
54        return R.layout.drawer_layout;
55    }
56
57    @Override
58    protected void onContentViewSet() {
59        super.onContentViewSet();
60
61        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
62        mDrawer = (ListView) findViewById(R.id.start_drawer);
63        mContent = (TextView) findViewById(R.id.content_text);
64
65        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
66
67        // The drawer title must be set in order to announce state changes when
68        // accessibility is turned on. This is typically a simple description,
69        // e.g. "Navigation".
70        mDrawerLayout.setDrawerTitle(GravityCompat.START, getString(R.string.drawer_title));
71
72        mDrawer.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
73                Shakespeare.TITLES));
74        mDrawer.setOnItemClickListener(new DrawerItemClickListener());
75
76        // Find the toolbar in our layout and set it as the support action bar on the activity.
77        // This is required to have the drawer slide "over" the toolbar.
78        mToolbar = (Toolbar) findViewById(R.id.toolbar);
79        mToolbar.setTitle(R.string.drawer_title);
80        setSupportActionBar(mToolbar);
81
82        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
83        getSupportActionBar().setDisplayShowHomeEnabled(false);
84
85        // ActionBarDrawerToggle provides convenient helpers for tying together the
86        // prescribed interactions between a top-level sliding drawer and the action bar.
87        // Note that, as the Javadocs of ActionBarDrawerToggle constructors say, we are
88        // *not* using a constructor that gets a Toolbar since we're setting our toolbar
89        // dynamically at runtime. Furthermore, as the drawer is sliding over the toolbar,
90        // we are suppressing the morphing animation from hamburger to back arrow by
91        // calling super.onDrawerSlide with slideOffset=0.0f. In case your app only has
92        // top-level pages and doesn't need back arrow visuals at all, you can set up
93        // your activity theme to have attribute named "drawerArrowStyle" that points
94        // to an extension of Widget.AppCompat.DrawerArrowToggle that has its "spinBars"
95        // attribute set to false.
96        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
97                R.string.drawer_open, R.string.drawer_close) {
98            @Override
99            public void onDrawerOpened(View drawerView) {
100                super.onDrawerOpened(drawerView);
101                super.onDrawerSlide(drawerView, 0.0f);
102            }
103
104            @Override
105            public void onDrawerSlide(View drawerView, float slideOffset) {
106                super.onDrawerSlide(drawerView, 0.0f);
107            }
108        };
109
110        mDrawerLayout.addDrawerListener(mDrawerToggle);
111
112        // Configure the background color fill of the system status bar (on supported platform
113        // versions) and the toolbar itself. We're using the same color, and android:statusBar
114        // from the theme makes the status bar slightly darker.
115        final int metalBlueColor = getResources().getColor(R.color.drawer_sample_metal_blue);
116        mDrawerLayout.setStatusBarBackgroundColor(metalBlueColor);
117        mToolbar.setBackgroundColor(metalBlueColor);
118
119        // Register a pre-draw listener to get the initial width of the DrawerLayout so
120        // that we can determine the width of the drawer based on the Material spec at
121        // https://www.google.com/design/spec/patterns/navigation-drawer.html#navigation-drawer-specs
122        mDrawerLayout.getViewTreeObserver().addOnPreDrawListener(
123                new ViewTreeObserver.OnPreDrawListener() {
124                    @Override
125                    public boolean onPreDraw() {
126                        // What is the width of the entire DrawerLayout?
127                        final int drawerLayoutWidth = mDrawerLayout.getWidth();
128
129                        // What is the action bar size?
130                        final Resources.Theme theme = mDrawerLayout.getContext().getTheme();
131                        final TypedArray a = theme.obtainStyledAttributes(
132                                new int[] { android.support.v7.appcompat.R.attr.actionBarSize });
133                        final int actionBarSize = a.getDimensionPixelSize(0, 0);
134                        if (a != null) {
135                            a.recycle();
136                        }
137
138                        // Compute the width of the drawer and set it on the layout params.
139                        final int idealDrawerWidth = 5 * actionBarSize;
140                        final int maxDrawerWidth = Math.max(0, drawerLayoutWidth - actionBarSize);
141                        final int drawerWidth = Math.min(idealDrawerWidth, maxDrawerWidth);
142
143                        final DrawerLayout.LayoutParams drawerLp =
144                                (DrawerLayout.LayoutParams) mDrawer.getLayoutParams();
145                        drawerLp.width = drawerWidth;
146                        mDrawer.setLayoutParams(drawerLp);
147
148                        // Remove ourselves as the pre-draw listener since this is a one-time
149                        // configuration.
150                        mDrawerLayout.getViewTreeObserver().removeOnPreDrawListener(this);
151                        return true;
152                    }
153                });
154    }
155
156    @Override
157    protected void onPostCreate(Bundle savedInstanceState) {
158        super.onPostCreate(savedInstanceState);
159
160        // Sync the toggle state after onRestoreInstanceState has occurred.
161        mDrawerToggle.syncState();
162    }
163
164    @Override
165    public boolean onOptionsItemSelected(MenuItem item) {
166        /*
167         * The action bar home/up action should open or close the drawer.
168         * The drawer toggle will take care of this.
169         */
170        if (mDrawerToggle.onOptionsItemSelected(item)) {
171            return true;
172        }
173        return super.onOptionsItemSelected(item);
174    }
175
176    @Override
177    public void onBackPressed() {
178        // Is the drawer open?
179        if (mDrawerLayout.isDrawerOpen(mDrawer)) {
180            // Close the drawer and return.
181            mDrawerLayout.closeDrawer(mDrawer);
182            return;
183        }
184
185        super.onBackPressed();
186    }
187
188    @Override
189    public void onConfigurationChanged(Configuration newConfig) {
190        super.onConfigurationChanged(newConfig);
191        mDrawerToggle.onConfigurationChanged(newConfig);
192    }
193
194    /**
195     * This list item click listener implements very simple view switching by changing
196     * the primary content text. The drawer is closed when a selection is made.
197     */
198    private class DrawerItemClickListener implements ListView.OnItemClickListener {
199        @Override
200        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
201            mContent.setText(Shakespeare.DIALOGUE[position]);
202            mToolbar.setTitle(Shakespeare.TITLES[position]);
203            mDrawerLayout.closeDrawer(mDrawer);
204        }
205    }
206}
207