1914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal/*
2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project
3914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal *
4914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * Licensed under the Apache License, Version 2.0 (the "License");
5914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * you may not use this file except in compliance with the License.
6914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * You may obtain a copy of the License at
7914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal *
8914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal *      http://www.apache.org/licenses/LICENSE-2.0
9914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal *
10914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * Unless required by applicable law or agreed to in writing, software
11914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * distributed under the License is distributed on an "AS IS" BASIS,
12914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * See the License for the specific language governing permissions and
14914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * limitations under the License.
15914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal */
16914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.browser.customtabs;
18914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
19914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysalimport android.content.ComponentName;
20914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysalimport android.content.Context;
21914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysalimport android.content.Intent;
22914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysalimport android.content.ServiceConnection;
23914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysalimport android.os.Bundle;
24914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysalimport android.os.IBinder;
25914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysalimport android.os.RemoteException;
26ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport android.support.customtabs.ICustomTabsCallback;
27ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport android.support.customtabs.IPostMessageService;
28914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
29914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal/**
30914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * A {@link ServiceConnection} for Custom Tabs providers to use while connecting to a
31914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal * {@link PostMessageService} on the client side.
32914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal */
33914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysalpublic abstract class PostMessageServiceConnection implements ServiceConnection {
34914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    private final Object mLock = new Object();
35914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    private final ICustomTabsCallback mSessionBinder;
36914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    private IPostMessageService mService;
37914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
38914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public PostMessageServiceConnection(CustomTabsSessionToken session) {
39914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        mSessionBinder = ICustomTabsCallback.Stub.asInterface(session.getCallbackBinder());
40914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    }
41914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
42914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    /**
43914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * Binds the browser side to the client app through the given {@link PostMessageService} name.
44914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * After this, this {@link PostMessageServiceConnection} can be used for sending postMessage
45914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * related communication back to the client.
46914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @param context A context to bind to the service.
47914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @param packageName The name of the package to be bound to.
48914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @return Whether the binding was successful.
49914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     */
50914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public boolean bindSessionToPostMessageService(Context context, String packageName) {
51914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        Intent intent = new Intent();
52914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        intent.setClassName(packageName, PostMessageService.class.getName());
53914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        return context.bindService(intent, this, Context.BIND_AUTO_CREATE);
54914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    }
55914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
56914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    /**
57914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * Unbinds this service connection from the given context.
58914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @param context The context to be unbound from.
59914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     */
60914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public void unbindFromContext(Context context) {
61914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        context.unbindService(this);
62914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    }
63914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
64914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    @Override
65914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public final void onServiceConnected(ComponentName name, IBinder service) {
66914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        mService = IPostMessageService.Stub.asInterface(service);
67914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        onPostMessageServiceConnected();
68914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    }
69914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
70914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    @Override
71914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public final void onServiceDisconnected(ComponentName name) {
72914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        mService = null;
73914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        onPostMessageServiceDisconnected();
74914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    }
75914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
76914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    /**
77914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * Notifies the client that the postMessage channel requested with
78914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * {@link CustomTabsService#requestPostMessageChannel(
79914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * CustomTabsSessionToken, android.net.Uri)} is ready. This method should be
80914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * called when the browser binds to the client side {@link PostMessageService} and also readies
81914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * a connection to the web frame.
82914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     *
83914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @param extras Reserved for future use.
84914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @return Whether the notification was sent to the remote successfully.
85914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     */
86914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public final boolean notifyMessageChannelReady(Bundle extras) {
87914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        if (mService == null) return false;
88914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        synchronized (mLock) {
89914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal            try {
90914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal                mService.onMessageChannelReady(mSessionBinder, extras);
91914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal            } catch (RemoteException e) {
92914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal                return false;
93914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal            }
94914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        }
95914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        return true;
96914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    }
97914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
98914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    /**
99914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * Posts a message to the client. This should be called when a tab controlled by related
100914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * {@link CustomTabsSession} has sent a postMessage. If postMessage() is called from a single
101914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * thread, then the messages will be posted in the same order.
102914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     *
103914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @param message The message sent.
104914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @param extras Reserved for future use.
105914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * @return Whether the postMessage was sent to the remote successfully.
106914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     */
107914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public final boolean postMessage(String message, Bundle extras) {
108914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        if (mService == null) return false;
109914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        synchronized (mLock) {
110914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal            try {
111914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal                mService.onPostMessage(mSessionBinder, message, extras);
112914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal            } catch (RemoteException e) {
113914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal                return false;
114914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal            }
115914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        }
116914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal        return true;
117914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    }
118914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
119914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    /**
120914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * Called when the {@link PostMessageService} connection is established.
121914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     */
122914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public void onPostMessageServiceConnected() {}
123914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal
124914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    /**
125914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     * Called when the connection is lost with the {@link PostMessageService}.
126914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal     */
127914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal    public void onPostMessageServiceDisconnected() {}
128914073c7cf933229a3f51ddeddb63bb9725a70beYusuf Ozuysal}
129