Add a TLV to support different result storage

Change-Id: Ic20a1720b783508cf85b234950b7fd0c79e9e7c3
diff --git a/framework/java/android/bluetooth/IBluetoothGatt.aidl b/framework/java/android/bluetooth/IBluetoothGatt.aidl
index edf823e..7070bae 100644
--- a/framework/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/framework/java/android/bluetooth/IBluetoothGatt.aidl
@@ -21,6 +21,7 @@
 import android.bluetooth.le.AdvertiseData;
 import android.bluetooth.le.ScanFilter;
 import android.bluetooth.le.ScanSettings;
+import android.bluetooth.le.ResultStorageDescriptor;
 import android.os.ParcelUuid;
 
 import android.bluetooth.IBluetoothGattCallback;
@@ -34,7 +35,8 @@
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
 
     void startScan(in int appIf, in boolean isServer, in ScanSettings settings,
-                   in List<ScanFilter> filters);
+                   in List<ScanFilter> filters,
+                   in List scanStorages);
     void stopScan(in int appIf, in boolean isServer);
     void flushPendingBatchResults(in int appIf, in boolean isServer);
     void startMultiAdvertising(in int appIf,
diff --git a/framework/java/android/bluetooth/le/BluetoothLeScanner.java b/framework/java/android/bluetooth/le/BluetoothLeScanner.java
index 6667cc4..7c3cbc6 100644
--- a/framework/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/framework/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -16,20 +16,19 @@
 
 package android.bluetooth.le;
 
+import android.annotation.SystemApi;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothGatt;
 import android.bluetooth.BluetoothGattCallbackWrapper;
 import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothGattCallback;
 import android.bluetooth.IBluetoothManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.util.Log;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -100,6 +99,11 @@
      */
     public void startScan(List<ScanFilter> filters, ScanSettings settings,
             final ScanCallback callback) {
+        startScan(filters, settings, callback, null);
+    }
+
+    private void startScan(List<ScanFilter> filters, ScanSettings settings,
+            final ScanCallback callback, List<List<ResultStorageDescriptor>> resultStorages) {
         checkAdapterState();
         if (settings == null || callback == null) {
             throw new IllegalArgumentException("settings or callback is null");
@@ -125,7 +129,7 @@
                 return;
             }
             BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
-                    settings, callback);
+                    settings, callback, resultStorages);
             try {
                 UUID uuid = UUID.randomUUID();
                 gatt.registerClient(new ParcelUuid(uuid), wrapper);
@@ -155,7 +159,8 @@
         synchronized (mLeScanClients) {
             BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback);
             if (wrapper == null) {
-                if (DBG) Log.d(TAG, "could not find callback wrapper");
+                if (DBG)
+                    Log.d(TAG, "could not find callback wrapper");
                 return;
             }
             wrapper.stopLeScan();
@@ -185,6 +190,25 @@
     }
 
     /**
+     * Start truncated scan.
+     *
+     * @hide
+     */
+    @SystemApi
+    public void startTruncatedScan(List<TruncatedFilter> truncatedFilters, ScanSettings settings,
+            final ScanCallback callback) {
+        int filterSize = truncatedFilters.size();
+        List<ScanFilter> scanFilters = new ArrayList<ScanFilter>(filterSize);
+        List<List<ResultStorageDescriptor>> scanStorages =
+                new ArrayList<List<ResultStorageDescriptor>>(filterSize);
+        for (TruncatedFilter filter : truncatedFilters) {
+            scanFilters.add(filter.getFilter());
+            scanStorages.add(filter.getStorageDescriptors());
+        }
+        startScan(scanFilters, settings, callback, scanStorages);
+    }
+
+    /**
      * Bluetooth GATT interface callbacks
      */
     private static class BleScanCallbackWrapper extends BluetoothGattCallbackWrapper {
@@ -194,6 +218,7 @@
         private final List<ScanFilter> mFilters;
         private ScanSettings mSettings;
         private IBluetoothGatt mBluetoothGatt;
+        private List<List<ResultStorageDescriptor>> mResultStorages;
 
         // mLeHandle 0: not registered
         // -1: scan stopped
@@ -202,12 +227,13 @@
 
         public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
                 List<ScanFilter> filters, ScanSettings settings,
-                ScanCallback scanCallback) {
+                ScanCallback scanCallback, List<List<ResultStorageDescriptor>> resultStorages) {
             mBluetoothGatt = bluetoothGatt;
             mFilters = filters;
             mSettings = settings;
             mScanCallback = scanCallback;
             mClientIf = 0;
+            mResultStorages = resultStorages;
         }
 
         public boolean scanStarted() {
@@ -272,7 +298,8 @@
                 if (status == BluetoothGatt.GATT_SUCCESS) {
                     mClientIf = clientIf;
                     try {
-                        mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters);
+                        mBluetoothGatt.startScan(mClientIf, false, mSettings, mFilters,
+                                mResultStorages);
                     } catch (RemoteException e) {
                         Log.e(TAG, "fail to start le scan: " + e);
                         mClientIf = -1;
@@ -330,23 +357,26 @@
 
             // Check null in case the scan has been stopped
             synchronized (this) {
-                if (mClientIf <= 0) return;
+                if (mClientIf <= 0)
+                    return;
             }
             Handler handler = new Handler(Looper.getMainLooper());
             handler.post(new Runnable() {
                     @Override
                 public void run() {
                     if (onFound) {
-                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH, scanResult);
+                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH,
+                                scanResult);
                     } else {
-                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST, scanResult);
+                        mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST,
+                                scanResult);
                     }
                 }
             });
         }
     }
 
