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

Commit 075e3af1 authored by Wei Wang's avatar Wei Wang Committed by Android Git Automerger
Browse files

am a13cc281: Merge "Add an AdvertiseManager for LE advertise operations." into lmp-dev

* commit 'a13cc281':
  Add an AdvertiseManager for LE advertise operations.
parents 9cc4edd2 a13cc281
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -833,10 +833,10 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
    method_onScanFilterConfig = env->GetMethodID(clazz, "onScanFilterConfig", "(IIIII)V");
    method_onScanFilterParamsConfigured = env->GetMethodID(clazz, "onScanFilterParamsConfigured", "(IIII)V");
    method_onScanFilterEnableDisabled = env->GetMethodID(clazz, "onScanFilterEnableDisabled", "(III)V");
    method_onMultiAdvEnable = env->GetMethodID(clazz, "onClientEnable", "(II)V");
    method_onMultiAdvUpdate = env->GetMethodID(clazz, "onClientUpdate", "(II)V");
    method_onMultiAdvSetAdvData = env->GetMethodID(clazz, "onClientData", "(II)V");
    method_onMultiAdvDisable = env->GetMethodID(clazz, "onClientDisable", "(II)V");
    method_onMultiAdvEnable = env->GetMethodID(clazz, "onAdvertiseInstanceEnabled", "(II)V");
    method_onMultiAdvUpdate = env->GetMethodID(clazz, "onAdvertiseDataUpdated", "(II)V");
    method_onMultiAdvSetAdvData = env->GetMethodID(clazz, "onAdvertiseDataSet", "(II)V");
    method_onMultiAdvDisable = env->GetMethodID(clazz, "onAdvertiseInstanceDisabled", "(II)V");
    method_onClientCongestion = env->GetMethodID(clazz, "onClientCongestion", "(IZ)V");
    method_onBatchScanStorageConfigured = env->GetMethodID(clazz, "onBatchScanStorageConfigured", "(II)V");
    method_onBatchScanStartStopped = env->GetMethodID(clazz, "onBatchScanStartStopped", "(III)V");
@@ -1709,6 +1709,14 @@ static void gattTestNative(JNIEnv *env, jobject object, jint command,
 * JNI function definitinos
 */

// JNI functions defined in AdvertiseManager class.
static JNINativeMethod sAdvertiseMethods[] = {
    {"gattClientEnableAdvNative", "(IIIIII)V", (void *) gattClientEnableAdvNative},
    {"gattClientUpdateAdvNative", "(IIIIII)V", (void *) gattClientUpdateAdvNative},
    {"gattClientSetAdvDataNative", "(IZZZI[B[B[B)V", (void *) gattClientSetAdvDataNative},
    {"gattClientDisableAdvNative", "(I)V", (void *) gattClientDisableAdvNative},
};

// JNI functions defined in GattStateMachine class.
static JNINativeMethod sStateMachineMethods[] = {
    {"gattClientScanNative", "(Z)V", (void *) gattClientScanNative},
@@ -1722,10 +1730,6 @@ static JNINativeMethod sStateMachineMethods[] = {
    {"gattClientScanFilterDeleteNative", "(IIIIIJJJJLjava/lang/String;Ljava/lang/String;B[B[B)V", (void *) gattClientScanFilterDeleteNative},
    {"gattClientScanFilterClearNative", "(II)V", (void *) gattClientScanFilterClearNative},
    {"gattClientScanFilterEnableNative", "(IZ)V", (void *) gattClientScanFilterEnableNative},
    {"gattClientEnableAdvNative", "(IIIIII)V", (void *) gattClientEnableAdvNative},
    {"gattClientUpdateAdvNative", "(IIIIII)V", (void *) gattClientUpdateAdvNative},
    {"gattClientSetAdvDataNative", "(IZZZI[B[B[B)V", (void *) gattClientSetAdvDataNative},
    {"gattClientDisableAdvNative", "(I)V", (void *) gattClientDisableAdvNative},
};

// JNI functions defined in GattService class.
@@ -1779,6 +1783,9 @@ int register_com_android_bluetooth_gatt(JNIEnv* env)
    int register_success =
        jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/GattServiceStateMachine",
                sStateMachineMethods, NELEM(sStateMachineMethods));
    register_success &=
        jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/AdvertiseManager$AdvertiseNative",
                sAdvertiseMethods, NELEM(sAdvertiseMethods));
    return register_success &
        jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/GattService",
                sMethods, NELEM(sMethods));
