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