Merge "[Audiosharing] Add logging 2." into main
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceBadCodeState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceBadCodeState.java
index 1993377..56b1b2e 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceBadCodeState.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceBadCodeState.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
+import android.app.settings.SettingsEnums;
+
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
@@ -38,6 +40,17 @@
     }
 
     @Override
+    void performAction(
+            AudioStreamPreference preference,
+            AudioStreamsProgressCategoryController controller,
+            AudioStreamsHelper helper) {
+        mMetricsFeatureProvider.action(
+                preference.getContext(),
+                SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_BAD_CODE,
+                preference.getSourceOriginForLogging().ordinal());
+    }
+
+    @Override
     int getSummary() {
         return AUDIO_STREAM_ADD_SOURCE_BAD_CODE_STATE_SUMMARY;
     }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceFailedState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceFailedState.java
index 5d151ee..df41c14 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceFailedState.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceFailedState.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
+import android.app.settings.SettingsEnums;
+
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
@@ -38,6 +40,17 @@
     }
 
     @Override
+    void performAction(
+            AudioStreamPreference preference,
+            AudioStreamsProgressCategoryController controller,
+            AudioStreamsHelper helper) {
+        mMetricsFeatureProvider.action(
+                preference.getContext(),
+                SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_OTHER,
+                preference.getSourceOriginForLogging().ordinal());
+    }
+
+    @Override
     int getSummary() {
         return AUDIO_STREAM_ADD_SOURCE_FAILED_STATE_SUMMARY;
     }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java
index d314d3f..00342b1 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseState.java
@@ -17,6 +17,7 @@
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
 import android.app.AlertDialog;
+import android.app.settings.SettingsEnums;
 import android.content.Context;
 
 import androidx.annotation.Nullable;
