• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.customization.picker.grid;
17 
18 import static android.app.Activity.RESULT_OK;
19 
20 import static com.android.customization.picker.ViewOnlyFullPreviewActivity.SECTION_GRID;
21 import static com.android.customization.picker.grid.GridFullPreviewFragment.EXTRA_GRID_OPTION;
22 import static com.android.customization.picker.grid.GridFullPreviewFragment.EXTRA_WALLPAPER_INFO;
23 import static com.android.wallpaper.widget.BottomActionBar.BottomAction.APPLY;
24 
25 import android.content.Context;
26 import android.content.Intent;
27 import android.os.Bundle;
28 import android.util.Log;
29 import android.view.LayoutInflater;
30 import android.view.SurfaceView;
31 import android.view.View;
32 import android.view.ViewGroup;
33 import android.widget.Toast;
34 
35 import androidx.annotation.NonNull;
36 import androidx.annotation.Nullable;
37 import androidx.core.widget.ContentLoadingProgressBar;
38 import androidx.recyclerview.widget.RecyclerView;
39 
40 import com.android.customization.model.CustomizationManager.Callback;
41 import com.android.customization.model.CustomizationManager.OptionsFetchedListener;
42 import com.android.customization.model.CustomizationOption;
43 import com.android.customization.model.grid.GridOption;
44 import com.android.customization.model.grid.GridOptionsManager;
45 import com.android.customization.module.ThemesUserEventLogger;
46 import com.android.customization.picker.ViewOnlyFullPreviewActivity;
47 import com.android.customization.picker.WallpaperPreviewer;
48 import com.android.customization.widget.OptionSelectorController;
49 import com.android.wallpaper.R;
50 import com.android.wallpaper.model.WallpaperInfo;
51 import com.android.wallpaper.module.CurrentWallpaperInfoFactory;
52 import com.android.wallpaper.module.InjectorProvider;
53 import com.android.wallpaper.picker.AppbarFragment;
54 import com.android.wallpaper.widget.BottomActionBar;
55 
56 import com.bumptech.glide.Glide;
57 
58 import java.util.List;
59 
60 /**
61  * Fragment that contains the UI for selecting and applying a GridOption.
62  */
63 public class GridFragment extends AppbarFragment {
64 
65     private static final int FULL_PREVIEW_REQUEST_CODE = 1000;
66     private static final String KEY_STATE_SELECTED_OPTION = "GridFragment.selectedOption";
67     private static final String KEY_STATE_BOTTOM_ACTION_BAR_VISIBLE =
68             "GridFragment.bottomActionBarVisible";
69 
70     private static final String TAG = "GridFragment";
71 
72     /**
73      * Interface to be implemented by an Activity hosting a {@link GridFragment}
74      */
75     public interface GridFragmentHost {
getGridOptionsManager()76         GridOptionsManager getGridOptionsManager();
77     }
78 
newInstance(CharSequence title)79     public static GridFragment newInstance(CharSequence title) {
80         GridFragment fragment = new GridFragment();
81         fragment.setArguments(AppbarFragment.createArguments(title));
82         return fragment;
83     }
84 
85     private WallpaperInfo mHomeWallpaper;
86     private RecyclerView mOptionsContainer;
87     private OptionSelectorController<GridOption> mOptionsController;
88     private GridOptionsManager mGridManager;
89     private GridOption mSelectedOption;
90     private ContentLoadingProgressBar mLoading;
91     private View mContent;
92     private View mError;
93     private BottomActionBar mBottomActionBar;
94     private ThemesUserEventLogger mEventLogger;
95 
96     private GridOptionPreviewer mGridOptionPreviewer;
97 
98     private final Callback mApplyGridCallback = new Callback() {
99         @Override
100         public void onSuccess() {
101             Toast.makeText(getContext(), R.string.applied_grid_msg, Toast.LENGTH_SHORT).show();
102             getActivity().overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
103             getActivity().finish();
104         }
105 
106         @Override
107         public void onError(@Nullable Throwable throwable) {
108             // Since we disabled it when clicked apply button.
109             mBottomActionBar.enableActions();
110             mBottomActionBar.hide();
111             //TODO(chihhangchuang): handle
112         }
113     };
114 
115     @Override
onAttach(Context context)116     public void onAttach(Context context) {
117         super.onAttach(context);
118         mGridManager = ((GridFragmentHost) context).getGridOptionsManager();
119         mEventLogger = (ThemesUserEventLogger)
120                 InjectorProvider.getInjector().getUserEventLogger(context);
121     }
122 
123     @Nullable
124     @Override
onCreateView(@onNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)125     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
126             @Nullable Bundle savedInstanceState) {
127         View view = inflater.inflate(
128                 R.layout.fragment_grid_picker, container, /* attachToRoot */ false);
129         setUpToolbar(view);
130         mContent = view.findViewById(R.id.content_section);
131         mOptionsContainer = view.findViewById(R.id.options_container);
132         mLoading = view.findViewById(R.id.loading_indicator);
133         mError = view.findViewById(R.id.error_section);
134 
135         // Clear memory cache whenever grid fragment view is being loaded.
136         Glide.get(getContext()).clearMemory();
137         setUpOptions(savedInstanceState);
138 
139         SurfaceView wallpaperSurface = view.findViewById(R.id.wallpaper_preview_surface);
140         WallpaperPreviewer wallpaperPreviewer = new WallpaperPreviewer(getLifecycle(),
141                 getActivity(), view.findViewById(R.id.wallpaper_preview_image), wallpaperSurface);
142         // Loads current Wallpaper.
143         CurrentWallpaperInfoFactory factory = InjectorProvider.getInjector()
144                 .getCurrentWallpaperFactory(getContext().getApplicationContext());
145         factory.createCurrentWallpaperInfos((homeWallpaper, lockWallpaper, presentationMode) -> {
146             mHomeWallpaper = homeWallpaper;
147             wallpaperPreviewer.setWallpaper(mHomeWallpaper, /* listener= */ null);
148         }, false);
149 
150         mGridOptionPreviewer = new GridOptionPreviewer(mGridManager,
151                 view.findViewById(R.id.grid_preview_container));
152 
153         view.findViewById(R.id.grid_preview_card).setOnClickListener(v -> showFullPreview());
154         return view;
155     }
156 
157     @Override
onDestroy()158     public void onDestroy() {
159         super.onDestroy();
160         if (mGridOptionPreviewer != null) {
161             mGridOptionPreviewer.release();
162         }
163     }
164 
165     @Override
onSaveInstanceState(@onNull Bundle outState)166     public void onSaveInstanceState(@NonNull Bundle outState) {
167         super.onSaveInstanceState(outState);
168         if (mSelectedOption != null) {
169             outState.putParcelable(KEY_STATE_SELECTED_OPTION, mSelectedOption);
170         }
171         if (mBottomActionBar != null) {
172             outState.putBoolean(KEY_STATE_BOTTOM_ACTION_BAR_VISIBLE, mBottomActionBar.isVisible());
173         }
174     }
175 
176     @Override
onActivityResult(int requestCode, int resultCode, @Nullable Intent data)177     public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
178         super.onActivityResult(requestCode, resultCode, data);
179         if (requestCode == FULL_PREVIEW_REQUEST_CODE && resultCode == RESULT_OK) {
180             applyGridOption(data.getParcelableExtra(EXTRA_GRID_OPTION));
181         }
182     }
183 
184 
185     @Override
onBottomActionBarReady(BottomActionBar bottomActionBar)186     protected void onBottomActionBarReady(BottomActionBar bottomActionBar) {
187         mBottomActionBar = bottomActionBar;
188         mBottomActionBar.showActionsOnly(APPLY);
189         mBottomActionBar.setActionClickListener(APPLY, unused -> applyGridOption(mSelectedOption));
190     }
191 
applyGridOption(GridOption gridOption)192     private void applyGridOption(GridOption gridOption) {
193         mBottomActionBar.disableActions();
194         mGridManager.apply(gridOption, mApplyGridCallback);
195     }
196 
setUpOptions(@ullable Bundle savedInstanceState)197     private void setUpOptions(@Nullable Bundle savedInstanceState) {
198         hideError();
199         mLoading.show();
200         mGridManager.fetchOptions(new OptionsFetchedListener<GridOption>() {
201             @Override
202             public void onOptionsLoaded(List<GridOption> options) {
203                 mLoading.hide();
204                 mOptionsController = new OptionSelectorController<>(mOptionsContainer, options);
205                 mOptionsController.initOptions(mGridManager);
206 
207                 // Find the selected Grid option.
208                 GridOption previouslySelectedOption = null;
209                 if (savedInstanceState != null) {
210                     previouslySelectedOption = findEquivalent(
211                             options, savedInstanceState.getParcelable(KEY_STATE_SELECTED_OPTION));
212                 }
213                 mSelectedOption = previouslySelectedOption != null
214                         ? previouslySelectedOption
215                         : getActiveOption(options);
216 
217                 mOptionsController.setSelectedOption(mSelectedOption);
218                 onOptionSelected(mSelectedOption);
219                 restoreBottomActionBarVisibility(savedInstanceState);
220 
221                 mOptionsController.addListener(selectedOption -> {
222                     onOptionSelected(selectedOption);
223                     mBottomActionBar.show();
224                 });
225             }
226 
227             @Override
228             public void onError(@Nullable Throwable throwable) {
229                 if (throwable != null) {
230                     Log.e(TAG, "Error loading grid options", throwable);
231                 }
232                 showError();
233             }
234         }, false);
235     }
236 
getActiveOption(List<GridOption> options)237     private GridOption getActiveOption(List<GridOption> options) {
238         return options.stream()
239                 .filter(option -> option.isActive(mGridManager))
240                 .findAny()
241                 // For development only, as there should always be a grid set.
242                 .orElse(options.get(0));
243     }
244 
245     @Nullable
findEquivalent(List<GridOption> options, GridOption target)246     private GridOption findEquivalent(List<GridOption> options, GridOption target) {
247         return options.stream()
248                 .filter(option -> option.equals(target))
249                 .findAny()
250                 .orElse(null);
251     }
252 
hideError()253     private void hideError() {
254         mContent.setVisibility(View.VISIBLE);
255         mError.setVisibility(View.GONE);
256     }
257 
showError()258     private void showError() {
259         mLoading.hide();
260         mContent.setVisibility(View.GONE);
261         mError.setVisibility(View.VISIBLE);
262     }
263 
onOptionSelected(CustomizationOption selectedOption)264     private void onOptionSelected(CustomizationOption selectedOption) {
265         mSelectedOption = (GridOption) selectedOption;
266         mEventLogger.logGridSelected(mSelectedOption);
267         mGridOptionPreviewer.setGridOption(mSelectedOption);
268     }
269 
restoreBottomActionBarVisibility(@ullable Bundle savedInstanceState)270     private void restoreBottomActionBarVisibility(@Nullable Bundle savedInstanceState) {
271         boolean isBottomActionBarVisible = savedInstanceState != null
272                 && savedInstanceState.getBoolean(KEY_STATE_BOTTOM_ACTION_BAR_VISIBLE);
273         if (isBottomActionBarVisible) {
274             mBottomActionBar.show();
275         } else {
276             mBottomActionBar.hide();
277         }
278     }
279 
showFullPreview()280     private void showFullPreview() {
281         Bundle bundle = new Bundle();
282         bundle.putParcelable(EXTRA_WALLPAPER_INFO, mHomeWallpaper);
283         bundle.putParcelable(EXTRA_GRID_OPTION, mSelectedOption);
284         Intent intent = ViewOnlyFullPreviewActivity.newIntent(getContext(), SECTION_GRID, bundle);
285         startActivityForResult(intent, FULL_PREVIEW_REQUEST_CODE);
286     }
287 }
288