Merge changes from topics "presubmit-am-3fca48eecdb74a8e96804b9a78256e56", "presubmit-am-563ae16077714dd0a7da266e4a698052", "presubmit-am-9cc0354ba3f24063b26fb042cc9dbf89" into tm-dev

* changes:
  [Media TTT] Fix the generic icon on the receiver chip by making it smaller so it fits in the circle.
  [Media TTT] Add a ripple to the undo button.
  [Media TTT] Update the error message string.
This commit is contained in:
TreeHugger Robot
2022-03-18 20:11:12 +00:00
committed by Android (Google) Code Review
8 changed files with 126 additions and 34 deletions

View File

@@ -14,9 +14,14 @@
~ See the License for the specific language governing permissions and ~ See the License for the specific language governing permissions and
~ limitations under the License. ~ limitations under the License.
--> -->
<shape <ripple
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
<solid android:color="?androidprv:attr/colorAccentPrimary" /> android:color="?android:textColorPrimary">
<corners android:radius="24dp" /> <item android:id="@android:id/background">
</shape> <shape>
<solid android:color="?androidprv:attr/colorAccentPrimary"/>
<corners android:radius="24dp" />
</shape>
</item>
</ripple>

View File

@@ -1008,6 +1008,9 @@
<!-- Media tap-to-transfer chip for receiver device --> <!-- Media tap-to-transfer chip for receiver device -->
<dimen name="media_ttt_chip_size_receiver">100dp</dimen> <dimen name="media_ttt_chip_size_receiver">100dp</dimen>
<dimen name="media_ttt_icon_size_receiver">95dp</dimen> <dimen name="media_ttt_icon_size_receiver">95dp</dimen>
<!-- Since the generic icon isn't circular, we need to scale it down so it still fits within
the circular chip. -->
<dimen name="media_ttt_generic_icon_size_receiver">70dp</dimen>
<!-- Window magnification --> <!-- Window magnification -->
<dimen name="magnification_border_drag_size">35dp</dimen> <dimen name="magnification_border_drag_size">35dp</dimen>

View File

@@ -2184,7 +2184,7 @@
<!-- Text informing the user that their media is now playing on this device. [CHAR LIMIT=50] --> <!-- Text informing the user that their media is now playing on this device. [CHAR LIMIT=50] -->
<string name="media_transfer_playing_this_device">Playing on this phone</string> <string name="media_transfer_playing_this_device">Playing on this phone</string>
<!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIMIT=50] --> <!-- Text informing the user that the media transfer has failed because something went wrong. [CHAR LIMIT=50] -->
<string name="media_transfer_failed">Something went wrong</string> <string name="media_transfer_failed">Something went wrong. Try again.</string>
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] --> <!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string> <string name="controls_error_timeout">Inactive, check app</string>

View File

@@ -128,19 +128,21 @@ class MediaTttCommandLineHelper @Inject constructor(
as StatusBarManager as StatusBarManager
val routeInfo = MediaRoute2Info.Builder("id", "Test Name") val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
.addFeature("feature") .addFeature("feature")
.setPackageName(TEST_PACKAGE_NAME) if (args.size >= 2 && args[1] == "useAppIcon=true") {
.build() routeInfo.setPackageName(TEST_PACKAGE_NAME)
}
statusBarManager.updateMediaTapToTransferReceiverDisplay( statusBarManager.updateMediaTapToTransferReceiverDisplay(
displayState, displayState,
routeInfo, routeInfo.build(),
null, null,
null null
) )
} }
override fun help(pw: PrintWriter) { override fun help(pw: PrintWriter) {
pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND <chipState>") pw.println("Usage: adb shell cmd statusbar $RECEIVER_COMMAND " +
"<chipState> useAppIcon=[true|false]")
} }
} }
} }

View File

