Merge commit 'fd41ddf0330246801271ee08e5855384c08146fb' into remote
diff --git a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
index 250163d..8c8062a 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.java
@@ -258,8 +258,6 @@
     private final static int MESSAGE_START_SHO = 34;
     private static final int MSG_SET_ACTIVE_DEVICE = 35;
 
-    private static final int STACK_CLEANUP = 0;
-    private static final int APP_CLEANUP = 1;
     private static final int CMD_TIMEOUT_DELAY = 2000;
     private static final int MAX_ERROR_RETRY_TIMES = 6;
     private static final int AVRCP_MAX_VOL = 127;
@@ -296,6 +294,7 @@
     /* Broadcast receiver for device connections intent broadcasts */
     private final BroadcastReceiver mAvrcpReceiver = new AvrcpServiceBroadcastReceiver();
     private final BroadcastReceiver mBootReceiver = new AvrcpServiceBootReceiver();
+    private final BroadcastReceiver mShutDownReceiver = new AvrcpServiceShutDownReceiver();
 
     /* Recording passthrough key dispatches */
     static private final int PASSTHROUGH_LOG_MAX_SIZE = DEBUG ? 50 : 10;
@@ -533,6 +532,10 @@
         pts_test = SystemProperties.getBoolean("vendor.bluetooth.avrcpct-passthrough.pts", false);
         avrcp_playstatus_blacklist = SystemProperties.getBoolean("persist.vendor.btstack.avrcp-playstatus.blacklist", false);
 
+        IntentFilter shutdownFilter = new IntentFilter();
+        shutdownFilter.addAction(Intent.ACTION_SHUTDOWN);
+        context.registerReceiver(mShutDownReceiver, shutdownFilter);
+
         // create Notification channel.
         mNotificationManager = (NotificationManager)
                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -617,6 +620,11 @@
 
         initMediaPlayersList();
 
