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

Commit c9d911a4 authored by Hyundo Moon's avatar Hyundo Moon Committed by Android (Google) Code Review
Browse files

Merge changes from topic "cherrypicker-L93900000956073894:N29000001289508871" into tm-mainline-prod

* changes:
  Add tests for BluetoothPbapSimVcardManager (2/2)
  Add tests for BluetoothPbapSimVcardManager (1/2)
  Add tests for BluetoothPbapObexServer#onGet/onSetPath
  Add BluetoothPbapObexServerTest
  Add BluetoothPbapCallLogComposerTest
  Add BluetoothPbapConfigTest
  Add BluetoothPbapAuthenticatorTest
parents 6ea547be 4845b36d
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ package com.android.bluetooth.pbap;

import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.obex.Authenticator;
import com.android.obex.PasswordAuthentication;

@@ -44,10 +45,10 @@ import com.android.obex.PasswordAuthentication;
public class BluetoothPbapAuthenticator implements Authenticator {
    private static final String TAG = "PbapAuthenticator";

    private boolean mChallenged;
    private boolean mAuthCancelled;
    private String mSessionKey;
    private PbapStateMachine mPbapStateMachine;
    @VisibleForTesting boolean mChallenged;
    @VisibleForTesting boolean mAuthCancelled;
    @VisibleForTesting String mSessionKey;
    @VisibleForTesting PbapStateMachine mPbapStateMachine;

