1 /*
2  * Copyright 2024 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 androidx.security.state.provider
18 
19 import androidx.security.state.SecurityPatchState
20 import java.text.SimpleDateFormat
21 import java.util.Date
22 import java.util.Objects
23 import kotlinx.serialization.KSerializer
24 import kotlinx.serialization.Serializable
25 import kotlinx.serialization.descriptors.PrimitiveKind
26 import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
27 import kotlinx.serialization.descriptors.SerialDescriptor
28 import kotlinx.serialization.encoding.Decoder
29 import kotlinx.serialization.encoding.Encoder
30 
31 private object DateSerializer : KSerializer<Date> {
32     override val descriptor: SerialDescriptor =
33         PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)
34 
35     private val dateFormat: SimpleDateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
36 
serializenull37     override fun serialize(encoder: Encoder, value: Date): Unit =
38         encoder.encodeString(dateFormat.format(value))
39 
40     override fun deserialize(decoder: Decoder): Date = dateFormat.parse(decoder.decodeString())!!
41 }
42 
43 @Serializable
44 internal class SerializableUpdateInfo(
45     private val uri: String,
46     private val component: String,
47     private val securityPatchLevel: String,
48     @Serializable(with = DateSerializer::class) private val publishedDate: Date
49 ) {
50     internal fun toUpdateInfo(): UpdateInfo =
51         UpdateInfo(uri, component, securityPatchLevel, publishedDate)
52 }
53 
54 /** Represents information about an available update for a component. */
55 public class UpdateInfo(
56     /** Uri of the content provider from OTA update client serving update information data. */
57     public val uri: String,
58     /** Component for which the update information is provided. */
59     public val component: String,
60     /**
61      * Security patch level of the available update ready to be applied by the reporting client. Use
62      * [SecurityPatchState.getComponentSecurityPatchLevel] method to get encapsulated value.
63      */
64     public val securityPatchLevel: String,
65     /** Date when the available update was published. */
66     public val publishedDate: Date
67 ) {
68 
toSerializableUpdateInfonull69     internal fun toSerializableUpdateInfo(): SerializableUpdateInfo =
70         SerializableUpdateInfo(uri, component, securityPatchLevel, publishedDate)
71 
72     /**
73      * Returns a string representation of the update information.
74      *
75      * @return A string that describes the update details.
76      */
77     public override fun toString(): String =
78         "UpdateInfo(" +
79             "uri=$uri, component=$component, SPL=$securityPatchLevel, date=$publishedDate)"
80 
81     /**
82      * Compares this UpdateInfo with another object for equality.
83      *
84      * @param other The object to compare with this instance.
85      * @return true if the other object is an instance of UpdateInfo and all properties match, false
86      *   otherwise.
87      */
88     public override fun equals(other: Any?): Boolean =
89         other is UpdateInfo &&
90             uri == other.uri &&
91             component == other.component &&
92             securityPatchLevel == other.securityPatchLevel &&
93             publishedDate == other.publishedDate
94 
95     /**
96      * Provides a hash code for an UpdateInfo object.
97      *
98      * @return A hash code produced by the properties of the update info.
99      */
100     public override fun hashCode(): Int =
101         Objects.hash(uri, component, securityPatchLevel, publishedDate)
102 
103     /** Builder class for creating an instance of UpdateInfo. */
104     public class Builder {
105         @set:JvmSynthetic private var uri: String = ""
106         @set:JvmSynthetic private var component: String = ""
107         @set:JvmSynthetic private var securityPatchLevel: String = ""
108         @set:JvmSynthetic private var publishedDate: Date = Date(0) // 1970-01-01
109 
110         /**
111          * Sets the URI of the update.
112          *
113          * @param uri The URI to set.
114          * @return The builder instance for chaining.
115          */
116         public fun setUri(uri: String): Builder = apply { this.uri = uri }
117 
118         /**
119          * Sets the component associated with the update.
120          *
121          * @param component The component to set.
122          * @return The builder instance for chaining.
123          */
124         public fun setComponent(component: String): Builder = apply { this.component = component }
125 
126         /**
127          * Sets the security patch level of the update.
128          *
129          * @param securityPatchLevel The security patch level to set.
130          * @return The builder instance for chaining.
131          */
132         public fun setSecurityPatchLevel(securityPatchLevel: String): Builder = apply {
133             this.securityPatchLevel = securityPatchLevel
134         }
135 
136         /**
137          * Sets the publication date of the update.
138          *
139          * @param publishedDate The date to set.
140          * @return The builder instance for chaining.
141          */
142         public fun setPublishedDate(publishedDate: Date): Builder = apply {
143             this.publishedDate = publishedDate
144         }
145 
146         /**
147          * Builds and returns an UpdateInfo object.
148          *
149          * @return The constructed UpdateInfo.
150          */
151         public fun build(): UpdateInfo =
152             UpdateInfo(uri, component, securityPatchLevel, publishedDate)
153     }
154 }
155