1 /* 2 * Copyright (C) 2016 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.VERBOSE; 20 21 import android.app.Activity; 22 import android.content.res.Resources; 23 import android.graphics.Outline; 24 import android.graphics.drawable.Drawable; 25 import android.util.Log; 26 import android.view.View; 27 import android.view.ViewOutlineProvider; 28 29 import androidx.annotation.Nullable; 30 import androidx.appcompat.widget.Toolbar; 31 32 import com.android.documentsui.R; 33 import com.android.documentsui.base.RootInfo; 34 import com.android.documentsui.base.State; 35 import com.android.documentsui.dirlist.AnimationView; 36 37 import com.google.android.material.appbar.AppBarLayout; 38 import com.google.android.material.appbar.CollapsingToolbarLayout; 39 40 import java.util.function.IntConsumer; 41 42 /** 43 * A facade over the portions of the app and drawer toolbars. 44 */ 45 public class NavigationViewManager { 46 47 private static final String TAG = "NavigationViewManager"; 48 49 private final DrawerController mDrawer; 50 private final Toolbar mToolbar; 51 private final State mState; 52 private final NavigationViewManager.Environment mEnv; 53 private final Breadcrumb mBreadcrumb; 54 private final View mSearchBarView; 55 private final CollapsingToolbarLayout mCollapsingBarLayout; 56 private final Drawable mDefaultActionBarBackground; 57 private final ViewOutlineProvider mSearchBarOutlineProvider; 58 private final boolean mShowSearchBar; 59 NavigationViewManager( Activity activity, DrawerController drawer, State state, NavigationViewManager.Environment env, Breadcrumb breadcrumb)60 public NavigationViewManager( 61 Activity activity, 62 DrawerController drawer, 63 State state, 64 NavigationViewManager.Environment env, 65 Breadcrumb breadcrumb) { 66 67 mToolbar = activity.findViewById(R.id.toolbar); 68 mDrawer = drawer; 69 mState = state; 70 mEnv = env; 71 mBreadcrumb = breadcrumb; 72 mBreadcrumb.setup(env, state, this::onNavigationItemSelected); 73 74 mToolbar.setNavigationOnClickListener( 75 new View.OnClickListener() { 76 @Override 77 public void onClick(View v) { 78 onNavigationIconClicked(); 79 } 80 }); 81 mSearchBarView = activity.findViewById(R.id.searchbar_title); 82 mCollapsingBarLayout = activity.findViewById(R.id.collapsing_toolbar); 83 mDefaultActionBarBackground = mToolbar.getBackground(); 84 mShowSearchBar = activity.getResources().getBoolean(R.bool.show_search_bar); 85 86 final Resources resources = mToolbar.getResources(); 87 final int radius = resources.getDimensionPixelSize(R.dimen.search_bar_radius); 88 final int marginStart = 89 resources.getDimensionPixelSize(R.dimen.search_bar_background_margin_start); 90 final int marginEnd = 91 resources.getDimensionPixelSize(R.dimen.search_bar_background_margin_end); 92 mSearchBarOutlineProvider = new ViewOutlineProvider() { 93 @Override 94 public void getOutline(View view, Outline outline) { 95 outline.setRoundRect(marginStart, 0, 96 view.getWidth() - marginEnd, view.getHeight(), radius); 97 } 98 }; 99 } 100 setSearchBarClickListener(View.OnClickListener listener)101 public void setSearchBarClickListener(View.OnClickListener listener) { 102 mSearchBarView.setOnClickListener(listener); 103 } 104 onNavigationIconClicked()105 private void onNavigationIconClicked() { 106 if (mDrawer.isPresent()) { 107 mDrawer.setOpen(true); 108 } 109 } 110 onNavigationItemSelected(int position)111 void onNavigationItemSelected(int position) { 112 boolean changed = false; 113 while (mState.stack.size() > position + 1) { 114 changed = true; 115 mState.stack.pop(); 116 } 117 if (changed) { 118 mEnv.refreshCurrentRootAndDirectory(AnimationView.ANIM_LEAVE); 119 } 120 } 121 update()122 public void update() { 123 updateScrollFlag(); 124 updateToolbar(); 125 126 // TODO: Looks to me like this block is never getting hit. 127 if (mEnv.isSearchExpanded()) { 128 mToolbar.setTitle(null); 129 mBreadcrumb.show(false); 130 return; 131 } 132 133 mDrawer.setTitle(mEnv.getDrawerTitle()); 134 135 mToolbar.setNavigationIcon(getActionBarIcon()); 136 mToolbar.setNavigationContentDescription(R.string.drawer_open); 137 138 if (shouldShowSearchBar()) { 139 mBreadcrumb.show(false); 140 mToolbar.setTitle(null); 141 mSearchBarView.setVisibility(View.VISIBLE); 142 } else if (mState.stack.size() <= 1) { 143 mBreadcrumb.show(false); 144 mSearchBarView.setVisibility(View.GONE); 145 String title = mEnv.getCurrentRoot().title; 146 if (VERBOSE) Log.v(TAG, "New toolbar title is: " + title); 147 mToolbar.setTitle(title); 148 } else { 149 mBreadcrumb.show(true); 150 mToolbar.setTitle(null); 151 mSearchBarView.setVisibility(View.GONE); 152 mBreadcrumb.postUpdate(); 153 } 154 } 155 updateScrollFlag()156 private void updateScrollFlag() { 157 if (mCollapsingBarLayout == null) { 158 return; 159 } 160 161 AppBarLayout.LayoutParams lp = 162 (AppBarLayout.LayoutParams) mCollapsingBarLayout.getLayoutParams(); 163 if (shouldShowSearchBar()) { 164 lp.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL 165 | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS 166 | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED); 167 } else { 168 lp.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL 169 | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED); 170 } 171 mCollapsingBarLayout.setLayoutParams(lp); 172 } 173 updateToolbar()174 private void updateToolbar() { 175 if (shouldShowSearchBar()) { 176 mToolbar.setBackgroundResource(R.drawable.search_bar_background); 177 mToolbar.setOutlineProvider(mSearchBarOutlineProvider); 178 } else { 179 mToolbar.setBackground(mDefaultActionBarBackground); 180 mToolbar.setOutlineProvider(null); 181 } 182 183 if (mCollapsingBarLayout != null) { 184 View overlayBackground = 185 mCollapsingBarLayout.findViewById(R.id.toolbar_background_layout); 186 overlayBackground.setVisibility(shouldShowSearchBar() ? View.GONE : View.VISIBLE); 187 } 188 } 189 shouldShowSearchBar()190 private boolean shouldShowSearchBar() { 191 return mState.stack.isRecents() && !mEnv.isSearchExpanded() && mShowSearchBar; 192 } 193 194 // Hamburger if drawer is present, else sad nullness. getActionBarIcon()195 private @Nullable Drawable getActionBarIcon() { 196 if (mDrawer.isPresent()) { 197 return mToolbar.getContext().getDrawable(R.drawable.ic_hamburger); 198 } else { 199 return null; 200 } 201 } 202 revealRootsDrawer(boolean open)203 void revealRootsDrawer(boolean open) { 204 mDrawer.setOpen(open); 205 } 206 207 interface Breadcrumb { setup(Environment env, State state, IntConsumer listener)208 void setup(Environment env, State state, IntConsumer listener); show(boolean visibility)209 void show(boolean visibility); postUpdate()210 void postUpdate(); 211 } 212 213 interface Environment { 214 @Deprecated // Use CommonAddones#getCurrentRoot getCurrentRoot()215 RootInfo getCurrentRoot(); getDrawerTitle()216 String getDrawerTitle(); 217 @Deprecated // Use CommonAddones#refreshCurrentRootAndDirectory refreshCurrentRootAndDirectory(int animation)218 void refreshCurrentRootAndDirectory(int animation); isSearchExpanded()219 boolean isSearchExpanded(); 220 } 221 } 222