+        BrowsedMediaPlayer_ext player =
+                mAvrcpBrowseManager.getBrowsedMediaPlayer(dummyaddr);
+        if (player != null)
+            player.start();
+
         UserManager manager = UserManager.get(mContext);
         if (manager == null || manager.isUserUnlocked()) {
             if (DEBUG) Log.d(TAG, "User already unlocked, initializing player lists");
@@ -659,7 +667,7 @@
             mAudioManager.unregisterAudioPlaybackCallback(mAudioManagerPlaybackCb);
 
         if (mMediaController != null) mMediaController.unregisterCallback(mMediaControllerCb);
-        Message msg = mHandler.obtainMessage(MESSAGE_DEVICE_RC_CLEANUP, APP_CLEANUP,
+        Message msg = mHandler.obtainMessage(MESSAGE_DEVICE_RC_CLEANUP, 0,
                0, null);
         mHandler.sendMessage(msg);
         if (mMediaSessionManager != null) {
@@ -687,6 +695,7 @@
         mAudioManagerPlaybackHandler = null;
         mContext.unregisterReceiver(mAvrcpReceiver);
         mContext.unregisterReceiver(mBootReceiver);
+        mContext.unregisterReceiver(mShutDownReceiver);
 
         mPkgRequestedMBSConnect.clear();
         mAddressedMediaPlayer.cleanup();
@@ -1491,27 +1500,11 @@
 
             case MESSAGE_DEVICE_RC_CLEANUP:
                 if (DEBUG)
-                    Log.v(TAG,"MESSAGE_DEVICE_RC_CLEANUP: " + msg.arg1);
-                if (msg.arg1 == STACK_CLEANUP) {
-                    deviceIndex = getIndexForDevice((BluetoothDevice) msg.obj);
-                    if (deviceIndex == INVALID_DEVICE_INDEX) {
-                        Log.e(TAG,"invalid device index for cleanup");
-                        break;
+                    Log.v(TAG, "MESSAGE_DEVICE_RC_CLEANUP");
+                    clearDeviceDependentFeature();
+                    for (int i = 0; i < maxAvrcpConnections; i++) {
+                       cleanupDeviceFeaturesIndex(i);
                     }
-                    cleanupDeviceFeaturesIndex(deviceIndex);
-                } else if (msg.arg1 == APP_CLEANUP) {
-                    if (msg.obj == null) {
-                        clearDeviceDependentFeature();
-                        for (int i = 0; i < maxAvrcpConnections; i++) {
-                            cleanupDeviceFeaturesIndex(i);
-                        }
-                    } else {
-                        Log.v(TAG, "Invalid message params");
-                        break;
-                    }
-                } else {
-                    Log.v(TAG, "Invalid Arguments to MESSAGE_DEVICE_RC_CLEANUP");
-                }
                 break;
 
             case MSG_NATIVE_REQ_GET_FOLDER_ITEMS: {
@@ -2302,7 +2295,7 @@
                         builder.setState(PlaybackState.STATE_PLAYING,
                                 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f);
                         newState = builder.build();
-                    } else if (!mAudioManagerIsPlaying && !mAudioManager.isMusicActive()){
+                    } else if (!mAudioManagerIsPlaying) {
                         builder.setState(PlaybackState.STATE_PAUSED,
                                 PlaybackState.PLAYBACK_POSITION_UNKNOWN, 0.0f);
                         newState = builder.build();
@@ -3552,22 +3545,16 @@
      */
     public void setAvrcpDisconnectedDevice(BluetoothDevice device) {
         Log.i(TAG,"Enter setAvrcpDisconnectedDevice");
+        int deviceIndex = INVALID_DEVICE_INDEX;
         for (int i = 0; i < maxAvrcpConnections; i++ ) {
-            if (deviceFeatures[i].mCurrentDevice !=null && device != null &&
+            if (deviceFeatures[i].mCurrentDevice != null && device != null &&
                     Objects.equals(deviceFeatures[i].mCurrentDevice, device)) {
+                deviceIndex = i;
                 if (deviceFeatures[i].isActiveDevice &&
                       deviceFeatures[i].isAbsoluteVolumeSupportingDevice) {
                     storeVolumeForDevice(device);
                     disconnectedActiveDevice = device;
-                 }
-                // initiate cleanup for all variables;
-                Message msg = mHandler.obtainMessage(MESSAGE_DEVICE_RC_CLEANUP, STACK_CLEANUP,
-                       0, device);
-                mHandler.sendMessage(msg);
-                Log.i(TAG,"Device removed is " + device);
-                Log.i(TAG,"removed at " + i);
-                deviceFeatures[i].mRemoteVolume = -1;
-                deviceFeatures[i].mLocalVolume = -1;
+                }
             }
             if (deviceFeatures[i].mCurrentDevice != null && device != null &&
                     !(Objects.equals(deviceFeatures[i].mCurrentDevice, device))) {
@@ -3582,6 +3569,13 @@
             }
         }
 
+        if (deviceIndex != INVALID_DEVICE_INDEX) {
+            // initiate cleanup for all variables;
+            cleanupDeviceFeaturesIndex(deviceIndex);
+            Log.i(TAG,"Device removed is " + device);
+            Log.i(TAG,"removed at " + deviceIndex);
+        }
+
         BATService mBatService = BATService.getBATService();
         if ((mBatService != null) && mBatService.isBATActive()) {
             Log.d(TAG," setAvrcpDisconnectedDevice BA Active, update absvol support as true  ");
@@ -3649,6 +3643,26 @@
         }
     }
 
+    private class AvrcpServiceShutDownReceiver extends BroadcastReceiver {
+    @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            BluetoothDevice device = null;
+            if (DEBUG) Log.d(TAG, "AvrcpServiceShutdownReceiver-> Action: " + action);
+            if (action.equals(Intent.ACTION_SHUTDOWN)) {
+                int storeVolume =  mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+                if (DEBUG) Log.d(TAG, "AvrcpServiceShutdownReceiver store volume " + storeVolume);
+                if (mA2dpService != null)
+                   device =  mA2dpService.getActiveDevice();
+                SharedPreferences.Editor pref = getVolumeMap().edit();
+                if (device != null) {
+                    pref.putInt(device.getAddress(), storeVolume);
+                    pref.apply();
+                }
+            }
+        }
+    }
+
     private void handlePackageModified(String packageName, boolean removed) {
         if (DEBUG) Log.d(TAG, "packageName: " + packageName + " removed: " + removed);
 
@@ -3993,8 +4007,6 @@
                 mBrowsePlayerInfoList.clear();
                 BrowsedMediaPlayer_ext player =
                         mAvrcpBrowseManager.getBrowsedMediaPlayer(dummyaddr);
-                if (player != null)
-                    player.start();
                 Log.d(TAG, "buildBrowsablePlayerList " + player);
                 Intent intent = new Intent(android.service.media.MediaBrowserService.SERVICE_INTERFACE);
                 List<ResolveInfo> playerList =
@@ -4724,6 +4736,8 @@
         deviceFeatures[index].mLastRemoteVolume = -1;
         deviceFeatures[index].mLastLocalVolume = -1;
         deviceFeatures[index].cache_play_cmd = false;
+        deviceFeatures[index].mRemoteVolume = -1;
+        deviceFeatures[index].mLocalVolume = -1;
     }
 
     private void onConnectionStateChanged(
@@ -5936,9 +5950,12 @@
     }
 
     public static String getImgHandleFromTitle(byte[] bdaddr, String title) {
+        String handle = null;
         if (DEBUG) Log.d(TAG, " getImgHandleFromTitle bdaddr:" + bdaddr + " title:" + title);
-        if (mAvrcpBipRsp != null && title != null)
-            return mAvrcpBipRsp.getImgHandleFromTitle(bdaddr, title);
-        return "";
+        if (mAvrcpBipRsp != null && title != null) {
+            handle = mAvrcpBipRsp.getImgHandleFromTitle(bdaddr, title);
+            return (handle != null && !handle.isEmpty()) ? handle:null;
+        }
+        return handle;
     }
 }
diff --git a/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java b/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
index 9699379..d0827bb 100644
--- a/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
+++ b/packages_apps_bluetooth_ext/src/avrcp/BrowsedMediaPlayer_ext.java
@@ -61,6 +61,10 @@
     private static final int BROWSED_FOLDER_ID_INDEX = 4;
     private static final String[] ROOT_FOLDER = {"root"};
     private static boolean mPlayerRoot = false;
+
+    private boolean mNeedToSendGetFolderItem = false;
+    private MediaBrowser mTempMediaBrowser = null;
+
     /*  package and service name of target Media Player which is set for browsing */
     private String mPackageName;
     private String mConnectingPackageName;
@@ -188,6 +192,7 @@
                 return;
             }
             mConnState = DISCONNECTED;
+            mTempMediaBrowser = null;
             // Remove what could be a circular dependency causing GC to never happen on this object
             mBrowser = null;
             Log.e(TAG, "mediaBrowser Connection failed with " + mPackageName
@@ -206,6 +211,7 @@
                 return;
             }
             mBrowser = null;
+            mTempMediaBrowser = null;
             mConnState = SUSPENDED;
             Log.e(TAG, "mediaBrowser SUSPENDED connection with " + mPackageName);
         }
@@ -222,18 +228,16 @@
                         Log.d(TAG, "OnChildren Loaded folder items: childrens= " + children.size());
                     }
 