@@ -31,6 +31,7 @@ import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import android.widget.LinearLayout
import com.android.internal.widget.CachingIconView import com.android.internal.widget.CachingIconView
import com.android.settingslib.Utils import com.android.settingslib.Utils
import com.android.systemui.R import com.android.systemui.R
@@ -136,6 +137,11 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
*/ */
abstract fun updateChipView(chipInfo: T, currentChipView: ViewGroup) abstract fun updateChipView(chipInfo: T, currentChipView: ViewGroup)
/**
* Returns the size that the icon should be, or null if no size override is needed.
*/
open fun getIconSize(isAppIcon: Boolean): Int? = null
/** /**
* An internal method to set the icon on the view. * An internal method to set the icon on the view.
* *
@@ -151,35 +157,47 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
appNameOverride: CharSequence? = null, appNameOverride: CharSequence? = null,
) { ) {
val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon) val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
val appInfo = getAppInfo(appPackageName) val iconInfo = getIconInfo(appPackageName)
appIconView.contentDescription = appNameOverride ?: appInfo.appName
appIconView.setImageDrawable(appIconDrawableOverride ?: appInfo.appIcon) getIconSize(iconInfo.isAppIcon)?.let { size ->
val lp = appIconView.layoutParams
lp.width = size
lp.height = size
appIconView.layoutParams = lp
}
appIconView.contentDescription = appNameOverride ?: iconInfo.iconName
appIconView.setImageDrawable(appIconDrawableOverride ?: iconInfo.icon)
} }
/** /**
* Returns the app name and icon of the app playing media, or a default name and icon if we * Returns the information needed to display the icon.
* can't find the app name/icon. *
* The information will either contain app name and icon of the app playing media, or a default
* name and icon if we can't find the app name/icon.
*/ */
private fun getAppInfo(appPackageName: String?): AppInfo { private fun getIconInfo(appPackageName: String?): IconInfo {
if (appPackageName != null) { if (appPackageName != null) {
try { try {
return AppInfo( return IconInfo(
appName = context.packageManager.getApplicationInfo( iconName = context.packageManager.getApplicationInfo(
appPackageName, PackageManager.ApplicationInfoFlags.of(0) appPackageName, PackageManager.ApplicationInfoFlags.of(0)
).loadLabel(context.packageManager).toString(), ).loadLabel(context.packageManager).toString(),
appIcon = context.packageManager.getApplicationIcon(appPackageName) icon = context.packageManager.getApplicationIcon(appPackageName),
isAppIcon = true
) )
} catch (e: PackageManager.NameNotFoundException) { } catch (e: PackageManager.NameNotFoundException) {
Log.w(TAG, "Cannot find package $appPackageName", e) Log.w(TAG, "Cannot find package $appPackageName", e)
} }
} }
return AppInfo( return IconInfo(
appName = context.getString(R.string.media_output_dialog_unknown_launch_app_name), iconName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
appIcon = context.resources.getDrawable(R.drawable.ic_cast).apply { icon = context.resources.getDrawable(R.drawable.ic_cast).apply {
this.setTint( this.setTint(
Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary) Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
) )
} },
isAppIcon = false
) )
} }
@@ -203,7 +221,9 @@ object MediaTttRemovalReason {
const val REASON_SCREEN_TAP = "SCREEN_TAP" const val REASON_SCREEN_TAP = "SCREEN_TAP"
} }
private data class AppInfo( private data class IconInfo(
val appName: String, val iconName: String,
val appIcon: Drawable val icon: Drawable,
/** True if [icon] is the app's icon, and false if [icon] is some generic default icon. */
val isAppIcon: Boolean
) )

View File

