Migrate USB audio device permission warning dialog
for both Direct USB Access and AoC Offload feature According to USB audio warning dialog message conditions matrix, add a UsbAudioWarningDialogMessage to handle the conditions. Test: manually install NeutronPlayer to test usb audio device permission warning dialog sentence. Test: manually modify each audio api condition to test each sentence correntness. Test: atest SystemUITests Change-Id: Ic9731590cb3bad259add1b93b43341af9518e107
This commit is contained in:
30
packages/SystemUI/docs/usb_audio.md
Normal file
30
packages/SystemUI/docs/usb_audio.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# USB audio Permission and Confirmation warning dialog resource string id matrix table
|
||||
### go/support-usb-access-aoc-offload-feature
|
||||
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| # | Permission |isUsbAudioDevice| hasAudioPlayback | hasAudioCapture | string resource ID |
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| 1 | TRUE | TRUE | TRUE | FALSE | usb_audio_device_
|
||||
permission_prompt |
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| 2 | TRUE | TRUE | FALSE | TRUE | usb_audio_device_
|
||||
permission_prompt |
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| 3 | TRUE | TRUE | TRUE | TRUE | usb_audio_device_
|
||||
permission_prompt |
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| 4 | TRUE | FALSE | N/A | N/A | usb_device_
|
||||
permission_prompt |
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| 5 | FALSE | TRUE | TRUE | FALSE | usb_audio_device_
|
||||
permission_prompt |
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| 6 | FALSE | TRUE | FALSE | TRUE | usb_audio_device_
|
||||
permission_prompt_warn
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| 7 | FALSE | TRUE | TRUE | TRUE | usb_audio_device_
|
||||
permission_prompt_warn
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
| 8 | FALSE | FALSE | N/A | N/A | usb_device_
|
||||
permission_prompt |
|
||||
|---|------------|----------------|------------------|-----------------|--------------------|
|
||||
@@ -29,8 +29,10 @@ import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity;
|
||||
import com.android.systemui.settings.brightness.BrightnessDialog;
|
||||
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
|
||||
import com.android.systemui.tuner.TunerActivity;
|
||||
import com.android.systemui.usb.UsbConfirmActivity;
|
||||
import com.android.systemui.usb.UsbDebuggingActivity;
|
||||
import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
|
||||
import com.android.systemui.usb.UsbPermissionActivity;
|
||||
import com.android.systemui.user.CreateUserActivity;
|
||||
|
||||
import dagger.Binds;
|
||||
@@ -80,6 +82,18 @@ public abstract class DefaultActivityBinder {
|
||||
public abstract Activity bindUsbDebuggingSecondaryUserActivity(
|
||||
UsbDebuggingSecondaryUserActivity activity);
|
||||
|
||||
/** Inject into UsbPermissionActivity. */
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(UsbPermissionActivity.class)
|
||||
public abstract Activity bindUsbPermissionActivity(UsbPermissionActivity activity);
|
||||
|
||||
/** Inject into UsbConfirmActivity. */
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ClassKey(UsbConfirmActivity.class)
|
||||
public abstract Activity bindUsbConfirmActivity(UsbConfirmActivity activity);
|
||||
|
||||
/** Inject into CreateUserActivity. */
|
||||
@Binds
|
||||
@IntoMap
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.usb;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.content.res.Resources;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* USB Audio devices warning dialog messages help class.
|
||||
*/
|
||||
public class UsbAudioWarningDialogMessage {
|
||||
private static final String TAG = "UsbAudioWarningDialogMessage";
|
||||
|
||||
@Retention(SOURCE)
|
||||
@IntDef({TYPE_PERMISSION, TYPE_CONFIRM})
|
||||
public @interface DialogType {}
|
||||
public static final int TYPE_PERMISSION = 0;
|
||||
public static final int TYPE_CONFIRM = 1;
|
||||
|
||||
private int mDialogType;
|
||||
private UsbDialogHelper mDialogHelper;
|
||||
|
||||
@Inject
|
||||
public UsbAudioWarningDialogMessage() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize USB audio warning dialog message type and helper class.
|
||||
* @param type Dialog type for Activity.
|
||||
* @param usbDialogHelper Helper class for getting USB permission and confirm dialogs
|
||||
*/
|
||||
public void init(@DialogType int type, UsbDialogHelper usbDialogHelper) {
|
||||
mDialogType = type;
|
||||
mDialogHelper = usbDialogHelper;
|
||||
}
|
||||
|
||||
boolean hasRecordPermission() {
|
||||
return mDialogHelper.packageHasAudioRecordingPermission();
|
||||
}
|
||||
|
||||
boolean isUsbAudioDevice() {
|
||||
return mDialogHelper.isUsbDevice() && (mDialogHelper.deviceHasAudioCapture()
|
||||
|| (mDialogHelper.deviceHasAudioPlayback()));
|
||||
}
|
||||
|
||||
boolean hasAudioPlayback() {
|
||||
return mDialogHelper.deviceHasAudioPlayback();
|
||||
}
|
||||
|
||||
boolean hasAudioCapture() {
|
||||
return mDialogHelper.deviceHasAudioCapture();
|
||||
}
|
||||
|
||||
/**
|
||||
* According to USB audio warning dialog matrix table to return warning message id.
|
||||
* @return string resId for USB audio warning dialog message, otherwise {ID_NULL}.
|
||||
* See usb_audio.md for USB audio Permission and Confirmation warning dialog resource
|
||||
* string id matrix table.
|
||||
*/
|
||||
public int getMessageId() {
|
||||
if (!mDialogHelper.isUsbDevice()) {
|
||||
return getUsbAccessoryPromptId();
|
||||
}
|
||||
|
||||
if (hasRecordPermission() && isUsbAudioDevice()) {
|
||||
// case# 1, 2, 3
|
||||
return R.string.usb_audio_device_prompt;
|
||||
} else if (!hasRecordPermission() && isUsbAudioDevice() && hasAudioPlayback()
|
||||
&& !hasAudioCapture()) {
|
||||
// case# 5
|
||||
return R.string.usb_audio_device_prompt;
|
||||
}
|
||||
|
||||
if (!hasRecordPermission() && isUsbAudioDevice() && hasAudioCapture()) {
|
||||
// case# 6,7
|
||||
return R.string.usb_audio_device_prompt_warn;
|
||||
}
|
||||
|
||||
Log.w(TAG, "Only shows title with empty content description!");
|
||||
return Resources.ID_NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets prompt dialog title.
|
||||
* @return string id for USB prompt dialog title.
|
||||
*/
|
||||
public int getPromptTitleId() {
|
||||
return (mDialogType == TYPE_PERMISSION)
|
||||
? R.string.usb_audio_device_permission_prompt_title
|
||||
: R.string.usb_audio_device_confirm_prompt_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets USB Accessory prompt message id.
|
||||
* @return string id for USB Accessory prompt message.
|
||||
*/
|
||||
public int getUsbAccessoryPromptId() {
|
||||
return (mDialogType == TYPE_PERMISSION)
|
||||
? R.string.usb_accessory_permission_prompt : R.string.usb_accessory_confirm_prompt;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.android.systemui.usb;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Dialog shown to confirm the package to start when a USB device or accessory is attached and there
|
||||
@@ -24,23 +27,35 @@ import com.android.systemui.R;
|
||||
*/
|
||||
public class UsbConfirmActivity extends UsbDialogActivity {
|
||||
|
||||
private UsbAudioWarningDialogMessage mUsbConfirmMessageHandler;
|
||||
|
||||
@Inject
|
||||
public UsbConfirmActivity(UsbAudioWarningDialogMessage usbAudioWarningDialogMessage) {
|
||||
mUsbConfirmMessageHandler = usbAudioWarningDialogMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
mUsbConfirmMessageHandler.init(UsbAudioWarningDialogMessage.TYPE_CONFIRM, mDialogHelper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
final int strId;
|
||||
boolean useRecordWarning = false;
|
||||
if (mDialogHelper.isUsbDevice()) {
|
||||
useRecordWarning = mDialogHelper.deviceHasAudioCapture()
|
||||
&& !mDialogHelper.packageHasAudioRecordingPermission();
|
||||
strId = useRecordWarning
|
||||
? R.string.usb_device_confirm_prompt_warn
|
||||
: R.string.usb_device_confirm_prompt;
|
||||
} else {
|
||||
// UsbAccessory case
|
||||
strId = R.string.usb_accessory_confirm_prompt;
|
||||
}
|
||||
setAlertParams(strId);
|
||||
// Only show the "always use" checkbox if there is no USB/Record warning
|
||||
final boolean useRecordWarning = mDialogHelper.isUsbDevice()
|
||||
&& (mDialogHelper.deviceHasAudioCapture()
|
||||
&& !mDialogHelper.packageHasAudioRecordingPermission());
|
||||
|
||||
final int titleId = mUsbConfirmMessageHandler.getPromptTitleId();
|
||||
final String title = getString(titleId, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription());
|
||||
final int messageId = mUsbConfirmMessageHandler.getMessageId();
|
||||
String message = (messageId != Resources.ID_NULL)
|
||||
? getString(messageId, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription()) : null;
|
||||
setAlertParams(title, message);
|
||||
if (!useRecordWarning) {
|
||||
addAlwaysUseCheckbox();
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ abstract class UsbDialogActivity extends AlertActivity
|
||||
private TextView mClearDefaultHint;
|
||||
|
||||
@Override
|
||||
protected final void onCreate(Bundle savedInstanceState) {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addSystemFlags(
|
||||
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
@@ -87,11 +87,10 @@ abstract class UsbDialogActivity extends AlertActivity
|
||||
}
|
||||
}
|
||||
|
||||
void setAlertParams(int strId) {
|
||||
void setAlertParams(String title, String message) {
|
||||
final AlertController.AlertParams ap = mAlertParams;
|
||||
ap.mTitle = mDialogHelper.getAppName();
|
||||
ap.mMessage = getString(strId, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription());
|
||||
ap.mTitle = title;
|
||||
ap.mMessage = message;
|
||||
ap.mPositiveButtonText = getString(android.R.string.ok);
|
||||
ap.mNegativeButtonText = getString(android.R.string.cancel);
|
||||
ap.mPositiveButtonListener = this;
|
||||
|
||||
@@ -133,6 +133,13 @@ public class UsbDialogHelper {
|
||||
return mDevice != null && mDevice.getHasAudioCapture();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the intent contains a UsbDevice which can play audio.
|
||||
*/
|
||||
public boolean deviceHasAudioPlayback() {
|
||||
return mDevice != null && mDevice.getHasAudioPlayback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the package has RECORD_AUDIO permission specified in its manifest.
|
||||
*/
|
||||
@@ -272,15 +279,15 @@ public class UsbDialogHelper {
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the calling package can set as default handler of the USB device or accessory.
|
||||
* In case of a UsbAccessory this is the case if the calling package has an intent filter for
|
||||
* {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} with a usb-accessory filter matching the
|
||||
* attached accessory. In case of a UsbDevice this is the case if the calling package has an
|
||||
* intent filter for {@link UsbManager#ACTION_USB_DEVICE_ATTACHED} with a usb-device filter
|
||||
* matching the attached device.
|
||||
*
|
||||
* @return True if the package can be default for the USB device.
|
||||
/**
|
||||
* Whether the calling package can set as default handler of the USB device or accessory.
|
||||
* In case of a UsbAccessory this is the case if the calling package has an intent filter for
|
||||
* {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} with a usb-accessory filter matching the
|
||||
* attached accessory. In case of a UsbDevice this is the case if the calling package has an
|
||||
* intent filter for {@link UsbManager#ACTION_USB_DEVICE_ATTACHED} with a usb-device filter
|
||||
* matching the attached device.
|
||||
*
|
||||
* @return True if the package can be default for the USB device.
|
||||
*/
|
||||
public boolean canBeDefault() {
|
||||
return mCanBeDefault;
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.android.systemui.usb;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Dialog shown when a package requests access to a USB device or accessory.
|
||||
@@ -24,23 +27,36 @@ import com.android.systemui.R;
|
||||
public class UsbPermissionActivity extends UsbDialogActivity {
|
||||
|
||||
private boolean mPermissionGranted = false;
|
||||
private UsbAudioWarningDialogMessage mUsbPermissionMessageHandler;
|
||||
|
||||
@Inject
|
||||
public UsbPermissionActivity(UsbAudioWarningDialogMessage usbAudioWarningDialogMessage) {
|
||||
mUsbPermissionMessageHandler = usbAudioWarningDialogMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
mUsbPermissionMessageHandler.init(UsbAudioWarningDialogMessage.TYPE_PERMISSION,
|
||||
mDialogHelper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
final int strId;
|
||||
boolean useRecordWarning = false;
|
||||
if (mDialogHelper.isUsbDevice()) {
|
||||
useRecordWarning = mDialogHelper.deviceHasAudioCapture()
|
||||
&& !mDialogHelper.packageHasAudioRecordingPermission();
|
||||
strId = useRecordWarning
|
||||
? R.string.usb_device_permission_prompt_warn
|
||||
: R.string.usb_device_permission_prompt;
|
||||
} else {
|
||||
// UsbAccessory case
|
||||
strId = R.string.usb_accessory_permission_prompt;
|
||||
}
|
||||
setAlertParams(strId);
|
||||
final boolean useRecordWarning = mDialogHelper.isUsbDevice()
|
||||
&& (mDialogHelper.deviceHasAudioCapture()
|
||||
&& !mDialogHelper.packageHasAudioRecordingPermission());
|
||||
|
||||
final int titleId = mUsbPermissionMessageHandler.getPromptTitleId();
|
||||
final String title = getString(titleId, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription());
|
||||
final int messageId = mUsbPermissionMessageHandler.getMessageId();
|
||||
String message = (messageId != Resources.ID_NULL)
|
||||
? getString(messageId, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription()) : null;
|
||||
setAlertParams(title, message);
|
||||
|
||||
// Only show the "always use" checkbox if there is no USB/Record warning
|
||||
if (!useRecordWarning && mDialogHelper.canBeDefault()) {
|
||||
addAlwaysUseCheckbox();
|
||||
|
||||
@@ -21,11 +21,16 @@ import android.hardware.usb.IUsbSerialReader
|
||||
import android.hardware.usb.UsbAccessory
|
||||
import android.hardware.usb.UsbManager
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import androidx.test.runner.intercepting.SingleActivityFactory
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
|
||||
import javax.inject.Inject
|
||||
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
@@ -37,14 +42,26 @@ import org.junit.runner.RunWith
|
||||
*/
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper
|
||||
class UsbPermissionActivityTest : SysuiTestCase() {
|
||||
|
||||
class UsbPermissionActivityTestable : UsbPermissionActivity()
|
||||
private var mMessage: UsbAudioWarningDialogMessage = UsbAudioWarningDialogMessage()
|
||||
|
||||
open class UsbPermissionActivityTestable @Inject constructor (
|
||||
val message: UsbAudioWarningDialogMessage
|
||||
)
|
||||
: UsbPermissionActivity(UsbAudioWarningDialogMessage())
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var activityRule = ActivityTestRule<UsbPermissionActivityTestable>(
|
||||
UsbPermissionActivityTestable::class.java, false, false)
|
||||
object : SingleActivityFactory<UsbPermissionActivityTestable>(
|
||||
UsbPermissionActivityTestable::class.java
|
||||
) {
|
||||
override fun create(intent: Intent?): UsbPermissionActivityTestable {
|
||||
return UsbPermissionActivityTestable(mMessage)
|
||||
}
|
||||
}, false, false)
|
||||
|
||||
private val activityIntent = Intent(mContext, UsbPermissionActivityTestable::class.java)
|
||||
.apply {
|
||||
@@ -72,6 +89,7 @@ class UsbPermissionActivityTest : SysuiTestCase() {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
UsbPermissionActivityTestable(mMessage)
|
||||
activityRule.launchActivity(activityIntent)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user