Bluetooth 5 enhanced scanning API

Bug: 30622771
Test: manual
Change-Id: I2c8065fbcedf48777ce18c7d8fe621e568b3fd75
(cherry picked from commit 9de522c6e48497028d36a1f8ad8f8adf4b7b1ae6)
diff --git a/api/current.txt b/api/current.txt
index ac91a0a..3e99316 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7544,19 +7544,37 @@
   }
 
   public final class ScanResult implements android.os.Parcelable {
-    ctor public ScanResult(android.bluetooth.BluetoothDevice, android.bluetooth.le.ScanRecord, int, long);
+    ctor public deprecated ScanResult(android.bluetooth.BluetoothDevice, android.bluetooth.le.ScanRecord, int, long);
+    ctor public ScanResult(android.bluetooth.BluetoothDevice, int, int, int, int, int, int, int, android.bluetooth.le.ScanRecord, long);
     method public int describeContents();
+    method public int getAdvertisingSid();
+    method public int getDataStatus();
     method public android.bluetooth.BluetoothDevice getDevice();
+    method public int getPeriodicAdvertisingInterval();
+    method public int getPrimaryPhy();
     method public int getRssi();
     method public android.bluetooth.le.ScanRecord getScanRecord();
+    method public int getSecondaryPhy();
     method public long getTimestampNanos();
+    method public int getTxPower();
+    method public boolean isConnectable();
+    method public boolean isLegacy();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
+    field public static final int DATA_COMPLETE = 0; // 0x0
+    field public static final int DATA_TRUNCATED = 2; // 0x2
+    field public static final int PHY_LE_1M = 1; // 0x1
+    field public static final int PHY_LE_2M = 2; // 0x2
+    field public static final int PHY_LE_CODED = 3; // 0x3
+    field public static final int PHY_UNUSED = 0; // 0x0
+    field public static final int SID_NOT_PRESENT = 255; // 0xff
   }
 
   public final class ScanSettings implements android.os.Parcelable {
     method public int describeContents();
     method public int getCallbackType();
+    method public boolean getLegacy();
+    method public int getPhy();
     method public long getReportDelayMillis();
     method public int getScanMode();
     method public int getScanResultType();
@@ -7570,6 +7588,9 @@
     field public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; // 0x2
     field public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; // 0x3
     field public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; // 0x1
+    field public static final int PHY_LE_1M = 1; // 0x1
+    field public static final int PHY_LE_ALL_SUPPORTED = 255; // 0xff
+    field public static final int PHY_LE_CODED = 3; // 0x3
     field public static final int SCAN_MODE_BALANCED = 1; // 0x1
     field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
     field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
@@ -7580,8 +7601,10 @@
     ctor public ScanSettings.Builder();
     method public android.bluetooth.le.ScanSettings build();
     method public android.bluetooth.le.ScanSettings.Builder setCallbackType(int);
+    method public android.bluetooth.le.ScanSettings.Builder setLegacy(boolean);
     method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
     method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
+    method public android.bluetooth.le.ScanSettings.Builder setPhy(int);
     method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
     method public android.bluetooth.le.ScanSettings.Builder setScanMode(int);
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index c122fcc..078a988 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7861,19 +7861,37 @@
   }
 
   public final class ScanResult implements android.os.Parcelable {
-    ctor public ScanResult(android.bluetooth.BluetoothDevice, android.bluetooth.le.ScanRecord, int, long);
+    ctor public deprecated ScanResult(android.bluetooth.BluetoothDevice, android.bluetooth.le.ScanRecord, int, long);
+    ctor public ScanResult(android.bluetooth.BluetoothDevice, int, int, int, int, int, int, int, android.bluetooth.le.ScanRecord, long);
     method public int describeContents();
+    method public int getAdvertisingSid();
+    method public int getDataStatus();
     method public android.bluetooth.BluetoothDevice getDevice();
+    method public int getPeriodicAdvertisingInterval();
+    method public int getPrimaryPhy();
     method public int getRssi();
     method public android.bluetooth.le.ScanRecord getScanRecord();
+    method public int getSecondaryPhy();
     method public long getTimestampNanos();
+    method public int getTxPower();
+    method public boolean isConnectable();
+    method public boolean isLegacy();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
+    field public static final int DATA_COMPLETE = 0; // 0x0
+    field public static final int DATA_TRUNCATED = 2; // 0x2
+    field public static final int PHY_LE_1M = 1; // 0x1
+    field public static final int PHY_LE_2M = 2; // 0x2
+    field public static final int PHY_LE_CODED = 3; // 0x3
+    field public static final int PHY_UNUSED = 0; // 0x0
+    field public static final int SID_NOT_PRESENT = 255; // 0xff
   }
 
   public final class ScanSettings implements android.os.Parcelable {
     method public int describeContents();
     method public int getCallbackType();
+    method public boolean getLegacy();
+    method public int getPhy();
     method public long getReportDelayMillis();
     method public int getScanMode();
     method public int getScanResultType();
@@ -7887,6 +7905,9 @@
     field public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; // 0x2
     field public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; // 0x3
     field public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; // 0x1
+    field public static final int PHY_LE_1M = 1; // 0x1
+    field public static final int PHY_LE_ALL_SUPPORTED = 255; // 0xff
+    field public static final int PHY_LE_CODED = 3; // 0x3
     field public static final int SCAN_MODE_BALANCED = 1; // 0x1
     field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
     field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
@@ -7899,8 +7920,10 @@
     ctor public ScanSettings.Builder();
     method public android.bluetooth.le.ScanSettings build();
     method public android.bluetooth.le.ScanSettings.Builder setCallbackType(int);
+    method public android.bluetooth.le.ScanSettings.Builder setLegacy(boolean);
     method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
     method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
+    method public android.bluetooth.le.ScanSettings.Builder setPhy(int);
     method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
     method public android.bluetooth.le.ScanSettings.Builder setScanMode(int);
     method public android.bluetooth.le.ScanSettings.Builder setScanResultType(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 03374bd..b7c9ace 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -7553,19 +7553,37 @@
   }
 
   public final class ScanResult implements android.os.Parcelable {
-    ctor public ScanResult(android.bluetooth.BluetoothDevice, android.bluetooth.le.ScanRecord, int, long);
+    ctor public deprecated ScanResult(android.bluetooth.BluetoothDevice, android.bluetooth.le.ScanRecord, int, long);
+    ctor public ScanResult(android.bluetooth.BluetoothDevice, int, int, int, int, int, int, int, android.bluetooth.le.ScanRecord, long);
     method public int describeContents();
+    method public int getAdvertisingSid();
+    method public int getDataStatus();
     method public android.bluetooth.BluetoothDevice getDevice();
+    method public int getPeriodicAdvertisingInterval();
+    method public int getPrimaryPhy();
     method public int getRssi();
     method public android.bluetooth.le.ScanRecord getScanRecord();
+    method public int getSecondaryPhy();
     method public long getTimestampNanos();
+    method public int getTxPower();
+    method public boolean isConnectable();
+    method public boolean isLegacy();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
+    field public static final int DATA_COMPLETE = 0; // 0x0
+    field public static final int DATA_TRUNCATED = 2; // 0x2
+    field public static final int PHY_LE_1M = 1; // 0x1
+    field public static final int PHY_LE_2M = 2; // 0x2
+    field public static final int PHY_LE_CODED = 3; // 0x3
+    field public static final int PHY_UNUSED = 0; // 0x0
+    field public static final int SID_NOT_PRESENT = 255; // 0xff
   }
 
   public final class ScanSettings implements android.os.Parcelable {
     method public int describeContents();
     method public int getCallbackType();
+    method public boolean getLegacy();
+    method public int getPhy();
     method public long getReportDelayMillis();
     method public int getScanMode();
     method public int getScanResultType();
@@ -7579,6 +7597,9 @@
     field public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; // 0x2
     field public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; // 0x3
     field public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; // 0x1
+    field public static final int PHY_LE_1M = 1; // 0x1
+    field public static final int PHY_LE_ALL_SUPPORTED = 255; // 0xff
+    field public static final int PHY_LE_CODED = 3; // 0x3
     field public static final int SCAN_MODE_BALANCED = 1; // 0x1
     field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
     field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
@@ -7589,8 +7610,10 @@
     ctor public ScanSettings.Builder();
     method public android.bluetooth.le.ScanSettings build();
     method public android.bluetooth.le.ScanSettings.Builder setCallbackType(int);
+    method public android.bluetooth.le.ScanSettings.Builder setLegacy(boolean);
     method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
     method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
+    method public android.bluetooth.le.ScanSettings.Builder setPhy(int);
     method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
     method public android.bluetooth.le.ScanSettings.Builder setScanMode(int);
   }
diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java
index 2fdfe7f..f92357b 100644
--- a/core/java/android/bluetooth/le/ScanResult.java
+++ b/core/java/android/bluetooth/le/ScanResult.java
@@ -27,7 +27,56 @@
  * ScanResult for Bluetooth LE scan.
  */
 public final class ScanResult implements Parcelable {
-    // Remote bluetooth device.
+
+    /**
+     * For chained advertisements, inidcates tha the data contained in this
+     * scan result is complete.
+     */
+    public static final int DATA_COMPLETE = 0x00;
+
+    /**
+     * For chained advertisements, indicates that the controller was
+     * unable to receive all chained packets and the scan result contains
+     * incomplete truncated data.
+     */
+    public static final int DATA_TRUNCATED = 0x02;
+
+    /**
+     * Indicates that the secondary physical layer was not used.
+     */
+    public static final int PHY_UNUSED = 0x00;
+
+    /**
+     * Bluetooth LE 1Mbit advertiser PHY.
+     */
+    public static final int PHY_LE_1M = 0x01;
+
+    /**
+     * Bluetooth LE 2Mbit advertiser PHY.
+     */
+    public static final int PHY_LE_2M = 0x02;
+
+    /**
+     * Bluetooth LE Coded advertiser PHY.
+     */
+    public static final int PHY_LE_CODED = 0x03;
+
+    /**
+     * Advertising Set ID is not present in the packet.
+     */
+    public static final int SID_NOT_PRESENT = 0xFF;
+
+    /**
+     * Mask for checking wether event type represents legacy advertisement.
+     */
+    private static final int ET_LEGACY_MASK = 0x10;
+
+    /**
+     * Mask for checking wether event type represents connectable advertisement.
+     */
+    private static final int ET_CONNECTABLE_MASK = 0x01;
+
+    // Remote Bluetooth device.
     private BluetoothDevice mDevice;
 
     // Scan record, including advertising data and scan response data.
@@ -40,13 +89,21 @@
     // Device timestamp when the result was last seen.
     private long mTimestampNanos;
 
+    private int mEventType;
+    private int mPrimaryPhy;
+    private int mSecondaryPhy;
+    private int mAdvertisingSid;
+    private int mTxPower;
+    private int mPeriodicAdvertisingInterval;
+
     /**
-     * Constructor of scan result.
+     * Constructs a new ScanResult.
      *
-     * @param device Remote bluetooth device that is found.
+     * @param device Remote Bluetooth device found.
      * @param scanRecord Scan record including both advertising data and scan response data.
      * @param rssi Received signal strength.
-     * @param timestampNanos Device timestamp when the scan result was observed.
+     * @param timestampNanos Timestamp at which the scan result was observed.
+     * @deprecated use {@link #ScanResult(BluetoothDevice, int, int, int, int, int, int, int, ScanRecord, long)}
      */
     public ScanResult(BluetoothDevice device, ScanRecord scanRecord, int rssi,
             long timestampNanos) {
@@ -54,6 +111,41 @@
         mScanRecord = scanRecord;
         mRssi = rssi;
         mTimestampNanos = timestampNanos;
+        mEventType = (DATA_COMPLETE << 5) | ET_LEGACY_MASK | ET_CONNECTABLE_MASK;
+        mPrimaryPhy = PHY_LE_1M;
+        mSecondaryPhy = PHY_UNUSED;
+        mAdvertisingSid = SID_NOT_PRESENT;
+        mTxPower = 127;
+        mPeriodicAdvertisingInterval = 0;
+    }
+
+    /**
+     * Constructs a new ScanResult.
+     *
+     * @param device Remote Bluetooth device found.
+     * @param eventType Event type.
+     * @param primaryPhy Primary advertising phy.
+     * @param secondaryPhy Secondary advertising phy.
+     * @param advertisingSid Advertising set ID.
+     * @param txPower Transmit power.
+     * @param rssi Received signal strength.
+     * @param periodicAdvertisingInterval Periodic advertising interval.
+     * @param scanRecord Scan record including both advertising data and scan response data.
+     * @param timestampNanos Timestamp at which the scan result was observed.
+     */
+    public ScanResult(BluetoothDevice device, int eventType, int primaryPhy, int secondaryPhy,
+                      int advertisingSid, int txPower, int rssi, int periodicAdvertisingInterval,
+                      ScanRecord scanRecord, long timestampNanos) {
+        mDevice = device;
+        mEventType = eventType;
+        mPrimaryPhy = primaryPhy;
+        mSecondaryPhy = secondaryPhy;
+        mAdvertisingSid = advertisingSid;
+        mTxPower = txPower;
+        mRssi = rssi;
+        mPeriodicAdvertisingInterval = periodicAdvertisingInterval;
+        mScanRecord = scanRecord;
+        mTimestampNanos = timestampNanos;
     }
 
     private ScanResult(Parcel in) {
@@ -76,6 +168,12 @@
         }
         dest.writeInt(mRssi);
         dest.writeLong(mTimestampNanos);
+        dest.writeInt(mEventType);
+        dest.writeInt(mPrimaryPhy);
+        dest.writeInt(mSecondaryPhy);
+        dest.writeInt(mAdvertisingSid);
+        dest.writeInt(mTxPower);
+        dest.writeInt(mPeriodicAdvertisingInterval);
     }
 
     private void readFromParcel(Parcel in) {
@@ -87,6 +185,12 @@
         }
         mRssi = in.readInt();
         mTimestampNanos = in.readLong();
+        mEventType = in.readInt();
+        mPrimaryPhy = in.readInt();
+        mSecondaryPhy = in.readInt();
+        mAdvertisingSid = in.readInt();
+        mTxPower = in.readInt();
+        mPeriodicAdvertisingInterval = in.readInt();
     }
 
     @Override
