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