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 21 import android.annotation.IntDef; 22 import android.app.Activity; 23 import android.support.annotation.ColorRes; 24 import android.support.v4.app.ActionBarDrawerToggle; 25 import android.support.v4.widget.DrawerLayout; 26 import android.support.v4.widget.DrawerLayout.DrawerListener; 27 import android.util.Log; 28 import android.view.View; 29 import android.widget.Toolbar; 30 31 import com.android.documentsui.base.Display; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 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); isPresent()46 public abstract boolean isPresent(); isOpen()47 public abstract boolean isOpen(); setTitle(String title)48 abstract void setTitle(String title); 49 50 /** 51 * Returns a controller suitable for {@code Layout}. 52 */ create(Activity activity, ActivityConfig activityConfig)53 public static DrawerController create(Activity activity, ActivityConfig activityConfig) { 54 55 DrawerLayout layout = (DrawerLayout) activity.findViewById(R.id.drawer_layout); 56 57 if (layout == null) { 58 return new DummyDrawerController(); 59 } 60 61 View drawer = activity.findViewById(R.id.drawer_roots); 62 Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar); 63 64 drawer.getLayoutParams().width = calculateDrawerWidth(activity); 65 66 ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( 67 activity, 68 layout, 69 R.drawable.ic_hamburger, 70 R.string.drawer_open, 71 R.string.drawer_close); 72 73 return new RuntimeDrawerController(layout, drawer, toggle, toolbar, activityConfig); 74 } 75 76 /** 77 * Returns a controller suitable for {@code Layout}. 78 */ createDummy()79 static DrawerController createDummy() { 80 return new DummyDrawerController(); 81 } 82 calculateDrawerWidth(Activity activity)83 private static int calculateDrawerWidth(Activity activity) { 84 // Material design specification for navigation drawer: 85 // https://www.google.com/design/spec/patterns/navigation-drawer.html 86 float width = Display.screenWidth(activity) - Display.actionBarHeight(activity); 87 float maxWidth = activity.getResources().getDimension(R.dimen.max_drawer_width); 88 int finalWidth = (int) ((width > maxWidth ? maxWidth : width)); 89 90 if (DEBUG) 91 Log.d(TAG, "Calculated drawer width:" + (finalWidth / Display.density(activity))); 92 93 return finalWidth; 94 } 95 96 /** 97 * Runtime controller that manages a real drawer. 98 */ 99 private static final class RuntimeDrawerController extends DrawerController 100 implements ItemDragListener.DragHost { 101 private static final int SPRING_TIMEOUT = 750; 102 private final ActionBarDrawerToggle mToggle; 103 private DrawerLayout mLayout; 104 private View mDrawer; 105 private Toolbar mToolbar; 106 RuntimeDrawerController( DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle, Toolbar drawerToolbar, ActivityConfig activityConfig)107 public RuntimeDrawerController( 108 DrawerLayout layout, 109 View drawer, 110 ActionBarDrawerToggle toggle, 111 Toolbar drawerToolbar, 112 ActivityConfig activityConfig) { 113 mToolbar = drawerToolbar; 114 assert(layout != null); 115 116 mLayout = layout; 117 mDrawer = drawer; 118 mToggle = toggle; 119 120 mLayout.setDrawerListener(this); 121 122 if (activityConfig.dragAndDropEnabled()) { 123 View edge = layout.findViewById(R.id.drawer_edge); 124 edge.setOnDragListener(new ItemDragListener<>(this, SPRING_TIMEOUT)); 125 } 126 } 127 128 @Override runOnUiThread(Runnable runnable)129 public void runOnUiThread(Runnable runnable) { 130 mDrawer.post(runnable); 131 } 132 133 @Override setDropTargetHighlight(View v, boolean highlight)134 public void setDropTargetHighlight(View v, boolean highlight) { 135 assert (v.getId() == R.id.drawer_edge); 136 137 @ColorRes int id = highlight ? R.color.item_doc_background_selected : 138 android.R.color.transparent; 139 v.setBackgroundColor(id); 140 } 141 142 @Override onDragEntered(View v)143 public void onDragEntered(View v) { 144 // do nothing; let drawer only open for onViewHovered 145 } 146 147 @Override onDragExited(View v)148 public void onDragExited(View v) { 149 // do nothing 150 } 151 152 @Override onViewHovered(View v)153 public void onViewHovered(View v) { 154 assert (v.getId() == R.id.drawer_edge); 155 156 setOpen(true); 157 } 158 159 @Override onDragEnded()160 public void onDragEnded() { 161 // do nothing 162 } 163 164 @Override setOpen(boolean open)165 public void setOpen(boolean open) { 166 if (open) { 167 mLayout.openDrawer(mDrawer); 168 } else { 169 mLayout.closeDrawer(mDrawer); 170 } 171 } 172 173 @Override isOpen()174 public boolean isOpen() { 175 return mLayout.isDrawerOpen(mDrawer); 176 } 177 178 @Override isPresent()179 public boolean isPresent() { 180 return true; 181 } 182 183 @Override setTitle(String title)184 void setTitle(String title) { 185 mToolbar.setTitle(title); 186 } 187 188 @Override update()189 public void update() { 190 mToggle.syncState(); 191 } 192 193 @Override onDrawerSlide(View drawerView, float slideOffset)194 public void onDrawerSlide(View drawerView, float slideOffset) { 195 mToggle.onDrawerSlide(drawerView, slideOffset); 196 } 197 198 @Override onDrawerOpened(View drawerView)199 public void onDrawerOpened(View drawerView) { 200 mToggle.onDrawerOpened(drawerView); 201 } 202 203 @Override onDrawerClosed(View drawerView)204 public void onDrawerClosed(View drawerView) { 205 mToggle.onDrawerClosed(drawerView); 206 } 207 208 @Override onDrawerStateChanged(int newState)209 public void onDrawerStateChanged(int newState) { 210 mToggle.onDrawerStateChanged(newState); 211 } 212 } 213 214 /* 215 * Dummy controller useful with clients that don't host a real drawer. 216 */ 217 private static final class DummyDrawerController extends DrawerController { 218 219 @Override setOpen(boolean open)220 public void setOpen(boolean open) {} 221 222 @Override isOpen()223 public boolean isOpen() { 224 return false; 225 } 226 227 @Override isPresent()228 public boolean isPresent() { 229 return false; 230 } 231 232 @Override setTitle(String title)233 void setTitle(String title) {} 234 235 @Override update()236 public void update() {} 237 238 @Override onDrawerSlide(View drawerView, float slideOffset)239 public void onDrawerSlide(View drawerView, float slideOffset) {} 240 241 @Override onDrawerOpened(View drawerView)242 public void onDrawerOpened(View drawerView) {} 243 244 @Override onDrawerClosed(View drawerView)245 public void onDrawerClosed(View drawerView) {} 246 247 @Override onDrawerStateChanged(int newState)248 public void onDrawerStateChanged(int newState) {} 249 } 250 } 251