diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceBadCodeState.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AddSourceBadCodeState.java index 19933775725..56b1b2eae45 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; @@ -37,6 +39,17 @@ class AddSourceBadCodeState extends SyncedState { return sInstance; } + @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 5d151eeb4da..df41c14a35c 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; @@ -37,6 +39,17 @@ class AddSourceFailedState extends SyncedState { return sInstance; } + @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 d314d3f1fe9..00342b14fd0 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 @@ class AddSourceWaitForResponseState extends AudioStreamStateHandler { 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 @@ class AddSourceWaitForResponseState extends AudioStreamStateHandler { && 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 ea5abdf6719..26610729a3f 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 androidx.preference.PreferenceScreen; 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 @@ public class AudioStreamButtonController extends BasePreferenceController 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 class AudioStreamButtonController extends BasePreferenceController 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 @@ public class AudioStreamButtonController extends BasePreferenceController 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 @@ public class AudioStreamButtonController extends BasePreferenceController 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 @@ public class AudioStreamButtonController extends BasePreferenceController 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 @@ public class AudioStreamButtonController extends BasePreferenceController mExecutor = Executors.newSingleThreadExecutor(); mAudioStreamsHelper = new AudioStreamsHelper(Utils.getLocalBtManager(context)); mLeBroadcastAssistant = mAudioStreamsHelper.getLeBroadcastAssistant(); + mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); } @Override @@ -124,59 +140,77 @@ public class AudioStreamButtonController extends BasePreferenceController } 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 f605e4b3695..071cf57c715 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 @@ class AudioStreamPreference extends TwoTargetPreference { : AudioStreamsProgressCategoryController.AudioStreamState.UNKNOWN; } + SourceOriginForLogging getSourceOriginForLogging() { + return mAudioStream != null + ? mAudioStream.getSourceOriginForLogging() + : SourceOriginForLogging.UNKNOWN; + } + @Override protected boolean shouldHideSecondTarget() { return mIsConnected || !mIsEncrypted; @@ -130,11 +136,13 @@ class AudioStreamPreference extends TwoTargetPreference { } 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 @@ class AudioStreamPreference extends TwoTargetPreference { 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 @@ class AudioStreamPreference extends TwoTargetPreference { 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 df176be505a..b0c5b6baebf 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.StringRes; 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 @@ class AudioStreamStateHandler { 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 f79c5973ba6..d643b89e411 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 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; 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.settings.dashboard.DashboardFragment; 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 @@ public class AudioStreamsDashboardFragment extends DashboardFragment { @Override public int getMetricsCategory() { - // TODO: update category id. - return 0; + return SettingsEnums.AUDIO_STREAM_MAIN; } @Override @@ -78,16 +76,17 @@ public class AudioStreamsDashboardFragment extends DashboardFragment { 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 @@ public class AudioStreamsDashboardFragment extends DashboardFragment { "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 749220f443e..0777dd47703 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 @@ package com.android.settings.connecteddevice.audiosharing.audiostreams; 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 androidx.preference.PreferenceScreen; 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 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro private final ConcurrentHashMap mBroadcastIdToPreferenceMap = new ConcurrentHashMap<>(); private @Nullable BluetoothLeBroadcastMetadata mSourceFromQrCode; + private SourceOriginForLogging mSourceFromQrCodeOriginForLogging; @Nullable private AudioStreamsProgressCategoryPreference mCategoryPreference; @Nullable private AudioStreamsDashboardFragment mFragment; @@ -149,11 +151,13 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro 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 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro 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 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro // 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 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro } 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 @@ public class AudioStreamsProgressCategoryController extends BasePreferenceContro 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 4fdaf15312f..ee84429663a 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 @@ class SourceAddedState extends AudioStreamStateHandler { 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 @@ class SourceAddedState extends AudioStreamStateHandler { .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 00000000000..6ca002ab60c --- /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 7e6d943db7f..4554a4de80f 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 android.content.Context; 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 @@ class WaitForSyncState extends AudioStreamStateHandler { 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 @@ class WaitForSyncState extends AudioStreamStateHandler { .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 00357b41894..6e5342bb3fe 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 @@ public class AddSourceWaitForResponseStateTest { @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 @@ public class AddSourceWaitForResponseStateTest { 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 456e45d302a..c8f93588c78 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 @@ public class AudioStreamPreferenceTest { @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 @@ public class AudioStreamPreferenceTest { @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 @@ public class AudioStreamPreferenceTest { @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 class AudioStreamPreferenceTest { 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 class AudioStreamPreferenceTest { 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 52971822b8c..3eb07a46f74 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 @@ public class WaitForSyncStateTest { .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);