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.view.LayoutInflater 20 import android.view.View 21 import android.view.ViewGroup 22 import android.widget.ImageButton 23 import android.widget.ImageView 24 import android.widget.SeekBar 25 import android.widget.TextView 26 import androidx.constraintlayout.widget.Barrier 27 import com.android.internal.widget.CachingIconView 28 import com.android.systemui.res.R 29 import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView 30 import com.android.systemui.surfaceeffects.ripple.MultiRippleView 31 import com.android.systemui.surfaceeffects.turbulencenoise.TurbulenceNoiseView 32 import com.android.systemui.util.animation.TransitionLayout 33 34 private const val TAG = "MediaViewHolder" 35 36 /** Holder class for media player view */ 37 class MediaViewHolder constructor(itemView: View) { 38 val player = itemView as TransitionLayout 39 40 // Player information 41 val albumView = itemView.requireViewById<ImageView>(R.id.album_art) 42 val multiRippleView = itemView.requireViewById<MultiRippleView>(R.id.touch_ripple_view) 43 val turbulenceNoiseView = 44 itemView.requireViewById<TurbulenceNoiseView>(R.id.turbulence_noise_view) 45 val loadingEffectView = itemView.requireViewById<LoadingEffectView>(R.id.loading_effect_view) 46 val appIcon = itemView.requireViewById<ImageView>(R.id.icon) 47 val titleText = itemView.requireViewById<TextView>(R.id.header_title) 48 val artistText = itemView.requireViewById<TextView>(R.id.header_artist) 49 val explicitIndicator = itemView.requireViewById<CachingIconView>(R.id.media_explicit_indicator) 50 51 // Output switcher 52 val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless) 53 val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image) 54 val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text) 55 val seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button) 56 57 // Seekbar views 58 val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar) 59 // These views are only shown while the user is actively scrubbing 60 val scrubbingElapsedTimeView: TextView = 61 itemView.requireViewById(R.id.media_scrubbing_elapsed_time) 62 val scrubbingTotalTimeView: TextView = itemView.requireViewById(R.id.media_scrubbing_total_time) 63 64 val gutsViewHolder = GutsViewHolder(itemView) 65 66 // Action Buttons 67 val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause) 68 val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext) 69 val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev) 70 val action0 = itemView.requireViewById<ImageButton>(R.id.action0) 71 val action1 = itemView.requireViewById<ImageButton>(R.id.action1) 72 val action2 = itemView.requireViewById<ImageButton>(R.id.action2) 73 val action3 = itemView.requireViewById<ImageButton>(R.id.action3) 74 val action4 = itemView.requireViewById<ImageButton>(R.id.action4) 75 76 val actionsTopBarrier = itemView.requireViewById<Barrier>(R.id.media_action_barrier_top) 77 getActionnull78 fun getAction(id: Int): ImageButton { 79 return when (id) { 80 R.id.actionPlayPause -> actionPlayPause 81 R.id.actionNext -> actionNext 82 R.id.actionPrev -> actionPrev 83 R.id.action0 -> action0 84 R.id.action1 -> action1 85 R.id.action2 -> action2 86 R.id.action3 -> action3 87 R.id.action4 -> action4 88 else -> { 89 throw IllegalArgumentException() 90 } 91 } 92 } 93 getTransparentActionButtonsnull94 fun getTransparentActionButtons(): List<ImageButton> { 95 return listOf(actionNext, actionPrev, action0, action1, action2, action3, action4) 96 } 97 marqueenull98 fun marquee(start: Boolean, delay: Long) { 99 gutsViewHolder.marquee(start, delay, TAG) 100 } 101 102 companion object { 103 /** 104 * Creates a MediaViewHolder. 105 * 106 * @param inflater LayoutInflater to use to inflate the layout. 107 * @param parent Parent of inflated view. 108 */ 109 @JvmStatic createnull110 fun create(inflater: LayoutInflater, parent: ViewGroup): MediaViewHolder { 111 val mediaView = inflater.inflate(R.layout.media_session_view, parent, false) 112 mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null) 113 // Because this media view (a TransitionLayout) is used to measure and layout the views 114 // in various states before being attached to its parent, we can't depend on the default 115 // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction. 116 mediaView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE 117 return MediaViewHolder(mediaView).apply { 118 // Media playback is in the direction of tape, not time, so it stays LTR 119 seekBar.layoutDirection = View.LAYOUT_DIRECTION_LTR 120 } 121 } 122 123 val controlsIds = 124 setOf( 125 R.id.icon, 126 R.id.app_name, 127 R.id.header_title, 128 R.id.header_artist, 129 R.id.media_explicit_indicator, 130 R.id.media_seamless, 131 R.id.media_progress_bar, 132 R.id.actionPlayPause, 133 R.id.actionNext, 134 R.id.actionPrev, 135 R.id.action0, 136 R.id.action1, 137 R.id.action2, 138 R.id.action3, 139 R.id.action4, 140 R.id.icon, 141 R.id.media_scrubbing_elapsed_time, 142 R.id.media_scrubbing_total_time 143 ) 144 145 // Buttons used for notification-based actions 146 val genericButtonIds = 147 setOf(R.id.action0, R.id.action1, R.id.action2, R.id.action3, R.id.action4) 148 149 val expandedBottomActionIds = 150 setOf( 151 R.id.media_progress_bar, 152 R.id.actionPrev, 153 R.id.actionNext, 154 R.id.action0, 155 R.id.action1, 156 R.id.action2, 157 R.id.action3, 158 R.id.action4, 159 R.id.media_scrubbing_elapsed_time, 160 R.id.media_scrubbing_total_time, 161 ) 162 163 val detailIds = 164 setOf( 165 R.id.header_title, 166 R.id.header_artist, 167 R.id.media_explicit_indicator, 168 R.id.actionPlayPause, 169 ) 170 171 val backgroundIds = 172 setOf( 173 R.id.album_art, 174 R.id.turbulence_noise_view, 175 R.id.loading_effect_view, 176 R.id.touch_ripple_view, 177 ) 178 } 179 } 180