Merge changes from topic "GROUP_CLIENT" into r-keystone-qcom-dev

* changes:
  DeviceGroup: Frameworks changes (for dual mode devices).
  DeviceGroup: Framework changes for Group Device operations.
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index a54d077..a5dee0e 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -2355,6 +2355,48 @@
     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
             BluetoothGattCallback callback, int transport,
             boolean opportunistic, int phy, Handler handler) {
+        return connectGatt(context, autoConnect, callback, transport, opportunistic,
+                phy, handler, false);
+    }
+
+    /**
+     * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as any further GATT client operations.
+     * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+     * GATT client operations.
+     *
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param autoConnect Whether to directly connect to the remote device (false) or to
+     * automatically connect as soon as the remote device becomes available (true).
+     * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
+     * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
+     * BluetoothDevice#TRANSPORT_LE}
+     * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client
+     * does not hold a GATT connection. It automatically disconnects when no other GATT connections
+     * are active for the remote device.
+     * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
+     * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
+     * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
+     * is set to true.
+     * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
+     * an un-specified background thread.
+     * @param eattSupport specifies whether client app needs EATT channel for client operations.
+     * If both local and remote devices support EATT and local app asks for EATT, GATT client
+     * operations will be performed using EATT channel.
+     * If either local or remote device doesn't support EATT but local App asks for EATT, GATT
+     * client operations will be performed using unenhanced ATT channel.
+     *
+     * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client
+     * operations.
+     *
+     * @throws NullPointerException if callback is null
+     *
+     * @hide
+     */
+    public BluetoothGatt connectGatt(Context context, boolean autoConnect,
+            BluetoothGattCallback callback, int transport, boolean opportunistic,
+            int phy, Handler handler, boolean eattSupport) {
         if (callback == null) {
             throw new NullPointerException("callback is null");
         }
@@ -2370,7 +2412,7 @@
                 return null;
             }
             BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, opportunistic, phy);
-            gatt.connect(autoConnect, callback, handler);
+            gatt.connect(autoConnect, callback, handler, eattSupport);
             return gatt;
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index f877f04..6fc1492 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -799,6 +799,28 @@
      * error
      */
     private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
