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