1 /*
2  * Copyright (C) 2014 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.tv.settings.connectivity;
18 
19 import android.app.Fragment;
20 import android.app.FragmentManager;
21 import android.app.FragmentTransaction;
22 import android.content.Context;
23 import android.os.Bundle;
24 import android.text.TextUtils;
25 import android.util.Log;
26 
27 import com.android.tv.settings.connectivity.setup.MessageWizardFragment;
28 import com.android.tv.settings.connectivity.setup.PasswordInputWizardFragment;
29 import com.android.tv.settings.connectivity.setup.SelectFromListWizardFragment;
30 import com.android.tv.settings.connectivity.setup.SelectFromListWizardFragment.ListItem;
31 import com.android.tv.settings.connectivity.setup.TextInputWizardFragment;
32 import com.android.tv.settings.form.FormPage;
33 import com.android.tv.settings.form.FormPageResultListener;
34 
35 import java.util.ArrayList;
36 
37 /**
38  * Displays form pages.
39  */
40 public class FormPageDisplayer
41         implements TextInputWizardFragment.Listener, SelectFromListWizardFragment.Listener,
42             PasswordInputWizardFragment.Listener {
43 
44     public static final int DISPLAY_TYPE_TEXT_INPUT = 1;
45     public static final int DISPLAY_TYPE_LIST_CHOICE = 2;
46     public static final int DISPLAY_TYPE_LOADING = 3;
47     // Minimum 8 characters
48     public static final int DISPLAY_TYPE_PSK_INPUT = 4;
49 
50     private static final int PSK_MIN_LENGTH = 8;
51 
52     public interface FormPageInfo {
53         /**
54          * @return the resource id of the title for this page.
55          */
getTitleResourceId()56         int getTitleResourceId();
57 
58         /**
59          * @return the resource id of the description for this page. 0 if no description.
60          */
getDescriptionResourceId()61         int getDescriptionResourceId();
62 
63         /**
64          * @return the input type for the editable text field for this page.
65          */
getInputType()66         int getInputType();
67 
68         /**
69          * @return the way this form page should be displayed.
70          */
getDisplayType()71         int getDisplayType();
72 
73         /**
74          * @return the default value for this input
75          */
getDefaultPrefillResourceId()76         int getDefaultPrefillResourceId();
77 
78         /**
79          * @return the set of choices for this form page.
80          */
getChoices(Context context, ArrayList<SelectFromListWizardFragment.ListItem> extraChoices)81         ArrayList<SelectFromListWizardFragment.ListItem> getChoices(Context context,
82                 ArrayList<SelectFromListWizardFragment.ListItem> extraChoices);
83     }
84 
85     public interface UserActivityListener {
onUserActivity()86         void onUserActivity();
87     }
88 
89     private static final String TAG = "FormPageDisplayer";
90     private static final boolean DEBUG = false;
91     private static final String RESULT_LIST_ITEM = "result_list_item";
92 
93     private final Context mContext;
94     private final FragmentManager mFragmentManager;
95     private TextInputWizardFragment.Listener mTextInputWizardFragmentListener;
96     private PasswordInputWizardFragment.Listener mPasswordInputWizardFragmentListener;
97     private SelectFromListWizardFragment.Listener mSelectFromListWizardFragmentListener;
98     private final int mContentViewId;
99 
FormPageDisplayer(Context context, FragmentManager fragmentManager, int contentViewId)100     public FormPageDisplayer(Context context, FragmentManager fragmentManager, int contentViewId) {
101         mContext = context;
102         mFragmentManager = fragmentManager;
103         mContentViewId = contentViewId;
104     }
105 
106     @Override
onTextInputComplete(String text)107     public boolean onTextInputComplete(String text) {
108         if (mTextInputWizardFragmentListener != null) {
109             return mTextInputWizardFragmentListener.onTextInputComplete(text);
110         }
111         return true;
112     }
113 
114     @Override
onPasswordInputComplete(String text, boolean obfuscate)115     public boolean onPasswordInputComplete(String text, boolean obfuscate) {
116         if (mPasswordInputWizardFragmentListener != null) {
117             return mPasswordInputWizardFragmentListener.onPasswordInputComplete(text, obfuscate);
118         }
119         return true;
120     }
121 
122     @Override
onListSelectionComplete(ListItem listItem)123     public void onListSelectionComplete(ListItem listItem) {
124         if (mSelectFromListWizardFragmentListener != null) {
125             mSelectFromListWizardFragmentListener.onListSelectionComplete(listItem);
126         }
127     }
128 
129     @Override
onListFocusChanged(ListItem listItem)130     public void onListFocusChanged(ListItem listItem) {
131         if (mSelectFromListWizardFragmentListener != null) {
132             mSelectFromListWizardFragmentListener.onListFocusChanged(listItem);
133         }
134     }
135 
displayPage(FormPageInfo formPageInfo, String titleArgument, String descriptionArgument, ArrayList<SelectFromListWizardFragment.ListItem> extraChoices, FormPage previousFormPage, UserActivityListener userActivityListener, boolean showProgress, FormPage currentFormPage, FormPageResultListener formPageResultListener, boolean forward, boolean emptyAllowed)136     public Fragment displayPage(FormPageInfo formPageInfo, String titleArgument,
137             String descriptionArgument,
138             ArrayList<SelectFromListWizardFragment.ListItem> extraChoices,
139             FormPage previousFormPage, UserActivityListener userActivityListener,
140             boolean showProgress, FormPage currentFormPage,
141             FormPageResultListener formPageResultListener, boolean forward, boolean emptyAllowed) {
142         if (DEBUG) {
143             Log.d(TAG, "Displaying: " + currentFormPage.getTitle());
144         }
145         switch (formPageInfo.getDisplayType()) {
146             case DISPLAY_TYPE_LIST_CHOICE:
147                 return displayList(formPageInfo, titleArgument, descriptionArgument, extraChoices,
148                         currentFormPage, formPageResultListener, previousFormPage,
149                         userActivityListener, forward);
150 
151             case DISPLAY_TYPE_TEXT_INPUT:
152                 return displayTextInput(formPageInfo, titleArgument, descriptionArgument,
153                         currentFormPage, formPageResultListener, previousFormPage, forward,
154                         emptyAllowed);
155 
156             case DISPLAY_TYPE_PSK_INPUT:
157                 return displayPskInput(formPageInfo, titleArgument, descriptionArgument,
158                         currentFormPage, formPageResultListener, previousFormPage, forward);
159 
160             case DISPLAY_TYPE_LOADING:
161                 return displayLoading(formPageInfo, titleArgument, showProgress, forward);
162 
163             default:
164                 return null;
165         }
166     }
167 
getListItem(FormPage formPage)168     public ListItem getListItem(FormPage formPage) {
169         return formPage.getData().getParcelable(RESULT_LIST_ITEM);
170     }
171 
displayFragment(Fragment fragment, boolean forward)172     public void displayFragment(Fragment fragment, boolean forward) {
173         FragmentTransaction transaction = mFragmentManager.beginTransaction();
174         if (forward) {
175             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
176         } else {
177             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
178         }
179         transaction.replace(mContentViewId, fragment).commit();
180     }
181 
displayList(final FormPageInfo formPageInfo, String titleArgument, String descriptionArgument, ArrayList<SelectFromListWizardFragment.ListItem> extraChoices, final FormPage formPage, final FormPageResultListener formPageResultListener, FormPage lastPage, final UserActivityListener userActivityListener, boolean forward)182     private Fragment displayList(final FormPageInfo formPageInfo, String titleArgument,
183             String descriptionArgument,
184             ArrayList<SelectFromListWizardFragment.ListItem> extraChoices, final FormPage formPage,
185             final FormPageResultListener formPageResultListener, FormPage lastPage,
186             final UserActivityListener userActivityListener, boolean forward) {
187         Fragment fragment = SelectFromListWizardFragment.newInstance(
188                 getTitle(formPageInfo, titleArgument),
189                 getDescription(formPageInfo, descriptionArgument),
190                 formPageInfo.getChoices(mContext, extraChoices), lastPage == null ? null
191                         : (ListItem) lastPage.getData().getParcelable(RESULT_LIST_ITEM));
192         displayFragment(fragment, forward);
193         mSelectFromListWizardFragmentListener = new SelectFromListWizardFragment.Listener() {
194             @Override
195             public void onListSelectionComplete(ListItem selection) {
196                 Bundle result = new Bundle();
197                 result.putParcelable(RESULT_LIST_ITEM, selection);
198                 result.putString(FormPage.DATA_KEY_SUMMARY_STRING, selection.getName());
199                 formPageResultListener.onBundlePageResult(formPage, result);
200             }
201 
202             @Override
203             public void onListFocusChanged(ListItem listItem) {
204                 if (userActivityListener != null) {
205                     userActivityListener.onUserActivity();
206                 }
207             }
208         };
209         return fragment;
210     }
211 
displayTextInput(FormPageInfo formPageInfo, String titleArgument, String descriptionArgument, final FormPage formPage, final FormPageResultListener listener, FormPage lastPage, boolean forward, final boolean emptyAllowed)212     private Fragment displayTextInput(FormPageInfo formPageInfo, String titleArgument,
213             String descriptionArgument, final FormPage formPage,
214             final FormPageResultListener listener, FormPage lastPage, boolean forward,
215             final boolean emptyAllowed) {
216         final String prefill = lastPage != null && !TextUtils.isEmpty(lastPage.getDataSummary())
217                 ? lastPage.getDataSummary() : getDefaultPrefill(formPageInfo);
218         Fragment fragment = TextInputWizardFragment.newInstance(
219                 getTitle(formPageInfo, titleArgument),
220                 getDescription(formPageInfo, descriptionArgument),
221                 formPageInfo.getInputType(),
222                 prefill);
223         displayFragment(fragment, forward);
224 
225         mTextInputWizardFragmentListener = new TextInputWizardFragment.Listener() {
226             @Override
227             public boolean onTextInputComplete(String text) {
228                 if (!TextUtils.isEmpty(text) || emptyAllowed) {
229                     Bundle result = new Bundle();
230                     result.putString(FormPage.DATA_KEY_SUMMARY_STRING, text);
231                     listener.onBundlePageResult(formPage, result);
232                     return true;
233                 }
234                 return false;
235             }
236         };
237         return fragment;
238     }
239 
displayPskInput(FormPageInfo formPageInfo, String titleArgument, String descriptionArgument, final FormPage formPage, final FormPageResultListener listener, FormPage lastPage, boolean forward)240     private Fragment displayPskInput(FormPageInfo formPageInfo, String titleArgument,
241             String descriptionArgument, final FormPage formPage,
242             final FormPageResultListener listener, FormPage lastPage, boolean forward) {
243         boolean obfuscate = lastPage != null
244                 ? TextUtils.equals(
245                           lastPage.getDataSecondary(), PasswordInputWizardFragment.OPTION_OBFUSCATE)
246                 : false;
247         Fragment fragment =
248                 PasswordInputWizardFragment.newInstance(getTitle(formPageInfo, titleArgument),
249                         getDescription(formPageInfo, descriptionArgument),
250                         lastPage == null ? null : lastPage.getDataSummary(), obfuscate);
251         displayFragment(fragment, forward);
252 
253         mPasswordInputWizardFragmentListener = new PasswordInputWizardFragment.Listener() {
254             @Override
255             public boolean onPasswordInputComplete(String text, boolean obfuscate) {
256                 if (!TextUtils.isEmpty(text) && text.length() >= PSK_MIN_LENGTH) {
257                     Bundle result = new Bundle();
258                     result.putString(FormPage.DATA_KEY_SUMMARY_STRING, text);
259                     if (obfuscate) {
260                         result.putString(FormPage.DATA_KEY_SECONDARY_STRING,
261                                 PasswordInputWizardFragment.OPTION_OBFUSCATE);
262                     }
263                     listener.onBundlePageResult(formPage, result);
264                     return true;
265                 }
266                 return false;
267             }
268         };
269         return fragment;
270     }
271 
displayLoading(FormPageInfo formPageInfo, String argument, boolean showProgress, boolean forward)272     private Fragment displayLoading(FormPageInfo formPageInfo, String argument,
273             boolean showProgress, boolean forward) {
274         Fragment fragment = MessageWizardFragment.newInstance(
275                 getTitle(formPageInfo, argument), showProgress);
276         displayFragment(fragment, forward);
277         return fragment;
278     }
279 
getTitle(FormPageInfo formPageInfo, String argument)280     private String getTitle(FormPageInfo formPageInfo, String argument) {
281         return mContext.getString(formPageInfo.getTitleResourceId(), argument);
282     }
283 
getDescription(FormPageInfo formPageInfo, String argument)284     private String getDescription(FormPageInfo formPageInfo, String argument) {
285         int descriptionResourceId = formPageInfo.getDescriptionResourceId();
286         return (descriptionResourceId != 0) ? mContext.getString(descriptionResourceId, argument)
287                 : null;
288     }
289 
getDefaultPrefill(FormPageInfo formPageInfo)290     private String getDefaultPrefill(FormPageInfo formPageInfo) {
291         int defaultPrefillResourceId = formPageInfo.getDefaultPrefillResourceId();
292         return (defaultPrefillResourceId != 0)
293                 ? mContext.getString(defaultPrefillResourceId) : null;
294     }
295 }
296