gt:                 data = generateAdvertiseData(SCANNABLE_UUID, SCANNABLE_DATA);
context: /*
   * Copyright (C) 2013 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.cts.verifier.bluetooth;
  
  import java.util.UUID;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import android.app.Service;
  import android.bluetooth.BluetoothAdapter;
  import android.bluetooth.BluetoothGattServer;
  import android.bluetooth.BluetoothGattServerCallback;
  import android.bluetooth.BluetoothManager;
  import android.bluetooth.le.BluetoothLeAdvertiser;
  import android.bluetooth.le.AdvertiseCallback;
  import android.bluetooth.le.AdvertiseData;
  import android.bluetooth.le.AdvertiseSettings;
  import android.content.Context;
  import android.content.Intent;
  import android.os.Handler;
  import android.os.IBinder;
  import android.os.ParcelUuid;
  import android.util.Log;
  import android.widget.Toast;
  
  public class BleAdvertiserService extends Service {
  
      public static final boolean DEBUG = true;
      public static final String TAG = "BleAdvertiserService";
  
      public static final int COMMAND_START_ADVERTISE = 0;
      public static final int COMMAND_STOP_ADVERTISE = 1;
      public static final int COMMAND_START_POWER_LEVEL = 2;
      public static final int COMMAND_STOP_POWER_LEVEL = 3;
      public static final int COMMAND_START_SCANNABLE = 4;
      public static final int COMMAND_STOP_SCANNABLE = 5;
      public static final int COMMAND_START_UNSCANNABLE = 6;
      public static final int COMMAND_STOP_UNSCANNABLE = 7;
  
      public static final String BLE_ADV_NOT_SUPPORT =
              "com.android.cts.verifier.bluetooth.BLE_ADV_NOT_SUPPORT";
      public static final String BLE_START_ADVERTISE =
              "com.android.cts.verifier.bluetooth.BLE_START_ADVERTISE";
      public static final String BLE_STOP_ADVERTISE =
              "com.android.cts.verifier.bluetooth.BLE_STOP_ADVERTISE";
      public static final String BLE_START_POWER_LEVEL =
              "com.android.cts.verifier.bluetooth.BLE_START_POWER_LEVEL";
      public static final String BLE_STOP_POWER_LEVEL =
              "com.android.cts.verifier.bluetooth.BLE_STOP_POWER_LEVEL";
      public static final String BLE_START_SCANNABLE =
              "com.android.cts.verifier.bluetooth.BLE_START_SCANNABLE";
      public static final String BLE_START_UNSCANNABLE =
              "com.android.cts.verifier.bluetooth.BLE_START_UNSCANNABLE";
      public static final String BLE_STOP_SCANNABLE =
              "com.android.cts.verifier.bluetooth.BLE_STOP_SCANNABLE";
      public static final String BLE_STOP_UNSCANNABLE =
              "com.android.cts.verifier.bluetooth.BLE_STOP_UNSCANNABLE";
  
      public static final String EXTRA_COMMAND =
              "com.android.cts.verifier.bluetooth.EXTRA_COMMAND";
  
      protected static final UUID PRIVACY_MAC_UUID =
              UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
      protected static final UUID POWER_LEVEL_UUID =
              UUID.fromString("00008888-0000-1000-8000-00805f9b34fb");
      protected static final UUID SCAN_RESP_UUID =
              UUID.fromString("00007777-0000-1000-8000-00805f9b34fb");
      protected static final UUID SCANNABLE_UUID =
              UUID.fromString("00006666-0000-1000-8000-00805f9b34fb");
      protected static final UUID UNSCANNABLE_UUID =
              UUID.fromString("00005555-0000-1000-8000-00805f9b34fb");
  
      public static final byte MANUFACTURER_TEST_ID = (byte)0x07;
      public static final byte[] PRIVACY_MAC_DATA = new byte[]{3, 1, 4};
      public static final byte[] PRIVACY_RESPONSE = new byte[]{9, 2, 6};
      public static final byte[] POWER_LEVEL_DATA = new byte[]{1, 5, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0};  // 15 bytes
      public static final byte[] POWER_LEVEL_MASK = new byte[]{1, 1, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0};  // 15 bytes
      public static final int POWER_LEVEL_DATA_LENGTH = 15;
      public static final byte[] SCANNABLE_DATA = new byte[]{5, 3, 5};
      public static final byte[] UNSCANNABLE_DATA = new byte[]{8, 9, 7};
  
      private BluetoothManager mBluetoothManager;
      private BluetoothAdapter mBluetoothAdapter;
      private BluetoothLeAdvertiser mAdvertiser;
      private BluetoothGattServer mGattServer;
      private AdvertiseCallback mCallback;
      private Handler mHandler;
  
      private int[] mPowerLevel;
      private Map<Integer, AdvertiseCallback> mPowerCallback;
      private int mAdvertiserStatus;
  
      private AdvertiseCallback mScannableCallback;
      private AdvertiseCallback mUnscannableCallback;
  
      @Override
      public void onCreate() {
          super.onCreate();
  
          mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
          mBluetoothAdapter = mBluetoothManager.getAdapter();
          mAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
          mGattServer = mBluetoothManager.openGattServer(getApplicationContext(),
              new BluetoothGattServerCallback() {});
          mHandler = new Handler();
          mAdvertiserStatus = 0;
  
          mCallback = new BLEAdvertiseCallback();
          mScannableCallback = new BLEAdvertiseCallback();
          mUnscannableCallback = new BLEAdvertiseCallback();
          mPowerLevel = new int[]{
              AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
              AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
              AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
              AdvertiseSettings.ADVERTISE_TX_POWER_HIGH};
          mPowerCallback = new HashMap<Integer, AdvertiseCallback>();
          for (int x : mPowerLevel) {
              mPowerCallback.put(x, new BLEAdvertiseCallback());
          }
      }
  
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
          if (intent != null) handleIntent(intent);
          return START_NOT_STICKY;
      }
  
      @Override
      public IBinder onBind(Intent intent) {
          return null;
      }
  
      @Override
      public void onDestroy() {
          super.onDestroy();
          if (mAdvertiser != null) {
              stopAdvertiser();
          }
      }
  
      private void stopAdvertiser() {
          if (mAdvertiser == null) {
              mAdvertiserStatus = 0;
              return;
          }
          if ((mAdvertiserStatus & (1 << COMMAND_START_ADVERTISE)) > 0) {
              mAdvertiser.stopAdvertising(mCallback);
          }
          if ((mAdvertiserStatus & (1 << COMMAND_START_POWER_LEVEL)) > 0) {
              for (int t : mPowerLevel) {
                  mAdvertiser.stopAdvertising(mPowerCallback.get(t));
              }
          }
          if ((mAdvertiserStatus & (1 << COMMAND_START_SCANNABLE)) > 0) {
              mAdvertiser.stopAdvertising(mScannableCallback);
          }
          if ((mAdvertiserStatus & (1 << COMMAND_START_UNSCANNABLE)) > 0) {
              mAdvertiser.stopAdvertising(mUnscannableCallback);
          }
          mAdvertiserStatus = 0;
      }
  
      private AdvertiseData generateAdvertiseData(UUID uuid, byte[] data) {
          return new AdvertiseData.Builder()
              .addManufacturerData(MANUFACTURER_TEST_ID, new byte[]{MANUFACTURER_TEST_ID, 0})
              .addServiceData(new ParcelUuid(uuid), data)
              .setIncludeTxPowerLevel(true)
              .build();
      }
  
      private AdvertiseSettings generateSetting(int power) {
          return new AdvertiseSettings.Builder()
              .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
              .setTxPowerLevel(power)
              .setConnectable(false)
              .build();
      }
  
      private void handleIntent(Intent intent) {
          if (mBluetoothAdapter != null && !mBluetoothAdapter.isMultipleAdvertisementSupported()) {
              showMessage("Multiple advertisement is not supported.");
              sendBroadcast(new Intent(BLE_ADV_NOT_SUPPORT));
              return;
          } else if (mAdvertiser == null) {
              showMessage("Cannot start advertising on this device.");
              return;
          }
          int command = intent.getIntExtra(EXTRA_COMMAND, -1);
          if (command >= 0) {
              stopAdvertiser();
              mAdvertiserStatus |= (1 << command);
          }
  
          switch (command) {
              case COMMAND_START_ADVERTISE:
                  AdvertiseData data = generateAdvertiseData(PRIVACY_MAC_UUID, PRIVACY_MAC_DATA);
                  AdvertiseData response = generateAdvertiseData(SCAN_RESP_UUID, PRIVACY_RESPONSE);
                  AdvertiseSettings setting =
                          generateSetting(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM);
  
                  mAdvertiser.startAdvertising(setting, data, response, mCallback);
                  sendBroadcast(new Intent(BLE_START_ADVERTISE));
                  break;
              case COMMAND_STOP_ADVERTISE:
                  sendBroadcast(new Intent(BLE_STOP_ADVERTISE));
                  break;
              case COMMAND_START_POWER_LEVEL:
                  for (int t : mPowerLevel) {
                      // Service data:
                      //    field overhead = 2 bytes
                      //    uuid = 2 bytes
                      //    data = 15 bytes
                      // Manufacturer data:
                      //    field overhead = 2 bytes
                      //    Specific data length = 2 bytes
                      //    data length = 2 bytes
                      // Include power level:
                      //    field overhead = 2 bytes
                      //    1 byte
                      // Connectable flag: 3 bytes (0 byte for Android 5.1+)
                      // SUM = 31 bytes
                      byte[] dataBytes = new byte[POWER_LEVEL_DATA_LENGTH];
                      dataBytes[0] = 0x01;
                      dataBytes[1] = 0x05;
                      for (int i = 2; i < POWER_LEVEL_DATA_LENGTH; i++) {
                          dataBytes[i] = (byte)t;
                      }
                      AdvertiseData d = generateAdvertiseData(POWER_LEVEL_UUID, dataBytes);
                      AdvertiseSettings settings = generateSetting(t);
                      mAdvertiser.startAdvertising(settings, d, mPowerCallback.get(t));
                  }
                  sendBroadcast(new Intent(BLE_START_POWER_LEVEL));
                  break;
              case COMMAND_STOP_POWER_LEVEL:
                  sendBroadcast(new Intent(BLE_STOP_POWER_LEVEL));
                  break;
              case COMMAND_START_SCANNABLE:
  