+40 −20
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.bluetooth;
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ContextWrapper;
import android.os.Binder;
import android.os.ParcelUuid;
import android.os.UserHandle;
@@ -41,7 +42,7 @@ final public class Utils {
    static final int BD_UUID_LEN = 16; // bytes

    public static String getAddressStringFromByte(byte[] address) {
        if (address == null || address.length !=6) {
        if (address == null || address.length != BD_ADDR_LEN) {
            return null;
        }

@@ -60,7 +61,7 @@ final public class Utils {

        for (i = 0; i < address.length(); i++) {
            if (address.charAt(i) != ':') {
                output[j] = (byte) Integer.parseInt(address.substring(i, i+2), 16);
                output[j] = (byte) Integer.parseInt(address.substring(i, i + 2), BD_UUID_LEN);
                j++;
                i++;
            }
@@ -115,8 +116,8 @@ final public class Utils {
            uuid = uuids[i].getUuid();
            msb = uuid.getMostSignificantBits();
            lsb = uuid.getLeastSignificantBits();
            converter.putLong(i * 16, msb);
            converter.putLong(i * 16 + 8, lsb);
            converter.putLong(i * BD_UUID_LEN, msb);
            converter.putLong(i * BD_UUID_LEN + 8, lsb);
        }
        return converter.array();
    }
@@ -133,22 +134,28 @@ final public class Utils {
        for (int i = 0; i < numUuids; i++) {
            puuids[i] = new ParcelUuid(new UUID(converter.getLong(offset),
                    converter.getLong(offset + 8)));
            offset += 16;
            offset += BD_UUID_LEN;
        }
        return puuids;
    }

    public static String debugGetAdapterStateString(int state) {
        switch (state) {
            case BluetoothAdapter.STATE_OFF : return "STATE_OFF";
            case BluetoothAdapter.STATE_ON : return "STATE_ON";
            case BluetoothAdapter.STATE_TURNING_ON : return "STATE_TURNING_ON";
            case BluetoothAdapter.STATE_TURNING_OFF : return "STATE_TURNING_OFF";
            default : return "UNKNOWN";
            case BluetoothAdapter.STATE_OFF:
                return "STATE_OFF";
            case BluetoothAdapter.STATE_ON:
                return "STATE_ON";
            case BluetoothAdapter.STATE_TURNING_ON:
                return "STATE_TURNING_ON";
            case BluetoothAdapter.STATE_TURNING_OFF:
                return "STATE_TURNING_OFF";
            default:
                return "UNKNOWN";
        }
    }

    public static void copyStream(InputStream is, OutputStream os, int bufferSize) throws IOException {
    public static void copyStream(InputStream is, OutputStream os, int bufferSize)
            throws IOException {
        if (is != null && os != null) {
            byte[] buffer = new byte[bufferSize];
            int bytesRead = 0;
@@ -197,4 +204,17 @@ final public class Utils {
        }
        return ok;
    }

    /**
     * Enforce the context has android.Manifest.permission.BLUETOOTH_ADMIN permission. A
     * {@link SecurityException} would be thrown if neither the calling process or the application
     * does not have BLUETOOTH_ADMIN permission.
     *
     * @param context Context for the permission check.
     */
    public static void enforceAdminPermission(ContextWrapper context) {
        context.enforceCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_ADMIN,
                "Need BLUETOOTH_ADMIN permission");
    }

}
+36 −2
Original line number Diff line number Diff line
@@ -20,7 +20,11 @@ import android.annotation.Nullable;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;

import java.util.Objects;

/**
 * Helper class that represents a client for Bluetooth LE advertise operations.
 *
 * @hide
 */
class AdvertiseClient {
@@ -30,11 +34,41 @@ class AdvertiseClient {
    @Nullable
    AdvertiseData scanResponse;

    AdvertiseClient(int clientIf, AdvertiseSettings settings, AdvertiseData data,
    /**
     * @param clientIf - Identifier of the client.
     */
    public AdvertiseClient(int clientIf) {
        this.clientIf = clientIf;
    }

    /**
     * @param clientIf - Identifier of the client.
     * @param settings - Settings for the advertising.
     * @param advertiseData - Advertise data broadcasted over the air.
     * @param scanResponse - Response of scan request, could be null.
     */
    AdvertiseClient(int clientIf, AdvertiseSettings settings, AdvertiseData advertiseData,
            AdvertiseData scanResponse) {
        this.clientIf = clientIf;
        this.settings = settings;
        this.advertiseData = data;
        this.advertiseData = advertiseData;
        this.scanResponse = scanResponse;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        AdvertiseClient other = (AdvertiseClient) obj;
        return clientIf == other.clientIf;
    }

    @Override
    public int hashCode() {
        return Objects.hash(clientIf);
    }
}
+429 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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.gatt;

import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;

import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Manages Bluetooth LE advertising operations and interacts with bluedroid stack.
 *
 * @hide
 */
class AdvertiseManager {
    private static final boolean DBG = GattServiceConfig.DBG;
    private static final String TAG = GattServiceConfig.TAG_PREFIX + "AdvertiseManager";

    // Timeout for each controller operation.
    private static final int OPERATION_TIME_OUT_MILLIS = 500;

    // Message for advertising operations.
    private static final int MSG_START_ADVERTISING = 0;
    private static final int MSG_STOP_ADVERTISING = 1;

    private final GattService mService;
    private final Set<AdvertiseClient> mAdvertiseClients;
    private final AdvertiseNative mAdvertiseNative;

    // Handles advertise operations.
    private ClientHandler mHandler;

    // CountDownLatch for blocking advertise operations.
    private CountDownLatch mLatch;

    /**
     * Constructor of {@link AdvertiseManager}.
     */
    AdvertiseManager(GattService service) {
        mService = service;
        logd("advertise manager created");
        mAdvertiseClients = new HashSet<AdvertiseClient>();
        mAdvertiseNative = new AdvertiseNative();
    }

    /**
     * Start a {@link HandlerThread} that handles advertising operations.
     */
    void start() {
        HandlerThread thread = new HandlerThread("BluetoothAdvertiseManager");
        thread.start();
        mHandler = new ClientHandler(thread.getLooper());
    }

    void cleanup() {
        logd("advertise clients cleared");
        mAdvertiseClients.clear();
    }

    /**
     * Start BLE advertising.
     *
     * @param client Advertise client.
     */
    void startAdvertising(AdvertiseClient client) {
        if (client == null) {
            return;
        }
        Message message = new Message();
        message.what = MSG_START_ADVERTISING;
        message.obj = client;
        mHandler.sendMessage(message);
    }

    /**
     * Stop BLE advertising.
     */
    void stopAdvertising(AdvertiseClient client) {
        if (client == null) {
            return;
        }
        Message message = new Message();
        message.what = MSG_STOP_ADVERTISING;
        message.obj = client;
        mHandler.sendMessage(message);
    }

    /**
     * Signals the callback is received.
     *
     * @param clientIf Identifier for the client.
     * @param status Status of the callback.
     */
    void callbackDone(int clientIf, int status) {
        if (status == AdvertiseCallback.ADVERTISE_SUCCESS) {
            mLatch.countDown();
        } else {
            // Note in failure case we'll wait for the latch to timeout(which takes 100ms) and
            // the mClientHandler thread will be blocked till timeout.
            postCallback(clientIf, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
        }
    }

    // Post callback status to app process.
    private void postCallback(int clientIf, int status) {
        try {
            mService.onMultipleAdvertiseCallback(clientIf, status);
        } catch (RemoteException e) {
            loge("failed onMultipleAdvertiseCallback", e);
        }
    }

    // Handler class that handles BLE advertising operations.
    private class ClientHandler extends Handler {

        ClientHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            logd("message : " + msg.what);
            AdvertiseClient client = (AdvertiseClient) msg.obj;
            switch (msg.what) {
                case MSG_START_ADVERTISING:
                    handleStartAdvertising(client);
                    break;
                case MSG_STOP_ADVERTISING:
                    handleStopAdvertising(client);
                    break;
                default:
                    // Shouldn't happen.
                    Log.e(TAG, "recieve an unknown message : " + msg.what);
                    break;
            }
        }

        private void handleStartAdvertising(AdvertiseClient client) {
            Utils.enforceAdminPermission(mService);
            int clientIf = client.clientIf;
            if (mAdvertiseClients.contains(clientIf)) {
                postCallback(clientIf, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
                return;
            }

            if (mAdvertiseClients.size() >= maxAdvertiseInstances()) {
                postCallback(clientIf,
                        AdvertiseCallback.ADVERTISE_FAILED_TOO_MANY_ADVERTISERS);
                return;
            }

            if (!isAllServiceRegistered(client)) {
                postCallback(clientIf, AdvertiseCallback.ADVERTISE_FAILED_SERVICE_UNKNOWN);
            }
            if (!mAdvertiseNative.startAdverising(client)) {
                postCallback(clientIf, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
                return;
            }
            mAdvertiseClients.add(client);
            postCallback(clientIf, AdvertiseCallback.ADVERTISE_SUCCESS);
        }

        // Handles stop advertising.
        private void handleStopAdvertising(AdvertiseClient client) {
            Utils.enforceAdminPermission(mService);
            if (client == null) {
                return;
            }
            int clientIf = client.clientIf;
            logd("advertise clients size " + mAdvertiseClients.size());
            if (mAdvertiseClients.contains(client)) {
                mAdvertiseNative.stopAdvertising(client);
                mAdvertiseClients.remove(clientIf);
            }
        }

        // Returns maximum advertise instances supported by controller.
        private int maxAdvertiseInstances() {
            AdapterService adapter = AdapterService.getAdapterService();
            int numOfAdvtInstances = adapter.getNumOfAdvertisementInstancesSupported();
            // Note numOfAdvtInstances includes the standard advertising instance.
            // TODO: remove - 1 once the stack is able to include standard instance for multiple
            // advertising.
            return numOfAdvtInstances - 1;
        }

        // Check whether all service uuids have been registered to GATT server.
        private boolean isAllServiceRegistered(AdvertiseClient client) {
            List<ParcelUuid> registeredUuids = mService.getRegisteredServiceUuids();
            return containsAll(registeredUuids, client.advertiseData) &&
                    containsAll(registeredUuids, client.scanResponse);
        }

        // Check whether the registeredUuids contains all uuids in advertiseData.
        private boolean containsAll(List<ParcelUuid> registeredUuids, AdvertiseData advertiseData) {
            if (advertiseData == null) {
                return true;
            }
            List<ParcelUuid> advertiseUuids = advertiseData.getServiceUuids();
            if (advertiseUuids == null) {
                return true;
            }
            return registeredUuids.containsAll(advertiseUuids);
        }
    }

    // Class that wraps advertise native related constants, methods etc.
    private class AdvertiseNative {
        // Advertise interval for different modes.
        private static final int ADVERTISING_INTERVAL_HIGH_MILLS = 1000;
        private static final int ADVERTISING_INTERVAL_MEDIUM_MILLS = 250;
        private static final int ADVERTISING_INTERVAL_LOW_MILLS = 100;

        // Add some randomness to the advertising min/max interval so the controller can do some
        // optimization.
        private static final int ADVERTISING_INTERVAL_DELTA_UNIT = 10;
        private static final int ADVERTISING_INTERVAL_MICROS_PER_UNIT = 625;

        // The following constants should be kept the same as those defined in bt stack.
        private static final int ADVERTISING_CHANNEL_37 = 1 << 0;
        private static final int ADVERTISING_CHANNEL_38 = 1 << 1;
        private static final int ADVERTISING_CHANNEL_39 = 1 << 2;
        private static final int ADVERTISING_CHANNEL_ALL =
                ADVERTISING_CHANNEL_37 | ADVERTISING_CHANNEL_38 | ADVERTISING_CHANNEL_39;

        private static final int ADVERTISING_TX_POWER_MIN = 0;
        private static final int ADVERTISING_TX_POWER_LOW = 1;
        private static final int ADVERTISING_TX_POWER_MID = 2;
        private static final int ADVERTISING_TX_POWER_UPPER = 3;
        // Note this is not exposed to the Java API.
        private static final int ADVERTISING_TX_POWER_MAX = 4;

        // Note we don't expose connectable directed advertising to API.
        private static final int ADVERTISING_EVENT_TYPE_CONNECTABLE = 0;
        private static final int ADVERTISING_EVENT_TYPE_SCANNABLE = 2;
        private static final int ADVERTISING_EVENT_TYPE_NON_CONNECTABLE = 3;

        boolean startAdverising(AdvertiseClient client) {
            int clientIf = client.clientIf;
            resetCountDownLatch();
            mAdvertiseNative.enableAdvertising(client);
            if (!waitForCallback()) {
                return false;
            }
            resetCountDownLatch();
            mAdvertiseNative.setAdvertisingData(clientIf, client.advertiseData, false);
            if (!waitForCallback()) {
                return false;
            }
            if (client.scanResponse != null) {
                resetCountDownLatch();
                mAdvertiseNative.setAdvertisingData(clientIf, client.scanResponse, true);
                if (!waitForCallback()) {
                    return false;
                }
            }
            return true;
        }

        void stopAdvertising(AdvertiseClient client) {
            gattClientDisableAdvNative(client.clientIf);
        }

        private void resetCountDownLatch() {
            mLatch = new CountDownLatch(1);
        }

        // Returns true if mLatch reaches 0, false if timeout or interrupted.
        private boolean waitForCallback() {
            try {
                return mLatch.await(OPERATION_TIME_OUT_MILLIS, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                return false;
            }
        }

        private void enableAdvertising(AdvertiseClient client) {
            int clientIf = client.clientIf;
            int minAdvertiseUnit = (int) getAdvertisingIntervalUnit(client.settings);
            int maxAdvertiseUnit = minAdvertiseUnit + ADVERTISING_INTERVAL_DELTA_UNIT;
            int advertiseEventType = getAdvertisingEventType(client);
            int txPowerLevel = getTxPowerLevel(client.settings);
            gattClientEnableAdvNative(
                    clientIf,
                    minAdvertiseUnit, maxAdvertiseUnit,
                    advertiseEventType,
                    ADVERTISING_CHANNEL_ALL,
                    txPowerLevel);
        }

        private void setAdvertisingData(int clientIf, AdvertiseData data, boolean isScanResponse) {
            if (data == null) {
                return;
            }
            boolean includeName = true;
            boolean includeTxPower = data.getIncludeTxPowerLevel();
            int appearance = 0;
            byte[] manufacturerData = data.getManufacturerSpecificData() == null ? new byte[0]
                    : data.getManufacturerSpecificData();
            byte[] serviceData = data.getServiceData() == null ? new byte[0]
                    : data.getServiceData();

            byte[] serviceUuids;
            if (data.getServiceUuids() == null) {
                serviceUuids = new byte[0];
            } else {
                ByteBuffer advertisingUuidBytes = ByteBuffer.allocate(
                        data.getServiceUuids().size() * 16)
                        .order(ByteOrder.LITTLE_ENDIAN);
                for (ParcelUuid parcelUuid : data.getServiceUuids()) {
                    UUID uuid = parcelUuid.getUuid();
                    // Least significant bits first as the advertising uuid should be in
                    // little-endian.
                    advertisingUuidBytes.putLong(uuid.getLeastSignificantBits())
                            .putLong(uuid.getMostSignificantBits());
                }
                serviceUuids = advertisingUuidBytes.array();
            }
            gattClientSetAdvDataNative(clientIf, isScanResponse, includeName, includeTxPower,
                    appearance,
                    manufacturerData, serviceData, serviceUuids);
        }

        // Convert settings tx power level to stack tx power level.
        private int getTxPowerLevel(AdvertiseSettings settings) {
            switch (settings.getTxPowerLevel()) {
                case AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW:
                    return ADVERTISING_TX_POWER_MIN;
                case AdvertiseSettings.ADVERTISE_TX_POWER_LOW:
                    return ADVERTISING_TX_POWER_LOW;
                case AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM:
                    return ADVERTISING_TX_POWER_MID;
                case AdvertiseSettings.ADVERTISE_TX_POWER_HIGH:
                    return ADVERTISING_TX_POWER_UPPER;
                default:
                    // Shouldn't happen, just in case.
                    return ADVERTISING_TX_POWER_MID;
            }
        }

        // Convert advertising event type to stack values.
        private int getAdvertisingEventType(AdvertiseClient client) {
            AdvertiseSettings settings = client.settings;
            if (settings.getIsConnectable()) {
                return ADVERTISING_EVENT_TYPE_CONNECTABLE;
            }
            return client.scanResponse == null ? ADVERTISING_EVENT_TYPE_NON_CONNECTABLE
                    : ADVERTISING_EVENT_TYPE_SCANNABLE;
        }

        // Convert advertising milliseconds to advertising units(one unit is 0.625 millisecond).
        private long getAdvertisingIntervalUnit(AdvertiseSettings settings) {
            switch (settings.getMode()) {
                case AdvertiseSettings.ADVERTISE_MODE_LOW_POWER:
                    return millsToUnit(ADVERTISING_INTERVAL_HIGH_MILLS);
                case AdvertiseSettings.ADVERTISE_MODE_BALANCED:
                    return millsToUnit(ADVERTISING_INTERVAL_MEDIUM_MILLS);
                case AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY:
                    return millsToUnit(ADVERTISING_INTERVAL_LOW_MILLS);
                default:
                    // Shouldn't happen, just in case.
                    return millsToUnit(ADVERTISING_INTERVAL_HIGH_MILLS);
            }
        }

        private long millsToUnit(int millisecond) {
            return TimeUnit.MILLISECONDS.toMicros(millisecond)
                    / ADVERTISING_INTERVAL_MICROS_PER_UNIT;
        }

        // Native functions
        private native void gattClientDisableAdvNative(int client_if);

        private native void gattClientEnableAdvNative(int client_if,
                int min_interval, int max_interval, int adv_type, int chnl_map,
                int tx_power);

        private native void gattClientUpdateAdvNative(int client_if,
                int min_interval, int max_interval, int adv_type, int chnl_map,
                int tx_power);

        private native void gattClientSetAdvDataNative(int client_if,
                boolean set_scan_rsp, boolean incl_name, boolean incl_txpower, int appearance,
                byte[] manufacturer_data, byte[] service_data, byte[] service_uuid);
    }

    private void logd(String s) {
        if (DBG) {
            Log.d(TAG, s);
        }
    }

    private void loge(String s, Exception e) {
        Log.e(TAG, s, e);
    }

}
+42 −61

File changed.

Preview size limit exceeded, changes collapsed.

Loading