GuidedStepAttributesTest.java revision 7d7bf9541e0203ec67df0fe53367e2c126355b9e
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14
15package android.support.v17.leanback.app.wizard;
16
17import android.app.Instrumentation;
18import android.content.Intent;
19import android.content.res.Resources;
20import android.support.v17.leanback.app.GuidedStepFragment;
21import android.support.v17.leanback.test.R;
22import android.support.v17.leanback.widget.GuidanceStylist;
23import android.support.v17.leanback.widget.GuidedAction;
24import android.test.ActivityInstrumentationTestCase2;
25import android.util.Log;
26import android.view.KeyEvent;
27
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.Collections;
31import java.util.List;
32
33public class GuidedStepAttributesTest extends
34        ActivityInstrumentationTestCase2<GuidedStepAttributesTestActivity>
35{
36    static final long TRANSITION_LENGTH = 1000;
37
38    static final String TAG = "GuidedStepAttributesTest";
39
40    Instrumentation mInstrumentation;
41    GuidedStepAttributesTestActivity mActivity;
42
43    public GuidedStepAttributesTest() {
44        super(GuidedStepAttributesTestActivity.class);
45    }
46
47    private void initActivity(Intent intent) {
48
49        setActivityIntent(intent);
50        mActivity = getActivity();
51        try {
52            Thread.sleep(2000);
53        } catch(InterruptedException e) {
54            e.printStackTrace();
55        }
56    }
57
58    public void testFocusDisabledOnActions() throws Throwable {
59
60        mInstrumentation = getInstrumentation();
61        Intent intent = new Intent(mInstrumentation.getContext(),
62                GuidedStepAttributesTestActivity.class);
63        Resources res = mInstrumentation.getContext().getResources();
64
65        final int NUM_SEARCH_ACTIONS = 10;
66        final List<Integer> ACTIONS_WITH_DISABLED_FOCUS = new ArrayList<>(
67                Arrays.asList(1, 3, 4, 5, 8));
68        final int ACTION_ID_SEARCH = 1;
69        List<Integer> EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT = new ArrayList<>();
70
71        // we will traverse actions from top to bottom and then back to the top
72        for(int i = 0; i < NUM_SEARCH_ACTIONS; i++) {
73            if (!ACTIONS_WITH_DISABLED_FOCUS.contains(i))
74                EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT.add(i);
75        }
76        for(int i = EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT.size(); i-- != 0;) {
77            EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT.add(EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT.get(i));
78        }
79
80
81        String title = "Guided Actions Focusable Test";
82        String breadcrumb = "Focusable Test Demo";
83        String description = "";
84        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
85                breadcrumb, null);
86
87        List<GuidedAction> actionList = new ArrayList<>();
88        for (int i = 0; i < NUM_SEARCH_ACTIONS; i++ ) {
89            actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
90                    .id(ACTION_ID_SEARCH)
91                    .title(res.getString(R.string.search) + "" + i)
92                    .description(res.getString(R.string.search_description) + i)
93                    .build()
94            );
95        }
96        for(int action_id : ACTIONS_WITH_DISABLED_FOCUS )
97            actionList.get(action_id).setFocusable(false);
98
99        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
100        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
101
102        initActivity(intent);
103
104        int lastSelectedActionId = -1;
105        int selectIndex = 0;
106        GuidedStepFragment mFragment = (GuidedStepFragment) mActivity.getGuidedStepTestFragment();
107        int prevSelectedActionPosition = -1;
108        int nextSelectedActionPosition = mFragment.getSelectedActionPosition();
109        while ( nextSelectedActionPosition != prevSelectedActionPosition ) {
110            lastSelectedActionId = mFragment.getSelectedActionPosition();
111            assertTrue(res.getString(R.string.focusable_test_error_message,
112                    actionList.get(lastSelectedActionId).getTitle()),
113                    lastSelectedActionId == EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT.get(selectIndex));
114            selectIndex++;
115            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
116            prevSelectedActionPosition = nextSelectedActionPosition;
117            nextSelectedActionPosition = mFragment.getSelectedActionPosition();
118            Thread.sleep(TRANSITION_LENGTH);
119        }
120
121        prevSelectedActionPosition = -1;
122        while ( nextSelectedActionPosition != prevSelectedActionPosition ) {
123            lastSelectedActionId = mFragment.getSelectedActionPosition();
124            assertTrue(res.getString(R.string.focusable_test_error_message,
125                    actionList.get(lastSelectedActionId).getTitle()),
126                    lastSelectedActionId == EXPECTED_ACTIONS_ID_AFTER_EACH_SELECT.get(selectIndex));
127            selectIndex++;
128            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
129            prevSelectedActionPosition = nextSelectedActionPosition;
130            nextSelectedActionPosition = mFragment.getSelectedActionPosition();
131            Thread.sleep(TRANSITION_LENGTH);
132        }
133
134    }
135
136    // Note: do not remove final or sRevertCallback gets null from 2nd test on!
137     static final GuidedStepAttributesTestFragment.Callback sRevertCallback = new
138            GuidedStepAttributesTestFragment.Callback() {
139        @Override
140        public void onActionClicked(GuidedStepFragment fragment, long id) {
141            List<GuidedAction> allActions = fragment.getActions();
142            for(int i = 1; i < allActions.size(); i++) {
143                GuidedAction action = allActions.get(i);
144                action.setEnabled(!action.isEnabled());
145                fragment.notifyActionChanged(fragment.findActionPositionById(action.getId()));
146            }
147        }
148    };
149
150    public void testDisabledActions() throws Throwable {
151
152        mInstrumentation = getInstrumentation();
153        Intent intent = new Intent(mInstrumentation.getContext(),
154                GuidedStepAttributesTestActivity.class);
155        Resources res = mInstrumentation.getContext().getResources();
156
157        final int NUM_SEARCH_ACTIONS = 10;
158        final List<Integer> DISABLED_ACTIONS = new ArrayList<>(
159                Arrays.asList(1, 3, 5, 7));
160        final int ACTION_ID_REVERT_BUTTON = 0;
161        final int ACTION_ID_SEARCH_BEGIN = ACTION_ID_REVERT_BUTTON + 1;
162        int ACTION_ID_SEARCH_END = ACTION_ID_SEARCH_BEGIN;
163
164        // sequence of clicked actions simulated in the test
165        List<Integer> CLICK_SEQUENCE = new ArrayList<>();
166
167        // Expected Clicked sequence can be different from focused ones since some of the actions
168        // are disabled hence not clickable
169        List<Integer> EXPECTED_FOCUSED_SEQUENCE = new ArrayList<>();
170        List<Integer> EXPECTED_CLICKED_SEQUENCE = new ArrayList<>();
171        // Expected actions state according to list of DISABLED_ACTIONS: false for disabled actions
172        List<Boolean> EXPECTED_ACTIONS_STATE = new ArrayList<>(
173                Arrays.asList(new Boolean[NUM_SEARCH_ACTIONS])
174        );
175        Collections.fill(EXPECTED_ACTIONS_STATE, Boolean.TRUE);
176
177        for(int i = 0; i < NUM_SEARCH_ACTIONS; i++) {
178            CLICK_SEQUENCE.add(i + 1);
179        }
180        for(int clickedActionId : CLICK_SEQUENCE) {
181            EXPECTED_FOCUSED_SEQUENCE.add(clickedActionId);
182            if (!DISABLED_ACTIONS.contains(clickedActionId - 1))
183                EXPECTED_CLICKED_SEQUENCE.add(clickedActionId);
184            else
185                EXPECTED_CLICKED_SEQUENCE.add(-1);
186        }
187
188        String title = "Guided Actions Enabled Test";
189        String breadcrumb = "Enabled Test Demo";
190        String description = "";
191        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
192                breadcrumb, null);
193
194        List<GuidedAction> actionList = new ArrayList<>();
195        actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
196                .id(ACTION_ID_REVERT_BUTTON)
197                .title(res.getString(R.string.invert_title))
198                .description(res.getString(R.string.revert_description))
199                .build()
200        );
201
202        for (int i = 0; i < NUM_SEARCH_ACTIONS; i++ ) {
203            actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
204                    .id(ACTION_ID_SEARCH_END++)
205                    .title(res.getString(R.string.search) + "" + i)
206                    .description(res.getString(R.string.search_description) + i)
207                    .build()
208            );
209        }
210        for(int action_id : DISABLED_ACTIONS ) {
211            if ( action_id >= 0 && action_id < NUM_SEARCH_ACTIONS ) {
212                actionList.get(action_id + 1).setEnabled(false);
213                EXPECTED_ACTIONS_STATE.set(action_id, Boolean.FALSE);
214            }
215        }
216
217        GuidedStepAttributesTestFragment.clear();
218        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
219        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
220        GuidedStepAttributesTestFragment.setActionClickCallback(ACTION_ID_REVERT_BUTTON,
221                sRevertCallback);
222
223        initActivity(intent);
224
225        final GuidedStepFragment mFragment = (GuidedStepFragment)
226                mActivity.getGuidedStepTestFragment();
227
228        examineEnabledAndDisabledActions(actionList, CLICK_SEQUENCE, EXPECTED_FOCUSED_SEQUENCE,
229                EXPECTED_CLICKED_SEQUENCE);
230        // now toggling all enabled/disabled actions to disabled/enabled and running the test again
231        Log.d(TAG, "Toggling actions...");
232        runTestOnUiThread(new Runnable() {
233            @Override
234            public void run() {
235                mFragment.setSelectedActionPosition(0);
236            }
237        });
238        Thread.sleep(TRANSITION_LENGTH);
239        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
240        Thread.sleep(TRANSITION_LENGTH);
241        for(int i = 0; i < EXPECTED_CLICKED_SEQUENCE.size(); i++) {
242            if (EXPECTED_CLICKED_SEQUENCE.get(i) == -1)
243                EXPECTED_CLICKED_SEQUENCE.set(i, CLICK_SEQUENCE.get(i));
244            else
245                EXPECTED_CLICKED_SEQUENCE.set(i, -1);
246        }
247
248        examineEnabledAndDisabledActions(actionList, CLICK_SEQUENCE, EXPECTED_FOCUSED_SEQUENCE,
249                EXPECTED_CLICKED_SEQUENCE);
250
251    }
252
253    private void examineEnabledAndDisabledActions(
254            List<GuidedAction> actionList, List<Integer> CLICK_SEQUENCE,
255                                List<Integer> EXPECTED_FOCUSED_SEQUENCE,
256                                List<Integer> EXPECTED_CLICKED_SEQUENCE)
257            throws Throwable {
258
259        final GuidedStepFragment mFragment = (GuidedStepFragment)
260                mActivity.getGuidedStepTestFragment();
261
262        for(int i = 0; i < CLICK_SEQUENCE.size(); i++) {
263            GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID =
264                    GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID = -1;
265            final int id = CLICK_SEQUENCE.get(i);
266            runTestOnUiThread(new Runnable() {
267                @Override
268                public void run() {
269                    mFragment.setSelectedActionPosition(id);
270                }
271            });
272            Thread.sleep(TRANSITION_LENGTH);
273
274            sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
275            Thread.sleep(TRANSITION_LENGTH);
276
277            assertTrue(mInstrumentation.getContext().getResources().getString(
278                    R.string.enabled_test_wrong_focus_error_message),
279                    GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
280                            EXPECTED_FOCUSED_SEQUENCE.get(i)
281            );
282            assertTrue(mInstrumentation.getContext().getResources().getString(
283                    R.string.enabled_test_wrong_click_error_message),
284                    GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID ==
285                            EXPECTED_CLICKED_SEQUENCE.get(i)
286            );
287            assertTrue(mInstrumentation.getContext().getResources().getString(
288                    R.string.enabled_test_wrong_flag_error_message),
289                    (GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID == -1) ?
290                            !actionList.get(id).isEnabled() :
291                            actionList.get(id).isEnabled()
292            );
293        }
294    }
295
296    public void testCheckedActions() throws Throwable {
297
298        mInstrumentation = getInstrumentation();
299        Intent intent = new Intent(mInstrumentation.getContext(),
300                GuidedStepAttributesTestActivity.class);
301        Resources res = mInstrumentation.getContext().getResources();
302
303        final int NUM_RADIO_ACTIONS = 3;
304        final int NUM_CHECK_BOX_ACTIONS = 3;
305        final int INITIALLY_CHECKED_RADIO_ACTION = 0;
306        final List<Integer> INITIALLY_CHECKED_CHECKBOX_ACTIONS = new ArrayList<>(
307                Arrays.asList(1, 2)
308        );
309
310        List<Integer> CLICK_SEQUENCE = new ArrayList<>();
311        for(int i = 0; i < NUM_RADIO_ACTIONS + NUM_CHECK_BOX_ACTIONS; i++) {
312            CLICK_SEQUENCE.add(i);
313        }
314
315        List<Boolean> EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK = new ArrayList<>(
316                Arrays.asList(new Boolean[CLICK_SEQUENCE.size()])
317        );
318        Collections.fill(EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK, Boolean.FALSE);
319
320        // initial state of actions before any clicks happen
321        EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.set(INITIALLY_CHECKED_RADIO_ACTION, true);
322        for(int checkedCheckBox : INITIALLY_CHECKED_CHECKBOX_ACTIONS) {
323            EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.set(NUM_RADIO_ACTIONS + checkedCheckBox, true);
324        }
325
326        String title = "Guided Actions Checked Test";
327        String breadcrumb = "Checked Test Demo";
328        String description = "";
329        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
330                breadcrumb, null);
331
332        List<GuidedAction> actionList = new ArrayList<>();
333        actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
334                .title(res.getString(R.string.radio_actions_info_title))
335                .description(res.getString(R.string.radio_actions_info_desc))
336                .infoOnly(true)
337                .enabled(true)
338                .focusable(false)
339                .build()
340        );
341
342        int firstRadioActionIndex = actionList.size();
343        for(int i = 0; i < NUM_RADIO_ACTIONS; i++) {
344            actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
345                    .title(res.getString(R.string.checkbox_title) + i)
346                    .description(res.getString(R.string.checkbox_desc) + i)
347                    .checkSetId(GuidedAction.DEFAULT_CHECK_SET_ID)
348                    .build()
349            );
350            if (i == INITIALLY_CHECKED_RADIO_ACTION)
351                actionList.get(firstRadioActionIndex + i).setChecked(true);
352        }
353
354        actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
355                .title(res.getString(R.string.checkbox_actions_info_title))
356                .description(res.getString(R.string.checkbox_actions_info_desc))
357                .infoOnly(true)
358                .enabled(true)
359                .focusable(false)
360                .build()
361        );
362        int firstCheckBoxActionIndex = actionList.size();
363        for(int i = 0; i < NUM_CHECK_BOX_ACTIONS; i++) {
364            actionList.add(new GuidedAction.Builder(mInstrumentation.getContext())
365                    .title(res.getString(R.string.checkbox_title) + i)
366                    .description(res.getString(R.string.checkbox_desc) + i)
367                    .checkSetId(GuidedAction.CHECKBOX_CHECK_SET_ID)
368                    .build()
369            );
370        }
371        for(int i = 0; i < INITIALLY_CHECKED_CHECKBOX_ACTIONS.size(); i++ ) {
372            actionList.get(firstCheckBoxActionIndex + INITIALLY_CHECKED_CHECKBOX_ACTIONS.get(i))
373                    .setChecked(true);
374        }
375
376        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
377        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
378        initActivity(intent);
379
380        examineCheckedAndUncheckedActions(actionList, EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK,
381                NUM_RADIO_ACTIONS, NUM_CHECK_BOX_ACTIONS);
382    }
383
384    private void updateExpectedActionsStateAfterClick(
385            List<Boolean> EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK, int NUM_RADIO_ACTIONS,
386            int NUM_CHECK_BOX_ACTIONS, int clickedActionIndex) {
387
388        if (clickedActionIndex < NUM_RADIO_ACTIONS) {
389            for(int i = 0; i < NUM_RADIO_ACTIONS; i++)
390                EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.set(i, false);
391            EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.set(clickedActionIndex, true);
392        }
393        else if (clickedActionIndex < NUM_RADIO_ACTIONS + NUM_CHECK_BOX_ACTIONS) {
394            EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.set(clickedActionIndex,
395                    !EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.get(clickedActionIndex));
396        }
397    }
398
399    private void verifyIfActionsStateIsCorrect(List<GuidedAction> actionList,
400            List<Boolean> EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK) {
401
402        int actionIndex = 0;
403        for(GuidedAction checkAction : actionList) {
404            if (checkAction.infoOnly())
405                continue;
406            assertTrue("Action " + actionIndex + " is " +
407                            (!checkAction.isChecked() ? "un-" : "") +
408                    "checked while it shouldn't be!",
409                    checkAction.isChecked() ==
410                            EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK.get(actionIndex));
411            actionIndex++;
412        }
413    }
414
415    private void examineCheckedAndUncheckedActions(List<GuidedAction> actionList,
416                                List<Boolean> EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK,
417                                int NUM_RADIO_ACTIONS,
418                                int NUM_CHECK_BOX_ACTIONS) throws Throwable {
419
420        final GuidedStepFragment guidedStepCheckedFragment = (GuidedStepFragment)
421                mActivity.getGuidedStepTestFragment();
422        final int firstRadioActionIndex = 1;
423        final int firstCheckBoxActionIndex = firstRadioActionIndex + NUM_RADIO_ACTIONS + 1;
424        for(int actionId = 0; actionId < NUM_RADIO_ACTIONS; actionId++) {
425            final int id = actionId;
426            runTestOnUiThread(new Runnable() {
427                @Override
428                public void run() {
429                    guidedStepCheckedFragment
430                            .setSelectedActionPosition(firstRadioActionIndex + id);
431                }
432            });
433            Thread.sleep(TRANSITION_LENGTH);
434
435            sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
436            Thread.sleep(TRANSITION_LENGTH);
437            updateExpectedActionsStateAfterClick(EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK,
438                    NUM_RADIO_ACTIONS, NUM_CHECK_BOX_ACTIONS, actionId);
439            verifyIfActionsStateIsCorrect(actionList, EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK);
440        }
441
442        for(int actionId = 0; actionId < NUM_CHECK_BOX_ACTIONS; actionId++) {
443            final int id = actionId;
444            runTestOnUiThread(new Runnable() {
445                @Override
446                public void run() {
447                    guidedStepCheckedFragment
448                            .setSelectedActionPosition(firstCheckBoxActionIndex + id);
449                }
450            });
451            Thread.sleep(TRANSITION_LENGTH);
452
453            sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
454            Thread.sleep(TRANSITION_LENGTH);
455            updateExpectedActionsStateAfterClick(EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK,
456                    NUM_RADIO_ACTIONS, NUM_CHECK_BOX_ACTIONS, NUM_RADIO_ACTIONS + actionId);
457            verifyIfActionsStateIsCorrect(actionList, EXPECTED_ACTIONS_STATE_AFTER_EACH_CLICK);
458        }
459    }
460
461    public void testSubActions() throws Throwable {
462
463        mInstrumentation = getInstrumentation();
464        Intent intent = new Intent(mInstrumentation.getContext(),
465                GuidedStepAttributesTestActivity.class);
466        Resources res = mInstrumentation.getContext().getResources();
467
468        String TAG = "testSubActions";
469        final int NUM_REGULAR_ACTIONS = 4;
470        final int[] NUM_SUBACTIONS_PER_ACTION = {2, 1, 0, 3};
471        final int[] REGULAR_ACTIONS_INDEX =  new int[NUM_REGULAR_ACTIONS];
472        final int[] BEGIN_SUBACTION_INDEX_PER_ACTION = new int[NUM_REGULAR_ACTIONS];
473        final int[] END_SUBACTION_INDEX_PER_ACTION = new int[NUM_REGULAR_ACTIONS];
474        // Actions and Subactions are assigned unique sequential IDs
475        int lastIndex = 0;
476        for(int i = 0; i < NUM_REGULAR_ACTIONS; i++) {
477            REGULAR_ACTIONS_INDEX[i] = lastIndex;
478            lastIndex++;
479            BEGIN_SUBACTION_INDEX_PER_ACTION[i] = lastIndex;
480            END_SUBACTION_INDEX_PER_ACTION[i] = (lastIndex += NUM_SUBACTIONS_PER_ACTION[i]);
481        }
482
483        // Sample click sequence for the main action list (not subactions)
484        List<Integer> ACTION_CLICK_SEQUENCE = new ArrayList<>(Arrays.asList(
485                3, 2, 1, 0
486        ));
487        List<Integer> EXPECTED_FOCUSED_SEQUENCE = new ArrayList<>();
488        List<Integer> EXPECTED_CLICKED_SEQUENCE = new ArrayList<>();
489
490        for(int clickedActionId : ACTION_CLICK_SEQUENCE) {
491            EXPECTED_FOCUSED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
492            if (NUM_SUBACTIONS_PER_ACTION[clickedActionId] > 0) {
493                for (int i = BEGIN_SUBACTION_INDEX_PER_ACTION[clickedActionId]; i <
494                        END_SUBACTION_INDEX_PER_ACTION[clickedActionId]; i++) {
495                    EXPECTED_CLICKED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
496                    for (int j = BEGIN_SUBACTION_INDEX_PER_ACTION[clickedActionId]; j <= i; j++) {
497                        EXPECTED_FOCUSED_SEQUENCE.add(j);
498                    }
499                    EXPECTED_CLICKED_SEQUENCE.add(i);
500                    EXPECTED_FOCUSED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
501                }
502            } else {
503                EXPECTED_CLICKED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
504                EXPECTED_FOCUSED_SEQUENCE.add(REGULAR_ACTIONS_INDEX[clickedActionId]);
505            }
506        }
507
508        String title = "Guided SubActions Test";
509        String breadcrumb = "SubActions Test Demo";
510        String description = "";
511        GuidanceStylist.Guidance guidance = new GuidanceStylist.Guidance(title, description,
512                breadcrumb, null);
513
514        List<GuidedAction> actionList = new ArrayList<>();
515
516        lastIndex = 0;
517        for (int i = 0; i < NUM_REGULAR_ACTIONS; i++ ) {
518            GuidedAction action = new GuidedAction.Builder(mInstrumentation.getContext())
519                    .id(lastIndex++)
520                    .title(res.getString(R.string.dropdown_action_title, i))
521                    .description(res.getString(R.string.dropdown_action_desc, i))
522                    .build();
523            if (NUM_SUBACTIONS_PER_ACTION[i] > 0) {
524                List<GuidedAction> subActions = new ArrayList<>();
525                action.setSubActions(subActions);
526                for(int j = 0; j < NUM_SUBACTIONS_PER_ACTION[i]; j++) {
527                    subActions.add(new GuidedAction.Builder(mInstrumentation.getContext())
528                            .id(lastIndex++)
529                            .title(res.getString(R.string.subaction_title, j))
530                            .description("")
531                            .build()
532                    );
533                }
534            }
535            actionList.add(action);
536        }
537
538        GuidedStepAttributesTestFragment.clear();
539        GuidedStepAttributesTestFragment.GUIDANCE = guidance;
540        GuidedStepAttributesTestFragment.ACTION_LIST = actionList;
541
542        initActivity(intent);
543
544        final GuidedStepFragment mFragment = (GuidedStepFragment) mActivity.
545                getGuidedStepTestFragment();
546
547        int focusStep = 0, clickStep = 0;
548        for(int i = 0; i < ACTION_CLICK_SEQUENCE.size(); i++) {
549            GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID =
550                    GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID = -1;
551            final int id = ACTION_CLICK_SEQUENCE.get(i);
552            final GuidedAction selectedAction = actionList.get(id);
553            runTestOnUiThread(new Runnable() {
554                @Override
555                public void run() {
556                    mFragment.setSelectedActionPosition(id);
557                }
558            });
559            Thread.sleep(TRANSITION_LENGTH);
560
561            assertTrue(mInstrumentation.getContext().getResources().getString(
562                    R.string.subaction_test_wrong_focus_error_message),
563                    GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
564                            EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
565            );
566
567            if (selectedAction.hasSubActions()) {
568                // Following for loop clicks on a specific action and scrolls & clicks through
569                // all its subactions
570                for (int j = 0; j < selectedAction.getSubActions().size(); j++) {
571                    sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
572                    Thread.sleep(TRANSITION_LENGTH);
573                    assertTrue(mInstrumentation.getContext().getResources().getString(
574                            R.string.subaction_test_wrong_focus_error_message),
575                            GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
576                                    EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
577                    );
578                    assertTrue(mInstrumentation.getContext().getResources().getString(
579                            R.string.subaction_test_wrong_click_error_message),
580                            GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID ==
581                                    EXPECTED_CLICKED_SEQUENCE.get(clickStep++)
582                    );
583                    for (int k = 0; k < j; k++) {
584                        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
585                        Thread.sleep(TRANSITION_LENGTH);
586                        assertTrue(mInstrumentation.getContext().getResources().getString(
587                                R.string.subaction_test_wrong_focus_error_message),
588                                GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
589                                        EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
590                        );
591                    }
592                    sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
593                    Thread.sleep(TRANSITION_LENGTH);
594
595                    assertTrue(mInstrumentation.getContext().getResources().getString(
596                            R.string.subaction_test_wrong_focus_error_message),
597                            GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
598                                    EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
599                    );
600                    assertTrue(mInstrumentation.getContext().getResources().getString(
601                            R.string.subaction_test_wrong_click_error_message),
602                            GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID ==
603                                    EXPECTED_CLICKED_SEQUENCE.get(clickStep++)
604                    );
605                }
606            } else {
607                sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
608                Thread.sleep(TRANSITION_LENGTH);
609                assertTrue(mInstrumentation.getContext().getResources().getString(
610                        R.string.subaction_test_wrong_focus_error_message),
611                        GuidedStepAttributesTestFragment.LAST_SELECTED_ACTION_ID ==
612                                EXPECTED_FOCUSED_SEQUENCE.get(focusStep++)
613                );
614                assertTrue(mInstrumentation.getContext().getResources().getString(
615                        R.string.subaction_test_wrong_click_error_message),
616                        GuidedStepAttributesTestFragment.LAST_CLICKED_ACTION_ID ==
617                                EXPECTED_CLICKED_SEQUENCE.get(clickStep++)
618                );
619            }
620        }
621
622    }
623}
624