@@ -95,7 +199,7 @@
     }
 
     /**
-     * Returns the remote bluetooth device identified by the bluetooth device address.
+     * Returns the remote Bluetooth device identified by the Bluetooth device address.
      */
     public BluetoothDevice getDevice() {
         return mDevice;
@@ -123,9 +227,79 @@
         return mTimestampNanos;
     }
 
+    /**
+     * Returns true if this object represents legacy scan result.
+     * Legacy scan results do not contain advanced advertising information
+     * as specified in the Bluetooth Core Specification v5.
+     */
+    public boolean isLegacy() {
+        return (mEventType & ET_LEGACY_MASK) != 0;
+    }
+
+    /**
+     * Returns true if this object represents connectable scan result.
+     */
+    public boolean isConnectable() {
+        return (mEventType & ET_CONNECTABLE_MASK) != 0;
+    }
+
+    /**
+     * Returns the data status.
+     * Can be one of {@link ScanResult#DATA_COMPLETE} or
+     * {@link ScanResult#DATA_TRUNCATED}.
+     */
+    public int getDataStatus() {
+        // return bit 5 and 6
+        return (mEventType >> 5) & 0x03;
+    }
+
+    /**
+     * Returns the primary Physical Layer
+     * on which this advertisment was received.
+     * Can be one of {@link ScanResult#PHY_LE_1M} or
+     * {@link ScanResult#PHY_LE_CODED}.
+     */
+    public int getPrimaryPhy() { return mPrimaryPhy; }
+
+    /**
+     * Returns the secondary Physical Layer
+     * on which this advertisment was received.
+     * Can be one of {@link ScanResult#PHY_LE_1M},
+     * {@link ScanResult#PHY_LE_2M}, {@link ScanResult#PHY_LE_CODED}
+     * or {@link ScanResult#PHY_UNUSED} - if the advertisement
+     * was not received on a secondary physical channel.
+     */
+    public int getSecondaryPhy() { return mSecondaryPhy; }
+
+    /**
+     * Returns the advertising set id.
+     * May return {@link ScanResult#SID_NOT_PRESENT} if
+     * no set id was is present.
+     */
+    public int getAdvertisingSid() { return mAdvertisingSid; }
+
+    /**
+     * Returns the transmit power in dBm.
+     * Valid range is [-127, 126]. A value of 127 indicates that the
+     * advertisement did not indicate TX power.
+     */
+    public int getTxPower() { return mTxPower; }
+
+    /**
+     * Returns the periodic advertising interval in units of 1.25ms.
+     * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of 0 means
+     * periodic advertising is not used for this scan result.
+     */
+    public int getPeriodicAdvertisingInterval() {
+        return mPeriodicAdvertisingInterval;
+    }
+
     @Override
     public int hashCode() {
-        return Objects.hash(mDevice, mRssi, mScanRecord, mTimestampNanos);
+        return Objects.hash(mDevice, mRssi, mScanRecord, mTimestampNanos,
+                            mEventType, mPrimaryPhy, mSecondaryPhy,
+                            mAdvertisingSid, mTxPower,
+                            mPeriodicAdvertisingInterval);
     }
 
     @Override
