• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.documentsui;
18 
19 import static com.android.documentsui.base.SharedMinimal.DEBUG;
20 import static com.android.documentsui.util.FlagUtils.isUseMaterial3FlagEnabled;
21 
22 import android.app.Activity;
23 import android.util.Log;
24 import android.view.Gravity;
25 import android.view.View;
26 
27 import androidx.annotation.ColorRes;
28 import androidx.appcompat.widget.Toolbar;
29 import androidx.drawerlayout.widget.DrawerLayout;
30 import androidx.drawerlayout.widget.DrawerLayout.DrawerListener;
31 import androidx.legacy.app.ActionBarDrawerToggle;
32 
33 import com.android.documentsui.base.Display;
34 import com.android.documentsui.base.Providers;
35 
36 /**
37  * A facade over the various pieces comprising "roots fragment in a Drawer".
38  *
39  * @see DrawerController#create(DrawerLayout)
40  */
41 public abstract class DrawerController implements DrawerListener {
42     public static final String TAG = "DrawerController";
43 
update()44     public abstract void update();
setOpen(boolean open)45     public abstract void setOpen(boolean open);
setLocked(boolean locked)46     public abstract void setLocked(boolean locked);
isPresent()47     public abstract boolean isPresent();
isOpen()48     public abstract boolean isOpen();
setTitle(String title)49     abstract void setTitle(String title);
50 
51     /**
52      * Returns a controller suitable for {@code Layout}.
53      */
create(BaseActivity activity, ActivityConfig activityConfig)54     public static DrawerController create(BaseActivity activity, ActivityConfig activityConfig) {
55 
56         DrawerLayout layout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
57 
58         if (layout == null) {
59             return new StubDrawerController();
60         }
61 
62         View drawer = activity.findViewById(R.id.drawer_roots);
63         // This will be null when use_material3 flag is ON, we will check the flag when it's used in
64         // RuntimeDrawerController.
65         Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar);
66         drawer.getLayoutParams().width = calculateDrawerWidth(activity);
67 
68         ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
69                 activity,
70                 layout,
71                 R.drawable.ic_hamburger,
72                 R.string.drawer_open,
73                 R.string.drawer_close);
74 
75         return new RuntimeDrawerController(layout, drawer, toggle, toolbar, activityConfig,
76                 activity);
77     }
78 
79     /**
80      * Returns a controller suitable for {@code Layout}.
81      */
createStub()82     static DrawerController createStub() {
83         return new StubDrawerController();
84     }
85 
calculateDrawerWidth(Activity activity)86     private static int calculateDrawerWidth(Activity activity) {
87         // Material design specification for navigation drawer:
88         // https://www.google.com/design/spec/patterns/navigation-drawer.html
89         float width = Display.screenWidth(activity) - Display.actionBarHeight(activity);
90         float maxWidth = activity.getResources().getDimension(R.dimen.max_drawer_width);
91         int finalWidth = (int) ((width > maxWidth ? maxWidth : width));
92 
93         if (DEBUG)
94             Log.d(TAG, "Calculated drawer width:" + (finalWidth / Display.density(activity)));
95 
96         return finalWidth;
97     }
98 
99     /**
100      * Runtime controller that manages a real drawer.
101      */
102     private static final class RuntimeDrawerController extends DrawerController
103             implements ItemDragListener.DragHost {
104         private static final int SPRING_TIMEOUT = 750;
105         private final ActionBarDrawerToggle mToggle;
106         private DrawerLayout mLayout;
107         private View mDrawer;
108         private Toolbar mToolbar;
109         private AbstractActionHandler.CommonAddons mCommonAddons;
110 
RuntimeDrawerController( DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle, Toolbar drawerToolbar, ActivityConfig activityConfig, AbstractActionHandler.CommonAddons commonAddons)111         public RuntimeDrawerController(
112                 DrawerLayout layout,
113                 View drawer,
114                 ActionBarDrawerToggle toggle,
115                 Toolbar drawerToolbar,
116                 ActivityConfig activityConfig,
117                 AbstractActionHandler.CommonAddons commonAddons) {
118             mToolbar = drawerToolbar;
119             assert(layout != null);
120 
121             mLayout = layout;
122             mDrawer = drawer;
123             mToggle = toggle;
124             mCommonAddons = commonAddons;
125 
126             mLayout.setDrawerListener(this);
127 
128             if (activityConfig.dragAndDropEnabled()) {
129                 View edge = layout.findViewById(R.id.drawer_edge);
130                 // nav_rail_layout also uses DrawerLayout, but it doesn't have drawer edge.
131                 if (edge != null) {
132                     edge.setOnDragListener(new ItemDragListener<>(this, SPRING_TIMEOUT));
133                 }
134             }
135         }
136 
137         @Override
runOnUiThread(Runnable runnable)138         public void runOnUiThread(Runnable runnable) {
139             mDrawer.post(runnable);
140         }
141 
142         @Override
setDropTargetHighlight(View v, boolean highlight)143         public void setDropTargetHighlight(View v, boolean highlight) {
144             assert (v.getId() == R.id.drawer_edge);
145 
146             @ColorRes int id = highlight ? R.color.secondary :
147                 android.R.color.transparent;
148             v.setBackgroundColor(id);
149         }
150 
151         @Override
onDragEntered(View v)152         public void onDragEntered(View v) {
153             // do nothing; let drawer only open for onViewHovered
154         }
155 
156         @Override
onDragExited(View v)157         public void onDragExited(View v) {
158             // do nothing
159         }
160 
161         @Override
onViewHovered(View v)162         public void onViewHovered(View v) {
163             assert (v.getId() == R.id.drawer_edge);
164 
165             setOpen(true);
166         }
167 
168         @Override
onDragEnded()169         public void onDragEnded() {
170             // do nothing
171         }
172 
173         @Override
setOpen(boolean open)174         public void setOpen(boolean open) {
175             View list = mDrawer.findViewById(R.id.roots_list);
176             if (open) {
177                 mLayout.openDrawer(mDrawer);
178                 if (list != null) {
179                     mDrawer.requestFocus();
180                 }
181             } else {
182                 mLayout.closeDrawer(mDrawer);
183                 if (list != null) {
184                     mDrawer.clearFocus();
185                 }
186             }
187         }
188 
189         @Override
setLocked(boolean locked)190         public void setLocked(boolean locked) {
191             if (locked) {
192                 mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
193             } else {
194                 mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
195             }
196         }
197 
198         @Override
isOpen()199         public boolean isOpen() {
200             return mLayout.isDrawerOpen(mDrawer);
201         }
202 
203         @Override
isPresent()204         public boolean isPresent() {
205             return DrawerLayout.LOCK_MODE_UNLOCKED
206                     == mLayout.getDrawerLockMode(Gravity.START);
207         }
208 
209         @Override
setTitle(String title)210         void setTitle(String title) {
211             if (!isUseMaterial3FlagEnabled()) {
212                 mToolbar.setTitle(title);
213             }
214         }
215 
216         @Override
update()217         public void update() {
218             mToggle.syncState();
219         }
220 
221         @Override
onDrawerSlide(View drawerView, float slideOffset)222         public void onDrawerSlide(View drawerView, float slideOffset) {
223             mToggle.onDrawerSlide(drawerView, slideOffset);
224         }
225 
226         @Override
onDrawerOpened(View drawerView)227         public void onDrawerOpened(View drawerView) {
228             mToggle.onDrawerOpened(drawerView);
229             // Update the information for Storage's root
230             DocumentsApplication.getProvidersCache(drawerView.getContext()).updateAuthorityAsync(
231                     mCommonAddons.getSelectedUser(), Providers.AUTHORITY_STORAGE);
232         }
233 
234         @Override
onDrawerClosed(View drawerView)235         public void onDrawerClosed(View drawerView) {
236             mToggle.onDrawerClosed(drawerView);
237         }
238 
239         @Override
onDrawerStateChanged(int newState)240         public void onDrawerStateChanged(int newState) {
241             mToggle.onDrawerStateChanged(newState);
242         }
243     }
244 
245     /*
246      * Stub controller useful with clients that don't host a real drawer.
247      */
248     private static final class StubDrawerController extends DrawerController {
249 
250         @Override
setOpen(boolean open)251         public void setOpen(boolean open) {}
252 
253         @Override
setLocked(boolean locked)254         public void setLocked(boolean locked) {}
255 
256         @Override
isOpen()257         public boolean isOpen() {
258             return false;
259         }
260 
261         @Override
isPresent()262         public boolean isPresent() {
263             return false;
264         }
265 
266         @Override
setTitle(String title)267         void setTitle(String title) {}
268 
269         @Override
update()270         public void update() {}
271 
272         @Override
onDrawerSlide(View drawerView, float slideOffset)273         public void onDrawerSlide(View drawerView, float slideOffset) {}
274 
275         @Override
onDrawerOpened(View drawerView)276         public void onDrawerOpened(View drawerView) {}
277 
278         @Override
onDrawerClosed(View drawerView)279         public void onDrawerClosed(View drawerView) {}
280 
281         @Override
onDrawerStateChanged(int newState)282         public void onDrawerStateChanged(int newState) {}
283     }
284 }
285