1 /* <lambda>null2 * Copyright (C) 2020 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.models.recommendation 18 19 import android.view.LayoutInflater 20 import android.view.View 21 import android.view.ViewGroup 22 import android.widget.ImageView 23 import android.widget.SeekBar 24 import android.widget.TextView 25 import com.android.internal.widget.CachingIconView 26 import com.android.systemui.R 27 import com.android.systemui.media.controls.models.GutsViewHolder 28 import com.android.systemui.media.controls.ui.IlluminationDrawable 29 import com.android.systemui.util.animation.TransitionLayout 30 31 private const val TAG = "RecommendationViewHolder" 32 33 /** ViewHolder for a Smartspace media recommendation. */ 34 class RecommendationViewHolder private constructor(itemView: View, updatedView: Boolean) { 35 36 val recommendations = itemView as TransitionLayout 37 38 // Recommendation screen 39 lateinit var cardIcon: ImageView 40 lateinit var mediaAppIcons: List<CachingIconView> 41 lateinit var mediaProgressBars: List<SeekBar> 42 lateinit var cardTitle: TextView 43 44 val mediaCoverContainers = 45 listOf<ViewGroup>( 46 itemView.requireViewById(R.id.media_cover1_container), 47 itemView.requireViewById(R.id.media_cover2_container), 48 itemView.requireViewById(R.id.media_cover3_container) 49 ) 50 val mediaTitles: List<TextView> = 51 if (updatedView) { 52 mediaCoverContainers.map { it.requireViewById(R.id.media_title) } 53 } else { 54 listOf( 55 itemView.requireViewById(R.id.media_title1), 56 itemView.requireViewById(R.id.media_title2), 57 itemView.requireViewById(R.id.media_title3) 58 ) 59 } 60 val mediaSubtitles: List<TextView> = 61 if (updatedView) { 62 mediaCoverContainers.map { it.requireViewById(R.id.media_subtitle) } 63 } else { 64 listOf( 65 itemView.requireViewById(R.id.media_subtitle1), 66 itemView.requireViewById(R.id.media_subtitle2), 67 itemView.requireViewById(R.id.media_subtitle3) 68 ) 69 } 70 71 val mediaCoverItems: List<ImageView> = 72 if (updatedView) { 73 mediaCoverContainers.map { it.requireViewById(R.id.media_cover) } 74 } else { 75 listOf( 76 itemView.requireViewById(R.id.media_cover1), 77 itemView.requireViewById(R.id.media_cover2), 78 itemView.requireViewById(R.id.media_cover3) 79 ) 80 } 81 val gutsViewHolder = GutsViewHolder(itemView) 82 83 init { 84 if (updatedView) { 85 mediaAppIcons = mediaCoverContainers.map { it.requireViewById(R.id.media_rec_app_icon) } 86 cardTitle = itemView.requireViewById(R.id.media_rec_title) 87 mediaProgressBars = 88 mediaCoverContainers.map { 89 it.requireViewById<SeekBar?>(R.id.media_progress_bar).apply { 90 // Media playback is in the direction of tape, not time, so it stays LTR 91 layoutDirection = View.LAYOUT_DIRECTION_LTR 92 } 93 } 94 } else { 95 cardIcon = itemView.requireViewById<ImageView>(R.id.recommendation_card_icon) 96 } 97 (recommendations.background as IlluminationDrawable).let { background -> 98 mediaCoverContainers.forEach { background.registerLightSource(it) } 99 background.registerLightSource(gutsViewHolder.cancel) 100 background.registerLightSource(gutsViewHolder.dismiss) 101 background.registerLightSource(gutsViewHolder.settings) 102 } 103 } 104 105 fun marquee(start: Boolean, delay: Long) { 106 gutsViewHolder.marquee(start, delay, TAG) 107 } 108 109 companion object { 110 /** 111 * Creates a RecommendationViewHolder. 112 * 113 * @param inflater LayoutInflater to use to inflate the layout. 114 * @param parent Parent of inflated view. 115 */ 116 @JvmStatic 117 fun create( 118 inflater: LayoutInflater, 119 parent: ViewGroup, 120 updatedView: Boolean, 121 ): RecommendationViewHolder { 122 val itemView = 123 if (updatedView) { 124 inflater.inflate( 125 R.layout.media_recommendations, 126 parent, 127 false /* attachToRoot */ 128 ) 129 } else { 130 inflater.inflate( 131 R.layout.media_smartspace_recommendations, 132 parent, 133 false /* attachToRoot */ 134 ) 135 } 136 // Because this media view (a TransitionLayout) is used to measure and layout the views 137 // in various states before being attached to its parent, we can't depend on the default 138 // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction. 139 itemView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE 140 return RecommendationViewHolder(itemView, updatedView) 141 } 142 143 // Res Ids for the control components on the recommendation view. 144 val controlsIds = 145 setOf( 146 R.id.recommendation_card_icon, 147 R.id.media_rec_title, 148 R.id.media_cover1, 149 R.id.media_cover2, 150 R.id.media_cover3, 151 R.id.media_cover, 152 R.id.media_cover1_container, 153 R.id.media_cover2_container, 154 R.id.media_cover3_container, 155 R.id.media_title1, 156 R.id.media_title2, 157 R.id.media_title3, 158 R.id.media_title, 159 R.id.media_subtitle1, 160 R.id.media_subtitle2, 161 R.id.media_subtitle3, 162 R.id.media_subtitle, 163 ) 164 165 val mediaTitlesAndSubtitlesIds = 166 setOf( 167 R.id.media_title1, 168 R.id.media_title2, 169 R.id.media_title3, 170 R.id.media_title, 171 R.id.media_subtitle1, 172 R.id.media_subtitle2, 173 R.id.media_subtitle3, 174 R.id.media_subtitle, 175 ) 176 177 val mediaContainersIds = 178 setOf( 179 R.id.media_cover1_container, 180 R.id.media_cover2_container, 181 R.id.media_cover3_container 182 ) 183 } 184 } 185