-            /*
-             * cache current folder items and send as rsp when remote requests
-             * get_folder_items (scope = vfs)
-             */
+                    /*
+                     * cache current folder items and send as rsp when remote requests
+                     * get_folder_items (scope = vfs)
+                     */
                     if (mFolderItems == null) {
-                        if (DEBUG) {
-                            Log.d(TAG, "sending setbrowsed player rsp");
-                        }
                         Log.w(TAG, "sending setbrowsed player rsp");
                         mFolderItems = children;
                         mMediaInterface.setBrowsedPlayerRsp(mBDAddr, AvrcpConstants_ext.RSP_NO_ERROR,
                                 (byte) 0x00, children.size(), ROOT_FOLDER);
+                        RespondPendingGetFolderItemsVFS();
                     } else {
                         mFolderItems = children;
                         mCurrFolderNumItems = mFolderItems.size();
@@ -247,6 +251,7 @@
                 /* UID is invalid */
                 @Override
                 public void onError(String id) {
+                    RespondPendingGetFolderItemsVFS();
                     Log.e(TAG, "set browsed player rsp. Could not get root folder items");
                     mMediaInterface.setBrowsedPlayerRsp(mBDAddr, AvrcpConstants_ext.RSP_INTERNAL_ERR,
                             (byte) 0x00, 0, null);
@@ -371,6 +376,7 @@
                     "we aren't connecting to " + connectedPackage);
             mMediaInterface.setBrowsedPlayerRsp(
                     mBDAddr, AvrcpConstants_ext.RSP_INTERNAL_ERR, (byte) 0x00, 0, null);
+            RespondPendingGetFolderItemsVFS();
             return;
         }
         mConnectingPackageName = null;
@@ -379,6 +385,7 @@
             Log.e(TAG, "onBrowseConnect: received a null browser for " + connectedPackage);
             mMediaInterface.setBrowsedPlayerRsp(mBDAddr, AvrcpConstants_ext.RSP_INTERNAL_ERR,
                     (byte) 0x00, 0, null);
+            RespondPendingGetFolderItemsVFS();
             return;
         }
 
@@ -405,6 +412,7 @@
                         Log.e(TAG, "onBrowseConnect: root value is empty or null");
                         mMediaInterface.setBrowsedPlayerRsp(
                                 mBDAddr, AvrcpConstants_ext.RSP_INTERNAL_ERR, (byte) 0x00, 0, null);
+                        RespondPendingGetFolderItemsVFS();
                         return;
                     }
 
@@ -440,6 +448,7 @@
             ex.printStackTrace();
         }
 
+        RespondPendingGetFolderItemsVFS();
         mMediaInterface.setBrowsedPlayerRsp(mBDAddr, AvrcpConstants_ext.RSP_INTERNAL_ERR, (byte) 0x00,
                 0, null);
     }
