1 /*
2  * Copyright (C) 2018 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 package com.android.wallpaper.picker;
17 
18 import static android.view.View.GONE;
19 import static android.view.View.VISIBLE;
20 
21 import android.annotation.MenuRes;
22 import android.app.Activity;
23 import android.content.Context;
24 import android.graphics.drawable.Drawable;
25 import android.os.Bundle;
26 import android.text.TextUtils;
27 import android.view.MenuItem;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.view.Window;
31 import android.widget.TextView;
32 import android.widget.Toolbar;
33 import android.widget.Toolbar.OnMenuItemClickListener;
34 
35 import androidx.annotation.Nullable;
36 import androidx.core.view.WindowCompat;
37 import androidx.core.view.WindowInsetsControllerCompat;
38 
39 import com.android.wallpaper.R;
40 import com.android.wallpaper.config.BaseFlags;
41 import com.android.wallpaper.util.ResourceUtils;
42 import com.android.wallpaper.widget.BottomActionBar;
43 
44 import com.google.android.material.transition.MaterialSharedAxis;
45 
46 /**
47  * Base class for Fragments that own a {@link Toolbar} widget and a {@link BottomActionBar}.
48  *
49  * A Fragment extending this class is expected to have a {@link Toolbar} in its root view, with id
50  * {@link R.id#toolbar}, which can optionally have a TextView with id custom_toolbar_title for
51  * the title.
52  * If the Bundle returned by {@link #createArguments(CharSequence)} is used as Arguments for this
53  * Fragment, the title provided to that method will be used as the Fragment's toolbar title,
54  * otherwise, the value returned by {@link #getDefaultTitle()} (default being {@code null}) will be
55  * used as title.
56  *
57  * @see #setArguments(Bundle)
58  * @see BottomActionBarFragment
59  */
60 public abstract class AppbarFragment extends BottomActionBarFragment
61         implements OnMenuItemClickListener {
62 
63     private static final String ARG_TITLE = "ToolbarFragment.title";
64     private AppbarFragmentHost mHost;
65     private boolean mUpArrowEnabled;
66 
67     /**
68      * Interface to be implemented by an Activity hosting a {@link AppbarFragment}.
69      */
70     public interface AppbarFragmentHost {
71         /**
72          * Called when a up arrow had been pressed.
73          */
onUpArrowPressed()74         void onUpArrowPressed();
75 
76         /**
77          * Check if it supports up arrow.
78          */
isUpArrowSupported()79         boolean isUpArrowSupported();
80     }
81 
82     @Override
onCreate(@ullable Bundle savedInstanceState)83     public void onCreate(@Nullable Bundle savedInstanceState) {
84         super.onCreate(savedInstanceState);
85         if (BaseFlags.get().isPageTransitionsFeatureEnabled(requireContext())) {
86             setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.X, /* forward */ true));
87             setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.X, /* forward */ false));
88             setExitTransition(new MaterialSharedAxis(MaterialSharedAxis.X, /* forward */ true));
89             setReenterTransition(new MaterialSharedAxis(MaterialSharedAxis.X, /* forward */ false));
90         }
91     }
92 
93     @Override
onAttach(Context context)94     public void onAttach(Context context) {
95         super.onAttach(context);
96         mHost = (AppbarFragmentHost) context;
97     }
98 
99     /**
100      * Returns a newly created {@link Bundle} containing the given title as an argument.
101      * If set as a ToolbarFragment's arguments bundle, this will be used to set up the title of
102      * the Toolbar in {@link #setUpToolbar(View)}
103      */
createArguments(CharSequence title)104     protected static Bundle createArguments(CharSequence title) {
105         Bundle args = new Bundle();
106         args.putCharSequence(ARG_TITLE, title);
107         return args;
108     }
109 
110     protected Toolbar mToolbar;
111     private TextView mTitleView;
112 
113     /**
114      * Configures a toolbar in the given rootView, with id {@code toolbar} and sets its title to
115      * the value in Arguments or {@link #getDefaultTitle()}.
116      * Default upArrow value is true.
117      */
setUpToolbar(View rootView)118     public void setUpToolbar(View rootView) {
119         setUpToolbar(rootView, /* upArrow= */ true, false);
120     }
121 
122     /**
123      * Configures a toolbar in the given rootView, inflating the menu corresponding to the given id
124      * for the toolbar menu.
125      *
126      * @param rootView given root view.
127      * @param upArrow  true to enable up arrow feature.
128      * @param transparentToolbar whether the toolbar should be transparent
129      */
setUpToolbar(View rootView, boolean upArrow, boolean transparentToolbar)130     protected void setUpToolbar(View rootView, boolean upArrow, boolean transparentToolbar) {
131         mUpArrowEnabled = upArrow;
132         mToolbar = rootView.findViewById(getToolbarId());
133 
134         mTitleView = mToolbar.findViewById(R.id.custom_toolbar_title);
135 
136         if (transparentToolbar) {
137             setToolbarColor(android.R.color.transparent);
138         }
139         setUpStatusBar(isStatusBarLightText());
140 
141         CharSequence title;
142         if (getArguments() != null) {
143             title = getArguments().getCharSequence(ARG_TITLE, getDefaultTitle());
144         } else {
145             title = getDefaultTitle();
146         }
147         if (!TextUtils.isEmpty(title)) {
148             setTitle(title);
149         }
150 
151         if (upArrow && mHost.isUpArrowSupported()) {
152             setUpUpArrow();
153         }
154     }
155 
156     /**
157      * Configures the menu in the toolbar.
158      *
159      * @param menuResId the resource id of the menu
160      */
setUpToolbarMenu(@enuRes int menuResId)161     public void setUpToolbarMenu(@MenuRes int menuResId) {
162         mToolbar.inflateMenu(menuResId);
163         mToolbar.setOnMenuItemClickListener(this);
164     }
165 
setUpToolbarMenuClickListener(int menuItemResId, View.OnClickListener listener)166     protected void setUpToolbarMenuClickListener(int menuItemResId, View.OnClickListener listener) {
167         MenuItem menuItem = mToolbar.getMenu().findItem(menuItemResId);
168         menuItem.getActionView().setOnClickListener(listener);
169     }
170 
getToolbarId()171     protected int getToolbarId() {
172         return R.id.toolbar;
173     }
174 
setUpStatusBar(boolean shouldUseLightText)175     protected void setUpStatusBar(boolean shouldUseLightText) {
176         Activity activity = getActivity();
177         if (activity == null) {
178             return;
179         }
180         Window window = activity.getWindow();
181         WindowInsetsControllerCompat windowInsetsController =
182                 WindowCompat.getInsetsController(window, window.getDecorView());
183         windowInsetsController.setAppearanceLightStatusBars(!shouldUseLightText);
184     }
185 
isStatusBarLightText()186     protected boolean isStatusBarLightText() {
187         return getResources().getBoolean(R.bool.isFragmentStatusBarLightText);
188     }
189 
getToolbarTextColor()190     protected int getToolbarTextColor() {
191         return ResourceUtils.getColorAttr(getActivity(), android.R.attr.textColorPrimary);
192     }
193 
194     /**
195      * Set up arrow feature status to enabled or not. Enable it for updating
196      * onBottomActionBarReady() while initializing without toolbar setup.
197      *
198      * @param upArrow true to enable up arrow feature.
199      */
setUpArrowEnabled(boolean upArrow)200     public void setUpArrowEnabled(boolean upArrow) {
201         mUpArrowEnabled = upArrow;
202     }
203 
setUpUpArrow()204     private void setUpUpArrow() {
205         Drawable backIcon = getResources().getDrawable(R.drawable.material_ic_arrow_back_black_24,
206                 null).mutate();
207         backIcon.setAutoMirrored(true);
208         backIcon.setTint(getToolbarTextColor());
209         mToolbar.setNavigationIcon(backIcon);
210         mToolbar.setNavigationContentDescription(R.string.bottom_action_bar_back);
211         mToolbar.setNavigationOnClickListener(v -> mHost.onUpArrowPressed());
212     }
213 
214     /**
215      * Configures a toolbar in the given rootView, inflating the menu corresponding to the given id
216      * for the toolbar menu.
217      * Override {@link #onMenuItemClick(MenuItem)} to listen to item click events.
218      * @see #setUpToolbar(View)
219      */
setUpToolbar(View rootView, @MenuRes int menuResId)220     public void setUpToolbar(View rootView, @MenuRes int menuResId) {
221         setUpToolbar(rootView);
222         setUpToolbarMenu(menuResId);
223     }
224 
setToolbarColor(int colorId)225     protected void setToolbarColor(int colorId) {
226         mToolbar.setBackgroundResource(colorId);
227         ((ViewGroup) mToolbar.getParent()).setBackgroundResource(colorId);
228     }
229 
230     /**
231      * Provides a title for this Fragment's toolbar to be used if none is found in
232      * {@link #getArguments()}.
233      * Default implementation returns {@code null}.
234      */
getDefaultTitle()235     public CharSequence getDefaultTitle() {
236         return null;
237     }
238 
getAccessibilityTitle()239     protected String getAccessibilityTitle() {
240         return null;
241     }
242 
setTitle(CharSequence title)243     protected void setTitle(CharSequence title) {
244         if (mToolbar == null) {
245             return;
246         }
247         if (mTitleView != null) {
248             mToolbar.setTitle(null);
249             mTitleView.setText(title);
250             mTitleView.setTextColor(getToolbarTextColor());
251         } else {
252             mToolbar.setTitle(title);
253             mToolbar.setTitleTextColor(getToolbarTextColor());
254         }
255 
256         // Set Activity title to make TalkBack announce title after updating toolbar title.
257         if (getActivity() != null) {
258             String accessibilityTitle = getAccessibilityTitle();
259             getActivity().setTitle(TextUtils.isEmpty(accessibilityTitle) ? title
260                     : accessibilityTitle);
261         }
262     }
263 
264     @Override
onBottomActionBarReady(BottomActionBar bottomActionBar)265     protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
266         bottomActionBar.setBackButtonVisibility(
267                 mUpArrowEnabled && mHost.isUpArrowSupported() ? GONE : VISIBLE);
268         super.onBottomActionBarReady(bottomActionBar);
269     }
270 
271     @Override
onMenuItemClick(MenuItem item)272     public boolean onMenuItemClick(MenuItem item) {
273         return false;
274     }
275 }
276