1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.media.controls.ui.view 18 19 import android.graphics.Typeface 20 import android.view.LayoutInflater 21 import android.view.View 22 import android.view.ViewGroup 23 import android.widget.ImageButton 24 import android.widget.ImageView 25 import android.widget.SeekBar 26 import android.widget.TextView 27 import androidx.constraintlayout.widget.Barrier 28 import com.android.internal.widget.CachingIconView 29 import com.android.systemui.FontStyles.GSF_HEADLINE_SMALL 30 import com.android.systemui.FontStyles.GSF_LABEL_LARGE 31 import com.android.systemui.FontStyles.GSF_LABEL_MEDIUM 32 import com.android.systemui.FontStyles.GSF_TITLE_MEDIUM 33 import com.android.systemui.res.R 34 import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView 35 import com.android.systemui.surfaceeffects.ripple.MultiRippleView 36 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView 37 import com.android.systemui.util.animation.TransitionLayout 38 39 private const val TAG = "MediaViewHolder" 40 41 /** Holder class for media player view */ 42 class MediaViewHolder constructor(itemView: View) { 43 val player = itemView as TransitionLayout 44 45 // Player information 46 val albumView = itemView.requireViewById<ImageView>(R.id.album_art) 47 val multiRippleView = itemView.requireViewById<MultiRippleView>(R.id.touch_ripple_view) 48 val turbulenceNoiseView = 49 itemView.requireViewById<TurbulenceNoiseView>(R.id.turbulence_noise_view) 50 val loadingEffectView = itemView.requireViewById<LoadingEffectView>(R.id.loading_effect_view) 51 val appIcon = itemView.requireViewById<ImageView>(R.id.icon) 52 val titleText = itemView.requireViewById<TextView>(R.id.header_title) 53 val artistText = itemView.requireViewById<TextView>(R.id.header_artist) 54 val explicitIndicator = itemView.requireViewById<CachingIconView>(R.id.media_explicit_indicator) 55 56 // Output switcher 57 val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless) 58 val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image) 59 val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text) 60 val seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button) 61 62 // Seekbar views 63 val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar) 64 // These views are only shown while the user is actively scrubbing 65 val scrubbingElapsedTimeView: TextView = 66 itemView.requireViewById(R.id.media_scrubbing_elapsed_time) 67 val scrubbingTotalTimeView: TextView = itemView.requireViewById(R.id.media_scrubbing_total_time) 68 69 val gutsViewHolder = GutsViewHolder(itemView) 70 71 // Action Buttons 72 val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause) 73 val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext) 74 val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev) 75 val action0 = itemView.requireViewById<ImageButton>(R.id.action0) 76 val action1 = itemView.requireViewById<ImageButton>(R.id.action1) 77 val action2 = itemView.requireViewById<ImageButton>(R.id.action2) 78 val action3 = itemView.requireViewById<ImageButton>(R.id.action3) 79 val action4 = itemView.requireViewById<ImageButton>(R.id.action4) 80 81 val actionsTopBarrier = itemView.requireViewById<Barrier>(R.id.media_action_barrier_top) 82 getActionnull83 fun getAction(id: Int): ImageButton { 84 return when (id) { 85 R.id.actionPlayPause -> actionPlayPause 86 R.id.actionNext -> actionNext 87 R.id.actionPrev -> actionPrev 88 R.id.action0 -> action0 89 R.id.action1 -> action1 90 R.id.action2 -> action2 91 R.id.action3 -> action3 92 R.id.action4 -> action4 93 else -> { 94 throw IllegalArgumentException() 95 } 96 } 97 } 98 getTransparentActionButtonsnull99 fun getTransparentActionButtons(): List<ImageButton> { 100 return listOf(actionNext, actionPrev, action0, action1, action2, action3, action4) 101 } 102 marqueenull103 fun marquee(start: Boolean, delay: Long) { 104 gutsViewHolder.marquee(start, delay, TAG) 105 } 106 107 companion object { 108 /** 109 * Creates a MediaViewHolder. 110 * 111 * @param inflater LayoutInflater to use to inflate the layout. 112 * @param parent Parent of inflated view. 113 */ 114 @JvmStatic createnull115 fun create(inflater: LayoutInflater, parent: ViewGroup): MediaViewHolder { 116 val mediaView = inflater.inflate(R.layout.media_session_view, parent, false) 117 mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null) 118 // Because this media view (a TransitionLayout) is used to measure and layout the views 119 // in various states before being attached to its parent, we can't depend on the default 120 // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction. 121 mediaView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE 122 return MediaViewHolder(mediaView).apply { 123 // Media playback is in the direction of tape, not time, so it stays LTR 124 seekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR 125 } 126 } 127 128 val controlsIds = 129 setOf( 130 R.id.icon, 131 R.id.app_name, 132 R.id.header_title, 133 R.id.header_artist, 134 R.id.media_explicit_indicator, 135 R.id.media_seamless, 136 R.id.media_progress_bar, 137 R.id.actionPlayPause, 138 R.id.actionNext, 139 R.id.actionPrev, 140 R.id.action0, 141 R.id.action1, 142 R.id.action2, 143 R.id.action3, 144 R.id.action4, 145 R.id.icon, 146 R.id.media_scrubbing_elapsed_time, 147 R.id.media_scrubbing_total_time, 148 ) 149 150 // Buttons used for notification-based actions 151 val genericButtonIds = 152 setOf(R.id.action0, R.id.action1, R.id.action2, R.id.action3, R.id.action4) 153 154 val expandedBottomActionIds = 155 setOf( 156 R.id.media_progress_bar, 157 R.id.actionPrev, 158 R.id.actionNext, 159 R.id.action0, 160 R.id.action1, 161 R.id.action2, 162 R.id.action3, 163 R.id.action4, 164 R.id.media_scrubbing_elapsed_time, 165 R.id.media_scrubbing_total_time, 166 ) 167 168 val detailIds = 169 setOf( 170 R.id.header_title, 171 R.id.header_artist, 172 R.id.media_explicit_indicator, 173 R.id.actionPlayPause, 174 ) 175 176 val backgroundIds = 177 setOf( 178 R.id.album_art, 179 R.id.turbulence_noise_view, 180 R.id.loading_effect_view, 181 R.id.touch_ripple_view, 182 ) 183 184 val headlineSmallTF: Typeface = Typeface.create(GSF_HEADLINE_SMALL, Typeface.NORMAL) 185 val titleMediumTF: Typeface = Typeface.create(GSF_TITLE_MEDIUM, Typeface.NORMAL) 186 val labelMediumTF: Typeface = Typeface.create(GSF_LABEL_MEDIUM, Typeface.NORMAL) 187 val labelLargeTF: Typeface = Typeface.create(GSF_LABEL_LARGE, Typeface.NORMAL) 188 } 189 } 190