ServiceBinder.java revision c499c1c0758dcb4b02048df96e7405994660ab3f
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 1763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonpackage com.android.telecomm; 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 2663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport com.google.common.base.Preconditions; 2763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonimport com.google.common.base.Strings; 28c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 29c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordonimport com.google.common.collect.ImmutableSet; 305c12c6e00101d16d2db776839a027c62c109dea8Santos Cordonimport com.google.common.collect.Sets; 315c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 325c12c6e00101d16d2db776839a027c62c109dea8Santos Cordonimport java.util.Set; 3363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 3463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon/** 3563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Abstract class to perform the work of binding and unbinding to the specified service interface. 3663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Subclasses supply the service intent and component name and this class will invoke protected 3763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * methods when the class is bound, unbound, or upon failure. 3863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 3963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordonabstract class ServiceBinder<ServiceInterface extends IInterface> { 4063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 415c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon /** 425c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Callback to notify after a binding succeeds or fails. 435c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon */ 445c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon interface BindCallback { 45c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon void onSuccess(); 46c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon void onFailure(); 47c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 48c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 49c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 50c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * Listener for bind events on ServiceBinder. 51c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 52c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon interface Listener { 53c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon @SuppressWarnings("rawtypes") 54c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon void onUnbind(ServiceBinder 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 856192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Log.d(ServiceBinder.this, "Binding to call 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. 157c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 158c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon private Set<Listener> mListeners = Sets.newHashSet(); 159c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 160c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 16163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Persists the specified parameters and initializes the new instance. 16263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * 16363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * @param serviceAction The intent-action used with {@link Context#bindService}. 16463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * @param componentName The component name of the service with which to bind. 16563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 16663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon protected ServiceBinder(String serviceAction, ComponentName componentName) { 16763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon Preconditions.checkState(!Strings.isNullOrEmpty(serviceAction)); 16863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon Preconditions.checkNotNull(componentName); 16963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 17063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mContext = TelecommApp.getInstance(); 17163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mServiceAction = serviceAction; 17263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mComponentName = componentName; 17363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 17463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 1758e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final void incrementAssociatedCallCount() { 1768e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad mAssociatedCallCount++; 177c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.v(this, "Call count increment %d, %s", mAssociatedCallCount, 178c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mComponentName.flattenToShortString()); 1798e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 1808e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 1818e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final void decrementAssociatedCallCount() { 1828e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad if (mAssociatedCallCount > 0) { 1838e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad mAssociatedCallCount--; 184c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.v(this, "Call count decrement %d, %s", mAssociatedCallCount, 185c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mComponentName.flattenToShortString()); 186c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 187c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (mAssociatedCallCount == 0) { 188c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon unbind(); 189c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 1908e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } else { 191f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal Log.wtf(this, "%s: ignoring a request to decrement mAssociatedCallCount below zero", 192f1c191d3974fed3f57680c63571ae0212c4622e7Sailesh Nepal mComponentName.getClassName()); 1938e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 1948e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 1958e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 1968e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad final int getAssociatedCallCount() { 1978e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad return mAssociatedCallCount; 1988e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad } 1998e55d1d7ea86f768acb90f88dc9e5b5368d3398aBen Gilad 20063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 20163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Unbinds from the service if already bound, no-op otherwise. 20263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 20363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon final void unbind() { 20463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon ThreadUtil.checkOnMainThread(); 20563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 20663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon if (mServiceConnection == null) { 20763aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon // We're not yet bound, so queue up an abort request. 20863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mIsBindingAborted = true; 20963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } else { 210c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon logServiceDisconnected("unbind"); 21163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mContext.unbindService(mServiceConnection); 21263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mServiceConnection = null; 2136192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad setBinder(null); 21463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 21563aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 21663aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 217bb167cdd0dffa8103ba051b0e115dcaecf2b649dBen Gilad final ComponentName getComponentName() { 21863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon return mComponentName; 21963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 22063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 2216192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad final boolean isServiceValid(String actionName) { 2226192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad if (mBinder == null) { 2236192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad Log.wtf(this, "%s invoked while service is unbound", actionName); 2246192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return false; 2256192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 2266192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 2276192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad return true; 2286192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 2296192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 230c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon final void addListener(Listener listener) { 231c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mListeners.add(listener); 232c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 233c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 234c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon final void removeListener(Listener listener) { 235c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mListeners.remove(listener); 236c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 237c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 238c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon /** 239c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * Logs a standard message upon service disconnection. This method exists because there is no 240c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * single method called whenever the service unbinds and we want to log the same string in all 241c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * instances where that occurs. (Context.unbindService() does not cause onServiceDisconnected 242c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * to execute). 243c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * 244c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon * @param sourceTag Tag to disambiguate 245c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon */ 246c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon private void logServiceDisconnected(String sourceTag) { 247c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon Log.i(this, "Service unbound %s, from %s.", mComponentName, sourceTag); 248c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 249c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 25063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 2515c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Notifies all the outstanding callbacks that the service is successfully bound. The list of 2525c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * outstanding callbacks is cleared afterwards. 25363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 254b6141aec99bcf399faea1bfc9f48503492c4fb2dSailesh Nepal private void handleSuccessfulConnection() { 2555c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon for (BindCallback callback : mCallbacks) { 2565c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon callback.onSuccess(); 2575c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 2585c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon mCallbacks.clear(); 2595c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 26063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 26163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 2625c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Notifies all the outstanding callbacks that the service failed to bind. The list of 2635c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * outstanding callbacks is cleared afterwards. 26463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 2655c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon private void handleFailedConnection() { 2665c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon for (BindCallback callback : mCallbacks) { 2675c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon callback.onFailure(); 2685c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 2695c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon mCallbacks.clear(); 2705c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 27163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 27263aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon /** 27363aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon * Handles a service disconnection. 27463aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon */ 2755c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon private void handleServiceDisconnected() { 2766192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad setBinder(null); 2775c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon } 27863aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon 27963aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon private void clearAbort() { 28063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon mIsBindingAborted = false; 28163aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon } 2825c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon 2835c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon /** 2846192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * Sets the (private) binder and updates the child class. 2856192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * 2866192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad * @param binder The new binder value. 2876192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad */ 2886192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad private void setBinder(IBinder binder) { 289c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (mBinder != binder) { 290c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon mBinder = binder; 291c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 292c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon setServiceInterface(binder); 293c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon 294c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon if (binder == null) { 295c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon // Use a copy of the listener list to allow the listeners to unregister themselves 296c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon // as part of the unbind without causing issues. 297c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon for (Listener l : ImmutableSet.copyOf(mListeners)) { 298c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon l.onUnbind(this); 299c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 300c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 301c499c1c0758dcb4b02048df96e7405994660ab3fSantos Cordon } 3026192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad } 3036192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad 3046192561b1f56d7c4e6c650e178e07ba61ad02667Ben Gilad /** 3055c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * Sets the service interface after the service is bound or unbound. 3065c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * 3075c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon * @param binder The actual bound service implementation. 3085c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon */ 3095c12c6e00101d16d2db776839a027c62c109dea8Santos Cordon protected abstract void setServiceInterface(IBinder binder); 31063aeb16a14a94dd44345f6200c7c002e780a15ffSantos Cordon} 311