public final class

ConnectionManager

extends java.lang.Object

implements ServiceConnection.Callback

 java.lang.Object

↳androidx.health.platform.client.impl.ipc.internal.ConnectionManager

Gradle dependencies

compile group: 'androidx.health', name: 'health-connect-client', version: '1.0.0-alpha03'

  • groupId: androidx.health
  • artifactId: health-connect-client
  • version: 1.0.0-alpha03

Artifact androidx.health:health-connect-client:1.0.0-alpha03 it located at Google repository (https://maven.google.com/)

Overview

Manages connections to a service in a different process.

Summary

Constructors
publicConnectionManager(Context context, Looper looper)

Methods
public booleanhandleMessage(Message msg)

public booleanisBindToSelfEnabled()

public voidonConnected(ServiceConnection connection)

public voidonDisconnected(ServiceConnection connection, long reconnectDelayMs)

public voidregisterListener(ListenerKey listenerKey, QueueOperation registerOperation)

Registers a listener by executing an operation represented by the QueueOperation.

public voidscheduleForExecution(QueueOperation operation)

Schedules operation for execution

public voidsetBindToSelf(boolean bindToSelfEnabled)

public voidunregisterListener(ListenerKey listenerKey, QueueOperation unregisterOperation)

Unregisters a listener by executing an operation represented by the QueueOperation.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ConnectionManager(Context context, Looper looper)

Methods

public void scheduleForExecution(QueueOperation operation)

Schedules operation for execution

Parameters:

operation: Operation prepared for scheduling on the connection queue.

public void registerListener(ListenerKey listenerKey, QueueOperation registerOperation)

Registers a listener by executing an operation represented by the QueueOperation.

Parameters:

listenerKey: Key based on which listeners will be distinguished.
registerOperation: Queue operation executed against the corresponding connection to register the listener. Will be used to re-register when connection is lost.

public void unregisterListener(ListenerKey listenerKey, QueueOperation unregisterOperation)

Unregisters a listener by executing an operation represented by the QueueOperation.

Parameters:

listenerKey: Key based on which listeners will be distinguished.
unregisterOperation: Queue operation executed against the corresponding connection to unregister the listener.

public void onConnected(ServiceConnection connection)

public void onDisconnected(ServiceConnection connection, long reconnectDelayMs)

public boolean isBindToSelfEnabled()

public boolean handleMessage(Message msg)

public void setBindToSelf(boolean bindToSelfEnabled)

Source

/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.health.platform.client.impl.ipc.internal;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.annotation.VisibleForTesting;

import java.util.HashMap;
import java.util.Map;


/**
 * Manages connections to a service in a different process.
 *
 */
@RestrictTo(Scope.LIBRARY)
public final class ConnectionManager implements Handler.Callback, ServiceConnection.Callback {
    private static final String TAG = "ConnectionManager";

    @VisibleForTesting
    static final int UNBIND_IDLE_DELAY_MILLISECONDS = 15_000;

    private static final int MSG_CONNECTED = 1;
    private static final int MSG_DISCONNECTED = 2;
    private static final int MSG_EXECUTE = 3;
    private static final int MSG_REGISTER_LISTENER = 4;
    private static final int MSG_UNREGISTER_LISTENER = 5;

    private static final int MSG_UNBIND = 6;

    private final Context mContext;
    private final Handler mHandler;
    private final Map<String, ServiceConnection> mServiceConnectionMap = new HashMap<>();

    private boolean mBindToSelfEnabled;

    public ConnectionManager(Context context, Looper looper) {
        this.mContext = context;
        this.mHandler = new Handler(looper, this);
    }

    /**
     * Schedules operation for execution
     *
     * @param operation Operation prepared for scheduling on the connection queue.
     */
    public void scheduleForExecution(QueueOperation operation) {
        mHandler.sendMessage(mHandler.obtainMessage(MSG_EXECUTE, operation));
    }

    /**
     * Registers a listener by executing an operation represented by the {@link QueueOperation}.
     *
     * @param listenerKey       Key based on which listeners will be distinguished.
     * @param registerOperation Queue operation executed against the corresponding connection to
     *                          register the listener. Will be used to re-register when
     *                          connection is lost.
     */
    public void registerListener(ListenerKey listenerKey, QueueOperation registerOperation) {
        mHandler.sendMessage(
                mHandler.obtainMessage(
                        MSG_REGISTER_LISTENER, new ListenerHolder(listenerKey, registerOperation)));
    }

    /**
     * Unregisters a listener by executing an operation represented by the {@link QueueOperation}.
     *
     * @param listenerKey         Key based on which listeners will be distinguished.
     * @param unregisterOperation Queue operation executed against the corresponding connection to
     *                            unregister the listener.
     */
    public void unregisterListener(ListenerKey listenerKey, QueueOperation unregisterOperation) {
        mHandler.sendMessage(
                mHandler.obtainMessage(
                        MSG_UNREGISTER_LISTENER,
                        new ListenerHolder(listenerKey, unregisterOperation)));
    }

    /**
     * Delays any existing {@code MSG_UNBIND} message to {@code UNBIND_IDLE_DELAY_MILLISECONDS}
     * later.
     *
     * @param serviceConnection Service connection that we will auto-unbind.
     */
    void delayIdleServiceUnbindCheck(@NonNull ServiceConnection serviceConnection) {
        mHandler.removeMessages(MSG_UNBIND, serviceConnection);
        mHandler.sendMessageDelayed(
                mHandler.obtainMessage(MSG_UNBIND, serviceConnection),
                UNBIND_IDLE_DELAY_MILLISECONDS);
    }

    @Override
    public void onConnected(ServiceConnection connection) {
        mHandler.sendMessage(mHandler.obtainMessage(MSG_CONNECTED, connection));
    }

    @Override
    public void onDisconnected(ServiceConnection connection, long reconnectDelayMs) {
        mHandler.sendMessageDelayed(
                mHandler.obtainMessage(MSG_DISCONNECTED, connection), reconnectDelayMs);
    }

    @Override
    public boolean isBindToSelfEnabled() {
        return mBindToSelfEnabled;
    }

    @Override
    public boolean handleMessage(@NonNull Message msg) {
        switch (msg.what) {
            case MSG_CONNECTED:
                ServiceConnection serviceConnection = ((ServiceConnection) msg.obj);
                serviceConnection.reRegisterAllListeners();
                serviceConnection.refreshServiceVersion();
                serviceConnection.flushQueue();
                delayIdleServiceUnbindCheck(serviceConnection);
                return true;
            case MSG_DISCONNECTED:
                ((ServiceConnection) msg.obj).maybeReconnect();
                return true;
            case MSG_EXECUTE:
                QueueOperation queueOperation = (QueueOperation) msg.obj;
                ServiceConnection serviceConnectionForExecute =
                        getConnection(queueOperation.getConnectionConfiguration());
                serviceConnectionForExecute.enqueue(queueOperation);
                delayIdleServiceUnbindCheck(serviceConnectionForExecute);
                return true;
            case MSG_REGISTER_LISTENER:
                ListenerHolder registerListenerHolder = (ListenerHolder) msg.obj;
                ServiceConnection serviceConnectionForRegister =
                        getConnection(
                                registerListenerHolder
                                        .getListenerOperation()
                                        .getConnectionConfiguration());
                serviceConnectionForRegister
                        .registerListener(
                                registerListenerHolder.getListenerKey(),
                                registerListenerHolder.getListenerOperation());
                delayIdleServiceUnbindCheck(serviceConnectionForRegister);
                return true;
            case MSG_UNREGISTER_LISTENER:
                ListenerHolder unregisterListenerHolder = (ListenerHolder) msg.obj;
                ServiceConnection serviceConnectionForUnregister =
                        getConnection(
                                unregisterListenerHolder
                                        .getListenerOperation()
                                        .getConnectionConfiguration());
                serviceConnectionForUnregister
                        .unregisterListener(
                                unregisterListenerHolder.getListenerKey(),
                                unregisterListenerHolder.getListenerOperation());
                delayIdleServiceUnbindCheck(serviceConnectionForUnregister);
                return true;
            case MSG_UNBIND:
                ServiceConnection serviceConnectionToClear = ((ServiceConnection) msg.obj);
                if (mHandler.hasMessages(MSG_EXECUTE)
                        || mHandler.hasMessages(MSG_REGISTER_LISTENER)
                        || mHandler.hasMessages(MSG_UNREGISTER_LISTENER)) {
                    return true;
                }
                boolean isIdle = serviceConnectionToClear.clearConnectionIfIdle();
                if (!isIdle) {
                    delayIdleServiceUnbindCheck(serviceConnectionToClear);
                }
                return true;
            default:
                Log.e(TAG, "Received unknown message: " + msg.what);
                return false;
        }
    }

    public void setBindToSelf(boolean bindToSelfEnabled) {
        this.mBindToSelfEnabled = bindToSelfEnabled;
    }

    @VisibleForTesting
    ServiceConnection getConnection(ConnectionConfiguration connectionConfiguration) {
        String connectionKey = connectionConfiguration.getKey();
        ServiceConnection serviceConnection = mServiceConnectionMap.get(connectionKey);
        if (serviceConnection == null) {
            serviceConnection =
                    new ServiceConnection(
                            mContext, connectionConfiguration, new DefaultExecutionTracker(), this);
            mServiceConnectionMap.put(connectionKey, serviceConnection);
        }
        return serviceConnection;
    }

    private static class ListenerHolder {
        private final ListenerKey mListenerKey;
        private final QueueOperation mListenerOperation;

        ListenerHolder(ListenerKey listenerKey, QueueOperation listenerOperation) {
            this.mListenerKey = listenerKey;
            this.mListenerOperation = listenerOperation;
        }

        ListenerKey getListenerKey() {
            return mListenerKey;
        }

        QueueOperation getListenerOperation() {
            return mListenerOperation;
        }
    }
}