Merge "[Audiosharing] Impl the stop audio sharing dialog." into main
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
index d4803c6..0a6795f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
@@ -16,10 +16,12 @@
 
 package com.android.settings.connecteddevice.audiosharing;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothLeBroadcastAssistant;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.util.Log;
@@ -38,9 +40,14 @@
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.flags.Flags;
 import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LeAudioProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
 
+import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 
@@ -53,11 +60,13 @@
             "connected_device_audio_sharing_settings";
 
     private final LocalBluetoothManager mLocalBtManager;
+    private final LocalBluetoothLeBroadcast mBroadcast;
     private final LocalBluetoothLeBroadcastAssistant mAssistant;
     private final Executor mExecutor;
     private PreferenceGroup mPreferenceGroup;
     private Preference mAudioSharingSettingsPreference;
     private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+    private DashboardFragment mFragment;
 
     private BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
             new BluetoothLeBroadcastAssistant.Callback() {
@@ -149,6 +158,7 @@
     public AudioSharingDevicePreferenceController(Context context) {
         super(context, KEY);
         mLocalBtManager = Utils.getLocalBtManager(mContext);
+        mBroadcast = mLocalBtManager.getProfileManager().getLeAudioBroadcastProfile();
         mAssistant = mLocalBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
         mExecutor = Executors.newSingleThreadExecutor();
     }
@@ -156,15 +166,15 @@
     @Override
     public void onStart(@NonNull LifecycleOwner owner) {
         if (mLocalBtManager == null) {
-            Log.e(TAG, "onStart() Bluetooth is not supported on this device");
+            Log.d(TAG, "onStart() Bluetooth is not supported on this device");
             return;
         }
         if (mAssistant == null) {
-            Log.e(TAG, "onStart() Broadcast assistant is not supported on this device");
+            Log.d(TAG, "onStart() Broadcast assistant is not supported on this device");
             return;
         }
         if (mBluetoothDeviceUpdater == null) {
-            Log.e(TAG, "onStart() Bluetooth device updater is not initialized");
+            Log.d(TAG, "onStart() Bluetooth device updater is not initialized");
             return;
         }
         mLocalBtManager.getEventManager().registerCallback(this);
@@ -176,15 +186,15 @@
     @Override
     public void onStop(@NonNull LifecycleOwner owner) {
         if (mLocalBtManager == null) {
-            Log.e(TAG, "onStop() Bluetooth is not supported on this device");
+            Log.d(TAG, "onStop() Bluetooth is not supported on this device");
             return;
         }
         if (mAssistant == null) {
-            Log.e(TAG, "onStop() Broadcast assistant is not supported on this device");
+            Log.d(TAG, "onStop() Broadcast assistant is not supported on this device");
             return;
         }
         if (mBluetoothDeviceUpdater == null) {
-            Log.e(TAG, "onStop() Bluetooth device updater is not initialized");
+            Log.d(TAG, "onStop() Bluetooth device updater is not initialized");
             return;
         }
         mLocalBtManager.getEventManager().unregisterCallback(this);
@@ -244,17 +254,60 @@
         }
     }
 
+    @Override
+    public void onProfileConnectionStateChanged(
+            @NonNull CachedBluetoothDevice cachedDevice,
+            @ConnectionState int state,
+            int bluetoothProfile) {
+        if (state != BluetoothAdapter.STATE_CONNECTED || !cachedDevice.getDevice().isConnected()) {
+            Log.d(TAG, "Ignore onProfileConnectionStateChanged, not connected state");
+            return;
+        }
+        List<LocalBluetoothProfile> supportedProfiles = cachedDevice.getProfiles();
+        boolean isLeAudioSupported = false;
+        for (LocalBluetoothProfile profile : supportedProfiles) {
+            if (profile instanceof LeAudioProfile && profile.isEnabled(cachedDevice.getDevice())) {
+                isLeAudioSupported = true;
+            }
+            if (profile.getProfileId() != bluetoothProfile
+                    && profile.getConnectionStatus(cachedDevice.getDevice())
+                            == BluetoothProfile.STATE_CONNECTED) {
+                Log.d(
+                        TAG,
+                        "Ignore onProfileConnectionStateChanged, not the first connected profile");
+                return;
+            }
+        }
+        // Show stop audio sharing dialog when an ineligible (not le audio) remote device connected
+        // during a sharing session.
+        if (isBroadcasting() && !isLeAudioSupported) {
+            if (mFragment != null) {
+                AudioSharingStopDialogFragment.show(
+                        mFragment,
+                        cachedDevice.getName(),
+                        () -> {
+                            mBroadcast.stopBroadcast(mBroadcast.getLatestBroadcastId());
+                        });
+            }
+        }
+    }
+
     /**
      * Initialize the controller.
      *
      * @param fragment The fragment to provide the context and metrics category for {@link
-     *     AudioSharingBluetoothDeviceUpdater}.
+     *     AudioSharingBluetoothDeviceUpdater} and provide the host for dialogs.
      */
     public void init(DashboardFragment fragment) {
+        mFragment = fragment;
         mBluetoothDeviceUpdater =
                 new AudioSharingBluetoothDeviceUpdater(
                         fragment.getContext(),
                         AudioSharingDevicePreferenceController.this,
                         fragment.getMetricsCategory());
     }
+
+    private boolean isBroadcasting() {
+        return mBroadcast != null && mBroadcast.isEnabled(null);
+    }
 }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
