Display the current connected audio device

If connected via bluetooth.

Also fix long press behavior on the ringer footer, and
change the output chooser icon.

Test: manual
Bug: 63096355
Change-Id: I2c4d86fb03f8ac38721b6fc580bba45871d59f5d
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index 903ff72..32eb5d5 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -172,5 +172,6 @@
         void onScreenOff();
         void onShowSafetyWarning(int flags);
         void onAccessibilityModeChanged(Boolean showA11yStream);
+        void onConnectedDeviceChanged(String deviceName);
     }
 }
diff --git a/packages/SystemUI/res/drawable/ic_swap.xml b/packages/SystemUI/res/drawable/ic_swap.xml
new file mode 100644
index 0000000..30da2a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_swap.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorForeground">
+    <path
+        android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"
+        android:fillColor="#FFFFFF"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 3590b76..1d1f95b 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -38,23 +38,34 @@
             android:maxLines="1"
             android:textColor="?android:attr/colorControlNormal"
             android:textAppearance="?android:attr/textAppearanceSmall" />
-        <TextView
-            android:id="@+id/volume_row_connected_device"
-            android:visibility="gone"
+        <LinearLayout
+            android:id="@+id/output_chooser"
+            android:orientation="vertical"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:maxLines="1"
-            android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" />
-        <com.android.keyguard.AlphaOptimizedImageButton
-            android:id="@+id/output_chooser"
-            style="@style/VolumeButtons"
+            android:minWidth="48dp"
+            android:minHeight="48dp"
+            android:paddingTop="10dp"
             android:background="?android:selectableItemBackgroundBorderless"
-            android:layout_width="@dimen/volume_button_size"
-            android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
-            android:src="@drawable/ic_volume_expand_animation"
-            android:soundEffectsEnabled="false" />
+            android:gravity="center">
+            <TextView
+                android:id="@+id/volume_row_connected_device"
+                android:visibility="gone"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ellipsize="end"
+                android:maxLines="1"
+                android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" />
+            <com.android.keyguard.AlphaOptimizedImageButton
+                android:id="@+id/output_chooser_button"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:background="?android:selectableItemBackgroundBorderless"
+                style="@style/VolumeButtons"
+                android:layout_centerVertical="true"
+                android:src="@drawable/ic_swap"
+                android:soundEffectsEnabled="false" />
+        </LinearLayout>
     </LinearLayout>
     <FrameLayout
         android:id="@+id/volume_row_slider_frame"
diff --git a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
index e3c8503..5c888ac 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/OutputChooserDialog.java
@@ -514,5 +514,8 @@
 
         @Override
         public void onAccessibilityModeChanged(Boolean showA11yStream) {}
+
+        @Override
+        public void onConnectedDeviceChanged(String deviceName) {}
     };
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 4464f75..2e23920 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -26,6 +26,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.ContentObserver;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.IVolumeController;
@@ -105,6 +107,8 @@
     private boolean mShowA11yStream;
     private boolean mShowVolumeDialog;
     private boolean mShowSafetyWarning;
+    private DeviceCallback mDeviceCallback = new DeviceCallback();
+    private AudioDeviceInfo mConnectedDevice;
 
     private boolean mDestroyed;
     private VolumePolicy mVolumePolicy;
@@ -180,6 +184,7 @@
         } catch (SecurityException e) {
             Log.w(TAG, "No access to media sessions", e);
         }
+        mAudio.registerAudioDeviceCallback(mDeviceCallback, mWorker);
     }
 
     public void setVolumePolicy(VolumePolicy policy) {
@@ -205,6 +210,7 @@
         mMediaSessions.destroy();
         mObserver.destroy();
         mReceiver.destroy();
+        mAudio.unregisterAudioDeviceCallback(mDeviceCallback);
         mWorkerThread.quitSafely();
     }
 
@@ -664,6 +670,7 @@
                 case USER_ACTIVITY: onUserActivityW(); break;
                 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
                 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
+
             }
         }
     }
@@ -803,6 +810,18 @@
                 });
             }
         }
+
+        @Override
+        public void onConnectedDeviceChanged(String deviceName) {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onConnectedDeviceChanged(deviceName);
+                    }
+                });
+            }
+        }
     }
 
 
@@ -1005,6 +1024,34 @@
         }
     }
 
+    protected final class DeviceCallback extends AudioDeviceCallback {
+        public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+            for (AudioDeviceInfo info : addedDevices) {
+                if (info.isSink()
+                        && (info.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP
+                        || info.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO)) {
+                    mConnectedDevice = info;
+                    mCallbacks.onConnectedDeviceChanged(info.getProductName().toString());
+                }
+            }
+        }
+
+        public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+            if (mConnectedDevice == null) {
+                mCallbacks.onConnectedDeviceChanged(null);
+                return;
+            }
+            for (AudioDeviceInfo info : removedDevices) {
+                if (info.isSink() == mConnectedDevice.isSink()
+                        && Objects.equals(info.getProductName(), mConnectedDevice.getProductName())
+                        && info.getType() == mConnectedDevice.getType()) {
+                    mConnectedDevice = null;
+                    mCallbacks.onConnectedDeviceChanged(null);
+                }
+            }
+        }
+    }
+
     public interface UserActivityListener {
         void onUserActivity();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 385438c..56b7201 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -48,6 +48,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.support.v7.media.MediaRouter;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -73,6 +74,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.VolumeDialog;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.plugins.VolumeDialogController.State;
@@ -332,8 +334,11 @@
         row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
         row.anim = null;
 
-        ImageButton outputChooser = row.view.findViewById(R.id.output_chooser);
-        outputChooser.setOnClickListener(mClickOutputChooser);
+        row.outputChooser = row.view.findViewById(R.id.output_chooser);
+        row.outputChooser.setOnClickListener(mClickOutputChooser);
+        row.outputChooser.findViewById(R.id.output_chooser_button)
+                .setOnClickListener(mClickOutputChooser);
+        row.connectedDevice = row.view.findViewById(R.id.volume_row_connected_device);
 
         // forward events above the slider into the slider
         row.view.setOnTouchListener(new OnTouchListener() {
@@ -422,7 +427,7 @@
             Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             dismissH(DISMISS_REASON_SETTINGS_CLICKED);
-            mContext.startActivity(intent);
+            Dependency.get(ActivityStarter.class).startActivity(intent, true /* dismissShade */);
             return true;
         });
         updateRingerH();
@@ -546,6 +551,13 @@
         }
     }
 
+    protected void updateConnectedDeviceH(String deviceName) {
+        for (final VolumeRow row : mRows) {
+            row.connectedDevice.setText(deviceName);
+            Util.setVisOrGone(row.connectedDevice, !TextUtils.isEmpty(deviceName));
+        }
+    }
+
     protected void updateRingerH() {
         if (mState != null) {
             final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
@@ -957,6 +969,11 @@
             }
 
         }
+
+        @Override
+        public void onConnectedDeviceChanged(String deviceName) {
+            updateConnectedDeviceH(deviceName);
+        }
     };
 
     private final class H extends Handler {
@@ -1155,5 +1172,7 @@
         private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
         private int animTargetProgress;
         private int lastAudibleLevel = 1;
+        private View outputChooser;
+        private TextView connectedDevice;
     }
 }