+        return registerApp(callback, handler, false);
+    }
+
+    /**
+     * Register an application callback to start using GATT.
+     *
+     * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
+     * is used to notify success or failure if the function returns true.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param eattSupport specifies whether client app needs EATT channel for client operations.
+     * If both local and remote devices support EATT and local app asks for EATT, GATT client
+     * operations will be performed using EATT channel.
+     * If either local or remote device doesn't support EATT but local App asks for EATT, GATT
+     * client operations will be performed using unenhanced ATT channel.
+     * @return If true, the callback will be called to notify success or failure, false on immediate
+     * error
+     * @hide
+     */
+    private boolean registerApp(BluetoothGattCallback callback, Handler handler, boolean eattSupport) {
         if (DBG) Log.d(TAG, "registerApp()");
         if (mService == null) return false;
 
@@ -808,7 +830,7 @@
         if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
 
         try {
-            mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
+            mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback, eattSupport);
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
             return false;
@@ -859,9 +881,45 @@
     @UnsupportedAppUsage
     /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
             Handler handler) {
+        return connect(autoConnect, callback, handler, false);
+    }
+
+    /**
+     * Initiate a connection to a Bluetooth GATT capable device.
+     *
+     * <p>The connection may not be established right away, but will be
+     * completed when the remote device is available. A
+     * {@link BluetoothGattCallback#onConnectionStateChange} callback will be
+     * invoked when the connection state changes as a result of this function.
+     *
+     * <p>The autoConnect parameter determines whether to actively connect to
+     * the remote device, or rather passively scan and finalize the connection
+     * when the remote device is in range/available. Generally, the first ever
+     * connection to a device should be direct (autoConnect set to false) and
+     * subsequent connections to known devices should be invoked with the
+     * autoConnect parameter set to true.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param device Remote device to connect to
+     * @param autoConnect Whether to directly connect to the remote device (false) or to
+     * automatically connect as soon as the remote device becomes available (true).
+     * @param eattSupport specifies whether client app needs EATT channel for client operations.
+     * If both local and remote devices support EATT and local app asks for EATT, GATT client
+     * operations will be performed using EATT channel.
+     * If either local or remote device doesn't support EATT but local App asks for EATT, GATT
+     * client operations will be performed using unenhanced ATT channel.
+     * @return true, if the connection attempt was initiated successfully
+     *
+     * @hide
+     */
+    @UnsupportedAppUsage
+    /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
+            Handler handler, boolean eattSupport) {
         if (DBG) {
             Log.d(TAG,
-                    "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
+                    "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect
+                    + ", eattSupport: " + eattSupport);
         }
         synchronized (mStateLock) {
             if (mConnState != CONN_STATE_IDLE) {
@@ -872,7 +930,7 @@
 
         mAutoConnect = autoConnect;
 
-        if (!registerApp(callback, handler)) {
+        if (!registerApp(callback, handler, eattSupport)) {
             synchronized (mStateLock) {
                 mConnState = CONN_STATE_IDLE;
             }
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index 13b1b4f..00daa75 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -443,6 +443,24 @@
      * error
      */
     /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
+        return registerCallback(callback, false);
+    }
+
+    /**
+     * Register an application callback to start using GattServer.
+     *
+     * <p>This is an asynchronous call. The callback is used to notify
+     * success or failure if the function returns true.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @param callback GATT callback handler that will receive asynchronous callbacks.
+     * @param eattSupport whether eattSupport is needed for Gatt server
+     * @return true, the callback will be called to notify success or failure, false on immediate
+     * error
+     * @hide
+     */
+    /*package*/ boolean registerCallback(BluetoothGattServerCallback callback, boolean eattSupport) {
         if (DBG) Log.d(TAG, "registerCallback()");
         if (mService == null) {
             Log.e(TAG, "GATT service not available");
@@ -459,7 +477,7 @@
 
             mCallback = callback;
             try {
-                mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback);
+                mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback, eattSupport);
             } catch (RemoteException e) {
                 Log.e(TAG, "", e);
                 mCallback = null;
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 3b4fe0a..7f51664 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -233,6 +233,31 @@
      */
     public BluetoothGattServer openGattServer(Context context,
             BluetoothGattServerCallback callback, int transport) {
+        return (openGattServer(context, callback, transport, false));
+    }
+
+    /**
+     * Open a GATT Server
+     * The callback is used to deliver results to Caller, such as connection status as well
+     * as the results of any other GATT server operations.
+     * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
+     * to conduct GATT server operations.
+     *
+     * @param context App context
+     * @param callback GATT server callback handler that will receive asynchronous callbacks.
+     * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
+     * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
+     * BluetoothDevice#TRANSPORT_LE}
+     * @param eattSupport specifies whether server app needs EATT channel for server operations.
+     * If both local and remote devices support EATT, local app asks for EATT using this API and
+     * calls server connect, GATT server operations will be performed using EATT channel.
+     * If either local or remote device doesn't support EATT but local App asks for EATT, GATT
+     * server operations will be performed using unenhanced ATT channel.
+     * @return BluetoothGattServer instance
+     * @hide
+     */
+    public BluetoothGattServer openGattServer(Context context,
+            BluetoothGattServerCallback callback, int transport, boolean eattSupport) {
         if (context == null || callback == null) {
             throw new IllegalArgumentException("null parameter: " + context + " " + callback);
         }
@@ -248,7 +273,7 @@
                 return null;
             }
             BluetoothGattServer mGattServer = new BluetoothGattServer(iGatt, transport);
-            Boolean regStatus = mGattServer.registerCallback(callback);
+            Boolean regStatus = mGattServer.registerCallback(callback, eattSupport);
             return regStatus ? mGattServer : null;
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java b/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java
index 14ac911..b3fd484 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java
@@ -78,4 +78,13 @@
      */
     public void onSyncLost(int syncHandle) {
     }
+
+    /**
+     * Callback when periodic sync transfered.
+     *
+     * @param device
+     * @param status
+     */
+    public void onSyncTransfered(BluetoothDevice device, int status) {
+    }
 }
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
index 0f1a8e9..4930473 100644
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
+++ b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
@@ -196,6 +196,62 @@
         }
     }
 
+    public void transferSync(BluetoothDevice bda, int service_data, int sync_handle) {
+        IBluetoothGatt gatt;
+        try {
+            gatt = mBluetoothManager.getBluetoothGatt();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
+            PeriodicAdvertisingCallback callback = null;
+            for (PeriodicAdvertisingCallback cb : mCallbackWrappers.keySet()) {
+                callback = cb;
+            }
+            if (callback != null) {
+                callback.onSyncTransfered(bda,
+                        PeriodicAdvertisingCallback.SYNC_NO_RESOURCES);
+            }
+            return;
+        }
+        try {
+            gatt.transferSync(bda, service_data , sync_handle);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register sync - ", e);
+            return;
+        }
+    }
+
+    public void transferSetInfo(BluetoothDevice bda, int service_data,
+                      int adv_handle, PeriodicAdvertisingCallback callback) {
+        transferSetInfo(bda, service_data, adv_handle, callback, null);
+    }
+
+    public void transferSetInfo (BluetoothDevice bda, int service_data,
+                        int adv_handle, PeriodicAdvertisingCallback callback, Handler handler) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback can't be null");
+        }
+        IBluetoothGatt gatt;
+        try {
+            gatt = mBluetoothManager.getBluetoothGatt();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
+            return;
+        }
+        if (handler == null) {
+            handler = new Handler(Looper.getMainLooper());
+        }
+        IPeriodicAdvertisingCallback wrapper = wrap(callback, handler);
+        if (wrapper == null) {
+            throw new IllegalArgumentException("callback was not properly registered");
+        }
+        try {
+            gatt.transferSetInfo(bda, service_data , adv_handle, wrapper);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to register sync - ", e);
+            return;
+        }
+
+    }
     private IPeriodicAdvertisingCallback wrap(PeriodicAdvertisingCallback callback,
             Handler handler) {
         return new IPeriodicAdvertisingCallback.Stub() {
@@ -239,6 +295,18 @@
                     }
                 });
             }
