Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 777e2a0f authored by Sanket Agarwal's avatar Sanket Agarwal Committed by Gerrit Code Review
Browse files

Merge "PBAPClient State Machine"

parents 0bfb869d 27b77c8a
Loading
Loading
Loading
Loading
+157 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 com.android.bluetooth.pbapclient;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.BluetoothUuid;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.util.Log;

import java.io.IOException;

import javax.obex.ClientSession;
import javax.obex.HeaderSet;
import javax.obex.ResponseCodes;

/* Bluetooth/pbapclient/PbapClientConnectionHandler is responsible
 * for connecting, disconnecting and downloading contacts from the
 * PBAP PSE when commanded. It receives all direction from the
 * controlling state machine.
 */
class PbapClientConnectionHandler extends Handler {
    static final String TAG = "PBAP PCE handler";
    static final boolean DBG = true;
    static final int MSG_CONNECT = 1;
    static final int MSG_DISCONNECT = 2;
    static final int MSG_DOWNLOAD = 3;

    private static final byte[] PBAP_TARGET = new byte[] {
            0x79, 0x61, 0x35, (byte) 0xf0, (byte) 0xf0, (byte) 0xc5, 0x11, (byte) 0xd8, 0x09, 0x66,
            0x08, 0x00, 0x20, 0x0c, (byte) 0x9a, 0x66
    };

    public static final String PB_PATH = "telecom/pb.vcf";
    public static final String MCH_PATH = "telecom/mch.vcf";
    public static final byte VCARD_TYPE_21 = 0;

    private BluetoothSocket mSocket;
    private final BluetoothAdapter mAdapter;
    private final BluetoothDevice mDevice;
    private ClientSession mObexSession;
    private BluetoothPbapObexAuthenticator mAuth = null;
    private final PbapClientStateMachine mPbapClientStateMachine;

    PbapClientConnectionHandler(Looper looper, PbapClientStateMachine stateMachine,
            BluetoothDevice device) {
        super(looper);
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mDevice = device;
        mPbapClientStateMachine = stateMachine;
        mAuth = new BluetoothPbapObexAuthenticator(this);
    }

    @Override
    public void handleMessage(Message msg) {
        if (DBG) Log.d(TAG,"Handling Message = " +msg.what);
        switch(msg.what) {
            case MSG_CONNECT:
                boolean connectionSuccessful = false;

                try {
                    /* To establish a connection first open a socket, establish a OBEX Transport
                     * abstraction, establish a Bluetooth Authenticator, and finally attempt to
                     * connect via an OBEX session */
                    mSocket = mDevice.createRfcommSocketToServiceRecord(
                            BluetoothUuid.PBAP_PSE.getUuid());
                    mSocket.connect();

                    BluetoothPbapObexTransport transport;
                    transport = new BluetoothPbapObexTransport(mSocket);

                    mObexSession  = new ClientSession(transport);
                    mObexSession.setAuthenticator(mAuth);

                    HeaderSet connectionRequest = new HeaderSet();
                    connectionRequest.setHeader(HeaderSet.TARGET, PBAP_TARGET);
                    HeaderSet connectionResponse = mObexSession.connect(connectionRequest);

                    connectionSuccessful = (connectionResponse.getResponseCode() ==
                            ResponseCodes.OBEX_HTTP_OK);
                    if (DBG) Log.d(TAG,"Success = " + Boolean.toString(connectionSuccessful));
                } catch (IOException e) {
                    Log.w(TAG,"CONNECT Failure " + e.toString());
                    closeSocket();
                }

                if (connectionSuccessful) {
                    mPbapClientStateMachine.obtainMessage(
                            PbapClientStateMachine.MSG_CONNECTION_COMPLETE).sendToTarget();
                } else {
                    mPbapClientStateMachine.obtainMessage(
                            PbapClientStateMachine.MSG_CONNECTION_FAILED).sendToTarget();
                }
                break;

            case MSG_DISCONNECT:
                try {
                    if (mObexSession != null) {
                        mObexSession.disconnect(null);
                    }
                } catch (IOException e) {
                    Log.w(TAG,"DISCONNECT Failure " + e.toString());
                }
                mPbapClientStateMachine.obtainMessage(
                        PbapClientStateMachine.MSG_CONNECTION_CLOSED).sendToTarget();
                break;

            case MSG_DOWNLOAD:
                try {
                    BluetoothPbapRequestPullPhoneBook request =
                            new BluetoothPbapRequestPullPhoneBook(PB_PATH, null, 0, VCARD_TYPE_21,
                            0, 0);
                    request.execute(mObexSession);
                    if (DBG) Log.d(TAG,"Download success? " + request.isSuccess());
                } catch (IOException e) {
                    Log.w(TAG,"DOWNLOAD_CONTACTS Failure" + e.toString());
                }
                break;
            default:
                Log.w(TAG,"Received Unexpected Message");
        }
        return;
    }

    public void abort() {
        closeSocket();
    }

    private void closeSocket() {
        try {
            if (mSocket != null) {
                mSocket.close();
                mSocket = null;
            }
        } catch (IOException e) {
            Log.e(TAG, "Error when closing socket", e);
        }
    }
}
+34 −53
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.Utils;
import com.android.vcard.VCardEntry;