    BluetoothPbapAuthenticator(final PbapStateMachine stateMachine) {
        mPbapStateMachine = stateMachine;
+16 −12
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
 */
package com.android.bluetooth.pbap;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
@@ -26,6 +25,7 @@ import android.text.TextUtils;
import android.util.Log;

import com.android.bluetooth.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.vcard.VCardBuilder;
import com.android.vcard.VCardConfig;
import com.android.vcard.VCardConstants;
@@ -41,19 +41,24 @@ import java.util.Calendar;
public class BluetoothPbapCallLogComposer {
    private static final String TAG = "PbapCallLogComposer";

    private static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO =
    @VisibleForTesting
    static final String FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO =
            "Failed to get database information";

    private static final String FAILURE_REASON_NO_ENTRY = "There's no exportable in the database";
    @VisibleForTesting
    static final String FAILURE_REASON_NO_ENTRY = "There's no exportable in the database";

    private static final String FAILURE_REASON_NOT_INITIALIZED =
    @VisibleForTesting
    static final String FAILURE_REASON_NOT_INITIALIZED =
            "The vCard composer object is not correctly initialized";

    /** Should be visible only from developers... (no need to translate, hopefully) */
    private static final String FAILURE_REASON_UNSUPPORTED_URI =
    @VisibleForTesting
    static final String FAILURE_REASON_UNSUPPORTED_URI =
            "The Uri vCard composer received is not supported by the composer.";

    private static final String NO_ERROR = "No error";
    @VisibleForTesting
    static final String NO_ERROR = "No error";

    /** The projection to use when querying the call log table */
    private static final String[] sCallLogProjection = new String[]{
@@ -80,7 +85,6 @@ public class BluetoothPbapCallLogComposer {
    private static final String VCARD_PROPERTY_CALLTYPE_MISSED = "MISSED";

    private final Context mContext;
    private ContentResolver mContentResolver;
    private Cursor mCursor;

    private boolean mTerminateIsCalled;
@@ -91,7 +95,6 @@ public class BluetoothPbapCallLogComposer {

    public BluetoothPbapCallLogComposer(final Context context) {
        mContext = context;
        mContentResolver = context.getContentResolver();
    }

    public boolean init(final Uri contentUri, final String selection, final String[] selectionArgs,
@@ -104,8 +107,9 @@ public class BluetoothPbapCallLogComposer {
            return false;
        }

        mCursor =
                mContentResolver.query(contentUri, projection, selection, selectionArgs, sortOrder);
        mCursor = BluetoothPbapMethodProxy.getInstance().contentResolverQuery(
                mContext.getContentResolver(), contentUri, projection, selection, selectionArgs,
                sortOrder);

        if (mCursor == null) {
            mErrorReason = FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO;
@@ -175,8 +179,8 @@ public class BluetoothPbapCallLogComposer {
    /**
     * This static function is to compose vCard for phone own number
     */
    public String composeVCardForPhoneOwnNumber(int phonetype, String phoneName, String phoneNumber,
            boolean vcardVer21) {
    public static String composeVCardForPhoneOwnNumber(int phonetype, String phoneName,
            String phoneNumber, boolean vcardVer21) {
        final int vcardType = (vcardVer21 ? VCardConfig.VCARD_TYPE_V21_GENERIC
                : VCardConfig.VCARD_TYPE_V30_GENERIC)
                | VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING;
+91 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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.pbap;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;

import com.android.bluetooth.Utils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.obex.HeaderSet;

import java.io.IOException;

/**
 * Proxy class for method calls to help with unit testing
 */
public class BluetoothPbapMethodProxy {
    private static final String TAG = BluetoothPbapMethodProxy.class.getSimpleName();
    private static BluetoothPbapMethodProxy sInstance;
    private static final Object INSTANCE_LOCK = new Object();

    private BluetoothPbapMethodProxy() {}

    /**
     * Get the singleton instance of proxy
     *
     * @return the singleton instance, guaranteed not null
     */
    public static BluetoothPbapMethodProxy getInstance() {
        synchronized (INSTANCE_LOCK) {
            if (sInstance == null) {
                sInstance = new BluetoothPbapMethodProxy();
            }
        }
        return sInstance;
    }

    /**
     * Allow unit tests to substitute BluetoothPbapMethodCallProxy with a test instance
     *
     * @param proxy a test instance of the BluetoothPbapMethodCallProxy
     */
    @VisibleForTesting
    public static void setInstanceForTesting(BluetoothPbapMethodProxy proxy) {
        Utils.enforceInstrumentationTestMode();
        synchronized (INSTANCE_LOCK) {
            Log.d(TAG, "setInstanceForTesting(), set to " + proxy);
            sInstance = proxy;
        }
    }

    /**
     * Proxies {@link ContentResolver#query(Uri, String[], String, String[], String)}.
     */
    public Cursor contentResolverQuery(ContentResolver contentResolver, final Uri contentUri,
            final String[] projection, final String selection, final String[] selectionArgs,
            final String sortOrder) {
        return contentResolver.query(contentUri, projection, selection, selectionArgs, sortOrder);
    }

    /**
     * Proxies {@link HeaderSet#getHeader}.
     */
    public Object getHeader(HeaderSet headerSet, int headerId) throws IOException {
        return headerSet.getHeader(headerId);
    }

    /**
     * Proxies {@link Context#getSystemService(Class)}.
     */
    public <T> T getSystemService(Context context, Class<T> serviceClass) {
        return context.getSystemService(serviceClass);
    }
}
+75 −35
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.provider.CallLog.Calls;
import android.text.TextUtils;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.obex.ApplicationParameter;
import com.android.obex.HeaderSet;
import com.android.obex.Operation;
@@ -74,7 +75,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
    private static final int VCARD_NAME_SUFFIX_LENGTH = 5;

    // 128 bit UUID for PBAP
    private static final byte[] PBAP_TARGET = new byte[]{
    @VisibleForTesting
    public static final byte[] PBAP_TARGET = new byte[]{
            0x79,
            0x61,
            0x35,
@@ -122,39 +124,53 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
    };

    // SIM card
    private static final String SIM1 = "SIM1";
    @VisibleForTesting
    public static final String SIM1 = "SIM1";

    // missed call history
    private static final String MCH = "mch";
    @VisibleForTesting
    public static final String MCH = "mch";

    // incoming call history
    private static final String ICH = "ich";
    @VisibleForTesting
    public static final String ICH = "ich";

    // outgoing call history
    private static final String OCH = "och";
    @VisibleForTesting
    public static final String OCH = "och";

    // combined call history
    private static final String CCH = "cch";
    @VisibleForTesting
    public static final String CCH = "cch";

    // phone book
    private static final String PB = "pb";
    @VisibleForTesting
    public static final String PB = "pb";

    // favorites
    private static final String FAV = "fav";
    @VisibleForTesting
    public static final String FAV = "fav";

    private static final String TELECOM_PATH = "/telecom";
    @VisibleForTesting
    public static final String TELECOM_PATH = "/telecom";

    private static final String ICH_PATH = "/telecom/ich";
    @VisibleForTesting
    public static final String ICH_PATH = "/telecom/ich";

    private static final String OCH_PATH = "/telecom/och";
    @VisibleForTesting
    public static final String OCH_PATH = "/telecom/och";

    private static final String MCH_PATH = "/telecom/mch";
    @VisibleForTesting
    public static final String MCH_PATH = "/telecom/mch";

    private static final String CCH_PATH = "/telecom/cch";
    @VisibleForTesting
    public static final String CCH_PATH = "/telecom/cch";

    private static final String PB_PATH = "/telecom/pb";
    @VisibleForTesting
    public static final String PB_PATH = "/telecom/pb";

    private static final String FAV_PATH = "/telecom/fav";
    @VisibleForTesting
    public static final String FAV_PATH = "/telecom/fav";

    // SIM Support
    private static final String SIM_PATH = "/SIM1/telecom";
@@ -170,16 +186,19 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
    private static final String SIM_PB_PATH = "/SIM1/telecom/pb";

    // type for list vcard objects
    private static final String TYPE_LISTING = "x-bt/vcard-listing";
    @VisibleForTesting
    public static final String TYPE_LISTING = "x-bt/vcard-listing";

    // type for get single vcard object
    private static final String TYPE_VCARD = "x-bt/vcard";
    @VisibleForTesting
    public static final String TYPE_VCARD = "x-bt/vcard";

    // to indicate if need send body besides headers
    private static final int NEED_SEND_BODY = -1;

    // type for download all vcard objects
    private static final String TYPE_PB = "x-bt/phonebook";
    @VisibleForTesting
    public static final String TYPE_PB = "x-bt/phonebook";

    // The number of indexes in the phone book.
    private boolean mNeedPhonebookSize = false;
@@ -223,6 +242,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {

    private PbapStateMachine mStateMachine;

    private BluetoothPbapMethodProxy mPbapMethodProxy;

    private enum ContactsType {
        TYPE_PHONEBOOK , TYPE_SIM ;
    }
@@ -251,6 +272,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        mVcardManager = new BluetoothPbapVcardManager(mContext);
        mVcardSimManager = new BluetoothPbapSimVcardManager(mContext);
        mStateMachine = stateMachine;
        mPbapMethodProxy = BluetoothPbapMethodProxy.getInstance();
    }

    @Override
@@ -260,7 +282,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        }
        notifyUpdateWakeLock();
        try {
            byte[] uuid = (byte[]) request.getHeader(HeaderSet.TARGET);
            byte[] uuid = (byte[]) mPbapMethodProxy.getHeader(request, HeaderSet.TARGET);
            if (uuid == null) {
                return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
            }
@@ -285,7 +307,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        }

        try {
            byte[] remote = (byte[]) request.getHeader(HeaderSet.WHO);
            byte[] remote = (byte[]) mPbapMethodProxy.getHeader(request, HeaderSet.WHO);
            if (remote != null) {
                if (D) {
                    Log.d(TAG, "onConnect(): remote=" + Arrays.toString(remote));
@@ -300,7 +322,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        try {
            byte[] appParam = null;
            mConnAppParamValue = new AppParamValue();
            appParam = (byte[]) request.getHeader(HeaderSet.APPLICATION_PARAMETER);
            appParam = (byte[])
                    mPbapMethodProxy.getHeader(request, HeaderSet.APPLICATION_PARAMETER);
            if ((appParam != null) && !parseApplicationParameter(appParam, mConnAppParamValue)) {
                return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
            }
@@ -369,7 +392,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        String currentPathTmp = mCurrentPath;
        String tmpPath = null;
        try {
            tmpPath = (String) request.getHeader(HeaderSet.NAME);
            tmpPath = (String) mPbapMethodProxy.getHeader(request, HeaderSet.NAME);
        } catch (IOException e) {
            Log.e(TAG, "Get name header fail");
            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -385,10 +408,14 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        } else {
            if (tmpPath == null) {
                currentPathTmp = "";
            } else {
                if (tmpPath.startsWith("/")) {
                    currentPathTmp = currentPathTmp + tmpPath;
                } else {
                    currentPathTmp = currentPathTmp + "/" + tmpPath;
                }
            }
        }

        if ((currentPathTmp.length() != 0) && (!isLegalPath(currentPathTmp))) {
            if (create) {
@@ -424,9 +451,10 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        AppParamValue appParamValue = new AppParamValue();
        try {
            request = op.getReceivedHeader();
            type = (String) request.getHeader(HeaderSet.TYPE);
            name = (String) request.getHeader(HeaderSet.NAME);
            appParam = (byte[]) request.getHeader(HeaderSet.APPLICATION_PARAMETER);
            type = (String) mPbapMethodProxy.getHeader(request, HeaderSet.TYPE);
            name = (String) mPbapMethodProxy.getHeader(request, HeaderSet.NAME);
            appParam = (byte[]) mPbapMethodProxy.getHeader(
                    request, HeaderSet.APPLICATION_PARAMETER);
        } catch (IOException e) {
            Log.e(TAG, "request headers error");
            return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
@@ -445,7 +473,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
            return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
        }

        if (!mContext.getSystemService(UserManager.class).isUserUnlocked()) {
        if (!mPbapMethodProxy.getSystemService(mContext, UserManager.class).isUserUnlocked()) {
            Log.e(TAG, "Storage locked, " + type + " failed");
            return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
        }
@@ -608,7 +636,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        return false;
    }

    private class AppParamValue {
    @VisibleForTesting
    public static class AppParamValue {
        public int maxListCount;

        public int listStartOffset;
@@ -641,7 +670,7 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {

        public byte[] callHistoryVersionCounter;

        AppParamValue() {
        public AppParamValue() {
            maxListCount = 0xFFFF;
            listStartOffset = 0;
            searchValue = "";
@@ -1278,8 +1307,8 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                        appParamValue.ignorefilter ? null : appParamValue.propertySelector);
                return pushBytes(op, ownerVcard);
            } else {
                return mVcardSimManager.composeAndSendSIMPhonebookOneVcard(op, intIndex,
                        vcard21, null, mOrderBy);
                return BluetoothPbapSimVcardManager.composeAndSendSIMPhonebookOneVcard(
                        mContext, op, intIndex, vcard21, null, mOrderBy);
            }
        } else {
            if (intIndex <= 0 || intIndex > size) {
@@ -1396,12 +1425,12 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
                if (endPoint == 0) {
                    return pushBytes(op, ownerVcard);
                } else {
                    return mVcardSimManager.composeAndSendSIMPhonebookVcards(op, 1, endPoint,
                        vcard21, ownerVcard);
                    return BluetoothPbapSimVcardManager.composeAndSendSIMPhonebookVcards(
                            mContext, op, 1, endPoint, vcard21, ownerVcard);
                }
            } else {
                return mVcardSimManager.composeAndSendSIMPhonebookVcards(op, startPoint,
                        endPoint, vcard21, null);
                return BluetoothPbapSimVcardManager.composeAndSendSIMPhonebookVcards(
                        mContext, op, startPoint, endPoint, vcard21, null);
            }
        } else {
            return mVcardManager.composeAndSendSelectedCallLogVcards(appParamValue.needTag, op,
@@ -1590,4 +1619,15 @@ public class BluetoothPbapObexServer extends ServerRequestHandler {
        return ((ByteBuffer.wrap(mConnAppParamValue.supportedFeature).getInt() & featureBitMask)
                != 0);
    }

    @VisibleForTesting
    public void setCurrentPath(String path) {
        mCurrentPath = path != null ? path : "";
    }

    @VisibleForTesting
    public void setConnAppParamValue(AppParamValue connAppParamValue) {
        mConnAppParamValue = connAppParamValue;
    }

}
+5 −1
Original line number Diff line number Diff line
@@ -43,7 +43,6 @@ import android.bluetooth.BluetoothSocket;
import android.bluetooth.IBluetoothPbap;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -555,6 +554,11 @@ public class BluetoothPbapService extends ProfileService implements IObexConnect
        return sLocalPhoneNum;
    }

    @VisibleForTesting
    static void setLocalPhoneName(String localPhoneName) {
        sLocalPhoneName = localPhoneName;
    }

    static String getLocalPhoneName() {
        return sLocalPhoneName;
    }
Loading