163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon/* 263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Copyright (C) 2014 The Android Open Source Project 363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * you may not use this file except in compliance with the License. 663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * You may obtain a copy of the License at 763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * http://www.apache.org/licenses/LICENSE-2.0 963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 1063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Unless required by applicable law or agreed to in writing, software 1163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 1263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * See the License for the specific language governing permissions and 1463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * limitations under the License. 1563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 1663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 177cc70b4f0ad1064a4a0dce6056ad82b205887160Tyler Gunnpackage com.android.server.telecom; 1863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.content.ComponentName; 2063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.content.Context; 2163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.content.Intent; 2263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.content.ServiceConnection; 2363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.os.IBinder; 2463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport android.os.IInterface; 2563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 2691d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunnimport com.android.internal.util.Preconditions; 2763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport com.google.common.base.Strings; 28c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 295c12c6e00101d16d2db776839a027c62c109dea8Santos Cordonimport com.google.common.collect.Sets; 305c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 31a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shraunerimport java.util.Collections; 325c12c6e00101d16d2db776839a027c62c109dea8Santos Cordonimport java.util.Set; 33a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shraunerimport java.util.concurrent.ConcurrentHashMap; 3463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 3563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon/** 3663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Abstract class to perform the work of binding and unbinding to the specified service interface. 3763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Subclasses supply the service intent and component name and this class will invoke protected 3863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * methods when the class is bound, unbound, or upon failure. 3963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 4063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonabstract class ServiceBinder<ServiceInterface extends IInterface> { 4163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 425c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon /** 435c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Callback to notify after a binding succeeds or fails. 445c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon */ 455c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon interface BindCallback { 46c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon void onSuccess(); 47c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon void onFailure(); 48c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 49c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 50c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 51c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * Listener for bind events on ServiceBinder. 52c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 5374d420be72fa30735fe9b7a25715f6db046c0398Santos Cordon interface Listener<ServiceBinderClass extends ServiceBinder<?>> { 5474d420be72fa30735fe9b7a25715f6db046c0398Santos Cordon void onUnbind(ServiceBinderClass serviceBinder); 555c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 565c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 576192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad /** 586192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * Helper class to perform on-demand binding. 596192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad */ 606192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad final class Binder { 616192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad /** 626192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * Performs an asynchronous bind to the service (only if not already bound) and executes the 636192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * specified callback. 646192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * 656192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * @param callback The callback to notify of the binding's success or failure. 666192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad */ 676192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad void bind(BindCallback callback) { 686192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad ThreadUtil.checkOnMainThread(); 696192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Log.d(ServiceBinder.this, "bind()"); 706192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 716192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad // Reset any abort request if we're asked to bind again. 726192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad clearAbort(); 736192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 746192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad if (!mCallbacks.isEmpty()) { 756192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad // Binding already in progress, append to the list of callbacks and bail out. 766192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad mCallbacks.add(callback); 776192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return; 786192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 796192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 806192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad mCallbacks.add(callback); 816192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad if (mServiceConnection == null) { 826192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName); 836192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad ServiceConnection connection = new ServiceBinderConnection(); 846192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 85c92c436d84de46bb85100df9138378d9ffe0f2f2Sailesh Nepal Log.d(ServiceBinder.this, "Binding to service with intent: %s", serviceIntent); 866192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { 876192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad handleFailedConnection(); 886192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return; 896192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 906192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } else { 916192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Log.d(ServiceBinder.this, "Service is already bound."); 926192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Preconditions.checkNotNull(mBinder); 936192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad handleSuccessfulConnection(); 946192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 956192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 966192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 976192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 9863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private final class ServiceBinderConnection implements ServiceConnection { 9963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon @Override 10063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon public void onServiceConnected(ComponentName componentName, IBinder binder) { 10163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon ThreadUtil.checkOnMainThread(); 102c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.i(this, "Service bound %s", componentName); 10363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 10463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon // Unbind request was queued so unbind immediately. 10563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon if (mIsBindingAborted) { 10663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon clearAbort(); 107c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon logServiceDisconnected("onServiceConnected"); 10863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mContext.unbindService(this); 1095c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon handleFailedConnection(); 11063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon return; 11163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 11263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 11363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mServiceConnection = this; 1146192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad setBinder(binder); 115b6141aec99bcf399faea1bfc9f48503492c4fb2dSailesh Nepal handleSuccessfulConnection(); 11663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 11763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 11863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon @Override 11963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon public void onServiceDisconnected(ComponentName componentName) { 120c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon logServiceDisconnected("onServiceDisconnected"); 121c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 12263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mServiceConnection = null; 12363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon clearAbort(); 12463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 12563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon handleServiceDisconnected(); 12663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 12763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 12863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 12963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** The application context. */ 13063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private final Context mContext; 13163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 13263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** The intent action to use when binding through {@link Context#bindService}. */ 13363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private final String mServiceAction; 13463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 13563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** The component name of the service to bind to. */ 13663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private final ComponentName mComponentName; 13763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1385c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon /** The set of callbacks waiting for notification of the binding's success or failure. */ 1395c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon private final Set<BindCallback> mCallbacks = Sets.newHashSet(); 1405c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 14163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** Used to bind and unbind from the service. */ 14263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private ServiceConnection mServiceConnection; 14363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 14463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** The binder provided by {@link ServiceConnection#onServiceConnected} */ 14563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private IBinder mBinder; 14663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1478e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad private int mAssociatedCallCount = 0; 1488e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 14963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 15063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Indicates that an unbind request was made when the service was not yet bound. If the service 15163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * successfully connects when this is true, it should be unbound immediately. 15263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 15363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private boolean mIsBindingAborted; 15463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 15563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 156c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * Set of currently registered listeners. 157a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 158a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner * load factor before resizing, 1 means we only expect a single thread to 159a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner * access the map so make only a single shard 160c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 161a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner private final Set<Listener> mListeners = Collections.newSetFromMap( 162a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 163c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 164c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 16563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Persists the specified parameters and initializes the new instance. 16663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 16763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * @param serviceAction The intent-action used with {@link Context#bindService}. 16863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * @param componentName The component name of the service with which to bind. 16991d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn * @param context The context. 17063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 17191d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn protected ServiceBinder(String serviceAction, ComponentName componentName, Context context) { 17263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon Preconditions.checkState(!Strings.isNullOrEmpty(serviceAction)); 17363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon Preconditions.checkNotNull(componentName); 17463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 17591d43cf9c985cc5a83795f256ef5c46ebb8fbdc1Tyler Gunn mContext = context; 17663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mServiceAction = serviceAction; 17763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mComponentName = componentName; 17863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 17963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1808e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final void incrementAssociatedCallCount() { 1818e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad mAssociatedCallCount++; 182c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.v(this, "Call count increment %d, %s", mAssociatedCallCount, 183c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mComponentName.flattenToShortString()); 1848e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 1858e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 1868e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final void decrementAssociatedCallCount() { 1878e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad if (mAssociatedCallCount > 0) { 1888e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad mAssociatedCallCount--; 189c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.v(this, "Call count decrement %d, %s", mAssociatedCallCount, 190c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mComponentName.flattenToShortString()); 191c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 192c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (mAssociatedCallCount == 0) { 193c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon unbind(); 194c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 1958e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } else { 196f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal Log.wtf(this, "%s: ignoring a request to decrement mAssociatedCallCount below zero", 197f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal mComponentName.getClassName()); 1988e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 1998e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 2008e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 2018e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final int getAssociatedCallCount() { 2028e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad return mAssociatedCallCount; 2038e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 2048e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 20563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 20663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Unbinds from the service if already bound, no-op otherwise. 20763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 20863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon final void unbind() { 20963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon ThreadUtil.checkOnMainThread(); 21063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 21163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon if (mServiceConnection == null) { 21263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon // We're not yet bound, so queue up an abort request. 21363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mIsBindingAborted = true; 21463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } else { 215c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon logServiceDisconnected("unbind"); 21663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mContext.unbindService(mServiceConnection); 21763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mServiceConnection = null; 2186192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad setBinder(null); 21963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 22063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 22163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 222bb167cdd0dffa8103ba051b0e115dcaecf2b649dBen Gilad final ComponentName getComponentName() { 22363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon return mComponentName; 22463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 22563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 2266192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad final boolean isServiceValid(String actionName) { 2276192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad if (mBinder == null) { 228682fe6ba2fe99e209d72a051539697a755b994c0Santos Cordon Log.w(this, "%s invoked while service is unbound", actionName); 2296192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return false; 2306192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 2316192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 2326192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return true; 2336192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 2346192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 235c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon final void addListener(Listener listener) { 236c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mListeners.add(listener); 237c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 238c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 239c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon final void removeListener(Listener listener) { 240a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner if (listener != null) { 241a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner mListeners.remove(listener); 242a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner } 243c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 244c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 245c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 246c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * Logs a standard message upon service disconnection. This method exists because there is no 247c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * single method called whenever the service unbinds and we want to log the same string in all 248c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * instances where that occurs. (Context.unbindService() does not cause onServiceDisconnected 249c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * to execute). 250c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * 251c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * @param sourceTag Tag to disambiguate 252c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 253c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon private void logServiceDisconnected(String sourceTag) { 254c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.i(this, "Service unbound %s, from %s.", mComponentName, sourceTag); 255c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 256c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 25763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 2585c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Notifies all the outstanding callbacks that the service is successfully bound. The list of 2595c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * outstanding callbacks is cleared afterwards. 26063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 261b6141aec99bcf399faea1bfc9f48503492c4fb2dSailesh Nepal private void handleSuccessfulConnection() { 2625c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon for (BindCallback callback : mCallbacks) { 2635c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon callback.onSuccess(); 2645c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 2655c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon mCallbacks.clear(); 2665c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 26763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 26863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 2695c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Notifies all the outstanding callbacks that the service failed to bind. The list of 2705c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * outstanding callbacks is cleared afterwards. 27163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 2725c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon private void handleFailedConnection() { 2735c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon for (BindCallback callback : mCallbacks) { 2745c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon callback.onFailure(); 2755c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 2765c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon mCallbacks.clear(); 2775c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 27863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 27963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 28063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Handles a service disconnection. 28163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 2825c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon private void handleServiceDisconnected() { 2836192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad setBinder(null); 2845c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 28563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 28663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private void clearAbort() { 28763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mIsBindingAborted = false; 28863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 2895c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 2905c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon /** 2916192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * Sets the (private) binder and updates the child class. 2926192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * 2936192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * @param binder The new binder value. 2946192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad */ 2956192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad private void setBinder(IBinder binder) { 296c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (mBinder != binder) { 297c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mBinder = binder; 298c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 299c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon setServiceInterface(binder); 300c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 301c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (binder == null) { 302a82c8f794a0a1a9eaa1329a6361abe28043d139aJay Shrauner for (Listener l : mListeners) { 303c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon l.onUnbind(this); 304c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 305c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 306c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 3076192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 3086192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 3096192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad /** 3105c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Sets the service interface after the service is bound or unbound. 3115c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * 3125c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * @param binder The actual bound service implementation. 3135c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon */ 3145c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon protected abstract void setServiceInterface(IBinder binder); 31563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon} 316