blob: 87144924b2bae6f8a3face6064012ae1839f2d39 [file]
/*
* Copyright (C) 2024 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.
*/
package com.android.car.appcard
import android.os.Bundle
import android.util.Size
import com.android.car.appcard.annotations.EnforceFastUpdateRate
import com.android.car.appcard.component.Button
import com.android.car.appcard.component.Header
/**
* Provides application developers with certain contextual information on how their app
* cards are going to be displayed.
*/
class AppCardContext(
apiLevel: Int,
refreshPeriod: Int,
fastRefreshPeriod: Int,
isInteractable: Boolean,
imageContext: ImageAppCardContext?
) {
/** Get system's app card version */
val apiLevel: Int
/** Get OEM defined refresh period in ms (minimum of 1000ms) */
val refreshPeriod: Int
/** Get OEM defined refresh period for [EnforceFastUpdateRate] in ms (minimum of 500ms) */
val fastRefreshPeriod: Int
/**
* @return `true` if App Card view will be interactable
*/
val isInteractable: Boolean
/**
* @return [ImageAppCardContext]
*/
val imageAppCardContext: ImageAppCardContext
constructor(
apiLevel: Int,
refreshPeriod: Int,
fastRefreshPeriod: Int,
isInteractable: Boolean,
imageAppCardSize: Size,
buttonSize: Size,
headerSize: Size,
minGuaranteedButtons: Int
) : this(
apiLevel,
refreshPeriod,
fastRefreshPeriod,
isInteractable,
ImageAppCardContext(imageAppCardSize, buttonSize, headerSize, minGuaranteedButtons)
)
init {
check(value = apiLevel == 1) { "API Level must be valid" }
check(value = refreshPeriod >= 0) { "Refresh period must not be negative" }
check(value = fastRefreshPeriod >= 0) { "Fast update refresh period must not be negative" }
check(imageContext != null) { "ImageAppCardContext cannot be null" }
this.apiLevel = apiLevel
this.refreshPeriod = refreshPeriod
this.fastRefreshPeriod = fastRefreshPeriod
this.isInteractable = isInteractable
imageAppCardContext = imageContext
}
/** Create bundle from a [AppCardContext] */
fun toBundle(): Bundle {
val b = Bundle()
b.apply {
putInt(BUNDLE_KEY_API_LEVEL, apiLevel)
putInt(BUNDLE_KEY_REFRESH_PERIOD, refreshPeriod)
putInt(BUNDLE_KEY_FAST_REFRESH_PERIOD, fastRefreshPeriod)
putBoolean(BUNDLE_KEY_INTERACTABLE, isInteractable)
putBundle(BUNDLE_KEY_IMAGE_CONTEXT, imageAppCardContext.toBundle())
}
return b
}
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is AppCardContext) return false
var result = apiLevel == other.apiLevel
result = result and (refreshPeriod == other.refreshPeriod)
result = result and (fastRefreshPeriod == other.fastRefreshPeriod)
result = result and (isInteractable == other.isInteractable)
result = result and (imageAppCardContext == other.imageAppCardContext)
return result
}
override fun hashCode(): Int {
var result = apiLevel
result = 31 * result + refreshPeriod
result = 31 * result + fastRefreshPeriod
result = 31 * result + isInteractable.hashCode()
result = 31 * result + imageAppCardContext.hashCode()
return result
}
/**
* Provides application developers with certain contextual information on how their
* [ImageAppCard] cards are going to be displayed.
*/
class ImageAppCardContext(
private val mImageAppCardSize: Size,
private val mButtonSize: Size,
private val mHeaderSize: Size,
/** Minimum number of buttons guaranteed to show in a row inside [ImageAppCard] */
val minimumGuaranteedButtons: Int
) {
internal fun toBundle(): Bundle {
val b = Bundle()
b.apply {
putString(BUNDLE_KEY_IMAGE_SIZE_IMAGE_APP_CARD, mImageAppCardSize.toString())
putString(BUNDLE_KEY_IMAGE_SIZE_BUTTON, mButtonSize.toString())
putString(BUNDLE_KEY_IMAGE_SIZE_HEADER, mHeaderSize.toString())
putInt(BUNDLE_KEY_MIN_BUTTONS_IN_IMAGE_APP_CARD, minimumGuaranteedButtons)
}
return b
}
/**
* Get maximum image size depending on the component it is housed in
* inside a [ImageAppCard] such as Image, Button, etc
* If an object doesn't contain an [com.android.car.appcard.component.Image],
* return `null`
*/
fun getMaxImageSize(c: Class<*>): Size {
return when (c) {
Button::class.java -> mButtonSize
ImageAppCard::class.java -> mImageAppCardSize
Header::class.java -> mHeaderSize
else -> throw IllegalStateException("Maximum image size requested for unrecognized class")
}
}
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is ImageAppCardContext) return false
var result = mImageAppCardSize == other.mImageAppCardSize
result = result and (mButtonSize == other.mButtonSize)
result = result and (mHeaderSize == other.mHeaderSize)
result = result and (minimumGuaranteedButtons == other.minimumGuaranteedButtons)
return result
}
override fun hashCode(): Int {
var result = mImageAppCardSize.hashCode()
result = 31 * result + mButtonSize.hashCode()
result = 31 * result + mHeaderSize.hashCode()
result = 31 * result + minimumGuaranteedButtons
return result
}
companion object {
const val BUNDLE_KEY_IMAGE_SIZE_IMAGE_APP_CARD = "imageAppCardImageSize"
const val BUNDLE_KEY_IMAGE_SIZE_BUTTON = "imageAppCardButtonImageSize"
const val BUNDLE_KEY_IMAGE_SIZE_HEADER = "imageAppCardHeaderImageSize"
const val BUNDLE_KEY_MIN_BUTTONS_IN_IMAGE_APP_CARD =
"imageAppCardMinGuaranteedButtonsInRow"
internal fun fromBundle(b: Bundle?): ImageAppCardContext? {
b ?: run {
return null
}
return ImageAppCardContext(
Size.parseSize(b.getString(BUNDLE_KEY_IMAGE_SIZE_IMAGE_APP_CARD)),
Size.parseSize(b.getString(BUNDLE_KEY_IMAGE_SIZE_BUTTON)),
Size.parseSize(b.getString(BUNDLE_KEY_IMAGE_SIZE_HEADER)),
b.getInt(BUNDLE_KEY_MIN_BUTTONS_IN_IMAGE_APP_CARD)
)
}
}
}
companion object {
const val BUNDLE_KEY_API_LEVEL = "appCardApiLevel"
const val BUNDLE_KEY_REFRESH_PERIOD = "appCardRefreshPeriod"
const val BUNDLE_KEY_FAST_REFRESH_PERIOD = "appCardFastRefreshPeriod"
const val BUNDLE_KEY_INTERACTABLE = "isAppCardInteractable"
const val BUNDLE_KEY_IMAGE_CONTEXT = "imageAppCardContext"
/** Create [AppCardContext] from a bundle */
@JvmStatic
fun fromBundle(b: Bundle?): AppCardContext? {
b ?: run {
return null
}
val intDefaultValue = 0
val apiLevel = b.getInt(BUNDLE_KEY_API_LEVEL, intDefaultValue)
val refreshPeriodDefaultValue = -1
val refreshPeriod = b.getInt(BUNDLE_KEY_REFRESH_PERIOD, refreshPeriodDefaultValue)
val fastRefreshPeriod = b.getInt(BUNDLE_KEY_FAST_REFRESH_PERIOD, refreshPeriodDefaultValue)
val boolDefaultValue = false
val isInteractable = b.getBoolean(BUNDLE_KEY_INTERACTABLE, boolDefaultValue)
val imageContextBundle = b.getBundle(BUNDLE_KEY_IMAGE_CONTEXT)
return AppCardContext(
apiLevel,
refreshPeriod,
fastRefreshPeriod,
isInteractable,
ImageAppCardContext.fromBundle(imageContextBundle)
)
}
}
}