Add support for a generic action to show output switcher in the platform.

- We need to add this action in the platform so that WearOS can also handle it, not only SysUi.
- Add tests for MediaOutputDialogReceiver class.
- Add android:priority=1 to the MediaOutputDialogReceiver so that it's always the default handler for the action.

Bug: 246997969
Test: atest MediaOutputDialogReceiverTest
Change-Id: I25d60eef7d4170b5f0b748b9b61ebf043a7c189c
This commit is contained in:
Bishoy Gendy
2022-10-18 10:05:43 +00:00
parent 3163e22190
commit 6234d7472a
5 changed files with 213 additions and 17 deletions

View File

@@ -10392,6 +10392,7 @@ package android.content {
field public static final String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
field public static final String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
field public static final String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
field public static final String ACTION_SHOW_OUTPUT_SWITCHER = "android.intent.action.SHOW_OUTPUT_SWITCHER";
field public static final String ACTION_SHOW_WORK_APPS = "android.intent.action.SHOW_WORK_APPS";
field public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
field public static final String ACTION_SYNC = "android.intent.action.SYNC";

View File

@@ -3560,6 +3560,17 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
/**
* Broadcast action: Launch System output switcher. Includes a single extra field,
* {@link #EXTRA_PACKAGE_NAME}, which specifies the package name of the calling app
* so that the system can get the corresponding MediaSession for the output switcher.
*
* @see #EXTRA_PACKAGE_NAME
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SHOW_OUTPUT_SWITCHER =
"android.intent.action.SHOW_OUTPUT_SWITCHER";
/**
* Broadcast Action: The "Camera Button" was pressed. Includes a single
* extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that

View File

@@ -971,10 +971,11 @@
<receiver android:name=".media.dialog.MediaOutputDialogReceiver"
android:exported="true">
<intent-filter>
<intent-filter android:priority="1">
<action android:name="com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG" />
<action android:name="com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG" />
<action android:name="com.android.systemui.action.DISMISS_MEDIA_OUTPUT_DIALOG" />
<action android:name="android.intent.action.SHOW_OUTPUT_SWITCHER" />
</intent-filter>
</receiver>

View File

@@ -35,25 +35,40 @@ class MediaOutputDialogReceiver @Inject constructor(
private val mediaOutputBroadcastDialogFactory: MediaOutputBroadcastDialogFactory
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (TextUtils.equals(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG,
intent.action)) {
val packageName: String? =
intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
if (!TextUtils.isEmpty(packageName)) {
mediaOutputDialogFactory.create(packageName!!, false)
} else if (DEBUG) {
Log.e(TAG, "Unable to launch media output dialog. Package name is empty.")
when {
TextUtils.equals(Intent.ACTION_SHOW_OUTPUT_SWITCHER, intent.action) -> {
val packageName: String? = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME)
launchMediaOutputDialogIfPossible(packageName)
}
} else if (TextUtils.equals(
MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG,
intent.action)) {
val packageName: String? =
TextUtils.equals(
MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG, intent.action) -> {
val packageName: String? =
intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
if (!TextUtils.isEmpty(packageName)) {
mediaOutputBroadcastDialogFactory.create(packageName!!, false)
} else if (DEBUG) {
Log.e(TAG, "Unable to launch media output broadcast dialog. Package name is empty.")
launchMediaOutputDialogIfPossible(packageName)
}
TextUtils.equals(
MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG,
intent.action) -> {
val packageName: String? =
intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
launchMediaOutputBroadcastDialogIfPossible(packageName)
}
}
}
private fun launchMediaOutputDialogIfPossible(packageName: String?) {
if (!packageName.isNullOrEmpty()) {
mediaOutputDialogFactory.create(packageName, false)
} else if (DEBUG) {
Log.e(TAG, "Unable to launch media output dialog. Package name is empty.")
}
}
private fun launchMediaOutputBroadcastDialogIfPossible(packageName: String?) {
if (!packageName.isNullOrEmpty()) {
mediaOutputBroadcastDialogFactory.create(packageName, false)
} else if (DEBUG) {
Log.e(TAG, "Unable to launch media output broadcast dialog. Package name is empty.")
}
}
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright (C) 2020 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.dialog;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Intent;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.settingslib.media.MediaOutputConstants;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class MediaOutputDialogReceiverTest extends SysuiTestCase {
private MediaOutputDialogReceiver mMediaOutputDialogReceiver;
private final MediaOutputDialogFactory mMockMediaOutputDialogFactory =
mock(MediaOutputDialogFactory.class);
private final MediaOutputBroadcastDialogFactory mMockMediaOutputBroadcastDialogFactory =
mock(MediaOutputBroadcastDialogFactory.class);
@Before
public void setup() {
mMediaOutputDialogReceiver = new MediaOutputDialogReceiver(mMockMediaOutputDialogFactory,
mMockMediaOutputBroadcastDialogFactory);
}
@Test
public void showOutputSwitcher_ExtraPackageName_DialogFactoryCalled() {
Intent intent = new Intent(Intent.ACTION_SHOW_OUTPUT_SWITCHER);
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, getContext().getPackageName());
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, times(1))
.create(getContext().getPackageName(), false, null);
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void showOutputSwitcher_WrongExtraKey_DialogFactoryNotCalled() {
Intent intent = new Intent(Intent.ACTION_SHOW_OUTPUT_SWITCHER);
intent.putExtra("Wrong Package Name Key", getContext().getPackageName());
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void showOutputSwitcher_NoExtra_DialogFactoryNotCalled() {
Intent intent = new Intent(Intent.ACTION_SHOW_OUTPUT_SWITCHER);
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void launchMediaOutputDialog_ExtraPackageName_DialogFactoryCalled() {
Intent intent = new Intent(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG);
intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName());
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, times(1))
.create(getContext().getPackageName(), false, null);
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void launchMediaOutputDialog_WrongExtraKey_DialogFactoryNotCalled() {
Intent intent = new Intent(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG);
intent.putExtra("Wrong Package Name Key", getContext().getPackageName());
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void launchMediaOutputDialog_NoExtra_DialogFactoryNotCalled() {
Intent intent = new Intent(MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG);
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void launchMediaOutputBroadcastDialog_ExtraPackageName_BroadcastDialogFactoryCalled() {
Intent intent = new Intent(
MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName());
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, times(1))
.create(getContext().getPackageName(), false, null);
}
@Test
public void launchMediaOutputBroadcastDialog_WrongExtraKey_DialogBroadcastFactoryNotCalled() {
Intent intent = new Intent(
MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
intent.putExtra("Wrong Package Name Key", getContext().getPackageName());
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void launchMediaOutputBroadcastDialog_NoExtra_BroadcastDialogFactoryNotCalled() {
Intent intent = new Intent(
MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void unKnownAction_ExtraPackageName_FactoriesNotCalled() {
Intent intent = new Intent("UnKnown Action");
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, getContext().getPackageName());
intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName());
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
@Test
public void unKnownActionAnd_NoExtra_FactoriesNotCalled() {
Intent intent = new Intent("UnKnown Action");
mMediaOutputDialogReceiver.onReceive(getContext(), intent);
verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
}
}