Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf06e737 authored by Beth Thibodeau's avatar Beth Thibodeau Committed by Android (Google) Code Review
Browse files

Merge "Add new layout for session based media players"

parents d5db154d 2cf8ba50
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2021 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.
  -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/media_seamless_border">
    <item android:id="@android:id/background">
        <shape android:shape="oval">
            <solid android:color="@color/media_seamless_border" />
            <size android:width="48dp" android:height="48dp" />
        </shape>
    </item>
</ripple>
+313 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2021 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.
  -->

<!-- Layout for media session-based controls -->
<com.android.systemui.util.animation.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/qs_media_controls"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:gravity="center_horizontal|fill_vertical"
    android:forceHasOverlappingRendering="false"
    android:background="@drawable/qs_media_background"
    android:theme="@style/MediaPlayer">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/center_vertical_guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.6" />

    <!-- App icon -->
    <com.android.internal.widget.CachingIconView
        android:id="@+id/icon"
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_marginStart="@dimen/qs_media_padding"
        android:layout_marginTop="@dimen/qs_media_padding"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- Seamless Output Switcher -->
    <LinearLayout
        android:id="@+id/media_seamless"
        android:orientation="horizontal"
        android:gravity="top|end"
        android:paddingTop="@dimen/qs_media_padding"
        android:paddingEnd="@dimen/qs_media_padding"
        android:background="@drawable/qs_media_light_source"
        android:forceHasOverlappingRendering="false"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_marginStart="@dimen/qs_center_guideline_padding"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
        app:layout_constraintHorizontal_bias="1"
        app:layout_constrainedWidth="true"
        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
        app:layout_constraintHeight_min="@dimen/min_clickable_item_size">
        <LinearLayout
            android:id="@+id/media_seamless_button"
            android:layout_width="wrap_content"
            android:layout_height="@dimen/qs_seamless_height"
            android:minHeight="@dimen/qs_seamless_height"
            android:theme="@style/MediaPlayer.SolidButton"
            android:background="@drawable/qs_media_seamless_background"
            android:orientation="horizontal"
            android:contentDescription="@string/quick_settings_media_device_label">
            <ImageView
                android:id="@+id/media_seamless_image"
                android:layout_width="@dimen/qs_seamless_icon_size"
                android:layout_height="@dimen/qs_seamless_icon_size"
                android:layout_gravity="center"
                android:tint="?android:attr/textColorPrimary"
                android:src="@*android:drawable/ic_media_seamless" />
            <TextView
                android:id="@+id/media_seamless_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginStart="4dp"
                android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
                android:singleLine="true"
                android:text="@*android:string/ext_media_seamless_action"
                android:textDirection="locale"
                android:textSize="12sp"
                android:lineHeight="16sp" />
        </LinearLayout>
    </LinearLayout>

    <!-- Song name -->
    <TextView
        android:id="@+id/header_title"
        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
        android:singleLine="true"
        android:textSize="16sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginStart="@dimen/qs_media_padding"
        android:layout_marginEnd="@dimen/qs_media_padding"
        app:layout_constrainedWidth="true"
        app:layout_constraintTop_toBottomOf="@id/icon"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
        app:layout_constraintHorizontal_bias="0" />

    <!-- Artist name -->
    <TextView
        android:id="@+id/header_artist"
        android:fontFamily="@*android:string/config_headlineFontFamily"
        android:singleLine="true"
        style="@style/MediaPlayer.Subtitle"
        android:textSize="14sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="@dimen/qs_media_padding"
        app:layout_constrainedWidth="true"
        android:layout_marginTop="1dp"
        app:layout_constraintTop_toBottomOf="@id/header_title"
        app:layout_constraintStart_toStartOf="@id/header_title"
        app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
        app:layout_constraintBottom_toBottomOf="@id/actionPlayPause"
        app:layout_constraintHorizontal_bias="0" />

    <ImageButton
        android:id="@+id/actionPlayPause"
        style="@style/MediaPlayer.SessionAction.Primary"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginStart="@dimen/qs_media_padding"
        android:layout_marginEnd="@dimen/qs_media_padding"
        android:layout_marginTop="0dp"
        android:layout_marginBottom="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/media_seamless"
        app:layout_constraintBottom_toTopOf="@id/actionEnd" />

    <ImageButton
        android:id="@+id/actionPrev"
        style="@style/MediaPlayer.SessionAction"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginEnd="0dp"
        android:layout_marginBottom="0dp"
        android:layout_marginTop="0dp"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />

    <!-- Seek Bar -->
    <!-- As per Material Design on Bidirectionality, this is forced to LTR in code -->
    <SeekBar
        android:id="@+id/media_progress_bar"
        style="@style/MediaPlayer.ProgressBar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/qs_media_session_enabled_seekbar_vertical_padding"
        android:paddingBottom="12dp"
        android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
        android:splitTrack="false"
        android:layout_marginBottom="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="0dp"
        app:layout_constraintStart_toEndOf="@id/actionPrev"
        app:layout_constraintEnd_toStartOf="@id/actionNext"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />

    <ImageButton
        android:id="@+id/actionNext"
        style="@style/MediaPlayer.SessionAction"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="@dimen/qs_media_action_spacing"
        android:layout_marginBottom="0dp"
        android:layout_marginTop="0dp"
        app:layout_constraintStart_toEndOf="@id/media_progress_bar"
        app:layout_constraintEnd_toStartOf="@id/actionStart"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />

    <ImageButton
        android:id="@+id/actionStart"
        style="@style/MediaPlayer.SessionAction"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginStart="@dimen/qs_media_action_spacing"
        android:layout_marginEnd="@dimen/qs_media_action_spacing"
        android:layout_marginBottom="0dp"
        android:layout_marginTop="0dp"
        app:layout_constraintStart_toEndOf="@id/actionNext"
        app:layout_constraintEnd_toStartOf="@id/actionEnd"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />

    <ImageButton
        android:id="@+id/actionEnd"
        style="@style/MediaPlayer.SessionAction"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_marginStart="@dimen/qs_media_action_spacing"
        android:layout_marginEnd="4dp"
        android:layout_marginBottom="0dp"
        android:layout_marginTop="0dp"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toEndOf="@id/actionStart"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />

    <!-- Long press menu -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/qs_media_padding"
        android:layout_marginStart="@dimen/qs_media_padding"
        android:layout_marginEnd="@dimen/qs_media_padding"
        android:id="@+id/remove_text"
        android:fontFamily="@*android:string/config_headlineFontFamily"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:marqueeRepeatLimit="marquee_forever"
        android:text="@string/controls_media_close_session"
        android:gravity="center_horizontal|top"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toTopOf="@id/cancel" />

    <FrameLayout
        android:id="@+id/settings"
        android:background="@drawable/qs_media_light_source"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/qs_media_padding"
        android:layout_marginEnd="@dimen/qs_media_action_spacing"
        android:layout_marginBottom="@dimen/qs_media_padding"
        app:layout_constrainedWidth="true"
        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
        app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/cancel"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/remove_text">
        <TextView
            android:id="@+id/settings_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center|bottom"
            style="@style/MediaPlayer.OutlineButton"
            android:text="@string/controls_media_settings_button" />
    </FrameLayout>

    <FrameLayout
        android:id="@+id/cancel"
        android:background="@drawable/qs_media_light_source"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/qs_media_action_spacing"
        android:layout_marginEnd="@dimen/qs_media_action_spacing"
        android:layout_marginBottom="@dimen/qs_media_padding"
        app:layout_constrainedWidth="true"
        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
        app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
        app:layout_constraintStart_toEndOf="@id/settings"
        app:layout_constraintEnd_toStartOf="@id/dismiss"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/remove_text">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center|bottom"
            style="@style/MediaPlayer.OutlineButton"
            android:text="@string/cancel" />
    </FrameLayout>

    <FrameLayout
        android:id="@+id/dismiss"
        android:background="@drawable/qs_media_light_source"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/qs_media_action_spacing"
        android:layout_marginEnd="@dimen/qs_media_padding"
        android:layout_marginBottom="@dimen/qs_media_padding"
        app:layout_constrainedWidth="true"
        app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
        app:layout_constraintHeight_min="@dimen/min_clickable_item_size"
        app:layout_constraintStart_toEndOf="@id/cancel"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/remove_text">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center|bottom"
            style="@style/MediaPlayer.OutlineButton"
            android:text="@string/controls_media_dismiss_button" />
    </FrameLayout>
