1/*
2 * Copyright (C) 2017 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 */
16
17package android.support.customtabs;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertTrue;
21import static org.junit.Assert.fail;
22
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.net.Uri;
27import android.os.Bundle;
28import android.support.test.filters.SmallTest;
29import android.support.test.rule.ActivityTestRule;
30import android.support.test.rule.ServiceTestRule;
31import android.support.test.runner.AndroidJUnit4;
32import android.support.testutils.PollingCheck;
33
34import org.junit.Before;
35import org.junit.Rule;
36import org.junit.Test;
37import org.junit.runner.RunWith;
38
39import java.util.concurrent.TimeoutException;
40import java.util.concurrent.atomic.AtomicBoolean;
41
42
43/**
44 * Tests for a complete loop between a browser side {@link CustomTabsService}
45 * and a client side {@link PostMessageService}. Both services are bound to through
46 * {@link ServiceTestRule}, but {@link CustomTabsCallback#extraCallback} is used to link browser
47 * side actions.
48 */
49@RunWith(AndroidJUnit4.class)
50@SmallTest
51public class PostMessageTest {
52    @Rule
53    public final ServiceTestRule mServiceRule;
54    @Rule
55    public final ActivityTestRule<TestActivity> mActivityTestRule;
56    private TestCustomTabsCallback mCallback;
57    private Context mContext;
58    private CustomTabsServiceConnection mCustomTabsServiceConnection;
59    private PostMessageServiceConnection mPostMessageServiceConnection;
60    private AtomicBoolean mCustomTabsServiceConnected;
61    private boolean mPostMessageServiceConnected;
62    private CustomTabsSession mSession;
63
64    public PostMessageTest() {
65        mActivityTestRule = new ActivityTestRule<TestActivity>(TestActivity.class);
66        mServiceRule = new ServiceTestRule();
67        mCustomTabsServiceConnected = new AtomicBoolean(false);
68    }
69
70
71    @Before
72    public void setup() {
73        // Bind to PostMessageService only after CustomTabsService sends the callback to do so. This
74        // callback is sent after requestPostMessageChannel is called.
75        mCallback = new TestCustomTabsCallback() {
76            @Override
77            public void extraCallback(String callbackName, Bundle args) {
78                if (TestCustomTabsService.CALLBACK_BIND_TO_POST_MESSAGE.equals(callbackName)) {
79                    Intent postMessageServiceIntent = new Intent();
80                    postMessageServiceIntent.setClassName(
81                            mContext.getPackageName(), PostMessageService.class.getName());
82                    try {
83                        mServiceRule.bindService(postMessageServiceIntent,
84                                mPostMessageServiceConnection, Context.BIND_AUTO_CREATE);
85                    } catch (TimeoutException e) {
86                        fail();
87                    }
88                }
89            }
90        };
91        mContext = mActivityTestRule.getActivity();
92        mCustomTabsServiceConnection = new CustomTabsServiceConnection() {
93            @Override
94            public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
95                mSession = client.newSession(mCallback);
96                mCustomTabsServiceConnected.set(true);
97            }
98
99            @Override
100            public void onServiceDisconnected(ComponentName componentName) {
101                mCustomTabsServiceConnected.set(false);
102            }
103        };
104        mPostMessageServiceConnection = new PostMessageServiceConnection(
105                new CustomTabsSessionToken(mCallback.getStub())) {
106            @Override
107            public void onPostMessageServiceConnected() {
108                mPostMessageServiceConnected = true;
109            }
110
111            @Override
112            public void onPostMessageServiceDisconnected() {
113                mPostMessageServiceConnected = false;
114            }
115        };
116        Intent customTabsServiceIntent = new Intent();
117        customTabsServiceIntent.setClassName(
118                mContext.getPackageName(), TestCustomTabsService.class.getName());
119        try {
120            mServiceRule.bindService(customTabsServiceIntent,
121                    mCustomTabsServiceConnection, Context.BIND_AUTO_CREATE);
122        } catch (TimeoutException e) {
123            fail();
124        }
125    }
126
127    @Test
128    public void testCustomTabsConnection() {
129        PollingCheck.waitFor(500, new PollingCheck.PollingCheckCondition() {
130            @Override
131            public boolean canProceed() {
132                return mCustomTabsServiceConnected.get();
133            }
134        });
135        assertTrue(mCustomTabsServiceConnected.get());
136        assertTrue(mSession.requestPostMessageChannel(Uri.EMPTY));
137        assertEquals(CustomTabsService.RESULT_SUCCESS, mSession.postMessage("", null));
138        PollingCheck.waitFor(500, new PollingCheck.PollingCheckCondition() {
139            @Override
140            public boolean canProceed() {
141                return mPostMessageServiceConnected;
142            }
143        });
144        assertTrue(mPostMessageServiceConnected);
145    }
146}
147