| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.documentsui; |
| |
| import static com.android.documentsui.base.Shared.DEBUG; |
| |
| import android.annotation.IntDef; |
| import android.app.Activity; |
| import android.support.v4.app.ActionBarDrawerToggle; |
| import android.support.v4.widget.DrawerLayout; |
| import android.support.v4.widget.DrawerLayout.DrawerListener; |
| import android.util.Log; |
| import android.view.View; |
| import android.widget.Toolbar; |
| |
| import com.android.documentsui.base.Display; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * A facade over the various pieces comprising "roots fragment in a Drawer". |
| * |
| * @see DrawerController#create(DrawerLayout) |
| */ |
| public abstract class DrawerController implements DrawerListener { |
| public static final String TAG = "DrawerController"; |
| |
| // Drawer opening triggered by tapping the navigation icon |
| public static final int OPENED_HAMBURGER = 0; |
| // Drawer opening triggered by swiping right from the edge of the screen |
| public static final int OPENED_SWIPE = 1; |
| // Mostly programmatically forced drawer opening |
| public static final int OPENED_OTHER = 2; |
| |
| @IntDef(flag = true, value = { |
| OPENED_HAMBURGER, |
| OPENED_SWIPE, |
| OPENED_OTHER |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface Trigger {} |
| |
| public abstract void update(); |
| /** |
| * Toggles the drawer and sets the OPENED_OTHER as the action that causes opening the drawer. |
| * @param open |
| */ |
| public abstract void setOpen(boolean open); |
| |
| /** |
| * Toggles the drawer. |
| * @param open |
| * @param trigger Indicates what action caused opening the drawer. It is ignored for closing. |
| */ |
| abstract void setOpen(boolean open, @Trigger int trigger); |
| public abstract boolean isPresent(); |
| public abstract boolean isOpen(); |
| abstract void setTitle(String title); |
| |
| /** |
| * Returns a controller suitable for {@code Layout}. |
| */ |
| public static DrawerController create(Activity activity, ActivityConfig activityConfig) { |
| |
| DrawerLayout layout = (DrawerLayout) activity.findViewById(R.id.drawer_layout); |
| |
| if (layout == null) { |
| return new DummyDrawerController(); |
| } |
| |
| View drawer = activity.findViewById(R.id.drawer_roots); |
| Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar); |
| |
| drawer.getLayoutParams().width = calculateDrawerWidth(activity); |
| |
| ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( |
| activity, |
| layout, |
| R.drawable.ic_hamburger, |
| R.string.drawer_open, |
| R.string.drawer_close); |
| |
| return new RuntimeDrawerController(layout, drawer, toggle, toolbar, activityConfig); |
| } |
| |
| /** |
| * Returns a controller suitable for {@code Layout}. |
| */ |
| static DrawerController createDummy() { |
| return new DummyDrawerController(); |
| } |
| |
| private static int calculateDrawerWidth(Activity activity) { |
| // Material design specification for navigation drawer: |
| // https://www.google.com/design/spec/patterns/navigation-drawer.html |
| float width = Display.screenWidth(activity) - Display.actionBarHeight(activity); |
| float maxWidth = activity.getResources().getDimension(R.dimen.max_drawer_width); |
| int finalWidth = (int) ((width > maxWidth ? maxWidth : width)); |
| |
| if (DEBUG) |
| Log.d(TAG, "Calculated drawer width:" + (finalWidth / Display.density(activity))); |
| |
| return finalWidth; |
| } |
| |
| /** |
| * Runtime controller that manages a real drawer. |
| */ |
| private static final class RuntimeDrawerController extends DrawerController |
| implements ItemDragListener.DragHost { |
| private final ActionBarDrawerToggle mToggle; |
| private DrawerLayout mLayout; |
| private View mDrawer; |
| private Toolbar mToolbar; |
| private @Trigger int mTrigger = OPENED_OTHER; |
| |
| public RuntimeDrawerController( |
| DrawerLayout layout, |
| View drawer, |
| ActionBarDrawerToggle toggle, |
| Toolbar drawerToolbar, |
| ActivityConfig activityConfig) { |
| mToolbar = drawerToolbar; |
| assert(layout != null); |
| |
| mLayout = layout; |
| mDrawer = drawer; |
| mToggle = toggle; |
| |
| mLayout.setDrawerListener(this); |
| |
| if (activityConfig.dragAndDropEnabled()) { |
| View edge = layout.findViewById(R.id.drawer_edge); |
| edge.setOnDragListener(new ItemDragListener<>(this)); |
| } |
| } |
| |
| @Override |
| public void runOnUiThread(Runnable runnable) { |
| mDrawer.post(runnable); |
| } |
| |
| @Override |
| public void setDropTargetHighlight(View v, boolean highlight) { |
| } |
| |
| @Override |
| public void onDragEntered(View v) { |
| assert (v.getId() == R.id.drawer_edge); |
| |
| setOpen(true); |
| } |
| |
| @Override |
| public void onViewHovered(View v) { |
| } |
| |
| @Override |
| public void setOpen(boolean open) { |
| setOpen(open, OPENED_OTHER); |
| } |
| |
| @Override |
| void setOpen(boolean open, @Trigger int trigger) { |
| if (open) { |
| mLayout.openDrawer(mDrawer); |
| mTrigger = trigger; |
| } else { |
| mLayout.closeDrawer(mDrawer); |
| } |
| } |
| |
| @Override |
| public boolean isOpen() { |
| return mLayout.isDrawerOpen(mDrawer); |
| } |
| |
| @Override |
| public boolean isPresent() { |
| return true; |
| } |
| |
| @Override |
| void setTitle(String title) { |
| mToolbar.setTitle(title); |
| } |
| |
| @Override |
| public void update() { |
| mToggle.syncState(); |
| } |
| |
| @Override |
| public void onDrawerSlide(View drawerView, float slideOffset) { |
| mToggle.onDrawerSlide(drawerView, slideOffset); |
| } |
| |
| @Override |
| public void onDrawerOpened(View drawerView) { |
| mToggle.onDrawerOpened(drawerView); |
| Metrics.logDrawerOpened(mToolbar.getContext(), mTrigger); |
| } |
| |
| @Override |
| public void onDrawerClosed(View drawerView) { |
| mToggle.onDrawerClosed(drawerView); |
| mTrigger = OPENED_OTHER; |
| } |
| |
| @Override |
| public void onDrawerStateChanged(int newState) { |
| mToggle.onDrawerStateChanged(newState); |
| if (newState == DrawerLayout.STATE_DRAGGING) { |
| mTrigger = OPENED_SWIPE; |
| } |
| } |
| } |
| |
| /* |
| * Dummy controller useful with clients that don't host a real drawer. |
| */ |
| private static final class DummyDrawerController extends DrawerController { |
| |
| @Override |
| public void setOpen(boolean open) {} |
| |
| @Override |
| public void setOpen(boolean open, @Trigger int trigger) {} |
| |
| @Override |
| public boolean isOpen() { |
| return false; |
| } |
| |
| @Override |
| public boolean isPresent() { |
| return false; |
| } |
| |
| @Override |
| void setTitle(String title) {} |
| |
| @Override |
| public void update() {} |
| |
| @Override |
| public void onDrawerSlide(View drawerView, float slideOffset) {} |
| |
| @Override |
| public void onDrawerOpened(View drawerView) {} |
| |
| @Override |
| public void onDrawerClosed(View drawerView) {} |
| |
| @Override |
| public void onDrawerStateChanged(int newState) {} |
| } |
| } |