@@ -127,6 +127,15 @@ class MediaTttChipControllerReceiver @Inject constructor(
chipInfo.appNameOverride chipInfo.appNameOverride
) )
} }
override fun getIconSize(isAppIcon: Boolean): Int? =
context.resources.getDimensionPixelSize(
if (isAppIcon) {
R.dimen.media_ttt_icon_size_receiver
} else {
R.dimen.media_ttt_generic_icon_size_receiver
}
)
} }
data class ChipReceiverInfo( data class ChipReceiverInfo(

View File

@@ -192,9 +192,9 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
verify(windowManager, never()).removeView(any()) verify(windowManager, never()).removeView(any())
} }
@Test @Test
fun displayChip_nullAppIconDrawableAndNullPackageName_stillHasIcon() { fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
controllerCommon.displayChip(getState()) controllerCommon.displayChip(getState())
val chipView = getChipView() val chipView = getChipView()
@@ -204,7 +204,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
} }
@Test @Test
fun displayChip_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() { fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
controllerCommon.displayChip(getState()) controllerCommon.displayChip(getState())
val chipView = getChipView() val chipView = getChipView()
@@ -226,7 +226,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
} }
@Test @Test
fun displayChip_hasAppIconDrawable_iconIsDrawable() { fun setIcon_hasAppIconDrawable_iconIsDrawable() {
controllerCommon.displayChip(getState()) controllerCommon.displayChip(getState())
val chipView = getChipView() val chipView = getChipView()
@@ -237,7 +237,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
} }
@Test @Test
fun displayChip_nullAppNameAndNullPackageName_stillHasContentDescription() { fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
controllerCommon.displayChip(getState()) controllerCommon.displayChip(getState())
val chipView = getChipView() val chipView = getChipView()
@@ -247,7 +247,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
} }
@Test @Test
fun displayChip_nullAppNameAndInvalidPackageName_stillHasContentDescription() { fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
controllerCommon.displayChip(getState()) controllerCommon.displayChip(getState())
val chipView = getChipView() val chipView = getChipView()
@@ -259,7 +259,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
} }
@Test @Test
fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() { fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
controllerCommon.displayChip(getState()) controllerCommon.displayChip(getState())
val chipView = getChipView() val chipView = getChipView()
@@ -269,7 +269,7 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
} }
@Test @Test
fun displayChip_hasAppName_iconContentDescriptionIsAppNameOverride() { fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
controllerCommon.displayChip(getState()) controllerCommon.displayChip(getState())
val chipView = getChipView() val chipView = getChipView()
@@ -279,6 +279,21 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName) assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName)
} }
@Test
fun setIcon_iconSizeMatchesGetIconSize() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
controllerCommon.setIcon(chipView, PACKAGE_NAME)
chipView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
}
@Test @Test
fun tapGestureDetected_outsideViewBounds_viewHidden() { fun tapGestureDetected_outsideViewBounds_viewHidden() {
controllerCommon.displayChip(getState()) controllerCommon.displayChip(getState())
@@ -344,6 +359,8 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) { override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) {
} }
override fun getIconSize(isAppIcon: Boolean): Int? = ICON_SIZE
} }
inner class ChipInfo : ChipInfoCommon { inner class ChipInfo : ChipInfoCommon {
@@ -354,3 +371,4 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() {
private const val PACKAGE_NAME = "com.android.systemui" private const val PACKAGE_NAME = "com.android.systemui"
private const val APP_NAME = "Fake App Name" private const val APP_NAME = "Fake App Name"
private const val TIMEOUT_MS = 10000L private const val TIMEOUT_MS = 10000L
private const val ICON_SIZE = 47

View File

@@ -174,12 +174,47 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() {
verify(logger).logStateChange(any(), any()) verify(logger).logStateChange(any(), any())
} }
@Test
fun setIcon_isAppIcon_usesAppIconSize() {
controllerReceiver.displayChip(getChipReceiverInfo())
val chipView = getChipView()
controllerReceiver.setIcon(chipView, PACKAGE_NAME)
chipView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
val expectedSize = controllerReceiver.getIconSize(isAppIcon = true)
assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
}
@Test
fun setIcon_notAppIcon_usesGenericIconSize() {
controllerReceiver.displayChip(getChipReceiverInfo())
val chipView = getChipView()
controllerReceiver.setIcon(chipView, appPackageName = null)
chipView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
val expectedSize = controllerReceiver.getIconSize(isAppIcon = false)
assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
}
private fun getChipView(): ViewGroup { private fun getChipView(): ViewGroup {
val viewCaptor = ArgumentCaptor.forClass(View::class.java) val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any()) verify(windowManager).addView(viewCaptor.capture(), any())
return viewCaptor.value as ViewGroup return viewCaptor.value as ViewGroup
} }
private fun getChipReceiverInfo(): ChipReceiverInfo =
ChipReceiverInfo(routeInfo, null, null)
private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon) private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon)
} }