Merge "DO NOT MERGE Initialize VolumeUI when volume change event is received." into qt-qpr1-dev
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 4169296..31fb118 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -23,15 +23,19 @@
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.car.Car;
+import android.car.CarNotConnectedException;
 import android.car.drivingstate.CarDrivingStateEvent;
 import android.car.drivingstate.CarUxRestrictionsManager;
 import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
+import android.car.media.CarAudioManager;
 import android.content.Context;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.inputmethodservice.InputMethodService;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.util.Log;
 import android.view.Display;
 import android.view.GestureDetector;
@@ -99,6 +103,7 @@
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeUI;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -155,6 +160,8 @@
     private NotificationDataManager mNotificationDataManager;
     private NotificationClickHandlerFactory mNotificationClickHandlerFactory;
     private ScreenLifecycle mScreenLifecycle;
+    private CarAudioManager mCarAudioManager;
+    private VolumeUI mVolumeUI;
 
     // The container for the notifications.
     private CarNotificationView mNotificationView;
@@ -216,6 +223,28 @@
                 }
             };
 
+    private final CarAudioManager.CarVolumeCallback mVolumeChangeCallback =
+            new CarAudioManager.CarVolumeCallback() {
+                @Override
+                public void onGroupVolumeChanged(int zoneId, int groupId, int flags) {
+                    if (mVolumeUI == null) {
+                        new Handler(Looper.getMainLooper()).post(() -> {
+                            // Initialize Volume UI
+                            mVolumeUI = new VolumeUI();
+                            mVolumeUI.mComponents = mComponents;
+                            mVolumeUI.mContext = mContext;
+                            mVolumeUI.start();
+                        });
+                        mCarAudioManager.unregisterCarVolumeCallback(mVolumeChangeCallback);
+                    }
+                }
+
+                @Override
+                public void onMasterMuteChanged(int zoneId, int flags) {
+                    // ignored
+                }
+            };
+
     @Override
     public void start() {
         // Non blocking call to connect to car service. Call this early so that we'll be connected
@@ -301,6 +330,22 @@
 
         mPowerManagerHelper = new PowerManagerHelper(mContext, mCarPowerStateListener);
         mPowerManagerHelper.connectToCarService();
+
+        ((CarSystemUIFactory) SystemUIFactory.getInstance()).getCarServiceProvider(mContext)
+                .addListener((car, ready) -> {
+                    if (!ready || mCarAudioManager != null) {
+                        return;
+                    }
+                    try {
+                        mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
+                        Log.d(TAG, "Registering mVolumeChangeCallback.");
+                        // This volume call back is never unregistered because CarStatusBar is
+                        // never destroyed.
+                        mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
+                    } catch (CarNotConnectedException e) {
+                        Log.wtf(TAG, " mVolumeChangeCallback failed to connect to car ", e);
+                    }
+                });
     }
 
     private void restartNavBarsIfNecessary() {
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
index 71cc19b..aa78b960 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
@@ -31,6 +31,10 @@
     }
 
     protected VolumeDialog createDefault() {
-        return new CarVolumeDialogImpl(mContext);
+        CarVolumeDialogImpl carVolumeDialog = new CarVolumeDialogImpl(mContext);
+        // Since VolumeUI is initialized when the first Volume Up/Down event is received we need to
+        // show the dialog on initialization too.
+        carVolumeDialog.show(Events.SHOW_REASON_VOLUME_CHANGED);
+        return carVolumeDialog;
     }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 0dad8e5..b184224 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -197,6 +197,7 @@
     @Override
     public void init(int windowType, Callback callback) {
         initDialog();
+
         ((CarSystemUIFactory) SystemUIFactory.getInstance()).getCarServiceProvider(mContext)
                 .addListener(mCarServiceLifecycleListener);
     }
@@ -265,6 +266,19 @@
         mListView.setLayoutManager(new LinearLayoutManager(mContext));
     }
 
+    /**
+     * Reveals volume dialog.
+     */
+    public void show(int reason) {
+        mHandler.obtainMessage(H.SHOW, reason).sendToTarget();
+    }
+
+    /**
+     * Hides volume dialog.
+     */
+    public void dismiss(int reason) {
+        mHandler.obtainMessage(H.DISMISS, reason).sendToTarget();
+    }
 
     private void showH(int reason) {
         if (D.BUG) {