/* * 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.SharedMinimal.DEBUG; import android.app.Activity; import android.util.Log; import android.view.Gravity; import android.view.View; import androidx.annotation.ColorRes; import androidx.appcompat.widget.Toolbar; import androidx.drawerlayout.widget.DrawerLayout; import androidx.drawerlayout.widget.DrawerLayout.DrawerListener; import androidx.legacy.app.ActionBarDrawerToggle; import com.android.documentsui.base.Display; import com.android.documentsui.base.Providers; /** * 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"; public abstract void update(); public abstract void setOpen(boolean open); public abstract void setLocked(boolean locked); public abstract boolean isPresent(); public abstract boolean isOpen(); abstract void setTitle(String title); /** * Returns a controller suitable for {@code Layout}. */ public static DrawerController create(BaseActivity activity, ActivityConfig activityConfig) { DrawerLayout layout = (DrawerLayout) activity.findViewById(R.id.drawer_layout); if (layout == null) { return new StubDrawerController(); } 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, activity); } /** * Returns a controller suitable for {@code Layout}. */ static DrawerController createStub() { return new StubDrawerController(); } 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 static final int SPRING_TIMEOUT = 750; private final ActionBarDrawerToggle mToggle; private DrawerLayout mLayout; private View mDrawer; private Toolbar mToolbar; private AbstractActionHandler.CommonAddons mCommonAddons; public RuntimeDrawerController( DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle, Toolbar drawerToolbar, ActivityConfig activityConfig, AbstractActionHandler.CommonAddons commonAddons) { mToolbar = drawerToolbar; assert(layout != null); mLayout = layout; mDrawer = drawer; mToggle = toggle; mCommonAddons = commonAddons; mLayout.setDrawerListener(this); if (activityConfig.dragAndDropEnabled()) { View edge = layout.findViewById(R.id.drawer_edge); edge.setOnDragListener(new ItemDragListener<>(this, SPRING_TIMEOUT)); } } @Override public void runOnUiThread(Runnable runnable) { mDrawer.post(runnable); } @Override public void setDropTargetHighlight(View v, boolean highlight) { assert (v.getId() == R.id.drawer_edge); @ColorRes int id = highlight ? R.color.secondary : android.R.color.transparent; v.setBackgroundColor(id); } @Override public void onDragEntered(View v) { // do nothing; let drawer only open for onViewHovered } @Override public void onDragExited(View v) { // do nothing } @Override public void onViewHovered(View v) { assert (v.getId() == R.id.drawer_edge); setOpen(true); } @Override public void onDragEnded() { // do nothing } @Override public void setOpen(boolean open) { View list = mDrawer.findViewById(R.id.roots_list); if (open) { mLayout.openDrawer(mDrawer); if (list != null) { mDrawer.requestFocus(); } } else { mLayout.closeDrawer(mDrawer); if (list != null) { mDrawer.clearFocus(); } } } @Override public void setLocked(boolean locked) { if (locked) { mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); } else { mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); } } @Override public boolean isOpen() { return mLayout.isDrawerOpen(mDrawer); } @Override public boolean isPresent() { return DrawerLayout.LOCK_MODE_UNLOCKED == mLayout.getDrawerLockMode(Gravity.START); } @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); // Update the information for Storage's root DocumentsApplication.getProvidersCache(drawerView.getContext()).updateAuthorityAsync( mCommonAddons.getSelectedUser(), Providers.AUTHORITY_STORAGE); } @Override public void onDrawerClosed(View drawerView) { mToggle.onDrawerClosed(drawerView); } @Override public void onDrawerStateChanged(int newState) { mToggle.onDrawerStateChanged(newState); } } /* * Stub controller useful with clients that don't host a real drawer. */ private static final class StubDrawerController extends DrawerController { @Override public void setOpen(boolean open) {} @Override public void setLocked(boolean locked) {} @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) {} } }