new file mode 100644
index 0000000..495fad3
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+package com.android.settings.connecteddevice.audiosharing;
+
+import android.app.Dialog;
+import android.app.settings.SettingsEnums;
+import android.os.Bundle;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.flags.Flags;
+
+public class AudioSharingStopDialogFragment extends InstrumentedDialogFragment {
+    private static final String TAG = "AudioSharingStopDialog";
+
+    private static final String BUNDLE_KEY_NEW_DEVICE_NAME = "bundle_key_new_device_name";
+
+    // The host creates an instance of this dialog fragment must implement this interface to receive
+    // event callbacks.
+    public interface DialogEventListener {
+        /** Called when users click the stop sharing button in the dialog. */
+        void onStopSharingClick();
+    }
+
+    private static DialogEventListener sListener;
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.DIALOG_STOP_AUDIO_SHARING;
+    }
+
+    /**
+     * Display the {@link AudioSharingStopDialogFragment} dialog.
+     *
+     * @param host The Fragment this dialog will be hosted.
+     */
+    public static void show(Fragment host, String newDeviceName, DialogEventListener listener) {
+        if (!Flags.enableLeAudioSharing()) return;
+        final FragmentManager manager = host.getChildFragmentManager();
+        sListener = listener;
+        if (manager.findFragmentByTag(TAG) == null) {
+            final Bundle bundle = new Bundle();
+            bundle.putString(BUNDLE_KEY_NEW_DEVICE_NAME, newDeviceName);
+            AudioSharingStopDialogFragment dialog = new AudioSharingStopDialogFragment();
+            dialog.setArguments(bundle);
+            dialog.show(manager, TAG);
+        }
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Bundle arguments = requireArguments();
+        String newDeviceName = arguments.getString(BUNDLE_KEY_NEW_DEVICE_NAME);
+        final AlertDialog.Builder builder =
+                new AlertDialog.Builder(getActivity())
+                        .setTitle("Stop sharing audio?")
+                        .setCancelable(false);
+        builder.setMessage(
+                newDeviceName + " is connected, devices in audio sharing will disconnect.");
+        builder.setPositiveButton(
+                "Stop sharing",
+                (dialog, which) -> {
+                    sListener.onStopSharingClick();
+                });
+        builder.setNegativeButton(
+                "Cancel",
+                (dialog, which) -> {
+                    dismiss();
+                });
+        AlertDialog dialog = builder.create();
+        dialog.setCanceledOnTouchOutside(false);
+        return dialog;
+    }
+}