+
+            public void onSyncTransfered(BluetoothDevice device, int status) {
+                handler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        callback.onSyncTransfered(device, status);
+                        // App can still unregister the sync until notified it's lost.
+                        // Remove callback after app was notifed.
+                        //mCallbackWrappers.remove(callback);
+                    }
+                });
+            }
         };
     }
 }
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 108141c..f7276c3 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -87,6 +87,10 @@
     private final int mTDSFlagsMask;
     private final byte[] mWifiNANHash;
 
+    private final boolean mGroupBasedFiltering;
+
+    private static final int GROUP_DATA_LEN = 6;
+
     /** @hide */
     public static final ScanFilter EMPTY = new ScanFilter.Builder().build();
 
@@ -96,7 +100,8 @@
             ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid,
             byte[] serviceData, byte[] serviceDataMask,
             int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask,
-            int orgId, int TDSFlags, int TDSFlagsMask, byte[] wifiNANHash) {
+            int orgId, int TDSFlags, int TDSFlagsMask, byte[] wifiNANHash,
+            boolean groupBasedFiltering) {
         mDeviceName = name;
         mServiceUuid = uuid;
         mServiceUuidMask = uuidMask;
@@ -113,6 +118,7 @@
         mTDSFlags = TDSFlags;
         mTDSFlagsMask = TDSFlagsMask;
         mWifiNANHash = wifiNANHash;
+        mGroupBasedFiltering = groupBasedFiltering;
     }
 
     @Override
@@ -184,6 +190,7 @@
                 dest.writeByteArray(mWifiNANHash);
             }
         }
+        dest.writeBoolean(mGroupBasedFiltering);
     }
 
     /**
@@ -277,6 +284,8 @@
                 }
             }
 
+            boolean groupBasedFiltering = in.readBoolean();
+            builder.setGroupBasedFiltering(groupBasedFiltering);
             return builder.build();
         }
     };
@@ -387,6 +396,14 @@
     }
 
     /**
+     * @hide
+     * Returns true, if Group AD Type based filtering is enabled. Otherwise, false.
+     */
+    public boolean getGroupFilteringValue() {
+        return mGroupBasedFiltering;
+    }
+
+    /**
      * Check if the scan filter matches a {@code scanResult}. A scan result is considered as a match
      * if it matches all the field filters.
      */
@@ -455,6 +472,13 @@
             }
         }
 
