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