content: /*
   * Copyright (C) 2009 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 android.bluetooth;
  
  import android.annotation.UnsupportedAppUsage;
  import android.os.Build;
  import android.os.ParcelUuid;
  
  import java.nio.ByteBuffer;
  import java.nio.ByteOrder;
  import java.util.Arrays;
  import java.util.HashSet;
  import java.util.UUID;
  
  /**
   * Static helper methods and constants to decode the ParcelUuid of remote devices.
   *
   * @hide
   */
  public final class BluetoothUuid {
  
      /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
       * for the various services.
       *
       * The following 128 bit values are calculated as:
       *  uuid * 2^96 + BASE_UUID
       */
      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
      public static final ParcelUuid AudioSink =
              ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid AudioSource =
              ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
      public static final ParcelUuid AdvAudioDist =
              ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
      public static final ParcelUuid HSP =
              ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid HSP_AG =
              ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
      @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
      public static final ParcelUuid Handsfree =
              ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid Handsfree_AG =
              ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid AvrcpController =
              ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid AvrcpTarget =
              ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
      @UnsupportedAppUsage
      public static final ParcelUuid ObexObjectPush =
              ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
      public static final ParcelUuid Hid =
              ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
      @UnsupportedAppUsage
      public static final ParcelUuid Hogp =
              ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
      public static final ParcelUuid PANU =
              ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
      @UnsupportedAppUsage
      public static final ParcelUuid NAP =
              ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid BNEP =
              ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid PBAP_PCE =
              ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
      @UnsupportedAppUsage
      public static final ParcelUuid PBAP_PSE =
              ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid MAP =
              ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid MNS =
              ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid MAS =
              ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid SAP =
              ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
      public static final ParcelUuid HearingAid =
              ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
  
      public static final ParcelUuid BASE_UUID =
              ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
  
      /** Length of bytes for 16 bit UUID */
      public static final int UUID_BYTES_16_BIT = 2;
      /** Length of bytes for 32 bit UUID */
      public static final int UUID_BYTES_32_BIT = 4;
      /** Length of bytes for 128 bit UUID */
      public static final int UUID_BYTES_128_BIT = 16;
  
      @UnsupportedAppUsage
      public static final ParcelUuid[] RESERVED_UUIDS = {
              AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
              ObexObjectPush, PANU, NAP, MAP, MNS, MAS, SAP};
  
      @UnsupportedAppUsage
      public static boolean isAudioSource(ParcelUuid uuid) {
          return uuid.equals(AudioSource);
      }
  
      public static boolean isAudioSink(ParcelUuid uuid) {
          return uuid.equals(AudioSink);
      }
  
      @UnsupportedAppUsage
      public static boolean isAdvAudioDist(ParcelUuid uuid) {
          return uuid.equals(AdvAudioDist);
      }
  
      public static boolean isHandsfree(ParcelUuid uuid) {
          return uuid.equals(Handsfree);
      }
  
      public static boolean isHeadset(ParcelUuid uuid) {
          return uuid.equals(HSP);
      }
  
      public static boolean isAvrcpController(ParcelUuid uuid) {
          return uuid.equals(AvrcpController);
      }
  
      @UnsupportedAppUsage
      public static boolean isAvrcpTarget(ParcelUuid uuid) {
          return uuid.equals(AvrcpTarget);
      }
  
      public static boolean isInputDevice(ParcelUuid uuid) {
          return uuid.equals(Hid);
      }
  
      public static boolean isPanu(ParcelUuid uuid) {
          return uuid.equals(PANU);
      }
  
      public static boolean isNap(ParcelUuid uuid) {
          return uuid.equals(NAP);
      }
  
      public static boolean isBnep(ParcelUuid uuid) {
          return uuid.equals(BNEP);
      }
  
      public static boolean isMap(ParcelUuid uuid) {
          return uuid.equals(MAP);
      }
  
      public static boolean isMns(ParcelUuid uuid) {
          return uuid.equals(MNS);
      }
  
      public static boolean isMas(ParcelUuid uuid) {
          return uuid.equals(MAS);
      }
  
      public static boolean isSap(ParcelUuid uuid) {
          return uuid.equals(SAP);
      }
  
      /**
       * Returns true if ParcelUuid is present in uuidArray
       *
       * @param uuidArray - Array of ParcelUuids
       * @param uuid
       */
      @UnsupportedAppUsage
      public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
          if ((uuidArray == null || uuidArray.length == 0) && uuid == null) {
              return true;
          }
  
          if (uuidArray == null) {
              return false;
          }
  
          for (ParcelUuid element : uuidArray) {
              if (element.equals(uuid)) return true;
          }
          return false;
      }
  
      /**
       * Returns true if there any common ParcelUuids in uuidA and uuidB.
       *
       * @param uuidA - List of ParcelUuids
       * @param uuidB - List of ParcelUuids
       */
      @UnsupportedAppUsage
      public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
          if (uuidA == null && uuidB == null) return true;
  
          if (uuidA == null) {
              return uuidB.length == 0;
          }
  
          if (uuidB == null) {
              return uuidA.length == 0;
          }
  
          HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA));
          for (ParcelUuid uuid : uuidB) {
              if (uuidSet.contains(uuid)) return true;
          }
          return false;
      }
  
      /**
       * Returns true if all the ParcelUuids in ParcelUuidB are present in
       * ParcelUuidA
       *
       * @param uuidA - Array of ParcelUuidsA
       * @param uuidB - Array of ParcelUuidsB
       */
      public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
          if (uuidA == null && uuidB == null) return true;
  
          if (uuidA == null) {
              return uuidB.length == 0;
          }
  
          if (uuidB == null) return true;
  
          HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA));
          for (ParcelUuid uuid : uuidB) {
              if (!uuidSet.contains(uuid)) return false;
          }
          return true;
      }
  
      /**
       * Extract the Service Identifier or the actual uuid from the Parcel Uuid.
       * For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid,
       * this function will return 110B
       *
       * @param parcelUuid
       * @return the service identifier.
       */
      public static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
          UUID uuid = parcelUuid.getUuid();
          long value = (uuid.getMostSignificantBits() & 0xFFFFFFFF00000000L) >>> 32;
          return (int) value;
      }
  
      /**
       * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
       * but the returned UUID is always in 128-bit format.
       * Note UUID is little endian in Bluetooth.
       *
       * @param uuidBytes Byte representation of uuid.
       * @return {@link ParcelUuid} parsed from bytes.
       * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
       */
      public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
          if (uuidBytes == null) {
              throw new IllegalArgumentException("uuidBytes cannot be null");
          }
          int length = uuidBytes.length;
          if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT
                  && length != UUID_BYTES_128_BIT) {
              throw new IllegalArgumentException("uuidBytes length invalid - " + length);
          }
  
          // Construct a 128 bit UUID.
          if (length == UUID_BYTES_128_BIT) {
              ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
              long msb = buf.getLong(8);
              long lsb = buf.getLong(0);
              return new ParcelUuid(new UUID(msb, lsb));
          }
  
          // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
          // 128_bit_value = uuid * 2^96 + BASE_UUID
          long shortUuid;
          if (length == UUID_BYTES_16_BIT) {
              shortUuid = uuidBytes[0] & 0xFF;
              shortUuid += (uuidBytes[1] & 0xFF) << 8;
          } else {
              shortUuid = uuidBytes[0] & 0xFF;
              shortUuid += (uuidBytes[1] & 0xFF) << 8;
              shortUuid += (uuidBytes[2] & 0xFF) << 16;
              shortUuid += (uuidBytes[3] & 0xFF) << 24;
          }
          long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
          long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
          return new ParcelUuid(new UUID(msb, lsb));
      }
  
      /**
       * Parse UUID to bytes. The returned value is shortest representation, a 16-bit, 32-bit or
       * 128-bit UUID, Note returned value is little endian (Bluetooth).
       *
       * @param uuid uuid to parse.
       * @return shortest representation of {@code uuid} as bytes.
       * @throws IllegalArgumentException If the {@code uuid} is null.
       */
      public static byte[] uuidToBytes(ParcelUuid uuid) {
          if (uuid == null) {
              throw new IllegalArgumentException("uuid cannot be null");
          }
  
          if (is16BitUuid(uuid)) {
              byte[] uuidBytes = new byte[UUID_BYTES_16_BIT];
              int uuidVal = getServiceIdentifierFromParcelUuid(uuid);
              uuidBytes[0] = (byte) (uuidVal & 0xFF);
              uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8);
              return uuidBytes;
          }
  
          if (is32BitUuid(uuid)) {
              byte[] uuidBytes = new byte[UUID_BYTES_32_BIT];
              int uuidVal = getServiceIdentifierFromParcelUuid(uuid);
              uuidBytes[0] = (byte) (uuidVal & 0xFF);
              uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8);
              uuidBytes[2] = (byte) ((uuidVal & 0xFF0000) >> 16);
              uuidBytes[3] = (byte) ((uuidVal & 0xFF000000) >> 24);
              return uuidBytes;
          }
  
          // Construct a 128 bit UUID.
          long msb = uuid.getUuid().getMostSignificantBits();
          long lsb = uuid.getUuid().getLeastSignificantBits();
  
          byte[] uuidBytes = new byte[UUID_BYTES_128_BIT];
          ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
          buf.putLong(8, msb);
          buf.putLong(0, lsb);
          return uuidBytes;
      }
  
      /**
       * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
       *
       * @param parcelUuid
       * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
       */
      @UnsupportedAppUsage
      public static boolean is16BitUuid(ParcelUuid parcelUuid) {
          UUID uuid = parcelUuid.getUuid();
          if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
              return false;
          }
          return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
      }
  
  
      /**
       * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid.
       *
       * @param parcelUuid
       * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
       */
      @UnsupportedAppUsage
      public static boolean is32BitUuid(ParcelUuid parcelUuid) {
          UUID uuid = parcelUuid.getUuid();
          if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
              return false;
          }
          if (is16BitUuid(parcelUuid)) {
              return false;
          }
          return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L);
      }
  }
  