Home | History | Annotate | Download | only in leanback
      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
     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
     82     public void onConfigurationChanged(Configuration newConfig) {
     83         Log.v(TAG, "onConfigurationChanged");
     84         super.onConfigurationChanged(newConfig);
     85     }
     86 
     87     @Override
     88     protected void onSaveInstanceState(Bundle outState) {
     89         Log.v(TAG, "onSaveInstanceState");
     90         super.onSaveInstanceState(outState);
     91     }
     92 
     93     @Override
     94     protected void onRestoreInstanceState(Bundle savedInstanceState) {
     95         Log.v(TAG, "onRestoreInstanceState");
     96         super.onRestoreInstanceState(savedInstanceState);
     97     }
     98 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    185         public int onProvideTheme() {
    186             return R.style.Theme_Example_Leanback_GuidedStep_First;
    187         }
    188 
    189         @Override
    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
    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
    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
    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
    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
    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
    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
    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 
    299         boolean isCardNumberValid(CharSequence number) {
    300             return TextUtils.isDigitsOnly(number) && number.length() == 16;
    301         }
    302 
    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 
    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 
    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