diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java new file mode 100644 index 0000000000000..9b7d49883222a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialog.java @@ -0,0 +1,134 @@ +/** + * Copyright (C) 2022 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.systemui.bluetooth; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.TextView; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.R; +import com.android.systemui.media.MediaDataUtils; +import com.android.systemui.media.dialog.MediaOutputDialogFactory; +import com.android.systemui.statusbar.phone.SystemUIDialog; + +/** + * Dialog for showing le audio broadcasting dialog. + */ +public class BroadcastDialog extends SystemUIDialog { + + private static final String TAG = "BroadcastDialog"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private Context mContext; + private UiEventLogger mUiEventLogger; + @VisibleForTesting + protected View mDialogView; + private MediaOutputDialogFactory mMediaOutputDialogFactory; + private String mSwitchBroadcastApp; + private String mOutputPackageName; + + public BroadcastDialog(Context context, MediaOutputDialogFactory mediaOutputDialogFactory, + String switchBroadcastApp, String outputPkgName, UiEventLogger uiEventLogger) { + super(context); + if (DEBUG) { + Log.d(TAG, "Init BroadcastDialog"); + } + + mContext = getContext(); + mMediaOutputDialogFactory = mediaOutputDialogFactory; + mSwitchBroadcastApp = switchBroadcastApp; + mOutputPackageName = outputPkgName; + mUiEventLogger = uiEventLogger; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (DEBUG) { + Log.d(TAG, "onCreate"); + } + + mUiEventLogger.log(BroadcastDialogEvent.BROADCAST_DIALOG_SHOW); + mDialogView = LayoutInflater.from(mContext).inflate(R.layout.broadcast_dialog, null); + final Window window = getWindow(); + window.setContentView(mDialogView); + + TextView title = mDialogView.requireViewById(R.id.dialog_title); + TextView subTitle = mDialogView.requireViewById(R.id.dialog_subtitle); + title.setText( + mContext.getString(R.string.bt_le_audio_broadcast_dialog_title, + MediaDataUtils.getAppLabel(mContext, mOutputPackageName, + mContext.getString( + R.string.bt_le_audio_broadcast_dialog_unknown_name)))); + subTitle.setText( + mContext.getString(R.string.bt_le_audio_broadcast_dialog_sub_title, + mSwitchBroadcastApp)); + + Button switchBroadcast = mDialogView.requireViewById(R.id.switch_broadcast); + Button changeOutput = mDialogView.requireViewById(R.id.change_output); + Button cancelBtn = mDialogView.requireViewById(R.id.cancel); + switchBroadcast.setText(mContext.getString( + R.string.bt_le_audio_broadcast_dialog_switch_app, mSwitchBroadcastApp), null); + changeOutput.setOnClickListener((view) -> { + mMediaOutputDialogFactory.create(mOutputPackageName, true, null); + dismiss(); + }); + cancelBtn.setOnClickListener((view) -> { + if (DEBUG) { + Log.d(TAG, "BroadcastDialog dismiss."); + } + dismiss(); + }); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (!hasFocus && isShowing()) { + dismiss(); + } + } + + public enum BroadcastDialogEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "The Broadcast dialog became visible on the screen.") + BROADCAST_DIALOG_SHOW(1062); + + private final int mId; + + BroadcastDialogEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java new file mode 100644 index 0000000000000..8a54345ae28cb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogController.java @@ -0,0 +1,60 @@ +/** + * Copyright (C) 2022 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.systemui.bluetooth; + +import android.content.Context; +import android.view.View; + +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.animation.DialogLaunchAnimator; +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.media.dialog.MediaOutputDialogFactory; + +import javax.inject.Inject; + +/** + * Controller to create BroadcastDialog objects. + */ +@SysUISingleton +public class BroadcastDialogController { + + private Context mContext; + private UiEventLogger mUiEventLogger; + private DialogLaunchAnimator mDialogLaunchAnimator; + private MediaOutputDialogFactory mMediaOutputDialogFactory; + + @Inject + public BroadcastDialogController(Context context, UiEventLogger uiEventLogger, + DialogLaunchAnimator dialogLaunchAnimator, + MediaOutputDialogFactory mediaOutputDialogFactory) { + mContext = context; + mUiEventLogger = uiEventLogger; + mDialogLaunchAnimator = dialogLaunchAnimator; + mMediaOutputDialogFactory = mediaOutputDialogFactory; + } + + public void createBroadcastDialog(String switchAppName, String outputPkgName, + boolean aboveStatusBar, View view) { + BroadcastDialog broadcastDialog = new BroadcastDialog(mContext, mMediaOutputDialogFactory, + switchAppName, outputPkgName, mUiEventLogger); + if (view != null) { + mDialogLaunchAnimator.showFromView(broadcastDialog, view); + } else { + broadcastDialog.show(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java b/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java new file mode 100644 index 0000000000000..b8185b9de7e88 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataUtils.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2022 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.systemui.media; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.text.TextUtils; + +public class MediaDataUtils { + + public static String getAppLabel(Context context, String packageName, String unknownName) { + if (TextUtils.isEmpty(packageName)) { + return null; + } + final PackageManager packageManager = context.getPackageManager(); + ApplicationInfo applicationInfo; + try { + applicationInfo = packageManager.getApplicationInfo(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + applicationInfo = null; + } + final String applicationName = + (String) (applicationInfo != null + ? packageManager.getApplicationLabel(applicationInfo) + : unknownName); + return applicationName; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java new file mode 100644 index 0000000000000..a61cecbabf305 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogTest.java @@ -0,0 +1,83 @@ +/** + * Copyright (C) 2022 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.systemui.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; + +import androidx.test.filters.SmallTest; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.media.dialog.MediaOutputDialogFactory; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class BroadcastDialogTest extends SysuiTestCase { + + private static final String SWITCH_APP = "Music"; + private static final String TEST_PACKAGE = "com.google.android.apps.nbu.files"; + private BroadcastDialog mBroadcastDialog; + private View mDialogView; + private TextView mSubTitle; + private Button mChangeOutputButton; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mBroadcastDialog = new BroadcastDialog(mContext, mock(MediaOutputDialogFactory.class), + SWITCH_APP, TEST_PACKAGE, mock(UiEventLogger.class)); + mBroadcastDialog.show(); + mDialogView = mBroadcastDialog.mDialogView; + } + + @After + public void tearDown() { + mBroadcastDialog.dismiss(); + } + + @Test + public void onCreate_withCurrentApp_checkSwitchAppContent() { + mSubTitle = mDialogView.requireViewById(R.id.dialog_subtitle); + + assertThat(mSubTitle.getText()).isEqualTo( + mContext.getString(R.string.bt_le_audio_broadcast_dialog_sub_title, SWITCH_APP)); + } + + @Test + public void onClick_withChangeOutput_dismissBroadcastDialog() { + mChangeOutputButton = mDialogView.requireViewById(R.id.change_output); + mChangeOutputButton.performClick(); + + assertThat(mBroadcastDialog.isShowing()).isFalse(); + } +}