+        // Group AD Type filter match
+        if (mGroupBasedFiltering) {
+            if (scanRecord.getGroupIdentifierData().length != GROUP_DATA_LEN) {
+                return false;
+            }
+        }
+
         // All filters match.
         return true;
     }
@@ -552,7 +576,8 @@
                 + ", mManufacturerDataMask=" + Arrays.toString(mManufacturerDataMask)
                 + ", mOrganizationId=" + mOrgId + ", mTDSFlags=" + mTDSFlags
                 + ", mTDSFlagsMask=" + mTDSFlagsMask
-                + ", mWifiNANHash=" + Arrays.toString(mWifiNANHash) +"]";
+                + ", mWifiNANHash=" + Arrays.toString(mWifiNANHash) +"]"
+                + ", mGroupBasedFiltering=" + mGroupBasedFiltering;
     }
 
     @Override
@@ -565,7 +590,8 @@
                 Arrays.hashCode(mServiceDataMask),
                 mServiceUuid, mServiceUuidMask,
                 mServiceSolicitationUuid, mServiceSolicitationUuidMask,
-                mOrgId, mTDSFlags, mTDSFlagsMask, Arrays.hashCode(mWifiNANHash));
+                mOrgId, mTDSFlags, mTDSFlagsMask, Arrays.hashCode(mWifiNANHash),
+                mGroupBasedFiltering);
     }
 
     @Override
@@ -593,7 +619,8 @@
                 && mOrgId == other.mOrgId
                 && mTDSFlags == other.mTDSFlags
                 && mTDSFlagsMask == other.mTDSFlagsMask
-                && Objects.deepEquals(mWifiNANHash, other.mWifiNANHash);
+                && Objects.deepEquals(mWifiNANHash, other.mWifiNANHash)
+                && mGroupBasedFiltering == other.mGroupBasedFiltering;
     }
 
     /**
@@ -632,6 +659,8 @@
         private int mTDSFlagsMask = -1;
         private byte[] mWifiNANHash;
 
+        private boolean mGroupBasedFiltering;
+
         /**
          * Set filter on device name.
          */
@@ -837,6 +866,17 @@
             mWifiNANHash = wifiNANHash;
             return this;
         }
+
+        /**
+         * @hide
+         * Enable filter on Group AD Type.
+         */
+        public @NonNull Builder setGroupBasedFiltering(
+                boolean enable) {
+            mGroupBasedFiltering = enable;
+            return this;
+        }
+
         /**
          * Build {@link ScanFilter}.
          *
@@ -848,7 +888,8 @@
                     mServiceSolicitationUuidMask,
                     mServiceDataUuid, mServiceData, mServiceDataMask,
                     mManufacturerId, mManufacturerData, mManufacturerDataMask,
-                    mOrgId, mTDSFlags, mTDSFlagsMask, mWifiNANHash);
+                    mOrgId, mTDSFlags, mTDSFlagsMask, mWifiNANHash,
+                    mGroupBasedFiltering);
         }
     }
 }
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index abcb381..9509c53 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -57,6 +57,10 @@
     private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15;
     private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
     private static final int DATA_TYPE_TRANSPORT_DISCOVERY_DATA = 0x26;
+    /**
+     * @hide
+     */
+    public static int DATA_TYPE_GROUP_AD_TYPE = 0x00;
 
     // Flags of the advertising data.
     private final int mAdvertiseFlags;
@@ -82,6 +86,9 @@
     // Transport Discovery data.
     private final byte[] mTDSData;
 
+    // Group Identifier Data
+    private final byte[] mGroupIdentifierData;
+
     /**
      * Returns the advertising flags indicating the discoverable mode and capability of the device.
      * Returns -1 if the flag field is not set.
@@ -174,6 +181,14 @@
     }
 
     /**
+     * @hide
+     * Returns Group Identifier data
+     */
+    public byte[] getGroupIdentifierData() {
+        return mGroupIdentifierData;
+    }
+
+    /**
      * Returns raw bytes of scan record.
      */
     public byte[] getBytes() {
@@ -185,7 +200,7 @@
             SparseArray<byte[]> manufacturerData,
             Map<ParcelUuid, byte[]> serviceData,
             int advertiseFlags, int txPowerLevel,
-            String localName, byte[] tdsData, byte[] bytes) {
+            String localName, byte[] tdsData, byte[] groupIdentifierData, byte[] bytes) {
         mServiceSolicitationUuids = serviceSolicitationUuids;
         mServiceUuids = serviceUuids;
         mManufacturerSpecificData = manufacturerData;
@@ -194,6 +209,7 @@
         mAdvertiseFlags = advertiseFlags;
         mTxPowerLevel = txPowerLevel;
         mTDSData = tdsData;
+        mGroupIdentifierData = groupIdentifierData;
         mBytes = bytes;
     }
 
