1 /* This file is auto-generated from GuidedStepActivity.java.  DO NOT MODIFY. */
2 
3 /*
4  * Copyright (C) 2014 The Android Open Source Project
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 package com.example.android.leanback;
20 
21 import android.support.v4.app.FragmentActivity;
22 import android.support.v4.app.FragmentManager;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.res.Configuration;
26 import android.graphics.drawable.Drawable;
27 import android.os.Bundle;
28 import android.support.v17.leanback.app.GuidedStepSupportFragment;
29 import android.support.v17.leanback.widget.GuidanceStylist;
30 import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
31 import android.support.v17.leanback.widget.GuidedAction;
32 import android.support.v17.leanback.widget.GuidedActionsStylist;
33 import android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder;
34 import android.support.v17.leanback.widget.GuidedDatePickerAction;
35 import android.text.InputType;
36 import android.text.TextUtils;
37 import android.util.Log;
38 import android.view.ViewGroup;
39 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
40 import android.view.inputmethod.EditorInfo;
41 
42 import java.util.ArrayList;
43 import java.util.Calendar;
44 import java.util.List;
45 
46 /**
47  * Activity that showcases different aspects of GuidedStepSupportFragments.
48  */
49 public class GuidedStepSupportActivity extends FragmentActivity {
50 
51     private static final int BACK = 2;
52 
53     private static final int FIRST_NAME = 3;
54     private static final int LAST_NAME = 4;
55     private static final int PASSWORD = 5;
56     private static final int PAYMENT = 6;
57     private static final int NEW_PAYMENT = 7;
58     private static final int PAYMENT_EXPIRE = 8;
59 
60     private static final long RADIO_ID_BASE = 0;
61     private static final long CHECKBOX_ID_BASE = 100;
62 
63     private static final long DEFAULT_OPTION = RADIO_ID_BASE;
64 
65     private static final String[] OPTION_NAMES = { "Option A", "Option B", "Option C" };
66     private static final String[] OPTION_DESCRIPTIONS = { "Here's one thing you can do",
67             "Here's another thing you can do", "Here's one more thing you can do" };
68 
69     private static final String TAG = GuidedStepSupportActivity.class.getSimpleName();
70 
71     @Override
onCreate(Bundle savedInstanceState)72     protected void onCreate(Bundle savedInstanceState) {
73         Log.v(TAG, "onCreate");
74         super.onCreate(savedInstanceState);
75         setContentView(R.layout.guided_step_activity);
76         if (savedInstanceState == null) {
77             GuidedStepSupportFragment.addAsRoot(this, new FirstStepFragment(), R.id.lb_guidedstep_host);
78         }
79     }
80 
81     @Override
onConfigurationChanged(Configuration newConfig)82     public void onConfigurationChanged(Configuration newConfig) {
83         Log.v(TAG, "onConfigurationChanged");
84         super.onConfigurationChanged(newConfig);
85     }
86 
87     @Override
onSaveInstanceState(Bundle outState)88     protected void onSaveInstanceState(Bundle outState) {
89         Log.v(TAG, "onSaveInstanceState");
90         super.onSaveInstanceState(outState);
91     }
92 
93     @Override
onRestoreInstanceState(Bundle savedInstanceState)94     protected void onRestoreInstanceState(Bundle savedInstanceState) {
95         Log.v(TAG, "onRestoreInstanceState");
96         super.onRestoreInstanceState(savedInstanceState);
97     }
98 
addAction(List<GuidedAction> actions, long id, String title, String desc)99     private static void addAction(List<GuidedAction> actions, long id, String title, String desc) {
100         actions.add(new GuidedAction.Builder()
101                 .id(id)
102                 .title(title)
103                 .description(desc)
104                 .build());
105     }
106 
addAction(List<GuidedAction> actions, long id, String title, String desc, List<GuidedAction> subActions)107     private static void addAction(List<GuidedAction> actions, long id, String title, String desc,
108             List<GuidedAction> subActions) {
109         actions.add(new GuidedAction.Builder()
110                 .id(id)
111                 .title(title)
112                 .description(desc)
113                 .subActions(subActions)
114                 .build());
115     }
116 
addEditableAction(Context context, List<GuidedAction> actions, long id, String title, String desc)117     private static void addEditableAction(Context context, List<GuidedAction> actions,
118             long id, String title, String desc) {
119         actions.add(new GuidedAction.Builder(context)
120                 .id(id)
121                 .title(title)
122                 .description(desc)
123                 .editable(true)
124                 .icon(R.drawable.lb_ic_search_mic)
125                 .build());
126     }
127 
addEditableAction(List<GuidedAction> actions, long id, String title, String editTitle, String desc)128     private static void addEditableAction(List<GuidedAction> actions, long id, String title,
129             String editTitle, String desc) {
130         actions.add(new GuidedAction.Builder()
131                 .id(id)
132                 .title(title)
133                 .editTitle(editTitle)
134                 .description(desc)
135                 .editable(true)
136                 .build());
137     }
138 
addEditableAction(List<GuidedAction> actions, long id, String title, String editTitle, int editInputType, String desc, String editDesc)139     private static void addEditableAction(List<GuidedAction> actions, long id, String title,
140             String editTitle, int editInputType, String desc, String editDesc) {
141         actions.add(new GuidedAction.Builder()
142                 .id(id)
143                 .title(title)
144                 .editTitle(editTitle)
145                 .editInputType(editInputType)
146                 .description(desc)
147                 .editDescription(editDesc)
148                 .editable(true)
149                 .build());
150     }
151 
addDatePickerAction(List<GuidedAction> actions, long id, String title)152     private static void addDatePickerAction(List<GuidedAction> actions, long id, String title) {
153         actions.add(new GuidedDatePickerAction.Builder(null)
154                 .id(id)
155                 .title(title)
156                 .datePickerFormat("MY")
157                 .build());
158     }
159 
addEditableDescriptionAction(List<GuidedAction> actions, long id, String title, String desc, String editDescription, int descriptionEditInputType)160     private static void addEditableDescriptionAction(List<GuidedAction> actions, long id,
161             String title, String desc, String editDescription, int descriptionEditInputType) {
162         actions.add(new GuidedAction.Builder()
163                 .id(id)
164                 .title(title)
165                 .description(desc)
166                 .editDescription(editDescription)
167                 .descriptionEditInputType(descriptionEditInputType)
168                 .descriptionEditable(true)
169                 .build());
170     }
171 
addCheckedAction(List<GuidedAction> actions, long id, Context context, String title, String desc, int checkSetId)172     private static void addCheckedAction(List<GuidedAction> actions, long id, Context context,
173             String title, String desc, int checkSetId) {
174         actions.add(new GuidedAction.Builder()
175                 .id(id)
176                 .title(title)
177                 .description(desc)
178                 .checkSetId(checkSetId)
179                 .build());
180     }
181 
182     public static class FirstStepFragment extends GuidedStepSupportFragment {
183 
184         @Override
onProvideTheme()185         public int onProvideTheme() {
186             return R.style.Theme_Example_Leanback_GuidedStep_First;
187         }
188 
189         @Override
onCreateGuidance(Bundle savedInstanceState)190         public Guidance onCreateGuidance(Bundle savedInstanceState) {
191             String title = getString(R.string.guidedstep_first_title);
192             String breadcrumb = getString(R.string.guidedstep_first_breadcrumb);
193             String description = getString(R.string.guidedstep_first_description);
194             Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
195             return new Guidance(title, description, breadcrumb, icon);
196         }
197 
198         @Override
onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState)199         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
200             Context context = getActivity();
201             actions.add(new GuidedAction.Builder(context)
202                     .clickAction(GuidedAction.ACTION_ID_CONTINUE)
203                     .description("Let's do it")
204                     .build());
205             actions.add(new GuidedAction.Builder(context)
206                     .clickAction(GuidedAction.ACTION_ID_CANCEL)
207                     .description("Never mind")
208                     .build());
209         }
210 
211         @Override
onGuidedActionClicked(GuidedAction action)212         public void onGuidedActionClicked(GuidedAction action) {
213             FragmentManager fm = getFragmentManager();
214             if (action.getId() == GuidedAction.ACTION_ID_CONTINUE) {
215                 GuidedStepSupportFragment.add(fm, new SecondStepFragment(), R.id.lb_guidedstep_host);
216             } else if (action.getId() == GuidedAction.ACTION_ID_CANCEL){
217                 finishGuidedStepSupportFragments();
218             }
219         }
220     }
221 
222     static ArrayList<String> sCards = new ArrayList<String>();
223     static int sSelectedCard = -1;
224     static {
225         sCards.add("Visa-1234");
226         sCards.add("Master-4321");
227     }
228 
229     public static class NewPaymentStepFragment extends GuidedStepSupportFragment {
230 
231         @Override
onCreateGuidance(Bundle savedInstanceState)232         public Guidance onCreateGuidance(Bundle savedInstanceState) {
233             String title = getString(R.string.guidedstep_newpayment_title);
234             String breadcrumb = getString(R.string.guidedstep_newpayment_breadcrumb);
235             String description = getString(R.string.guidedstep_newpayment_description);
236             Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
237             return new Guidance(title, description, breadcrumb, icon);
238         }
239 
240         @Override
onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState)241         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
242             addEditableAction(actions, NEW_PAYMENT, "Input credit card number", "",
243                     InputType.TYPE_CLASS_NUMBER,
244                     "Input credit card number", "Input credit card number");
245             addDatePickerAction(actions, PAYMENT_EXPIRE, "Exp:");
246         }
247 
248         @Override
onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState)249         public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
250             Context context = getActivity();
251             actions.add(new GuidedAction.Builder(context).clickAction(GuidedAction.ACTION_ID_OK)
252                     .build());
253             actions.get(actions.size() - 1).setEnabled(false);
254         }
255 
256         @Override
onGuidedActionClicked(GuidedAction action)257         public void onGuidedActionClicked(GuidedAction action) {
258             if (action.getId() == GuidedAction.ACTION_ID_OK) {
259                 CharSequence desc = findActionById(NEW_PAYMENT).getDescription();
260                 String cardNumber = desc.subSequence(desc.length() - 4, desc.length()).toString();
261                 String card;
262                 if ((Integer.parseInt(cardNumber) & 1) == 0) {
263                     card = "Visa "+cardNumber;
264                 } else {
265                     card = "Master "+cardNumber;
266                 }
267                 sSelectedCard = sCards.size();
268                 sCards.add(card);
269                 popBackStackToGuidedStepSupportFragment(NewPaymentStepFragment.class,
270                         FragmentManager.POP_BACK_STACK_INCLUSIVE);
271             }
272         }
273 
274         @Override
onGuidedActionEditedAndProceed(GuidedAction action)275         public long onGuidedActionEditedAndProceed(GuidedAction action) {
276             if (action.getId() == NEW_PAYMENT) {
277                 CharSequence editTitle = action.getEditTitle();
278                 if (isCardNumberValid(editTitle)) {
279                     editTitle = editTitle.subSequence(editTitle.length() - 4, editTitle.length());
280                     action.setDescription("Visa XXXX-XXXX-XXXX-" + editTitle);
281                     updateOkButton(isExpDateValid(findActionById(PAYMENT_EXPIRE)));
282                     return GuidedAction.ACTION_ID_NEXT;
283                 } else if (editTitle.length() == 0) {
284                     action.setDescription("Input credit card number");
285                     updateOkButton(false);
286                     return GuidedAction.ACTION_ID_CURRENT;
287                 } else {
288                     action.setDescription("Error credit card number");
289                     updateOkButton(false);
290                     return GuidedAction.ACTION_ID_CURRENT;
291                 }
292             } else if (action.getId() == PAYMENT_EXPIRE) {
293                 updateOkButton(isExpDateValid(action) &&
294                         isCardNumberValid(findActionById(NEW_PAYMENT).getEditTitle()));
295             }
296             return GuidedAction.ACTION_ID_NEXT;
297         }
298 
isCardNumberValid(CharSequence number)299         boolean isCardNumberValid(CharSequence number) {
300             return TextUtils.isDigitsOnly(number) && number.length() == 16;
301         }
302 
isExpDateValid(GuidedAction action)303         boolean isExpDateValid(GuidedAction action) {
304             long date = ((GuidedDatePickerAction) action).getDate();
305             Calendar c = Calendar.getInstance();
306             c.setTimeInMillis(date);
307             return Calendar.getInstance().before(c);
308         }
309 
updateOkButton(boolean enabled)310         void updateOkButton(boolean enabled) {
311             findButtonActionById(GuidedAction.ACTION_ID_OK).setEnabled(enabled);
312             notifyButtonActionChanged(findButtonActionPositionById(GuidedAction.ACTION_ID_OK));
313         }
314     }
315 
316     public static class SecondStepFragment extends GuidedStepSupportFragment {
317 
onCreateActionsStylist()318         public GuidedActionsStylist onCreateActionsStylist() {
319             return new GuidedActionsStylist() {
320                 protected void setupImeOptions(GuidedActionsStylist.ViewHolder vh,
321                         GuidedAction action) {
322                     if (action.getId() == PASSWORD) {
323                         vh.getEditableDescriptionView().setImeActionLabel("Confirm!",
324                                 EditorInfo.IME_ACTION_DONE);
325                     } else {
326                         super.setupImeOptions(vh, action);
327                     }
328                 }
329             };
330         }
331 
332         @Override
333         public Guidance onCreateGuidance(Bundle savedInstanceState) {
334             String title = getString(R.string.guidedstep_second_title);
335             String breadcrumb = getString(R.string.guidedstep_second_breadcrumb);
336             String description = getString(R.string.guidedstep_second_description);
337             Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
338             return new Guidance(title, description, breadcrumb, icon);
339         }
340 
341         @Override
342         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
343             addEditableAction(getContext(), actions, FIRST_NAME, "Pat", "Your first name");
344             addEditableAction(getContext(), actions, LAST_NAME, "Smith", "Your last name");
345             List<GuidedAction> subActions = new ArrayList<GuidedAction>();
346             addAction(actions, PAYMENT, "Select Payment", "", subActions);
347             addEditableDescriptionAction(actions, PASSWORD, "Password", "", "",
348                     InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
349         }
350 
351         @Override
352         public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
353             actions.add(new GuidedAction.Builder(getActivity())
354                     .clickAction(GuidedAction.ACTION_ID_CONTINUE)
355                     .description("Continue")
356                     .build());
357         }
358 
359         @Override
360         public void onGuidedActionClicked(GuidedAction action) {
361             if (action.getId() == GuidedAction.ACTION_ID_CONTINUE) {
362                 FragmentManager fm = getFragmentManager();
363                 GuidedStepSupportFragment.add(fm, new ThirdStepFragment(), R.id.lb_guidedstep_host);
364             }
365         }
366 
367         @Override
368         public long onGuidedActionEditedAndProceed(GuidedAction action) {
369             if (action.getId() == PASSWORD) {
370                 CharSequence password = action.getEditDescription();
371                 if (password.length() > 0) {
372                     if (isPaymentValid()) {
373                         updateContinue(true);
374                         return GuidedAction.ACTION_ID_NEXT;
375                     } else {
376                         updateContinue(false);
377                         return GuidedAction.ACTION_ID_CURRENT;
378                     }
379                 } else {
380                     updateContinue(false);
381                     return GuidedAction.ACTION_ID_CURRENT;
382                 }
383             }
384             return GuidedAction.ACTION_ID_NEXT;
385         }
386 
387         @Override
388         public boolean onSubGuidedActionClicked(GuidedAction action) {
389             if (action.isChecked()) {
390                 String payment = action.getTitle().toString();
391                 for (int i = 0; i < sCards.size(); i++) {
392                     if (payment.equals(sCards.get(i))) {
393                         sSelectedCard = i;
394                         findActionById(PAYMENT).setDescription(payment);
395                         notifyActionChanged(findActionPositionById(PAYMENT));
396                         updateContinue(isPasswordValid());
397                         break;
398                     }
399                 }
400                 return true;
401             } else {
402                 FragmentManager fm = getFragmentManager();
403                 GuidedStepSupportFragment.add(fm, new NewPaymentStepFragment(), R.id.lb_guidedstep_host);
404                 return false;
405             }
406         }
407 
408         @Override
409         public void onResume() {
410             super.onResume();
411             // when resumed, update sub actions list and selected index from data model.
412             GuidedAction payments = findActionById(PAYMENT);
413             payments.getSubActions().clear();
414             for (int i = 0; i < sCards.size(); i++) {
415                 addCheckedAction(payments.getSubActions(), -1, getActivity(), sCards.get(i), "",
416                         GuidedAction.DEFAULT_CHECK_SET_ID);
417                 if (i == sSelectedCard) {
418                     payments.getSubActions().get(i).setChecked(true);
419                 }
420             }
421             addAction(payments.getSubActions(), NEW_PAYMENT, "Add New Card", "");
422             if (sSelectedCard != -1) {
423                 payments.setDescription(sCards.get(sSelectedCard));
424             }
425             notifyActionChanged(findActionPositionById(PAYMENT));
426             updateContinue(isPasswordValid() && isPaymentValid());
427         }
428 
429         boolean isPaymentValid() {
430             CharSequence paymentType = findActionById(PAYMENT).getDescription();
431             return (paymentType.length() >= 4 &&
432                     paymentType.subSequence(0, 4).toString().equals("Visa")) ||
433                     (paymentType.length() >= 6 &&
434                     paymentType.subSequence(0, 6).toString().equals("Master"));
435         }
436 
437         boolean isPasswordValid() {
438             return findActionById(PASSWORD).getEditDescription().length() > 0;
439         }
440 
441         void updateContinue(boolean enabled) {
442             findButtonActionById(GuidedAction.ACTION_ID_CONTINUE).setEnabled(enabled);
443             notifyButtonActionChanged(findButtonActionPositionById(
444                     GuidedAction.ACTION_ID_CONTINUE));
445         }
446     }
447 
448     public static class ThirdStepFragment extends GuidedStepSupportFragment {
449 
450         private long mSelectedOption = DEFAULT_OPTION;
451 
452         @Override
453         public Guidance onCreateGuidance(Bundle savedInstanceState) {
454             String title = getString(R.string.guidedstep_third_title);
455             String breadcrumb = getString(R.string.guidedstep_third_breadcrumb);
456             String description = getString(R.string.guidedstep_third_description);
457             Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
458             return new Guidance(title, description, breadcrumb, icon);
459         }
460 
461         @Override
462         public GuidanceStylist onCreateGuidanceStylist() {
463             return new GuidanceStylist() {
464                 @Override
465                 public int onProvideLayoutId() {
466                     return R.layout.guidedstep_second_guidance;
467                 }
468             };
469         }
470 
471         @Override
472         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
473             String desc = "The description can be quite long as well.  " +
474                     "Just be sure to set multilineDescription to true in the GuidedAction.";
475             actions.add(new GuidedAction.Builder()
476                     .title("Note that Guided Actions can have titles that are quite long.")
477                     .description(desc)
478                     .multilineDescription(true)
479                     .infoOnly(true)
480                     .enabled(true)
481                     .focusable(false)
482                     .build());
483             for (int i = 0; i < OPTION_NAMES.length; i++) {
484                 addCheckedAction(actions, RADIO_ID_BASE + i, getActivity(), OPTION_NAMES[i],
485                         OPTION_DESCRIPTIONS[i], GuidedAction.DEFAULT_CHECK_SET_ID);
486                 if (i == DEFAULT_OPTION) {
487                     actions.get(actions.size() -1).setChecked(true);
488                 }
489             }
490             for (int i = 0; i < OPTION_NAMES.length; i++) {
491                 addCheckedAction(actions, CHECKBOX_ID_BASE + i, getActivity(), OPTION_NAMES[i],
492                         OPTION_DESCRIPTIONS[i], GuidedAction.CHECKBOX_CHECK_SET_ID);
493             }
494         }
495 
496         @Override
497         public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
498             actions.add(new GuidedAction.Builder(getActivity())
499                     .clickAction(GuidedAction.ACTION_ID_CONTINUE)
500                     .build());
501         }
502 
503         @Override
504         public void onGuidedActionClicked(GuidedAction action) {
505             if (action.getId() == GuidedAction.ACTION_ID_CONTINUE) {
506                 FragmentManager fm = getFragmentManager();
507                 FourthStepFragment f = new FourthStepFragment();
508                 Bundle arguments = new Bundle();
509                 arguments.putLong(FourthStepFragment.EXTRA_OPTION, mSelectedOption);
510                 f.setArguments(arguments);
511                 GuidedStepSupportFragment.add(fm, f, R.id.lb_guidedstep_host);
512             } else if (action.getCheckSetId() == GuidedAction.DEFAULT_CHECK_SET_ID) {
513                 mSelectedOption = action.getId();
514             }
515         }
516 
517     }
518 
519     public static class FourthStepFragment extends GuidedStepSupportFragment {
520         public static final String EXTRA_OPTION = "extra_option";
521 
522         public FourthStepFragment() {
523         }
524 
525         public long getOption() {
526             Bundle b = getArguments();
527             if (b == null) return 0;
528             return b.getLong(EXTRA_OPTION, 0);
529         }
530 
531         @Override
532         public Guidance onCreateGuidance(Bundle savedInstanceState) {
533             String title = getString(R.string.guidedstep_fourth_title);
534             String breadcrumb = getString(R.string.guidedstep_fourth_breadcrumb);
535             String description = "You chose: " + OPTION_NAMES[(int) getOption()];
536             Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_main_icon);
537             return new Guidance(title, description, breadcrumb, icon);
538         }
539 
540         @Override
541         public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
542             actions.add(new GuidedAction.Builder(getActivity())
543                     .clickAction(GuidedAction.ACTION_ID_FINISH)
544                     .description("All Done...")
545                     .build());
546             addAction(actions, BACK, "Start Over", "Let's try this again...");
547         }
548 
549         @Override
550         public void onGuidedActionClicked(GuidedAction action) {
551             if (action.getId() == GuidedAction.ACTION_ID_FINISH) {
552                 finishGuidedStepSupportFragments();
553             } else if (action.getId() == BACK) {
554                 // pop 4, 3, 2
555                 popBackStackToGuidedStepSupportFragment(SecondStepFragment.class,
556                         FragmentManager.POP_BACK_STACK_INCLUSIVE);
557             }
558         }
559 
560     }
561 
562 }
563