Merge "[ANR] Settings froze" into rvc-dev
diff --git a/src/com/android/settings/media/MediaOutputIndicatorWorker.java b/src/com/android/settings/media/MediaOutputIndicatorWorker.java
index 0c6c434..f094d47 100644
--- a/src/com/android/settings/media/MediaOutputIndicatorWorker.java
+++ b/src/com/android/settings/media/MediaOutputIndicatorWorker.java
@@ -38,6 +38,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
+import com.android.settingslib.utils.ThreadUtils;
 
 import com.google.common.annotations.VisibleForTesting;
 
@@ -81,25 +82,29 @@
         mContext.registerReceiver(mReceiver, intentFilter);
         mLocalBluetoothManager.getEventManager().registerCallback(this);
 
-        final MediaController controller = getActiveLocalMediaController();
-        if (controller == null) {
-            mPackageName = null;
-        } else {
-            mPackageName = controller.getPackageName();
-        }
-        if (mLocalMediaManager == null || !TextUtils.equals(mPackageName,
-                mLocalMediaManager.getPackageName())) {
-            mLocalMediaManager = new LocalMediaManager(mContext, mPackageName,
-                    null /* notification */);
-        }
-        mLocalMediaManager.registerCallback(this);
-        mLocalMediaManager.startScan();
+        ThreadUtils.postOnBackgroundThread(() -> {
+            final MediaController controller = getActiveLocalMediaController();
+            if (controller == null) {
+                mPackageName = null;
+            } else {
+                mPackageName = controller.getPackageName();
+            }
+            if (mLocalMediaManager == null || !TextUtils.equals(mPackageName,
+                    mLocalMediaManager.getPackageName())) {
+                mLocalMediaManager = new LocalMediaManager(mContext, mPackageName,
+                        null /* notification */);
+            }
+            mLocalMediaManager.registerCallback(this);
+            mLocalMediaManager.startScan();
+        });
     }
 
     @Override
     protected void onSliceUnpinned() {
-        mLocalMediaManager.unregisterCallback(this);
-        mLocalMediaManager.stopScan();
+        if (mLocalMediaManager != null) {
+            mLocalMediaManager.unregisterCallback(this);
+            mLocalMediaManager.stopScan();
+        }
 
         if (mLocalBluetoothManager == null) {
             Log.e(TAG, "Bluetooth is not supported on this device");
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java
index dd3a236..0aec952 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java
@@ -103,7 +103,13 @@
     @Test
     public void onSlicePinned_registerCallback() {
         mMediaOutputIndicatorWorker.mLocalMediaManager = mLocalMediaManager;
+        initPlayback();
+        when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+        when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+        when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(mLocalMediaManager.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
         mMediaOutputIndicatorWorker.onSlicePinned();
+        waitForLocalMediaManagerInit();
 
         verify(mBluetoothEventManager).registerCallback(mMediaOutputIndicatorWorker);
         verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
@@ -119,11 +125,14 @@
         when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
 
         mMediaOutputIndicatorWorker.onSlicePinned();
+        waitForLocalMediaManagerInit();
         assertThat(mMediaOutputIndicatorWorker.mLocalMediaManager.getPackageName()).matches(
                 TEST_PACKAGE_NAME);
 
         when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME2);
+        mMediaOutputIndicatorWorker.mLocalMediaManager = null;
         mMediaOutputIndicatorWorker.onSlicePinned();
+        waitForLocalMediaManagerInit();
 
         assertThat(mMediaOutputIndicatorWorker.mLocalMediaManager.getPackageName()).matches(
                 TEST_PACKAGE_NAME2);
@@ -134,14 +143,35 @@
         mMediaControllers.clear();
 
         mMediaOutputIndicatorWorker.onSlicePinned();
+        waitForLocalMediaManagerInit();
 
         assertThat(mMediaOutputIndicatorWorker.mLocalMediaManager.getPackageName()).isNull();
     }
 
+    private void waitForLocalMediaManagerInit() {
+        for (int i = 0; i < 20; i++) {
+            if (mMediaOutputIndicatorWorker.mLocalMediaManager != null) {
+                return;
+            }
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
     @Test
     public void onSliceUnpinned_unRegisterCallback() {
         mMediaOutputIndicatorWorker.mLocalMediaManager = mLocalMediaManager;
+        initPlayback();
+        when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+        when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+        when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(mLocalMediaManager.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
         mMediaOutputIndicatorWorker.onSlicePinned();
+        waitForLocalMediaManagerInit();
         mMediaOutputIndicatorWorker.onSliceUnpinned();
 
         verify(mBluetoothEventManager).unregisterCallback(mMediaOutputIndicatorWorker);
@@ -153,6 +183,7 @@
     @Test
     public void onReceive_shouldNotifyChange() {
         mMediaOutputIndicatorWorker.onSlicePinned();
+        waitForLocalMediaManagerInit();
         // onSlicePinned will registerCallback() and get first callback. Callback triggers this at
         // the first time.
         verify(mResolver, times(1)).notifyChange(URI, null);