@@ -52,6 +53,10 @@
         var metadata = preference.getAudioStreamMetadata();
         if (metadata != null) {
             helper.addSource(metadata);
+            mMetricsFeatureProvider.action(
+                    preference.getContext(),
+                    SettingsEnums.ACTION_AUDIO_STREAM_JOIN,
+                    preference.getSourceOriginForLogging().ordinal());
             // Cache the metadata that used for add source, if source is added successfully, we
             // will save it persistently.
             mAudioStreamsRepository.cacheMetadata(metadata);
@@ -66,6 +71,10 @@
                                 && preference.getAudioStreamState() == getStateEnum()) {
                             controller.handleSourceFailedToConnect(
                                     preference.getAudioStreamBroadcastId());
+                            mMetricsFeatureProvider.action(
+                                    preference.getContext(),
+                                    SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_TIMEOUT,
+                                    preference.getSourceOriginForLogging().ordinal());
                             ThreadUtils.postOnMainThread(
                                     () -> {
                                         if (controller.getFragment() != null) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java
index ea5abdf..2661072 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamButtonController.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
+import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothLeBroadcastAssistant;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
@@ -33,7 +34,9 @@
 import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.settingslib.widget.ActionButtonsPreference;
 
@@ -44,6 +47,7 @@
         implements DefaultLifecycleObserver {
     private static final String TAG = "AudioStreamButtonController";
     private static final String KEY = "audio_stream_button";
+    private static final int SOURCE_ORIGIN_REPOSITORY = SourceOriginForLogging.REPOSITORY.ordinal();
     private final BluetoothLeBroadcastAssistant.Callback mBroadcastAssistantCallback =
             new AudioStreamsBroadcastAssistantCallback() {
                 @Override
@@ -56,6 +60,8 @@
                 public void onSourceRemoveFailed(BluetoothDevice sink, int sourceId, int reason) {
                     super.onSourceRemoveFailed(sink, sourceId, reason);
                     updateButton();
+                    mMetricsFeatureProvider.action(
+                            mContext, SettingsEnums.ACTION_AUDIO_STREAM_LEAVE_FAILED);
                 }
 
                 @Override
@@ -66,6 +72,10 @@
                     super.onReceiveStateChanged(sink, sourceId, state);
                     if (AudioStreamsHelper.isConnected(state)) {
                         updateButton();
+                        mMetricsFeatureProvider.action(
+                                mContext,
+                                SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED,
+                                SOURCE_ORIGIN_REPOSITORY);
                     }
                 }
 
@@ -74,6 +84,10 @@
                         BluetoothDevice sink, BluetoothLeBroadcastMetadata source, int reason) {
                     super.onSourceAddFailed(sink, source, reason);
                     updateButton();
+                    mMetricsFeatureProvider.action(
+                            mContext,
+                            SettingsEnums.ACTION_AUDIO_STREAM_JOIN_FAILED_OTHER,
+                            SOURCE_ORIGIN_REPOSITORY);
                 }
 
                 @Override
@@ -88,6 +102,7 @@
     private final Executor mExecutor;
     private final AudioStreamsHelper mAudioStreamsHelper;
     private final @Nullable LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant;
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
     private @Nullable ActionButtonsPreference mPreference;
     private int mBroadcastId = -1;
 
@@ -96,6 +111,7 @@
         mExecutor = Executors.newSingleThreadExecutor();
         mAudioStreamsHelper = new AudioStreamsHelper(Utils.getLocalBtManager(context));
         mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant();
+        mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
     }
 
     @Override
@@ -124,59 +140,77 @@
     }
 
     private void updateButton() {
-        if (mPreference != null) {
-            if (mAudioStreamsHelper.getAllConnectedSources().stream()
-                    .map(BluetoothLeBroadcastReceiveState::getBroadcastId)
-                    .anyMatch(connectedBroadcastId -> connectedBroadcastId == mBroadcastId)) {
-                ThreadUtils.postOnMainThread(
-                        () -> {
-                            if (mPreference != null) {
-                                mPreference.setButton1Enabled(true);
-                                mPreference
-                                        .setButton1Text(R.string.audio_streams_disconnect)
-                                        .setButton1Icon(
-                                                com.android.settings.R.drawable.ic_settings_close)
-                                        .setButton1OnClickListener(
-                                                unused -> {
+        if (mPreference == null) {
+            Log.w(TAG, "updateButton(): preference is null!");
+            return;
+        }
+        boolean isConnected =
+                mAudioStreamsHelper.getAllConnectedSources().stream()
+                        .map(BluetoothLeBroadcastReceiveState::getBroadcastId)
+                        .anyMatch(connectedBroadcastId -> connectedBroadcastId == mBroadcastId);
+
+        View.OnClickListener onClickListener;
+
+        if (isConnected) {
+            onClickListener =
+                    unused ->
+                            ThreadUtils.postOnBackgroundThread(
+                                    () -> {
+                                        mAudioStreamsHelper.removeSource(mBroadcastId);
+                                        mMetricsFeatureProvider.action(
+                                                mContext,
+                                                SettingsEnums
+                                                        .ACTION_AUDIO_STREAM_LEAVE_BUTTON_CLICK);
+                                        ThreadUtils.postOnMainThread(
+                                                () -> {
                                                     if (mPreference != null) {
                                                         mPreference.setButton1Enabled(false);
                                                     }
-                                                    mAudioStreamsHelper.removeSource(mBroadcastId);
                                                 });
-                            }
-                        });
-            } else {
-                View.OnClickListener clickToRejoin =
-                        unused ->
-                                ThreadUtils.postOnBackgroundThread(
-                                        () -> {
-                                            var metadata =
-                                                    mAudioStreamsRepository.getSavedMetadata(
-                                                            mContext, mBroadcastId);
-                                            if (metadata != null) {
-                                                mAudioStreamsHelper.addSource(metadata);
-                                                ThreadUtils.postOnMainThread(
-                                                        () -> {
-                                                            if (mPreference != null) {
-                                                                mPreference.setButton1Enabled(
-                                                                        false);
-                                                            }
-                                                        });
-                                            }
-                                        });
-                ThreadUtils.postOnMainThread(
-                        () -> {
-                            if (mPreference != null) {
-                                mPreference.setButton1Enabled(true);
-                                mPreference
-                                        .setButton1Text(R.string.audio_streams_connect)
-                                        .setButton1Icon(com.android.settings.R.drawable.ic_add_24dp)
-                                        .setButton1OnClickListener(clickToRejoin);
-                            }
-                        });
-            }
+                                    });
+            ThreadUtils.postOnMainThread(
+                    () -> {
+                        if (mPreference != null) {
+                            mPreference.setButton1Enabled(true);
+                            mPreference
+                                    .setButton1Text(R.string.audio_streams_disconnect)
+                                    .setButton1Icon(
+                                            com.android.settings.R.drawable.ic_settings_close)
+                                    .setButton1OnClickListener(onClickListener);
+                        }
+                    });
         } else {
-            Log.w(TAG, "updateButton(): preference is null!");
+            onClickListener =
+                    unused ->
+                            ThreadUtils.postOnBackgroundThread(
+                                    () -> {
+                                        var metadata =
+                                                mAudioStreamsRepository.getSavedMetadata(
+                                                        mContext, mBroadcastId);
+                                        if (metadata != null) {
+                                            mAudioStreamsHelper.addSource(metadata);
+                                            mMetricsFeatureProvider.action(
+                                                    mContext,
+                                                    SettingsEnums.ACTION_AUDIO_STREAM_JOIN,
+                                                    SOURCE_ORIGIN_REPOSITORY);
+                                            ThreadUtils.postOnMainThread(
+                                                    () -> {
+                                                        if (mPreference != null) {
+                                                            mPreference.setButton1Enabled(false);
+                                                        }
+                                                    });
+                                        }
+                                    });
+            ThreadUtils.postOnMainThread(
+                    () -> {
+                        if (mPreference != null) {
+                            mPreference.setButton1Enabled(true);
+                            mPreference
+                                    .setButton1Text(R.string.audio_streams_connect)
+                                    .setButton1Icon(com.android.settings.R.drawable.ic_add_24dp)
+                                    .setButton1OnClickListener(onClickListener);
+                        }
+                    });
         }
     }
 
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreference.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreference.java
index f605e4b..071cf57 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreference.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreference.java
@@ -107,6 +107,12 @@
                 : AudioStreamsProgressCategoryController.AudioStreamState.UNKNOWN;
     }
 
+    SourceOriginForLogging getSourceOriginForLogging() {
+        return mAudioStream != null
+                ? mAudioStream.getSourceOriginForLogging()
+                : SourceOriginForLogging.UNKNOWN;
+    }
+
     @Override
     protected boolean shouldHideSecondTarget() {
         return mIsConnected || !mIsEncrypted;
@@ -130,11 +136,13 @@
     }
 
     static AudioStreamPreference fromMetadata(
-            Context context, BluetoothLeBroadcastMetadata source) {
+            Context context,
+            BluetoothLeBroadcastMetadata source,
+            SourceOriginForLogging sourceOriginForLogging) {
         AudioStreamPreference preference = new AudioStreamPreference(context, /* attrs= */ null);
         preference.setIsEncrypted(source.isEncrypted());
         preference.setTitle(AudioStreamsHelper.getBroadcastName(source));
-        preference.setAudioStream(new AudioStream(source));
+        preference.setAudioStream(new AudioStream(source, sourceOriginForLogging));
         return preference;
     }
 
@@ -158,11 +166,15 @@
         private static final int UNAVAILABLE = -1;
         @Nullable private BluetoothLeBroadcastMetadata mMetadata;
         @Nullable private BluetoothLeBroadcastReceiveState mReceiveState;
+        private SourceOriginForLogging mSourceOriginForLogging = SourceOriginForLogging.UNKNOWN;
         private AudioStreamsProgressCategoryController.AudioStreamState mState =
                 AudioStreamsProgressCategoryController.AudioStreamState.UNKNOWN;
 
-        private AudioStream(BluetoothLeBroadcastMetadata metadata) {
+        private AudioStream(
+                BluetoothLeBroadcastMetadata metadata,
+                SourceOriginForLogging sourceOriginForLogging) {
             mMetadata = metadata;
+            mSourceOriginForLogging = sourceOriginForLogging;
         }
 
         private AudioStream(BluetoothLeBroadcastReceiveState receiveState) {
@@ -191,6 +203,10 @@
             return mState;
         }
 
+        private SourceOriginForLogging getSourceOriginForLogging() {
+            return mSourceOriginForLogging;
+        }
+
         @Nullable
         private BluetoothLeBroadcastMetadata getMetadata() {
             return mMetadata;
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamStateHandler.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamStateHandler.java
index df176be..b0c5b6b 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamStateHandler.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamStateHandler.java
@@ -25,7 +25,9 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
 import com.android.settingslib.utils.ThreadUtils;
 
 class AudioStreamStateHandler {
@@ -35,6 +37,8 @@
 
     final AudioStreamsRepository mAudioStreamsRepository = AudioStreamsRepository.getInstance();
     final Handler mHandler = new Handler(Looper.getMainLooper());
+    final MetricsFeatureProvider mMetricsFeatureProvider =
+            FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
 
     AudioStreamStateHandler() {}
 
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java
index f79c597..d643b89 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsDashboardFragment.java
@@ -19,6 +19,7 @@
 import static com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsScanQrCodeController.REQUEST_SCAN_BT_BROADCAST_QR_CODE;
 
 import android.app.Activity;
+import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.content.Context;
 import android.content.Intent;
@@ -32,8 +33,6 @@
 import com.android.settingslib.bluetooth.BluetoothLeBroadcastMetadataExt;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 
-import com.google.common.base.Strings;
-
 public class AudioStreamsDashboardFragment extends DashboardFragment {
     public static final String KEY_BROADCAST_METADATA = "key_broadcast_metadata";
     private static final String TAG = "AudioStreamsDashboardFrag";
@@ -46,8 +45,7 @@
 
     @Override
     public int getMetricsCategory() {
-        // TODO: update category id.
-        return 0;
+        return SettingsEnums.AUDIO_STREAM_MAIN;
     }
 
     @Override
@@ -78,16 +76,17 @@
         mAudioStreamsProgressCategoryController.setFragment(this);
 
         if (getArguments() != null) {
-            String broadcastMetadataStr = getArguments().getString(KEY_BROADCAST_METADATA);
-            if (!Strings.isNullOrEmpty(broadcastMetadataStr)) {
-                BluetoothLeBroadcastMetadata broadcastMetadata =
-                        BluetoothLeBroadcastMetadataExt.INSTANCE.convertToBroadcastMetadata(
-                                broadcastMetadataStr);
-                if (broadcastMetadata == null) {
-                    Log.w(TAG, "onAttach() broadcastMetadata is null!");
-                } else {
-                    mAudioStreamsProgressCategoryController.setSourceFromQrCode(broadcastMetadata);
-                }
+            var broadcastMetadata =
+                    getArguments()
+                            .getParcelable(
+                                    KEY_BROADCAST_METADATA, BluetoothLeBroadcastMetadata.class);
+            if (broadcastMetadata != null) {
+                mAudioStreamsProgressCategoryController.setSourceFromQrCode(
+                        broadcastMetadata, SourceOriginForLogging.QR_CODE_SCAN_OTHER);
+                mMetricsFeatureProvider.action(
+                        getContext(),
+                        SettingsEnums.ACTION_AUDIO_STREAM_QR_CODE_SCAN_SUCCEED,
+                        SourceOriginForLogging.QR_CODE_SCAN_OTHER.ordinal());
             }
         }
     }
@@ -128,7 +127,12 @@
                             "onActivityResult() AudioStreamsProgressCategoryController is null!");
                     return;
                 }
-                mAudioStreamsProgressCategoryController.setSourceFromQrCode(source);
+                mAudioStreamsProgressCategoryController.setSourceFromQrCode(
+                        source, SourceOriginForLogging.QR_CODE_SCAN_SETTINGS);
+                mMetricsFeatureProvider.action(
+                        getContext(),
+                        SettingsEnums.ACTION_AUDIO_STREAM_QR_CODE_SCAN_SUCCEED,
+                        SourceOriginForLogging.QR_CODE_SCAN_SETTINGS.ordinal());
             }
         }
     }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java
index 749220f..0777dd4 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsProgressCategoryController.java
@@ -19,12 +19,11 @@
 import static java.util.Collections.emptyList;
 
 import android.app.AlertDialog;
+import android.app.settings.SettingsEnums;
 import android.bluetooth.BluetoothLeBroadcastMetadata;
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
-import android.content.Intent;
-import android.provider.Settings;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -34,8 +33,10 @@
 
 import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
 import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils;
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
 import com.android.settingslib.bluetooth.BluetoothCallback;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -100,6 +101,7 @@
     private final ConcurrentHashMap<Integer, AudioStreamPreference> mBroadcastIdToPreferenceMap =
             new ConcurrentHashMap<>();
     private @Nullable BluetoothLeBroadcastMetadata mSourceFromQrCode;
+    private SourceOriginForLogging mSourceFromQrCodeOriginForLogging;
     @Nullable private AudioStreamsProgressCategoryPreference mCategoryPreference;
     @Nullable private AudioStreamsDashboardFragment mFragment;
 
@@ -149,11 +151,13 @@
         return mFragment;
     }
 
-    void setSourceFromQrCode(BluetoothLeBroadcastMetadata source) {
+    void setSourceFromQrCode(
+            BluetoothLeBroadcastMetadata source, SourceOriginForLogging sourceOriginForLogging) {
         if (DEBUG) {
             Log.d(TAG, "setSourceFromQrCode(): broadcastId " + source.getBroadcastId());
         }
         mSourceFromQrCode = source;
+        mSourceFromQrCodeOriginForLogging = sourceOriginForLogging;
     }
 
     void setScanning(boolean isScanning) {
@@ -196,7 +200,10 @@
                 broadcastIdFound,
                 (k, existingPreference) -> {
                     if (existingPreference == null) {
-                        return addNewPreference(source, AudioStreamState.SYNCED);
+                        return addNewPreference(
+                                source,
+                                AudioStreamState.SYNCED,
+                                SourceOriginForLogging.BROADCAST_SEARCH);
                     }
                     var fromState = existingPreference.getAudioStreamState();
                     if (fromState == AudioStreamState.WAIT_FOR_SYNC && mSourceFromQrCode != null) {
@@ -268,7 +275,9 @@
                         // Check nullability to bypass NullAway check.
                         if (mSourceFromQrCode != null) {
                             return addNewPreference(
-                                    mSourceFromQrCode, AudioStreamState.WAIT_FOR_SYNC);
+                                    mSourceFromQrCode,
+                                    AudioStreamState.WAIT_FOR_SYNC,
+                                    mSourceFromQrCodeOriginForLogging);
                         }
                     }
                     Log.w(
@@ -525,23 +534,27 @@
     }
 
     private AudioStreamPreference addNewPreference(
-            BluetoothLeBroadcastMetadata metadata, AudioStreamState state) {
-        var preference = AudioStreamPreference.fromMetadata(mContext, metadata);
+            BluetoothLeBroadcastMetadata metadata,
+            AudioStreamState state,
+            SourceOriginForLogging sourceOriginForLogging) {
+        var preference =
+                AudioStreamPreference.fromMetadata(mContext, metadata, sourceOriginForLogging);
         moveToState(preference, state);
         return preference;
     }
 
     private void moveToState(AudioStreamPreference preference, AudioStreamState state) {
-        AudioStreamStateHandler stateHandler = switch (state) {
-            case SYNCED -> SyncedState.getInstance();
-            case WAIT_FOR_SYNC -> WaitForSyncState.getInstance();
-            case ADD_SOURCE_WAIT_FOR_RESPONSE ->
-                    AddSourceWaitForResponseState.getInstance();
-            case ADD_SOURCE_BAD_CODE -> AddSourceBadCodeState.getInstance();
-            case ADD_SOURCE_FAILED -> AddSourceFailedState.getInstance();
-            case SOURCE_ADDED -> SourceAddedState.getInstance();
-            default -> throw new IllegalArgumentException("Unsupported state: " + state);
-        };
+        AudioStreamStateHandler stateHandler =
+                switch (state) {
+                    case SYNCED -> SyncedState.getInstance();
+                    case WAIT_FOR_SYNC -> WaitForSyncState.getInstance();
+                    case ADD_SOURCE_WAIT_FOR_RESPONSE ->
+                            AddSourceWaitForResponseState.getInstance();
+                    case ADD_SOURCE_BAD_CODE -> AddSourceBadCodeState.getInstance();
+                    case ADD_SOURCE_FAILED -> AddSourceFailedState.getInstance();
+                    case SOURCE_ADDED -> SourceAddedState.getInstance();
+                    default -> throw new IllegalArgumentException("Unsupported state: " + state);
+                };
 
         stateHandler.handleStateChange(preference, this, mAudioStreamsHelper);
 
@@ -566,9 +579,12 @@
                         mContext.getString(R.string.audio_streams_dialog_no_le_device_button))
                 .setRightButtonOnClickListener(
                         dialog -> {
-                            mContext.startActivity(
-                                    new Intent(Settings.ACTION_BLUETOOTH_SETTINGS)
-                                            .setPackage(mContext.getPackageName()));
+                            new SubSettingLauncher(mContext)
+                                    .setDestination(
+                                            ConnectedDeviceDashboardFragment.class.getName())
+                                    .setSourceMetricsCategory(
+                                            SettingsEnums.DIALOG_AUDIO_STREAM_MAIN_NO_LE_DEVICE)
+                                    .launch();
                             dialog.dismiss();
                         });
     }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SourceAddedState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SourceAddedState.java
index 4fdaf15..ee84429 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SourceAddedState.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SourceAddedState.java
@@ -57,6 +57,10 @@
                 context,
                 preference.getAudioStreamBroadcastId(),
                 String.valueOf(preference.getTitle()));
+        mMetricsFeatureProvider.action(
+                preference.getContext(),
+                SettingsEnums.ACTION_AUDIO_STREAM_JOIN_SUCCEED,
+                preference.getSourceOriginForLogging().ordinal());
     }
 
     @Override
