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