import java.lang.IllegalArgumentException;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.ArrayList;
@@ -56,9 +56,7 @@ import java.util.HashMap;
public class PbapClientService extends ProfileService {
    private static final boolean DBG = false;
    private static final String TAG = "PbapClientService";
    private PbapPCEClient mClient;
    private HandlerThread mHandlerThread;
    private AccountManager mAccountManager;
    private PbapClientStateMachine mPbapClientStateMachine;
    private static PbapClientService sPbapClientService;
    private PbapBroadcastReceiver mPbapBroadcastReceiver = new PbapBroadcastReceiver();

@@ -68,43 +66,39 @@ public class PbapClientService extends ProfileService {
    }

    @Override
    public synchronized IProfileServiceBinder initBinder() {
    public IProfileServiceBinder initBinder() {
        return new BluetoothPbapClientBinder(this);
    }

    @Override
    protected synchronized boolean start() {
    protected boolean start() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        try {
            registerReceiver(mPbapBroadcastReceiver, filter);
        } catch (Exception e) {
            Log.w(TAG,"Unable to register pbapclient receiver",e);
        }
        mClient = new PbapPCEClient(this);
        mAccountManager = AccountManager.get(this);
        mPbapClientStateMachine = new PbapClientStateMachine(this);
        setPbapClientService(this);
        mClient.start();
        mPbapClientStateMachine.start();
        return true;
    }

    @Override
    protected synchronized boolean stop() {
    protected boolean stop() {
        try {
            unregisterReceiver(mPbapBroadcastReceiver);
        } catch (Exception e) {
            Log.w(TAG,"Unable to unregister sap receiver",e);
        }
        if (mClient != null) {
            mClient.disconnect(null);
            Log.w(TAG,"Unable to unregister pbapclient receiver",e);
        }
        mPbapClientStateMachine.disconnect(null);
        return true;
    }

    @Override
    protected synchronized boolean cleanup() {
        sPbapClientService = null;
    protected boolean cleanup() {
        clearPbapClientService();
        return true;
    }

@@ -113,12 +107,7 @@ public class PbapClientService extends ProfileService {
        public void onReceive(Context context, Intent intent) {
            Log.v(TAG, "onReceive");
            String action = intent.getAction();
            if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
                  BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                  if(getPriority(device) >= BluetoothProfile.PRIORITY_ON) {
                      connect(device);
                  }
            } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
            if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                disconnect(device);
            }
@@ -252,30 +241,35 @@ public class PbapClientService extends ProfileService {
        }
    }

    private static synchronized void clearPbapClientService() {
        sPbapClientService = null;
    }

    public boolean connect(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                "Need BLUETOOTH ADMIN permission");
        if (device == null) throw new IllegalArgumentException("Null device");
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
        Log.d(TAG,"Received request to ConnectPBAPPhonebook " + device.getAddress());
        int connectionState = mClient.getConnectionState();
        int connectionState = mPbapClientStateMachine.getConnectionState();
        if (connectionState == BluetoothProfile.STATE_CONNECTED ||
                connectionState == BluetoothProfile.STATE_CONNECTING) {
            Log.w(TAG,"Received connect request while already connecting/connected.");
            return false;
        }
        if (getPriority(device) > BluetoothProfile.PRIORITY_OFF) {
            mClient.connect(device);
            mPbapClientStateMachine.connect(device);
            return true;
        }
        return false;
    }

    private boolean disconnect(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                "Need BLUETOOTH ADMIN permission");
        mClient.disconnect(device);
    boolean disconnect(BluetoothDevice device) {
        if (device == null) throw new IllegalArgumentException("Null device");
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
        mPbapClientStateMachine.disconnect(device);
        return true;
    }

    private List<BluetoothDevice> getConnectedDevices() {
    public List<BluetoothDevice> getConnectedDevices() {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        int[] desiredStates = {BluetoothProfile.STATE_CONNECTED};
        return getDevicesMatchingConnectionStates(desiredStates);
@@ -283,31 +277,18 @@ public class PbapClientService extends ProfileService {

    private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        int clientState = mClient.getConnectionState();
        Log.d(TAG,"getDevicesMatchingConnectionStates " + Arrays.toString(states) + " == " + clientState);
        List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
        for (int state : states) {
            if (clientState == state) {
                BluetoothDevice currentDevice = mClient.getDevice();
                if (currentDevice != null) {
                    deviceList.add(currentDevice);
                }
            }
        }
        return deviceList;
        return mPbapClientStateMachine.getDevicesMatchingConnectionStates(states);
    }

    int getConnectionState(BluetoothDevice device) {
        if (device == null) throw new IllegalArgumentException("Null device");
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        if (device == mClient.getDevice()) {
            return mClient.getConnectionState();
        }
        return BluetoothProfile.STATE_DISCONNECTED;
        return mPbapClientStateMachine.getConnectionState(device);
    }

    public boolean setPriority(BluetoothDevice device, int priority) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                "Need BLUETOOTH_ADMIN permission");
        if (device == null) throw new IllegalArgumentException("Null device");
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
        Settings.Global.putInt(getContentResolver(),
                Settings.Global.getBluetoothPbapClientPriorityKey(device.getAddress()),
                priority);
@@ -318,8 +299,8 @@ public class PbapClientService extends ProfileService {
    }

    public int getPriority(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                "Need BLUETOOTH_ADMIN permission");
        if (device == null) throw new IllegalArgumentException("Null device");
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
        int priority = Settings.Global.getInt(getContentResolver(),
                Settings.Global.getBluetoothPbapClientPriorityKey(device.getAddress()),
                BluetoothProfile.PRIORITY_UNDEFINED);
+373 −0

File added.

Preview size limit exceeded, changes collapsed.