@@ -225,6 +241,7 @@
         Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();
 
         byte[] tdsData = null;
+        byte[] groupIdentifierData = null;
 
         try {
             while (currentPos < scanRecord.length) {
@@ -306,8 +323,12 @@
                     case DATA_TYPE_TRANSPORT_DISCOVERY_DATA:
                         tdsData = extractBytes(scanRecord, currentPos, dataLength);
                         break;
+
                     default:
-                        // Just ignore, we don't handle such data type.
+                        if (fieldType == DATA_TYPE_GROUP_AD_TYPE) {
+                            Log.d(TAG, "Parsing Group Identifier data");
+                            groupIdentifierData = extractBytes(scanRecord, currentPos, dataLength);
+                        }
                         break;
                 }
                 currentPos += dataLength;
@@ -317,12 +338,14 @@
                 serviceUuids = null;
             }
             return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData,
-                    serviceData, advertiseFlag, txPowerLevel, localName, tdsData, scanRecord);
+                    serviceData, advertiseFlag, txPowerLevel, localName, tdsData,
+                    groupIdentifierData, scanRecord);
         } catch (Exception e) {
             Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
             // As the record is invalid, ignore all the parsed results for this packet
             // and return an empty record with raw scanRecord bytes in results
-            return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, null, scanRecord);
+            return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, null,
+                                  null, scanRecord);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
old mode 100644
new mode 100755
index faeda81..2d0e268
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -434,7 +434,7 @@
             }
         }
         for (int i = 0; i < changedSubscriptions.size(); i++) {
-            SimData data = mSimDatas.get(changedSubscriptions.get(i).getSubscriptionId());
+            SimData data = mSimDatas.get(changedSubscriptions.get(i).getSimSlotIndex());
             for (int j = 0; j < mCallbacks.size(); j++) {
                 KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
                 if (cb != null) {
@@ -2386,7 +2386,13 @@
                 // Even though the subscription is not valid anymore, we need to notify that the
                 // SIM card was removed so we can update the UI.
                 becameAbsent = true;
-                mSimDatas.clear();
+                for (SimData data : mSimDatas.values()) {
+                    // Set the SIM state of all SimData associated with that slot to ABSENT se we
+                    // do not move back into PIN/PUK locked and not detect the change below.
+                    if (data.slotId == slotId) {
+                        data.simState = TelephonyManager.SIM_STATE_ABSENT;
+                    }
+                }
             } else if (state == TelephonyManager.SIM_STATE_CARD_IO_ERROR) {
                 updateTelephonyCapable(true);
             } else {
@@ -2394,11 +2400,11 @@
             }
         }
 
-        SimData data = mSimDatas.get(subId);
+        SimData data = mSimDatas.get(slotId);
         final boolean changed;
         if (data == null) {
             data = new SimData(state, slotId, subId);
-            mSimDatas.put(subId, data);
+            mSimDatas.put(slotId, data);
             changed = true; // no data yet; force update
         } else {
             changed = (data.simState != state || data.subId != subId || data.slotId != slotId);
@@ -2741,18 +2747,20 @@
     }
 
     public int getSimState(int subId) {
-        if (mSimDatas.containsKey(subId)) {
-            return mSimDatas.get(subId).simState;
+        int slotId = SubscriptionManager.getSlotIndex(subId);
+        if (mSimDatas.containsKey(slotId)) {
+            return mSimDatas.get(slotId).simState;
         } else {
             return TelephonyManager.SIM_STATE_UNKNOWN;
         }
     }
 
     private int getSlotId(int subId) {
-        if (!mSimDatas.containsKey(subId)) {
-            refreshSimState(subId, SubscriptionManager.getSlotIndex(subId));
+        int slotId = SubscriptionManager.getSlotIndex(subId);
+        if (!mSimDatas.containsKey(slotId)) {
+            refreshSimState(subId, slotId);
         }
-        return mSimDatas.get(subId).slotId;
+        return mSimDatas.get(slotId).slotId;
     }
 
     private final TaskStackChangeListener
@@ -2811,11 +2819,11 @@
                 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
         int state = (tele != null) ?
                 tele.getSimState(slotId) : TelephonyManager.SIM_STATE_UNKNOWN;
-        SimData data = mSimDatas.get(subId);
+        SimData data = mSimDatas.get(slotId);
         final boolean changed;
         if (data == null) {
             data = new SimData(state, slotId, subId);
-            mSimDatas.put(subId, data);
+            mSimDatas.put(slotId, data);
             changed = true; // no data yet; force update
         } else {
             changed = (data.simState != state) || (data.slotId != slotId);
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index dd001ba..dd74909 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -92,6 +92,8 @@
 
     void allowAutojoinGlobal(boolean choice);
 
+    void allowConnectOnPartialScanResults(boolean enable);
+
     void allowAutojoin(int netId, boolean choice);
 
     void allowAutojoinPasspoint(String fqdn, boolean enableAutoJoin);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 15415f0..3346e10 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1052,6 +1052,15 @@
     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
 
     /**
+     * An access point partial scan has completed, and results are available.
+     * Call {@link #getScanResults()} to obtain the results.
+     * The broadcast intent may contain an extra field with the key {@link #EXTRA_RESULTS_UPDATED}
+     * and a {@code boolean} value indicating if the scan was successful.
+     * @hide
+     */
+    public static final String PARTIAL_SCAN_RESULTS_AVAILABLE_ACTION = "com.qualcomm.qti.net.wifi.PARTIAL_SCAN_RESULTS";
+
+    /**
      * Lookup key for a {@code boolean} extra in intent {@link #SCAN_RESULTS_AVAILABLE_ACTION}
      * representing if the scan was successful or not.
      * Scans may fail for multiple reasons, these may include:
@@ -4578,6 +4587,19 @@
         }
     }
 
+    /**
+     * Enable/disable quick connect on partial scan results.
+     *
+     * @param  enable true to not allow quick connect, false to allow quick connect
+     * @hide
+     */
+    public void allowConnectOnPartialScanResults(boolean enable) {
+        try {
+            mService.allowConnectOnPartialScanResults(enable);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
     /**
      * Sets the user choice for allowing auto-join to a network.
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 94771ac..4d61351 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -154,6 +154,16 @@
     /** An outstanding request with the same listener hasn't finished yet. */
     public static final int REASON_DUPLICATE_REQEUST = -5;
 
+    /** Partial scan results msg arg
+     * @hide
+     */
+     public static final int ON_PARTIAL_SCAN_RESULTS = 1;
+
+    /** Complete scan results msg arg
+     * @hide
+     */
+     public static final int ON_COMPLETE_SCAN_RESULTS = 0;
+
     /** @hide */
     public static final String GET_AVAILABLE_CHANNELS_EXTRA = "Channels";
 
@@ -865,6 +875,11 @@
          */
         public void onResults(ScanData[] results);
         /**
+         * reports partial results retrieved from single shot scans
+         * @hide
+         */
+        default void onPartialScanResults(ScanData[] results) {}
+        /**
          * reports full scan result for each access point found in scan
          */
         public void onFullResult(ScanResult fullScanResult);
@@ -1648,7 +1663,11 @@
                     ScanListener scanListener = (ScanListener) listener;
                     ParcelableScanData parcelableScanData = (ParcelableScanData) msg.obj;
                     Binder.clearCallingIdentity();
-                    executor.execute(() -> scanListener.onResults(parcelableScanData.getResults()));
+                    if (msg.arg1 == ON_PARTIAL_SCAN_RESULTS) {
+                        executor.execute(() -> scanListener.onPartialScanResults(parcelableScanData.getResults()));
+                    } else {
+                        executor.execute(() -> scanListener.onResults(parcelableScanData.getResults()));
+                    }
                 } break;
                 case CMD_FULL_SCAN_RESULT: {
                     ScanResult result = (ScanResult) msg.obj;