• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.clock;
17 
18 import android.app.Activity;
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.os.Bundle;
22 import android.util.Log;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.widget.ImageView;
27 import android.widget.Toast;
28 
29 import androidx.annotation.NonNull;
30 import androidx.annotation.Nullable;
31 import androidx.core.widget.ContentLoadingProgressBar;
32 import androidx.recyclerview.widget.RecyclerView;
33 
34 import com.android.customization.model.CustomizationManager.Callback;
35 import com.android.customization.model.CustomizationManager.OptionsFetchedListener;
36 import com.android.customization.model.clock.BaseClockManager;
37 import com.android.customization.model.clock.Clockface;
38 import com.android.customization.module.ThemesUserEventLogger;
39 import com.android.customization.picker.BasePreviewAdapter;
40 import com.android.customization.picker.BasePreviewAdapter.PreviewPage;
41 import com.android.customization.widget.OptionSelectorController;
42 import com.android.wallpaper.R;
43 import com.android.wallpaper.asset.Asset;
44 import com.android.wallpaper.module.InjectorProvider;
45 import com.android.wallpaper.picker.AppbarFragment;
46 import com.android.wallpaper.widget.PreviewPager;
47 
48 import java.util.List;
49 
50 /**
51  * Fragment that contains the main UI for selecting and applying a Clockface.
52  */
53 public class ClockFragment extends AppbarFragment {
54 
55     private static final String TAG = "ClockFragment";
56 
57     /**
58      * Interface to be implemented by an Activity hosting a {@link ClockFragment}
59      */
60     public interface ClockFragmentHost {
getClockManager()61         BaseClockManager getClockManager();
62     }
63 
newInstance(CharSequence title)64     public static ClockFragment newInstance(CharSequence title) {
65         ClockFragment fragment = new ClockFragment();
66         fragment.setArguments(AppbarFragment.createArguments(title));
67         return fragment;
68     }
69 
70     private RecyclerView mOptionsContainer;
71     private OptionSelectorController<Clockface> mOptionsController;
72     private Clockface mSelectedOption;
73     private BaseClockManager mClockManager;
74     private PreviewPager mPreviewPager;
75     private ContentLoadingProgressBar mLoading;
76     private View mContent;
77     private View mError;
78     private ThemesUserEventLogger mEventLogger;
79 
80     @Override
onAttach(Context context)81     public void onAttach(Context context) {
82         super.onAttach(context);
83         mClockManager = ((ClockFragmentHost) context).getClockManager();
84         mEventLogger = (ThemesUserEventLogger)
85                 InjectorProvider.getInjector().getUserEventLogger(context);
86     }
87 
88     @Nullable
89     @Override
onCreateView(@onNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)90     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
91             @Nullable Bundle savedInstanceState) {
92         View view = inflater.inflate(
93                 R.layout.fragment_clock_picker, container, /* attachToRoot */ false);
94         setUpToolbar(view);
95         mContent = view.findViewById(R.id.content_section);
96         mPreviewPager = view.findViewById(R.id.clock_preview_pager);
97         mOptionsContainer = view.findViewById(R.id.options_container);
98         mLoading = view.findViewById(R.id.loading_indicator);
99         mError = view.findViewById(R.id.error_section);
100         setUpOptions();
101         view.findViewById(R.id.apply_button).setOnClickListener(v -> {
102             mClockManager.apply(mSelectedOption, new Callback() {
103                 @Override
104                 public void onSuccess() {
105                     mOptionsController.setAppliedOption(mSelectedOption);
106                     Toast.makeText(getContext(), R.string.applied_clock_msg,
107                             Toast.LENGTH_SHORT).show();
108                 }
109 
110                 @Override
111                 public void onError(@Nullable Throwable throwable) {
112                     if (throwable != null) {
113                         Log.e(TAG, "Error loading clockfaces", throwable);
114                     }
115                     //TODO(santie): handle
116                 }
117             });
118 
119         });
120         return view;
121     }
122 
createAdapter()123     private void createAdapter() {
124         mPreviewPager.setAdapter(new ClockPreviewAdapter(getActivity(), mSelectedOption));
125     }
126 
setUpOptions()127     private void setUpOptions() {
128         hideError();
129         mLoading.show();
130         mClockManager.fetchOptions(new OptionsFetchedListener<Clockface>() {
131            @Override
132            public void onOptionsLoaded(List<Clockface> options) {
133                mLoading.hide();
134                mOptionsController = new OptionSelectorController<>(mOptionsContainer, options);
135 
136                mOptionsController.addListener(selected -> {
137                    mSelectedOption = (Clockface) selected;
138                    mEventLogger.logClockSelected(mSelectedOption);
139                    createAdapter();
140                });
141                mOptionsController.initOptions(mClockManager);
142                for (Clockface option : options) {
143                    if (option.isActive(mClockManager)) {
144                        mSelectedOption = option;
145                    }
146                }
147                // For development only, as there should always be a grid set.
148                if (mSelectedOption == null) {
149                    mSelectedOption = options.get(0);
150                }
151                createAdapter();
152            }
153            @Override
154             public void onError(@Nullable Throwable throwable) {
155                 if (throwable != null) {
156                    Log.e(TAG, "Error loading clockfaces", throwable);
157                 }
158                 showError();
159             }
160        }, false);
161     }
162 
hideError()163     private void hideError() {
164         mContent.setVisibility(View.VISIBLE);
165         mError.setVisibility(View.GONE);
166     }
167 
showError()168     private void showError() {
169         mLoading.hide();
170         mContent.setVisibility(View.GONE);
171         mError.setVisibility(View.VISIBLE);
172     }
173 
174     private static class ClockfacePreviewPage extends PreviewPage {
175 
176         private final Asset mPreviewAsset;
177 
ClockfacePreviewPage(String title, Activity activity, Asset previewAsset)178         public ClockfacePreviewPage(String title, Activity activity, Asset previewAsset) {
179             super(title, activity);
180             mPreviewAsset = previewAsset;
181         }
182 
183         @Override
bindPreviewContent()184         public void bindPreviewContent() {
185             ImageView previewImage = card.findViewById(R.id.clock_preview_image);
186             Context context = previewImage.getContext();
187             Resources res = previewImage.getResources();
188             mPreviewAsset.loadDrawableWithTransition(context, previewImage,
189                     100 /* transitionDurationMillis */,
190                     null /* drawableLoadedListener */,
191                     res.getColor(android.R.color.transparent, null) /* placeholderColor */);
192             card.setContentDescription(card.getResources().getString(
193                     R.string.clock_preview_content_description, title));
194         }
195     }
196 
197     /**
198      * Adapter class for mPreviewPager.
199      * This is a ViewPager as it allows for a nice pagination effect (ie, pages snap on swipe,
200      * we don't want to just scroll)
201      */
202     private static class ClockPreviewAdapter extends BasePreviewAdapter<ClockfacePreviewPage> {
ClockPreviewAdapter(Activity activity, Clockface clockface)203         ClockPreviewAdapter(Activity activity, Clockface clockface) {
204             super(activity, R.layout.clock_preview_card);
205             addPage(new ClockfacePreviewPage(
206                     clockface.getTitle(), activity , clockface.getPreviewAsset()));
207         }
208     }
209 }
210