@@ -79,8 +83,10 @@
                     .setTitleText(
                             p.getContext().getString(R.string.audio_streams_detail_page_title))
                     .setDestination(AudioStreamDetailsFragment.class.getName())
-                    // TODO(chelseahao): Add logging enum
-                    .setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
+                    .setSourceMetricsCategory(
+                            controller.getFragment() == null
+                                    ? SettingsEnums.PAGE_UNKNOWN
+                                    : controller.getFragment().getMetricsCategory())
                     .setArguments(broadcast)
                     .launch();
             return true;
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SourceOriginForLogging.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SourceOriginForLogging.java
new file mode 100644
index 0000000..6ca002a
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/SourceOriginForLogging.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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.audiostreams;
+
+enum SourceOriginForLogging {
+    UNKNOWN,
+    QR_CODE_SCAN_SETTINGS,
+    QR_CODE_SCAN_OTHER,
+    BROADCAST_SEARCH,
+    REPOSITORY,
+}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncState.java
index 7e6d943..4554a4d 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncState.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncState.java
@@ -24,6 +24,7 @@
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.fragment.app.Fragment;
 
 import com.android.settings.R;
 import com.android.settings.core.SubSettingLauncher;
@@ -59,6 +60,11 @@
                         if (preference.isShown()
                                 && preference.getAudioStreamState() == getStateEnum()) {
                             controller.handleSourceLost(preference.getAudioStreamBroadcastId());
+                            mMetricsFeatureProvider.action(
+                                    preference.getContext(),
+                                    SettingsEnums
+                                            .ACTION_AUDIO_STREAM_JOIN_FAILED_WAIT_FOR_SYNC_TIMEOUT,
+                                    preference.getSourceOriginForLogging().ordinal());
                             ThreadUtils.postOnMainThread(
                                     () -> {
                                         if (controller.getFragment() != null) {
@@ -101,18 +107,19 @@
                 .setRightButtonOnClickListener(
                         dialog -> {
                             if (controller.getFragment() != null) {
-                                new SubSettingLauncher(context)
-                                        .setTitleRes(
-                                                R.string.audio_streams_main_page_scan_qr_code_title)
-                                        .setDestination(
-                                                AudioStreamsQrCodeScanFragment.class.getName())
-                                        .setResultListener(
-                                                controller.getFragment(),
-                                                REQUEST_SCAN_BT_BROADCAST_QR_CODE)
-                                        .setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
-                                        .launch();
+                                launchQrCodeScanFragment(context, controller.getFragment());
                                 dialog.dismiss();
                             }
                         });
     }
+
+    private void launchQrCodeScanFragment(Context context, Fragment fragment) {
+        new SubSettingLauncher(context)
+                .setTitleRes(R.string.audio_streams_main_page_scan_qr_code_title)
+                .setDestination(AudioStreamsQrCodeScanFragment.class.getName())
+                .setResultListener(fragment, REQUEST_SCAN_BT_BROADCAST_QR_CODE)
+                .setSourceMetricsCategory(
+                        SettingsEnums.DIALOG_AUDIO_STREAM_MAIN_WAIT_FOR_SYNC_TIMEOUT)
+                .launch();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseStateTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseStateTest.java
index 00357b4..6e5342b 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseStateTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceWaitForResponseStateTest.java
@@ -92,6 +92,8 @@
     @Test
     public void testPerformAction_metadataIsNotNull_addSource() {
         when(mMockPreference.getAudioStreamMetadata()).thenReturn(mMockMetadata);
+        when(mMockPreference.getSourceOriginForLogging())
+                .thenReturn(SourceOriginForLogging.UNKNOWN);
 
         mInstance.performAction(mMockPreference, mMockController, mMockHelper);
 
@@ -105,6 +107,8 @@
         when(mMockPreference.isShown()).thenReturn(true);
         when(mMockPreference.getAudioStreamState()).thenReturn(mInstance.getStateEnum());
         when(mMockPreference.getAudioStreamBroadcastId()).thenReturn(BROADCAST_ID);
+        when(mMockPreference.getSourceOriginForLogging())
+                .thenReturn(SourceOriginForLogging.UNKNOWN);
 
         mInstance.performAction(mMockPreference, mMockController, mMockHelper);
         ShadowLooper.idleMainLooper(ADD_SOURCE_WAIT_FOR_RESPONSE_TIMEOUT_MILLIS, TimeUnit.SECONDS);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreferenceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreferenceTest.java
index 456e45d3..c8f9358 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamPreferenceTest.java
@@ -107,7 +107,8 @@
     @Test
     public void setAudioStreamMetadata_shouldUpdateMetadata() {
         AudioStreamPreference p =
-                AudioStreamPreference.fromMetadata(mContext, mBluetoothLeBroadcastMetadata);
+                AudioStreamPreference.fromMetadata(
+                        mContext, mBluetoothLeBroadcastMetadata, SourceOriginForLogging.UNKNOWN);
         BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class);
         p.setAudioStreamMetadata(metadata);
 
@@ -117,7 +118,8 @@
     @Test
     public void setAudioStreamState_shouldUpdateState() {
         AudioStreamPreference p =
-                AudioStreamPreference.fromMetadata(mContext, mBluetoothLeBroadcastMetadata);
+                AudioStreamPreference.fromMetadata(
+                        mContext, mBluetoothLeBroadcastMetadata, SourceOriginForLogging.UNKNOWN);
         AudioStreamState state = AudioStreamState.SOURCE_ADDED;
         p.setAudioStreamState(state);
 
@@ -127,7 +129,8 @@
     @Test
     public void fromMetadata_shouldReturnBroadcastInfo() {
         AudioStreamPreference p =
-                AudioStreamPreference.fromMetadata(mContext, mBluetoothLeBroadcastMetadata);
+                AudioStreamPreference.fromMetadata(
+                        mContext, mBluetoothLeBroadcastMetadata, SourceOriginForLogging.UNKNOWN);
         assertThat(p.getAudioStreamBroadcastId()).isEqualTo(BROADCAST_ID);
         assertThat(p.getAudioStreamBroadcastName()).isEqualTo(BROADCAST_NAME);
         assertThat(p.getAudioStreamRssi()).isEqualTo(BROADCAST_RSSI);
@@ -152,7 +155,8 @@
     public void shouldHideSecondTarget_notEncrypted() {
         when(mBluetoothLeBroadcastMetadata.isEncrypted()).thenReturn(false);
         AudioStreamPreference p =
-                AudioStreamPreference.fromMetadata(mContext, mBluetoothLeBroadcastMetadata);
+                AudioStreamPreference.fromMetadata(
+                        mContext, mBluetoothLeBroadcastMetadata, SourceOriginForLogging.UNKNOWN);
         assertThat(p.shouldHideSecondTarget()).isTrue();
     }
 
@@ -160,7 +164,8 @@
     public void shouldShowSecondTarget_encrypted() {
         when(mBluetoothLeBroadcastMetadata.isEncrypted()).thenReturn(true);
         AudioStreamPreference p =
-                AudioStreamPreference.fromMetadata(mContext, mBluetoothLeBroadcastMetadata);
+                AudioStreamPreference.fromMetadata(
+                        mContext, mBluetoothLeBroadcastMetadata, SourceOriginForLogging.UNKNOWN);
         assertThat(p.shouldHideSecondTarget()).isFalse();
     }
 
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncStateTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncStateTest.java
index 5297182..3eb07a4 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncStateTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/audiostreams/WaitForSyncStateTest.java
@@ -93,6 +93,8 @@
                 .thenReturn(AudioStreamsProgressCategoryController.AudioStreamState.WAIT_FOR_SYNC);
         when(mMockPreference.getAudioStreamBroadcastId()).thenReturn(1);
         when(mMockPreference.getAudioStreamMetadata()).thenReturn(mMockMetadata);
+        when(mMockPreference.getSourceOriginForLogging())
+                .thenReturn(SourceOriginForLogging.UNKNOWN);
 
         mInstance.performAction(mMockPreference, mMockController, mMockHelper);
         ShadowLooper.idleMainLooper(WAIT_FOR_SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);