</com.android.systemui.util.animation.TransitionLayout>
+4 −0
Original line number Diff line number Diff line
@@ -969,6 +969,10 @@
    <dimen name="qs_media_enabled_seekbar_vertical_padding">28dp</dimen>
    <dimen name="qs_media_disabled_seekbar_vertical_padding">29dp</dimen>

    <!-- Sizes for alternate session-based layout -->
    <dimen name="qs_media_session_enabled_seekbar_vertical_padding">15dp</dimen>
    <dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen>

    <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
    <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
    <dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen>
+17 −0
Original line number Diff line number Diff line
@@ -581,6 +581,23 @@
        <item name="android:scaleType">centerInside</item>
    </style>

    <style name="MediaPlayer.SessionAction"
           parent="@android:style/Widget.Material.Button.Borderless.Small">
        <item name="android:background">@drawable/qs_media_light_source</item>
        <item name="android:tint">?android:attr/textColorPrimary</item>
        <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item>
        <item name="android:paddingTop">12dp</item>
        <item name="android:paddingStart">12dp</item>
        <item name="android:paddingEnd">12dp</item>
        <item name="android:paddingBottom">12dp</item>
        <item name="android:scaleType">centerInside</item>
    </style>

    <style name="MediaPlayer.SessionAction.Primary" parent="MediaPlayer.SessionAction">
        <item name="android:background">@drawable/qs_media_round_button_background</item>
        <item name="android:backgroundTint">@color/media_player_solid_button_bg</item>
    </style>

    <style name="MediaPlayer.OutlineButton">
        <item name="android:background">@drawable/qs_media_button_background</item>
        <item name="android:textColor">?android:attr/textColorPrimary</item>
