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.Shared.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, Object localState, boolean highlight)134 public void setDropTargetHighlight(View v, Object localState, 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, Object localState)143 public void onDragEntered(View v, Object localState) { 144 // do nothing; let drawer only open for onViewHovered 145 } 146 147 @Override onDragExited(View v, Object localState)148 public void onDragExited(View v, Object localState) { 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 setOpen(boolean open)160 public void setOpen(boolean open) { 161 if (open) { 162 mLayout.openDrawer(mDrawer); 163 } else { 164 mLayout.closeDrawer(mDrawer); 165 } 166 } 167 168 @Override isOpen()169 public boolean isOpen() { 170 return mLayout.isDrawerOpen(mDrawer); 171 } 172 173 @Override isPresent()174 public boolean isPresent() { 175 return true; 176 } 177 178 @Override setTitle(String title)179 void setTitle(String title) { 180 mToolbar.setTitle(title); 181 } 182 183 @Override update()184 public void update() { 185 mToggle.syncState(); 186 } 187 188 @Override onDrawerSlide(View drawerView, float slideOffset)189 public void onDrawerSlide(View drawerView, float slideOffset) { 190 mToggle.onDrawerSlide(drawerView, slideOffset); 191 } 192 193 @Override onDrawerOpened(View drawerView)194 public void onDrawerOpened(View drawerView) { 195 mToggle.onDrawerOpened(drawerView); 196 } 197 198 @Override onDrawerClosed(View drawerView)199 public void onDrawerClosed(View drawerView) { 200 mToggle.onDrawerClosed(drawerView); 201 } 202 203 @Override onDrawerStateChanged(int newState)204 public void onDrawerStateChanged(int newState) { 205 mToggle.onDrawerStateChanged(newState); 206 } 207 } 208 209 /* 210 * Dummy controller useful with clients that don't host a real drawer. 211 */ 212 private static final class DummyDrawerController extends DrawerController { 213 214 @Override setOpen(boolean open)215 public void setOpen(boolean open) {} 216 217 @Override isOpen()218 public boolean isOpen() { 219 return false; 220 } 221 222 @Override isPresent()223 public boolean isPresent() { 224 return false; 225 } 226 227 @Override setTitle(String title)228 void setTitle(String title) {} 229 230 @Override update()231 public void update() {} 232 233 @Override onDrawerSlide(View drawerView, float slideOffset)234 public void onDrawerSlide(View drawerView, float slideOffset) {} 235 236 @Override onDrawerOpened(View drawerView)237 public void onDrawerOpened(View drawerView) {} 238 239 @Override onDrawerClosed(View drawerView)240 public void onDrawerClosed(View drawerView) {} 241 242 @Override onDrawerStateChanged(int newState)243 public void onDrawerStateChanged(int newState) {} 244 } 245 } 246