Home | History | Annotate | Download | only in documentsui
      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.Shared.DEBUG;
     20 
     21 import android.annotation.IntDef;
     22 import android.app.Activity;
     23 import android.content.Context;
     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 java.lang.annotation.Retention;
     32 import java.lang.annotation.RetentionPolicy;
     33 
     34 /**
     35  * A facade over the various pieces comprising "roots fragment in a Drawer".
     36  *
     37  * @see DrawerController#create(DrawerLayout)
     38  */
     39 abstract class DrawerController implements DrawerListener {
     40     public static final String TAG = "DrawerController";
     41 
     42     // Drawer opening triggered by tapping the navigation icon
     43     public static final int OPENED_HAMBURGER = 0;
     44     // Drawer opening triggered by swiping right from the edge of the screen
     45     public static final int OPENED_SWIPE = 1;
     46     // Mostly programmatically forced drawer opening
     47     public static final int OPENED_OTHER = 2;
     48 
     49     @IntDef(flag = true, value = {
     50             OPENED_HAMBURGER,
     51             OPENED_SWIPE,
     52             OPENED_OTHER
     53     })
     54     @Retention(RetentionPolicy.SOURCE)
     55     public @interface Trigger {}
     56 
     57     /**
     58      * Toggles the drawer and sets the OPENED_OTHER as the action that causes opening the drawer.
     59      * @param open
     60      */
     61     abstract void setOpen(boolean open);
     62 
     63     /**
     64      * Toggles the drawer.
     65      * @param open
     66      * @param trigger Indicates what action caused opening the drawer. It is ignored for closing.
     67      */
     68     abstract void setOpen(boolean open, @Trigger int trigger);
     69     abstract boolean isPresent();
     70     abstract boolean isOpen();
     71     abstract void setTitle(String title);
     72     abstract void update();
     73 
     74     /**
     75      * Returns a controller suitable for {@code Layout}.
     76      */
     77     static DrawerController create(Activity activity) {
     78 
     79         DrawerLayout layout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
     80 
     81         if (layout == null) {
     82             return new DummyDrawerController();
     83         }
     84 
     85         View drawer = activity.findViewById(R.id.drawer_roots);
     86         Toolbar toolbar = (Toolbar) activity.findViewById(R.id.roots_toolbar);
     87 
     88         drawer.getLayoutParams().width = calculateDrawerWidth(activity);
     89 
     90         ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
     91                 activity,
     92                 layout,
     93                 R.drawable.ic_hamburger,
     94                 R.string.drawer_open,
     95                 R.string.drawer_close);
     96 
     97         return new RuntimeDrawerController(layout, drawer, toggle, toolbar);
     98     }
     99 
    100     /**
    101      * Returns a controller suitable for {@code Layout}.
    102      */
    103     static DrawerController createDummy() {
    104         return new DummyDrawerController();
    105     }
    106 
    107     private static int calculateDrawerWidth(Activity activity) {
    108         // Material design specification for navigation drawer:
    109         // https://www.google.com/design/spec/patterns/navigation-drawer.html
    110         float width = Display.screenWidth(activity) - Display.actionBarHeight(activity);
    111         float maxWidth = activity.getResources().getDimension(R.dimen.max_drawer_width);
    112         int finalWidth = (int) ((width > maxWidth ? maxWidth : width));
    113 
    114         if (DEBUG)
    115             Log.d(TAG, "Calculated drawer width:" + (finalWidth / Display.density(activity)));
    116 
    117         return finalWidth;
    118     }
    119 
    120     /**
    121      * Runtime controller that manages a real drawer.
    122      */
    123     private static final class RuntimeDrawerController extends DrawerController {
    124         private final ActionBarDrawerToggle mToggle;
    125         private DrawerLayout mLayout;
    126         private View mDrawer;
    127         private Toolbar mToolbar;
    128         private @Trigger int mTrigger = OPENED_OTHER;
    129 
    130         public RuntimeDrawerController(
    131                 DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle,
    132                 Toolbar drawerToolbar) {
    133             mToolbar = drawerToolbar;
    134             assert(layout != null);
    135 
    136             mLayout = layout;
    137             mDrawer = drawer;
    138             mToggle = toggle;
    139 
    140             mLayout.setDrawerListener(this);
    141         }
    142 
    143         @Override
    144         void setOpen(boolean open) {
    145             setOpen(open, OPENED_OTHER);
    146         }
    147 
    148         @Override
    149         void setOpen(boolean open, @Trigger int trigger) {
    150             if (open) {
    151                 mLayout.openDrawer(mDrawer);
    152                 mTrigger = trigger;
    153             } else {
    154                 mLayout.closeDrawer(mDrawer);
    155             }
    156         }
    157 
    158         @Override
    159         boolean isOpen() {
    160             return mLayout.isDrawerOpen(mDrawer);
    161         }
    162 
    163         @Override
    164         boolean isPresent() {
    165             return true;
    166         }
    167 
    168         @Override
    169         void setTitle(String title) {
    170             mToolbar.setTitle(title);
    171         }
    172 
    173         @Override
    174         void update() {
    175             mToggle.syncState();
    176         }
    177 
    178         @Override
    179         public void onDrawerSlide(View drawerView, float slideOffset) {
    180             mToggle.onDrawerSlide(drawerView, slideOffset);
    181         }
    182 
    183         @Override
    184         public void onDrawerOpened(View drawerView) {
    185             mToggle.onDrawerOpened(drawerView);
    186             Metrics.logDrawerOpened(mToolbar.getContext(), mTrigger);
    187         }
    188 
    189         @Override
    190         public void onDrawerClosed(View drawerView) {
    191             mToggle.onDrawerClosed(drawerView);
    192             mTrigger = OPENED_OTHER;
    193         }
    194 
    195         @Override
    196         public void onDrawerStateChanged(int newState) {
    197             mToggle.onDrawerStateChanged(newState);
    198             if (newState == DrawerLayout.STATE_DRAGGING) {
    199                 mTrigger = OPENED_SWIPE;
    200             }
    201         }
    202     }
    203 
    204     /*
    205      * Dummy controller useful with clients that don't host a real drawer.
    206      */
    207     private static final class DummyDrawerController extends DrawerController {
    208 
    209         @Override
    210         void setOpen(boolean open) {}
    211 
    212         @Override
    213         void setOpen(boolean open, @Trigger int trigger) {}
    214 
    215         @Override
    216         boolean isOpen() {
    217             return false;
    218         }
    219 
    220         @Override
    221         boolean isPresent() {
    222             return false;
    223         }
    224 
    225         @Override
    226         void setTitle(String title) {}
    227 
    228         @Override
    229         void update() {}
    230 
    231         @Override
    232         public void onDrawerSlide(View drawerView, float slideOffset) {}
    233 
    234         @Override
    235         public void onDrawerOpened(View drawerView) {}
    236 
    237         @Override
    238         public void onDrawerClosed(View drawerView) {}
    239 
    240         @Override
    241         public void onDrawerStateChanged(int newState) {}
    242     }
    243 }
    244