| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.support.v17.leanback.app; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.Mockito.any; |
| import static org.mockito.Mockito.doAnswer; |
| import static org.mockito.Mockito.timeout; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| |
| import android.os.Bundle; |
| import android.support.test.filters.LargeTest; |
| import android.support.test.runner.AndroidJUnit4; |
| import android.support.v17.leanback.testutils.PollingCheck; |
| import android.support.v17.leanback.widget.GuidedAction; |
| import android.support.v17.leanback.widget.GuidedActionsStylist; |
| import android.view.KeyEvent; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.invocation.InvocationOnMock; |
| import org.mockito.stubbing.Answer; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| @LargeTest |
| @RunWith(AndroidJUnit4.class) |
| public class GuidedStepFragmentTest extends GuidedStepFragmentTestBase { |
| |
| private static final int ON_DESTROY_TIMEOUT = 5000; |
| |
| @Test |
| public void nextAndBack() throws Throwable { |
| final String firstFragmentName = generateMethodTestName("first"); |
| final String secondFragmentName = generateMethodTestName("second"); |
| GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| List actions = (List) invocation.getArguments()[0]; |
| actions.add(new GuidedAction.Builder().id(1000).title("OK").build()); |
| return null; |
| } |
| }).when(first).onCreateActions(any(List.class), any(Bundle.class)); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| GuidedAction action = (GuidedAction) invocation.getArguments()[0]; |
| GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider) |
| invocation.getMock(); |
| if (action.getId() == 1000) { |
| GuidedStepFragment.add(obj.getFragmentManager(), |
| new GuidedStepTestFragment(secondFragmentName)); |
| } |
| return null; |
| } |
| }).when(first).onGuidedActionClicked(any(GuidedAction.class)); |
| |
| GuidedStepTestFragment.Provider second = mockProvider(secondFragmentName); |
| |
| GuidedStepFragmentTestActivity activity = launchTestActivity(firstFragmentName); |
| verify(first, times(1)).onCreate(any(Bundle.class)); |
| verify(first, times(1)).onCreateGuidance(any(Bundle.class)); |
| verify(first, times(1)).onCreateActions(any(List.class), any(Bundle.class)); |
| verify(first, times(1)).onCreateButtonActions(any(List.class), any(Bundle.class)); |
| verify(first, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| verify(first, times(1)).onViewStateRestored(any(Bundle.class)); |
| verify(first, times(1)).onStart(); |
| verify(first, times(1)).onResume(); |
| |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| verify(first, times(1)).onGuidedActionClicked(any(GuidedAction.class)); |
| |
| PollingCheck.waitFor(new EnterTransitionFinish(second)); |
| verify(first, times(1)).onPause(); |
| verify(first, times(1)).onStop(); |
| verify(first, times(1)).onDestroyView(); |
| verify(second, times(1)).onCreate(any(Bundle.class)); |
| verify(second, times(1)).onCreateGuidance(any(Bundle.class)); |
| verify(second, times(1)).onCreateActions(any(List.class), any(Bundle.class)); |
| verify(second, times(1)).onCreateButtonActions(any(List.class), any(Bundle.class)); |
| verify(second, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| verify(second, times(1)).onViewStateRestored(any(Bundle.class)); |
| verify(second, times(1)).onStart(); |
| verify(second, times(1)).onResume(); |
| |
| sendKey(KeyEvent.KEYCODE_BACK); |
| |
| PollingCheck.waitFor(new EnterTransitionFinish(first)); |
| verify(second, times(1)).onPause(); |
| verify(second, times(1)).onStop(); |
| verify(second, times(1)).onDestroyView(); |
| verify(second, times(1)).onDestroy(); |
| verify(first, times(1)).onCreateActions(any(List.class), any(Bundle.class)); |
| verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| verify(first, times(2)).onViewStateRestored(any(Bundle.class)); |
| verify(first, times(2)).onStart(); |
| verify(first, times(2)).onResume(); |
| |
| sendKey(KeyEvent.KEYCODE_BACK); |
| PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity)); |
| verify(first, timeout(ON_DESTROY_TIMEOUT).times(1)).onDestroy(); |
| assertTrue(activity.isDestroyed()); |
| } |
| |
| @Test |
| public void restoreFragments() throws Throwable { |
| final String firstFragmentName = generateMethodTestName("first"); |
| final String secondFragmentName = generateMethodTestName("second"); |
| GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| List actions = (List) invocation.getArguments()[0]; |
| actions.add(new GuidedAction.Builder().id(1000).title("OK").build()); |
| actions.add(new GuidedAction.Builder().id(1001).editable(true).title("text") |
| .build()); |
| actions.add(new GuidedAction.Builder().id(1002).editable(true).title("text") |
| .autoSaveRestoreEnabled(false).build()); |
| return null; |
| } |
| }).when(first).onCreateActions(any(List.class), any(Bundle.class)); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| GuidedAction action = (GuidedAction) invocation.getArguments()[0]; |
| GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider) |
| invocation.getMock(); |
| if (action.getId() == 1000) { |
| GuidedStepFragment.add(obj.getFragmentManager(), |
| new GuidedStepTestFragment(secondFragmentName)); |
| } |
| return null; |
| } |
| }).when(first).onGuidedActionClicked(any(GuidedAction.class)); |
| |
| GuidedStepTestFragment.Provider second = mockProvider(secondFragmentName); |
| |
| final GuidedStepFragmentTestActivity activity = launchTestActivity(firstFragmentName); |
| first.getFragment().findActionById(1001).setTitle("modified text"); |
| first.getFragment().findActionById(1002).setTitle("modified text"); |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| PollingCheck.waitFor(new EnterTransitionFinish(second)); |
| |
| activityTestRule.runOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| activity.recreate(); |
| } |
| }); |
| PollingCheck.waitFor(new EnterTransitionFinish(second)); |
| verify(first, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| verify(first, times(1)).onDestroy(); |
| verify(second, times(2)).onCreate(any(Bundle.class)); |
| verify(second, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| verify(second, times(1)).onDestroy(); |
| |
| sendKey(KeyEvent.KEYCODE_BACK); |
| PollingCheck.waitFor(new EnterTransitionFinish(first)); |
| verify(second, times(2)).onPause(); |
| verify(second, times(2)).onStop(); |
| verify(second, times(2)).onDestroyView(); |
| verify(second, times(2)).onDestroy(); |
| assertEquals("modified text", first.getFragment().findActionById(1001).getTitle()); |
| assertEquals("text", first.getFragment().findActionById(1002).getTitle()); |
| verify(first, times(2)).onCreate(any(Bundle.class)); |
| verify(first, times(2)).onCreateActions(any(List.class), any(Bundle.class)); |
| verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| } |
| |
| |
| @Test |
| public void finishGuidedStepFragment_finishes_activity() throws Throwable { |
| final String firstFragmentName = generateMethodTestName("first"); |
| GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| List actions = (List) invocation.getArguments()[0]; |
| actions.add(new GuidedAction.Builder().id(1001).title("Finish activity").build()); |
| return null; |
| } |
| }).when(first).onCreateActions(any(List.class), any(Bundle.class)); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| GuidedAction action = (GuidedAction) invocation.getArguments()[0]; |
| GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider) |
| invocation.getMock(); |
| if (action.getId() == 1001) { |
| obj.getFragment().finishGuidedStepFragments(); |
| } |
| return null; |
| } |
| }).when(first).onGuidedActionClicked(any(GuidedAction.class)); |
| |
| final GuidedStepFragmentTestActivity activity = launchTestActivity(firstFragmentName); |
| |
| View viewFinish = first.getFragment().getActionItemView(0); |
| assertTrue(viewFinish.hasFocus()); |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity)); |
| verify(first, timeout(ON_DESTROY_TIMEOUT).times(1)).onDestroy(); |
| } |
| |
| @Test |
| public void finishGuidedStepFragment_finishes_fragments() throws Throwable { |
| final String firstFragmentName = generateMethodTestName("first"); |
| GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| List actions = (List) invocation.getArguments()[0]; |
| actions.add(new GuidedAction.Builder().id(1001).title("Finish fragments").build()); |
| return null; |
| } |
| }).when(first).onCreateActions(any(List.class), any(Bundle.class)); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| GuidedAction action = (GuidedAction) invocation.getArguments()[0]; |
| GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider) |
| invocation.getMock(); |
| if (action.getId() == 1001) { |
| obj.getFragment().finishGuidedStepFragments(); |
| } |
| return null; |
| } |
| }).when(first).onGuidedActionClicked(any(GuidedAction.class)); |
| |
| final GuidedStepFragmentTestActivity activity = launchTestActivity(firstFragmentName, |
| false /*asRoot*/); |
| |
| View viewFinish = first.getFragment().getActionItemView(0); |
| assertTrue(viewFinish.hasFocus()); |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| |
| // fragment should be destroyed, activity should not destroyed |
| waitOnDestroy(first, 1); |
| assertFalse(activity.isDestroyed()); |
| } |
| |
| @Test |
| public void subActions() throws Throwable { |
| final String firstFragmentName = generateMethodTestName("first"); |
| final String secondFragmentName = generateMethodTestName("second"); |
| final boolean[] expandSubActionInOnCreateView = new boolean[] {false}; |
| GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider) |
| invocation.getMock(); |
| if (expandSubActionInOnCreateView[0]) { |
| obj.getFragment().expandAction(obj.getFragment().findActionById(1000), false); |
| } |
| return null; |
| } |
| }).when(first).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| List actions = (List) invocation.getArguments()[0]; |
| List<GuidedAction> subActions = new ArrayList<GuidedAction>(); |
| subActions.add(new GuidedAction.Builder().id(2000).title("item1").build()); |
| subActions.add(new GuidedAction.Builder().id(2001).title("item2").build()); |
| actions.add(new GuidedAction.Builder().id(1000).subActions(subActions) |
| .title("list").build()); |
| return null; |
| } |
| }).when(first).onCreateActions(any(List.class), any(Bundle.class)); |
| doAnswer(new Answer<Boolean>() { |
| public Boolean answer(InvocationOnMock invocation) { |
| GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider) |
| invocation.getMock(); |
| GuidedAction action = (GuidedAction) invocation.getArguments()[0]; |
| if (action.getId() == 2000) { |
| return true; |
| } else if (action.getId() == 2001) { |
| GuidedStepFragment.add(obj.getFragmentManager(), |
| new GuidedStepTestFragment(secondFragmentName)); |
| return false; |
| } |
| return false; |
| } |
| }).when(first).onSubGuidedActionClicked(any(GuidedAction.class)); |
| |
| GuidedStepTestFragment.Provider second = mockProvider(secondFragmentName); |
| |
| final GuidedStepFragmentTestActivity activity = launchTestActivity(firstFragmentName); |
| |
| // after clicked, it sub actions list should expand |
| View viewForList = first.getFragment().getActionItemView(0); |
| assertTrue(viewForList.hasFocus()); |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| PollingCheck.waitFor(new ExpandTransitionFinish(first)); |
| assertFalse(viewForList.hasFocus()); |
| |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| ArgumentCaptor<GuidedAction> actionCapture = ArgumentCaptor.forClass(GuidedAction.class); |
| verify(first, times(1)).onSubGuidedActionClicked(actionCapture.capture()); |
| assertEquals(2000, actionCapture.getValue().getId()); |
| // after clicked a sub action, it sub actions list should close |
| PollingCheck.waitFor(new ExpandTransitionFinish(first)); |
| assertTrue(viewForList.hasFocus()); |
| |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| PollingCheck.waitFor(new ExpandTransitionFinish(first)); |
| |
| assertFalse(viewForList.hasFocus()); |
| sendKey(KeyEvent.KEYCODE_DPAD_DOWN); |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| ArgumentCaptor<GuidedAction> actionCapture2 = ArgumentCaptor.forClass(GuidedAction.class); |
| verify(first, times(2)).onSubGuidedActionClicked(actionCapture2.capture()); |
| assertEquals(2001, actionCapture2.getValue().getId()); |
| |
| PollingCheck.waitFor(new EnterTransitionFinish(second)); |
| verify(second, times(1)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| |
| // test expand sub action when return to first fragment |
| expandSubActionInOnCreateView[0] = true; |
| sendKey(KeyEvent.KEYCODE_BACK); |
| PollingCheck.waitFor(new EnterTransitionFinish(first)); |
| verify(first, times(2)).onCreateView(any(LayoutInflater.class), any(ViewGroup.class), |
| any(Bundle.class), any(View.class)); |
| assertTrue(first.getFragment().isExpanded()); |
| |
| sendKey(KeyEvent.KEYCODE_BACK); |
| PollingCheck.waitFor(new ExpandTransitionFinish(first)); |
| assertFalse(first.getFragment().isExpanded()); |
| |
| sendKey(KeyEvent.KEYCODE_BACK); |
| PollingCheck.waitFor(new PollingCheck.ActivityDestroy(activity)); |
| verify(first, timeout(ON_DESTROY_TIMEOUT).times(1)).onDestroy(); |
| } |
| |
| @Test |
| public void setActionsWhenSubActionsExpanded() throws Throwable { |
| final String firstFragmentName = generateMethodTestName("first"); |
| GuidedStepTestFragment.Provider first = mockProvider(firstFragmentName); |
| doAnswer(new Answer<Void>() { |
| public Void answer(InvocationOnMock invocation) { |
| List actions = (List) invocation.getArguments()[0]; |
| List<GuidedAction> subActions = new ArrayList<GuidedAction>(); |
| subActions.add(new GuidedAction.Builder().id(2000).title("item1").build()); |
| actions.add(new GuidedAction.Builder().id(1000).subActions(subActions) |
| .title("list").build()); |
| return null; |
| } |
| }).when(first).onCreateActions(any(List.class), any(Bundle.class)); |
| doAnswer(new Answer<Boolean>() { |
| public Boolean answer(InvocationOnMock invocation) { |
| GuidedStepTestFragment.Provider obj = (GuidedStepTestFragment.Provider) |
| invocation.getMock(); |
| GuidedAction action = (GuidedAction) invocation.getArguments()[0]; |
| if (action.getId() == 2000) { |
| List<GuidedAction> newActions = new ArrayList<GuidedAction>(); |
| newActions.add(new GuidedAction.Builder().id(1001).title("item2").build()); |
| obj.getFragment().setActions(newActions); |
| return false; |
| } |
| return false; |
| } |
| }).when(first).onSubGuidedActionClicked(any(GuidedAction.class)); |
| |
| final GuidedStepFragmentTestActivity activity = launchTestActivity(firstFragmentName); |
| |
| // after clicked, it sub actions list should expand |
| View firstView = first.getFragment().getActionItemView(0); |
| assertTrue(firstView.hasFocus()); |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| PollingCheck.waitFor(new ExpandTransitionFinish(first)); |
| assertFalse(firstView.hasFocus()); |
| |
| sendKey(KeyEvent.KEYCODE_DPAD_CENTER); |
| ArgumentCaptor<GuidedAction> actionCapture = ArgumentCaptor.forClass(GuidedAction.class); |
| verify(first, times(1)).onSubGuidedActionClicked(actionCapture.capture()); |
| // after clicked a sub action, whole action list is replaced. |
| PollingCheck.waitFor(new ExpandTransitionFinish(first)); |
| assertFalse(first.getFragment().isExpanded()); |
| View newFirstView = first.getFragment().getActionItemView(0); |
| assertTrue(newFirstView.hasFocus()); |
| assertTrue(newFirstView.getVisibility() == View.VISIBLE); |
| GuidedActionsStylist.ViewHolder vh = (GuidedActionsStylist.ViewHolder) first.getFragment() |
| .getGuidedActionsStylist().getActionsGridView().getChildViewHolder(newFirstView); |
| assertEquals(1001, vh.getAction().getId()); |
| |
| } |
| |
| } |