1 /* 2 * Copyright (C) 2023 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 package com.android.intentresolver.validation.types 17 18 import com.android.intentresolver.validation.Importance 19 import com.android.intentresolver.validation.Invalid 20 import com.android.intentresolver.validation.NoValue 21 import com.android.intentresolver.validation.Valid 22 import com.android.intentresolver.validation.ValidationResult 23 import com.android.intentresolver.validation.Validator 24 import com.android.intentresolver.validation.ValueIsWrongType 25 import com.android.intentresolver.validation.WrongElementType 26 import kotlin.reflect.KClass 27 import kotlin.reflect.cast 28 29 class ParceledArray<T : Any>( 30 override val key: String, 31 private val elementType: KClass<T>, 32 ) : Validator<List<T>> { 33 validatenull34 override fun validate( 35 source: (String) -> Any?, 36 importance: Importance 37 ): ValidationResult<List<T>> { 38 return when (val value: Any? = source(key)) { 39 // No value present. 40 null -> 41 when (importance) { 42 Importance.WARNING -> Invalid() // No warnings if optional, but missing 43 Importance.CRITICAL -> Invalid(NoValue(key, importance, elementType)) 44 } 45 // A parcel does not transfer the element type information for parcelable 46 // arrays. This leads to a restored type of Array<Parcelable>, which is 47 // incompatible with Array<T : Parcelable>. 48 49 // To handle this safely, treat as Array<*>, assert contents of the expected 50 // parcelable type, and return as a list. 51 52 is Array<*> -> { 53 val invalid = value.filterNotNull().firstOrNull { !elementType.isInstance(it) } 54 when (invalid) { 55 // No invalid elements, result is ok. 56 null -> Valid(value.map { elementType.cast(it) }) 57 58 // At least one incorrect element type found. 59 else -> 60 Invalid( 61 WrongElementType( 62 key, 63 importance, 64 actualType = invalid::class, 65 container = Array::class, 66 expectedType = elementType 67 ) 68 ) 69 } 70 } 71 72 // The value is not an Array at all. 73 else -> 74 Invalid( 75 ValueIsWrongType( 76 key, 77 importance, 78 actualType = value::class, 79 allowedTypes = listOf(elementType) 80 ) 81 ) 82 } 83 } 84 } 85