1/* 2 * Copyright 2018 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 androidx.browser.customtabs; 18 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.Intent; 22import android.content.ServiceConnection; 23import android.os.Bundle; 24import android.os.IBinder; 25import android.os.RemoteException; 26import android.support.customtabs.ICustomTabsCallback; 27import android.support.customtabs.IPostMessageService; 28 29/** 30 * A {@link ServiceConnection} for Custom Tabs providers to use while connecting to a 31 * {@link PostMessageService} on the client side. 32 */ 33public abstract class PostMessageServiceConnection implements ServiceConnection { 34 private final Object mLock = new Object(); 35 private final ICustomTabsCallback mSessionBinder; 36 private IPostMessageService mService; 37 38 public PostMessageServiceConnection(CustomTabsSessionToken session) { 39 mSessionBinder = ICustomTabsCallback.Stub.asInterface(session.getCallbackBinder()); 40 } 41 42 /** 43 * Binds the browser side to the client app through the given {@link PostMessageService} name. 44 * After this, this {@link PostMessageServiceConnection} can be used for sending postMessage 45 * related communication back to the client. 46 * @param context A context to bind to the service. 47 * @param packageName The name of the package to be bound to. 48 * @return Whether the binding was successful. 49 */ 50 public boolean bindSessionToPostMessageService(Context context, String packageName) { 51 Intent intent = new Intent(); 52 intent.setClassName(packageName, PostMessageService.class.getName()); 53 return context.bindService(intent, this, Context.BIND_AUTO_CREATE); 54 } 55 56 /** 57 * Unbinds this service connection from the given context. 58 * @param context The context to be unbound from. 59 */ 60 public void unbindFromContext(Context context) { 61 context.unbindService(this); 62 } 63 64 @Override 65 public final void onServiceConnected(ComponentName name, IBinder service) { 66 mService = IPostMessageService.Stub.asInterface(service); 67 onPostMessageServiceConnected(); 68 } 69 70 @Override 71 public final void onServiceDisconnected(ComponentName name) { 72 mService = null; 73 onPostMessageServiceDisconnected(); 74 } 75 76 /** 77 * Notifies the client that the postMessage channel requested with 78 * {@link CustomTabsService#requestPostMessageChannel( 79 * CustomTabsSessionToken, android.net.Uri)} is ready. This method should be 80 * called when the browser binds to the client side {@link PostMessageService} and also readies 81 * a connection to the web frame. 82 * 83 * @param extras Reserved for future use. 84 * @return Whether the notification was sent to the remote successfully. 85 */ 86 public final boolean notifyMessageChannelReady(Bundle extras) { 87 if (mService == null) return false; 88 synchronized (mLock) { 89 try { 90 mService.onMessageChannelReady(mSessionBinder, extras); 91 } catch (RemoteException e) { 92 return false; 93 } 94 } 95 return true; 96 } 97 98 /** 99 * Posts a message to the client. This should be called when a tab controlled by related 100 * {@link CustomTabsSession} has sent a postMessage. If postMessage() is called from a single 101 * thread, then the messages will be posted in the same order. 102 * 103 * @param message The message sent. 104 * @param extras Reserved for future use. 105 * @return Whether the postMessage was sent to the remote successfully. 106 */ 107 public final boolean postMessage(String message, Bundle extras) { 108 if (mService == null) return false; 109 synchronized (mLock) { 110 try { 111 mService.onPostMessage(mSessionBinder, message, extras); 112 } catch (RemoteException e) { 113 return false; 114 } 115 } 116 return true; 117 } 118 119 /** 120 * Called when the {@link PostMessageService} connection is established. 121 */ 122 public void onPostMessageServiceConnected() {} 123 124 /** 125 * Called when the connection is lost with the {@link PostMessageService}. 126 */ 127 public void onPostMessageServiceDisconnected() {} 128} 129