1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.tv;
17
18import static android.support.test.InstrumentationRegistry.getInstrumentation;
19
20import android.content.Context;
21import android.os.SystemClock;
22import android.support.test.rule.ActivityTestRule;
23import android.text.TextUtils;
24
25import com.android.tv.data.Channel;
26import com.android.tv.data.ChannelDataManager;
27import com.android.tv.testing.ChannelInfo;
28import com.android.tv.testing.testinput.ChannelStateData;
29import com.android.tv.testing.testinput.TestInputControlConnection;
30import com.android.tv.testing.testinput.TestInputControlUtils;
31import com.android.tv.testing.testinput.TvTestInputConstants;
32
33import org.junit.Before;
34import org.junit.Rule;
35
36import java.util.List;
37
38/**
39 * Base TestCase for tests that need a {@link MainActivity}.
40 */
41public abstract class BaseMainActivityTestCase {
42    private static final String TAG = "BaseMainActivityTest";
43    private static final int CHANNEL_LOADING_CHECK_INTERVAL_MS = 10;
44
45    @Rule
46    public ActivityTestRule<MainActivity> mActivityTestRule =
47            new ActivityTestRule<>(MainActivity.class);
48
49    protected final TestInputControlConnection mConnection = new TestInputControlConnection();
50
51    protected MainActivity mActivity;
52
53    @Before
54    public void setUp() {
55        mActivity = mActivityTestRule.getActivity();
56        // TODO: ensure the SampleInputs are setup.
57        getInstrumentation().getTargetContext()
58                .bindService(TestInputControlUtils.createIntent(), mConnection,
59                        Context.BIND_AUTO_CREATE);
60    }
61
62    @Before
63    public void tearDown() {
64        if (mConnection.isBound()) {
65            getInstrumentation().getTargetContext().unbindService(mConnection);
66        }
67    }
68
69    /**
70     * Tune to {@code channel}.
71     *
72     * @param channel the channel to tune to.
73     */
74    protected void tuneToChannel(final Channel channel) {
75        // Run on UI thread so views can be modified
76        getInstrumentation().runOnMainSync(new Runnable() {
77            @Override
78            public void run() {
79                mActivity.tuneToChannel(channel);
80            }
81        });
82    }
83
84    /**
85     * Sleep until  @{@link ChannelDataManager#isDbLoadFinished()} is true.
86     */
87    protected void waitUntilChannelLoadingFinish() {
88        ChannelDataManager channelDataManager = mActivity.getChannelDataManager();
89        while (!channelDataManager.isDbLoadFinished()) {
90            getInstrumentation().waitForIdleSync();
91            SystemClock.sleep(CHANNEL_LOADING_CHECK_INTERVAL_MS);
92        }
93    }
94
95    /**
96     * Tune to the channel with {@code name}.
97     *
98     * @param name the name of the channel to find.
99     */
100    protected void tuneToChannel(String name) {
101        Channel c = findChannelWithName(name);
102        tuneToChannel(c);
103    }
104
105    /**
106     * Tune to channel.
107     */
108    protected void tuneToChannel(ChannelInfo channel) {
109        tuneToChannel(channel.name);
110    }
111
112    /**
113     * Update the channel state to {@code data} then tune to that channel.
114     *
115     * @param data    the state to update the channel with.
116     * @param channel the channel to tune to
117     */
118    protected void updateThenTune(ChannelStateData data, ChannelInfo channel) {
119        if (channel.equals(TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY)) {
120            throw new IllegalArgumentException(
121                    "By convention " + TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY.name
122                            + " should not be modified.");
123        }
124        mConnection.updateChannelState(channel, data);
125        tuneToChannel(channel);
126    }
127
128    private Channel findChannelWithName(String displayName) {
129        waitUntilChannelLoadingFinish();
130        Channel channel = null;
131        List <Channel> channelList = mActivity.getChannelDataManager().getChannelList();
132        for (Channel c : channelList) {
133            if (TextUtils.equals(c.getDisplayName(), displayName)) {
134                channel = c;
135                break;
136            }
137        }
138        if (channel == null) {
139            throw new AssertionError("'" + displayName + "' channel not found");
140        }
141        return channel;
142    }
143}
144