@@ -468,6 +477,7 @@
            MediaConnectionCallback callback = new MediaConnectionCallback(packageName);
            MediaBrowser tempBrowser = new MediaBrowser(
                    mContext, new ComponentName(packageName, mClassName), callback, null);
+           mTempMediaBrowser = tempBrowser;
            callback.setBrowser(tempBrowser);
            tempBrowser.connect();
         } else if (mFolderItems != null) {
@@ -570,13 +580,15 @@
             Log.w(TAG, "Already in MBS List don't reconnect" + mBrowsablePlayerList);
             return;
         }
-        Message msg = mHandler.obtainMessage(MSG_CONNECT_PLAYER);
-        Bundle data = new Bundle();
-        data.putCharSequence("package", packageName);
-        data.putCharSequence("class", cls);
-        msg.setData(data);
-        mHandler.sendMessage(msg);
-        Log.w(TAG, "Exit MSG_CONNECT_PLAYER for package = " + packageName);
+        if (mHandler != null) {
+            Message msg = mHandler.obtainMessage(MSG_CONNECT_PLAYER);
+            Bundle data = new Bundle();
+            data.putCharSequence("package", packageName);
+            data.putCharSequence("class", cls);
+            msg.setData(data);
+            mHandler.sendMessage(msg);
+            Log.w(TAG, "Exit MSG_CONNECT_PLAYER for package = " + packageName);
+        }
     }
 
     public boolean isPackageInMBSList(String packageName) {
@@ -811,17 +823,22 @@
             TryReconnectBrowse(mCurrentBrowsePackage, mCurrentBrowseClass);
         }
 
-        if (mFolderItems == null) {
+        if (mFolderItems == null && mTempMediaBrowser == null) {
             /* Failed to fetch folder items from media player. Send error to remote device */
             Log.e(TAG, "Failed to fetch folder items during getFolderItemsVFS");
             mMediaInterface.folderItemsRsp(mBDAddr, AvrcpConstants_ext.RSP_INTERNAL_ERR, null);
             return;
         }
 
-        /* Filter attributes based on the request and send response to remote device */
-        getFolderItemsFilterAttr(mBDAddr, reqObj, mFolderItems,
-                AvrcpConstants_ext.BTRC_SCOPE_FILE_SYSTEM, mFolderItemsReqObj.mStartItem,
-                mFolderItemsReqObj.mEndItem);
+        if (mFolderItems != null) {
+            /* Filter attributes based on the request and send response to remote device */
+            getFolderItemsFilterAttr(mBDAddr, reqObj, mFolderItems,
+                    AvrcpConstants_ext.BTRC_SCOPE_FILE_SYSTEM, mFolderItemsReqObj.mStartItem,
+                    mFolderItemsReqObj.mEndItem);
+        } else {
+            mNeedToSendGetFolderItem = true;
+            Log.w(TAG, "Need to send getFolderItemsVFS after obtaing VFS");
+        }
     }
 
     /* Instructs media player to play particular media item */
@@ -1077,6 +1094,17 @@
 
     /* Helper methods */
 
+    private void RespondPendingGetFolderItemsVFS() {
+        if (mNeedToSendGetFolderItem) {
+            Log.w(TAG, "send pending get foler item rsp");
+            mNeedToSendGetFolderItem = false;
+            getFolderItemsFilterAttr(mBDAddr, mFolderItemsReqObj, mFolderItems,
+                    AvrcpConstants_ext.BTRC_SCOPE_FILE_SYSTEM,
+                    mFolderItemsReqObj.mStartItem, mFolderItemsReqObj.mEndItem);
+        }
+        mTempMediaBrowser = null;
+    }
+
     /* check if item is browsable Down*/
     private boolean isBrowsableFolderDn(String uid) {
         for (MediaBrowser.MediaItem item : mFolderItems) {
diff --git a/system_bt_ext/conf/interop_database.conf b/system_bt_ext/conf/interop_database.conf
index cc3f770..c079694 100644
--- a/system_bt_ext/conf/interop_database.conf
+++ b/system_bt_ext/conf/interop_database.conf
@@ -415,8 +415,11 @@
 #request by adding some delay. Some remotes are very strict in the
 #order of call indicator and SCO connection request.
 #1 04:52:c7 - Bose Mini II sound link
+#2 24:A8:7D - Maruti Suzuki CIAZ 2018 - Delta
 [INTEROP_DELAY_SCO_FOR_MT_CALL]
 04:52:c7 = Address_Based
+AirPods Pro = Name_Based
+24:A8:7D = Address_Based
 
 # Some remotes ara taking longer to respond to +BCS during codec negotiation.
 # Disable codec negotiation and directly initiate SCO connection for those.