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