@@ -138,15 +312,24 @@
         }
         ScanResult other = (ScanResult) obj;
         return Objects.equals(mDevice, other.mDevice) && (mRssi == other.mRssi) &&
-                Objects.equals(mScanRecord, other.mScanRecord)
-                && (mTimestampNanos == other.mTimestampNanos);
+            Objects.equals(mScanRecord, other.mScanRecord) &&
+            (mTimestampNanos == other.mTimestampNanos) &&
+            mEventType == other.mEventType &&
+            mPrimaryPhy == other.mPrimaryPhy &&
+            mSecondaryPhy == other.mSecondaryPhy &&
+            mAdvertisingSid == other.mAdvertisingSid &&
+            mTxPower == other.mTxPower &&
+            mPeriodicAdvertisingInterval == other.mPeriodicAdvertisingInterval;
     }
 
     @Override
     public String toString() {
-        return "ScanResult{" + "mDevice=" + mDevice + ", mScanRecord="
-                + Objects.toString(mScanRecord) + ", mRssi=" + mRssi + ", mTimestampNanos="
-                + mTimestampNanos + '}';
+      return "ScanResult{" + "device=" + mDevice + ", scanRecord=" +
+          Objects.toString(mScanRecord) + ", rssi=" + mRssi +
+          ", timestampNanos=" + mTimestampNanos + ", eventType=" + mEventType +
+          ", primaryPhy=" + mPrimaryPhy + ", secondaryPhy=" + mSecondaryPhy +
+          ", advertisingSid=" + mAdvertisingSid + ", txPower=" + mTxPower +
+          ", periodicAdvertisingInterval=" + mPeriodicAdvertisingInterval + '}';
     }
 
     public static final Parcelable.Creator<ScanResult> CREATOR = new Creator<ScanResult>() {
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index d616624..69c9a8c 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -122,6 +122,24 @@
     @SystemApi
     public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1;
 
+    /**
+     * Use the Bluetooth LE 1Mbit PHY for scanning.
+     */
+    public static final int PHY_LE_1M = 1;
+
+    /**
+     * Use Bluetooth LE Coded PHY for scanning.
+     */
+    public static final int PHY_LE_CODED = 3;
+
+    /**
+     * Use all supported PHYs for scanning.
+     * This will check the controller capabilities, and start
+     * the scan on 1Mbit and LE Coded PHYs if supported, or on
+     * the 1Mbit PHY only.
+     */
+    public static final int PHY_LE_ALL_SUPPORTED = 255;
+
     // Bluetooth LE scan mode.
     private int mScanMode;
 
@@ -138,6 +156,11 @@
 
     private int mNumOfMatchesPerFilter;
 
+    // Include only legacy advertising results
+    private boolean mLegacy;
+
+    private int mPhy;
+
     public int getScanMode() {
         return mScanMode;
     }
@@ -165,6 +188,22 @@
     }
 
     /**
+     * Returns whether only legacy advertisements will be returned.
+     * Legacy advertisements include advertisements as specified
+     * by the Bluetooth core specification 4.2 and below.
+     */
+    public boolean getLegacy() {
+        return mLegacy;
+    }
+
+    /**
+     * Returns the physical layer used during a scan.
+     */
+    public int getPhy() {
+        return mPhy;
+    }
+
+    /**
      * Returns report delay timestamp based on the device clock.
      */
     public long getReportDelayMillis() {
@@ -172,13 +211,16 @@
     }
 
     private ScanSettings(int scanMode, int callbackType, int scanResultType,
-            long reportDelayMillis, int matchMode, int numOfMatchesPerFilter) {
+                         long reportDelayMillis, int matchMode,
+                         int numOfMatchesPerFilter, boolean legacy, int phy) {
         mScanMode = scanMode;
         mCallbackType = callbackType;
         mScanResultType = scanResultType;
         mReportDelayMillis = reportDelayMillis;
         mNumOfMatchesPerFilter = numOfMatchesPerFilter;
         mMatchMode = matchMode;
+        mLegacy = legacy;
+        mPhy = phy;
     }
 
     private ScanSettings(Parcel in) {
@@ -188,6 +230,8 @@
         mReportDelayMillis = in.readLong();
         mMatchMode = in.readInt();
         mNumOfMatchesPerFilter = in.readInt();
+        mLegacy = in.readInt() != 0 ? true : false;
+        mPhy = in.readInt();
     }
 
     @Override