-    //TODO: move this api to a common util class.
+    // TODO: move this api to a common util class.
     private void checkAdapterState() {
         if (mBluetoothAdapter.getState() != mBluetoothAdapter.STATE_ON) {
             throw new IllegalStateException("BT Adapter is not turned ON");
diff --git a/framework/java/android/bluetooth/le/ResultStorageDescriptor.aidl b/framework/java/android/bluetooth/le/ResultStorageDescriptor.aidl
new file mode 100644
index 0000000..f218a01
--- /dev/null
+++ b/framework/java/android/bluetooth/le/ResultStorageDescriptor.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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 android.bluetooth.le;
+
+/**
+ * {@hide}
+ */
+
+parcelable ResultStorageDescriptor;
diff --git a/framework/java/android/bluetooth/le/ResultStorageDescriptor.java b/framework/java/android/bluetooth/le/ResultStorageDescriptor.java
new file mode 100644
index 0000000..748f97d
--- /dev/null
+++ b/framework/java/android/bluetooth/le/ResultStorageDescriptor.java
@@ -0,0 +1,93 @@
+/*
+ * 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 android.bluetooth.le;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Describes the way to store scan result.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ResultStorageDescriptor implements Parcelable {
+    private int mType;
+    private int mOffset;
+    private int mLength;
+
+    public int getType() {
+        return mType;
+    }
+
+    public int getOffset() {
+        return mOffset;
+    }
+
+    public int getLength() {
+        return mLength;
+    }
+
+    /**
+     * Constructor of {@link ResultStorageDescriptor}
+     *
+     * @param type Type of the data.
+     * @param offset Offset from start of the advertise packet payload.
+     * @param length Byte length of the data
+     */
+    public ResultStorageDescriptor(int type, int offset, int length) {
+        mType = type;
+        mOffset = offset;
+        mLength = length;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mType);
+        dest.writeInt(mOffset);
+        dest.writeInt(mLength);
+    }
+
+    private ResultStorageDescriptor(Parcel in) {
+        ReadFromParcel(in);
+    }
+
+    private void ReadFromParcel(Parcel in) {
+        mType = in.readInt();
+        mOffset = in.readInt();
+        mLength = in.readInt();
+    }
+
+    public static final Parcelable.Creator<ResultStorageDescriptor>
+            CREATOR = new Creator<ResultStorageDescriptor>() {
+                    @Override
+                public ResultStorageDescriptor createFromParcel(Parcel source) {
+                    return new ResultStorageDescriptor(source);
+                }
+
+                    @Override
+                public ResultStorageDescriptor[] newArray(int size) {
+                    return new ResultStorageDescriptor[size];
+                }
+            };
+}
diff --git a/framework/java/android/bluetooth/le/TruncatedFilter.java b/framework/java/android/bluetooth/le/TruncatedFilter.java
new file mode 100644
index 0000000..6a6b3e3
--- /dev/null
+++ b/framework/java/android/bluetooth/le/TruncatedFilter.java
@@ -0,0 +1,61 @@
+/*
+ * 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 android.bluetooth.le;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * A special scan filter that lets the client decide how the scan record should be stored.
+ *
+ * @hide
+ */
+@SystemApi
+public final class TruncatedFilter {
+    private final ScanFilter mFilter;
+    private final List<ResultStorageDescriptor> mStorageDescriptors;
+
+    /**
+     * Constructor for {@link TruncatedFilter}.
+     *
+     * @param filter Scan filter of the truncated filter.
+     * @param storageDescriptors Describes how the scan should be stored.
+     */
+    public TruncatedFilter(ScanFilter filter, List<ResultStorageDescriptor> storageDescriptors) {
+        mFilter = filter;
+        mStorageDescriptors = storageDescriptors;
+    }
+
+    /**
+     * Returns the scan filter.
+     */
+    public ScanFilter getFilter() {
+        return mFilter;
+    }
+
+    /**
+     * Returns a list of descriptor for scan result storage.
+     */
+    public List<ResultStorageDescriptor> getStorageDescriptors() {
+        return mStorageDescriptors;
+    }
+
+
+}