1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.connecteddevice.audiosharing; 18 19 import android.app.Dialog; 20 import android.app.settings.SettingsEnums; 21 import android.os.Bundle; 22 import android.util.Log; 23 import android.util.Pair; 24 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 import androidx.annotation.VisibleForTesting; 28 import androidx.appcompat.app.AlertDialog; 29 import androidx.fragment.app.Fragment; 30 import androidx.fragment.app.FragmentManager; 31 32 import com.android.settings.R; 33 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 34 35 import com.google.common.collect.Iterables; 36 37 import java.util.List; 38 39 public class AudioSharingDialogFragment extends InstrumentedDialogFragment { 40 private static final String TAG = "AudioSharingDialog"; 41 42 private static final String BUNDLE_KEY_DEVICE_ITEMS = "bundle_key_device_items"; 43 44 // The host creates an instance of this dialog fragment must implement this interface to receive 45 // event callbacks. 46 public interface DialogEventListener { 47 /** 48 * Called when users click the device item for sharing in the dialog. 49 * 50 * @param item The device item clicked. 51 */ onItemClick(AudioSharingDeviceItem item)52 void onItemClick(AudioSharingDeviceItem item); 53 54 /** Called when users click the cancel button in the dialog. */ onCancelClick()55 void onCancelClick(); 56 } 57 58 @Nullable private static DialogEventListener sListener; 59 private static Pair<Integer, Object>[] sEventData = new Pair[0]; 60 61 @Override getMetricsCategory()62 public int getMetricsCategory() { 63 return SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE; 64 } 65 66 /** 67 * Display the {@link AudioSharingDialogFragment} dialog. 68 * 69 * @param host The Fragment this dialog will be hosted. 70 * @param deviceItems The connected device items eligible for audio sharing. 71 * @param listener The callback to handle the user action on this dialog. 72 * @param eventData The eventData to log with for dialog onClick events. 73 */ show( @onNull Fragment host, @NonNull List<AudioSharingDeviceItem> deviceItems, @NonNull DialogEventListener listener, @NonNull Pair<Integer, Object>[] eventData)74 public static void show( 75 @NonNull Fragment host, 76 @NonNull List<AudioSharingDeviceItem> deviceItems, 77 @NonNull DialogEventListener listener, 78 @NonNull Pair<Integer, Object>[] eventData) { 79 if (!AudioSharingUtils.isFeatureEnabled()) return; 80 final FragmentManager manager = host.getChildFragmentManager(); 81 sListener = listener; 82 sEventData = eventData; 83 AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG); 84 if (dialog != null) { 85 Log.d(TAG, "Dialog is showing, return."); 86 return; 87 } 88 Log.d(TAG, "Show up the dialog."); 89 final Bundle bundle = new Bundle(); 90 bundle.putParcelableList(BUNDLE_KEY_DEVICE_ITEMS, deviceItems); 91 AudioSharingDialogFragment dialogFrag = new AudioSharingDialogFragment(); 92 dialogFrag.setArguments(bundle); 93 dialogFrag.show(manager, TAG); 94 } 95 96 /** Return the tag of {@link AudioSharingDialogFragment} dialog. */ tag()97 public static @NonNull String tag() { 98 return TAG; 99 } 100 101 /** Test only: get the event data passed to the dialog. */ 102 @VisibleForTesting 103 @NonNull getEventData()104 Pair<Integer, Object>[] getEventData() { 105 return sEventData; 106 } 107 108 @Override 109 @NonNull onCreateDialog(Bundle savedInstanceState)110 public Dialog onCreateDialog(Bundle savedInstanceState) { 111 Bundle arguments = requireArguments(); 112 List<AudioSharingDeviceItem> deviceItems = 113 arguments.getParcelable(BUNDLE_KEY_DEVICE_ITEMS, List.class); 114 AudioSharingDialogFactory.DialogBuilder builder = 115 AudioSharingDialogFactory.newBuilder(getActivity()) 116 .setTitleIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing) 117 .setIsCustomBodyEnabled(true); 118 if (deviceItems == null) { 119 Log.d(TAG, "Create dialog error: null deviceItems"); 120 return builder.build(); 121 } 122 if (deviceItems.isEmpty()) { 123 builder.setTitle(R.string.audio_sharing_share_dialog_title) 124 .setCustomImage(R.drawable.audio_sharing_guidance) 125 .setCustomMessage(R.string.audio_sharing_dialog_connect_device_content) 126 .setNegativeButton( 127 R.string.audio_sharing_close_button_label, 128 (dig, which) -> onCancelClick()); 129 } else if (deviceItems.size() == 1) { 130 AudioSharingDeviceItem deviceItem = Iterables.getOnlyElement(deviceItems); 131 builder.setTitle( 132 getString( 133 R.string.audio_sharing_share_with_dialog_title, 134 deviceItem.getName())) 135 .setCustomMessage(R.string.audio_sharing_dialog_share_content) 136 .setCustomPositiveButton( 137 R.string.audio_sharing_share_button_label, 138 v -> { 139 if (sListener != null) { 140 sListener.onItemClick(deviceItem); 141 mMetricsFeatureProvider.action( 142 getContext(), 143 SettingsEnums 144 .ACTION_AUDIO_SHARING_DIALOG_POSITIVE_BTN_CLICKED, 145 sEventData); 146 } 147 dismiss(); 148 }) 149 .setCustomNegativeButton( 150 R.string.audio_sharing_no_thanks_button_label, v -> onCancelClick()); 151 } else { 152 builder.setTitle(R.string.audio_sharing_share_with_more_dialog_title) 153 .setCustomMessage(R.string.audio_sharing_dialog_share_more_content) 154 .setCustomDeviceActions( 155 new AudioSharingDeviceAdapter( 156 getContext(), 157 deviceItems, 158 (AudioSharingDeviceItem item) -> { 159 if (sListener != null) { 160 sListener.onItemClick(item); 161 } 162 dismiss(); 163 }, 164 AudioSharingDeviceAdapter.ActionType.SHARE)) 165 .setCustomNegativeButton( 166 com.android.settings.R.string.cancel, v -> onCancelClick()); 167 } 168 return builder.build(); 169 } 170 onCancelClick()171 private void onCancelClick() { 172 if (sListener != null) { 173 sListener.onCancelClick(); 174 mMetricsFeatureProvider.action( 175 getContext(), 176 SettingsEnums.ACTION_AUDIO_SHARING_DIALOG_NEGATIVE_BTN_CLICKED, 177 sEventData); 178 } 179 dismiss(); 180 } 181 } 182