@@ -198,6 +242,8 @@
         dest.writeLong(mReportDelayMillis);
         dest.writeInt(mMatchMode);
         dest.writeInt(mNumOfMatchesPerFilter);
+        dest.writeInt(mLegacy ? 1 : 0);
+        dest.writeInt(mPhy);
     }
 
     @Override
@@ -228,6 +274,9 @@
         private long mReportDelayMillis = 0;
         private int mMatchMode = MATCH_MODE_AGGRESSIVE;
         private int mNumOfMatchesPerFilter  = MATCH_NUM_MAX_ADVERTISEMENT;
+        private boolean mLegacy = true;
+        private int mPhy = PHY_LE_ALL_SUPPORTED;
+
         /**
          * Set scan mode for Bluetooth LE scan.
          *
@@ -341,11 +390,44 @@
         }
 
         /**
+         * Set whether only legacy advertisments should be returned in scan results.
+         * Legacy advertisements include advertisements as specified by the
+         * Bluetooth core specification 4.2 and below. This is true by default
+         * for compatibility with older apps.
+         *
+         * @param legacy true if only legacy advertisements will be returned
+         */
+        public Builder setLegacy(boolean legacy) {
+            mLegacy = legacy;
+            return this;
+        }
+
+        /**
+         * Set the Physical Layer to use during this scan.
+         * This is used only if {@link ScanSettings.Builder#setLegacy}
+         * is set to false.
+         * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}
+         * may be used to check whether LE Coded phy is supported by calling
+         * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}.
+         * Selecting an unsupported phy will result in failure to start scan.
+         *
+         * @param phy Can be one of
+         *   {@link ScanSettings#PHY_LE_1M},
+         *   {@link ScanSettings#PHY_LE_CODED} or
+         *   {@link ScanSettings#PHY_LE_ALL_SUPPORTED}
+         */
+        public Builder setPhy(int phy) {
+            mPhy = phy;
+            return this;
+        }
+
+        /**
          * Build {@link ScanSettings}.
          */
         public ScanSettings build() {
             return new ScanSettings(mScanMode, mCallbackType, mScanResultType,
-                    mReportDelayMillis, mMatchMode, mNumOfMatchesPerFilter);
+                                    mReportDelayMillis, mMatchMode,
+                                    mNumOfMatchesPerFilter, mLegacy, mPhy);
         }
     }
 }