+16 −7
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.media.MediaControlPanel.SMARTSPACE_CARD_DISMISS_EVENT
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.PageIndicator
@@ -56,7 +57,8 @@ class MediaCarouselController @Inject constructor(
    configurationController: ConfigurationController,
    falsingCollector: FalsingCollector,
    falsingManager: FalsingManager,
    dumpManager: DumpManager
    dumpManager: DumpManager,
    private val mediaFlags: MediaFlags
) : Dumpable {
    /**
     * The current width of the carousel
@@ -382,7 +384,7 @@ class MediaCarouselController @Inject constructor(
    private fun reorderAllPlayers(previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?) {
        mediaContent.removeAllViews()
        for (mediaPlayer in MediaPlayerData.players()) {
            mediaPlayer.playerViewHolder?.let {
            mediaPlayer.mediaViewHolder?.let {
                mediaContent.addView(it.player)
            } ?: mediaPlayer.recommendationViewHolder?.let {
                mediaContent.addView(it.recommendations)
@@ -416,12 +418,19 @@ class MediaCarouselController @Inject constructor(
                .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
        if (existingPlayer == null) {
            var newPlayer = mediaControlPanelFactory.get()
            if (mediaFlags.areMediaSessionActionsEnabled()) {
                newPlayer.attachPlayer(
                    PlayerViewHolder.create(LayoutInflater.from(context), mediaContent))
                        PlayerSessionViewHolder.create(LayoutInflater.from(context), mediaContent),
                        MediaViewController.TYPE.PLAYER_SESSION)
            } else {
                newPlayer.attachPlayer(
                        PlayerViewHolder.create(LayoutInflater.from(context), mediaContent),
                        MediaViewController.TYPE.PLAYER)
            }
            newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
            val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT)
            newPlayer.playerViewHolder?.player?.setLayoutParams(lp)
            newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
            newPlayer.bindPlayer(dataCopy, key)
            newPlayer.setListening(currentlyExpanded)
            MediaPlayerData.addMediaPlayer(key, dataCopy, newPlayer, systemClock)
@@ -493,7 +502,7 @@ class MediaCarouselController @Inject constructor(
        val removed = MediaPlayerData.removeMediaPlayer(key)
        removed?.apply {
            mediaCarouselScrollHandler.onPrePlayerRemoved(removed)
            mediaContent.removeView(removed.playerViewHolder?.player)
            mediaContent.removeView(removed.mediaViewHolder?.player)
            mediaContent.removeView(removed.recommendationViewHolder?.recommendations)
            removed.onDestroy()
            mediaCarouselScrollHandler.onPlayersChanged()
@@ -836,7 +845,7 @@ class MediaCarouselController @Inject constructor(
        MediaPlayerData.players().forEachIndexed {
            index, it ->
            if (it.mIsImpressed) {
                logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
                logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
                        it.mInstanceId,
                        it.mUid,
                        it.recommendationViewHolder != null,
Loading