1 /*
2  * Copyright 2025 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.appfunctions.schema.notes.translators
18 
19 import androidx.annotation.RequiresApi
20 import androidx.appfunctions.AppFunctionData
21 import androidx.appfunctions.AppFunctionSerializable
22 import androidx.appfunctions.ExecuteAppFunctionResponse.Success.Companion.PROPERTY_RETURN_VALUE
23 import androidx.appfunctions.internal.Translator
24 import androidx.appfunctions.schema.notes.FindNotesAppFunction
25 import androidx.appfunctions.schema.notes.translators.NoteTranslator.downgradeNote
26 import androidx.appfunctions.schema.notes.translators.NoteTranslator.upgradeNote
27 import java.time.LocalDateTime
28 import java.time.ZoneId
29 
30 @RequiresApi(33)
31 internal class FindNotesTranslator : Translator {
upgradeRequestnull32     override fun upgradeRequest(request: AppFunctionData): AppFunctionData {
33         val legacyFindNoteParams = checkNotNull(request.getAppFunctionData("findNotesParams"))
34 
35         val parameters =
36             FindNotesAppFunctionParams(
37                 query = legacyFindNoteParams.getStringOrNull("query"),
38                 modifiedAfter =
39                     legacyFindNoteParams.getAppFunctionData("startDate")?.toLocalDateTime(),
40                 modifiedBefore =
41                     legacyFindNoteParams.getAppFunctionData("endDate")?.toLocalDateTime()
42             )
43 
44         return AppFunctionData.Builder(qualifiedName = "")
45             .setAppFunctionData(
46                 "parameters",
47                 AppFunctionData.serialize(parameters, FindNotesAppFunctionParams::class.java)
48             )
49             .build()
50     }
51 
upgradeResponsenull52     override fun upgradeResponse(response: AppFunctionData): AppFunctionData {
53         val legacyFindNotesResponse =
54             checkNotNull(response.getAppFunctionDataList(PROPERTY_RETURN_VALUE))
55 
56         val notes = legacyFindNotesResponse.map { it.upgradeNote() }
57 
58         return AppFunctionData.Builder(qualifiedName = "")
59             .setAppFunctionData(
60                 PROPERTY_RETURN_VALUE,
61                 AppFunctionData.serialize(
62                     FindNotesAppFunctionResponse(notes),
63                     FindNotesAppFunctionResponse::class.java
64                 )
65             )
66             .build()
67     }
68 
downgradeRequestnull69     override fun downgradeRequest(request: AppFunctionData): AppFunctionData {
70         val parametersData = checkNotNull(request.getAppFunctionData("parameters"))
71         val findNotesAppFunctionParams =
72             parametersData.deserialize(FindNotesAppFunctionParams::class.java)
73         val downgradedRequestData =
74             AppFunctionData.Builder(qualifiedName = "")
75                 .apply {
76                     if (findNotesAppFunctionParams.query != null) {
77                         setString("query", findNotesAppFunctionParams.query)
78                     }
79                     if (findNotesAppFunctionParams.modifiedAfter != null) {
80                         setAppFunctionData(
81                             "startDate",
82                             findNotesAppFunctionParams.modifiedAfter.toLegacyAppFunctionData()
83                         )
84                     }
85                     if (findNotesAppFunctionParams.modifiedBefore != null) {
86                         setAppFunctionData(
87                             "endDate",
88                             findNotesAppFunctionParams.modifiedBefore.toLegacyAppFunctionData()
89                         )
90                     }
91 
92                     setInt("maxCount", Int.MAX_VALUE)
93                 }
94                 .build()
95         return AppFunctionData.Builder(qualifiedName = "")
96             .setAppFunctionData("findNotesParams", downgradedRequestData)
97             .build()
98     }
99 
downgradeResponsenull100     override fun downgradeResponse(response: AppFunctionData): AppFunctionData {
101         val responseData = checkNotNull(response.getAppFunctionData(PROPERTY_RETURN_VALUE))
102         val findNotesAppFunctionResponse =
103             responseData.deserialize(FindNotesAppFunctionResponse::class.java)
104         return AppFunctionData.Builder(qualifiedName = "")
105             .setAppFunctionDataList(
106                 PROPERTY_RETURN_VALUE,
107                 findNotesAppFunctionResponse.notes.map { it.downgradeNote() }
108             )
109             .build()
110     }
111 
112     companion object {
toLocalDateTimenull113         private fun AppFunctionData.toLocalDateTime(): LocalDateTime {
114             val date = checkNotNull(getAppFunctionData("date"))
115             val timeOfDay = checkNotNull(getAppFunctionData("timeOfDay"))
116             return LocalDateTime.of(
117                 /* year= */ date.getInt("year"),
118                 /* month= */ date.getInt("month"),
119                 /* dayOfMonth= */ date.getInt("day"),
120                 /* hour= */ timeOfDay.getInt("hours"),
121                 /* minute= */ timeOfDay.getInt("minutes"),
122                 /* second= */ timeOfDay.getInt("seconds"),
123                 /* nanoOfSecond= */ timeOfDay.getInt("nanos")
124             )
125         }
126 
LocalDateTimenull127         private fun LocalDateTime.toLegacyAppFunctionData() =
128             AppFunctionData.Builder(qualifiedName = "")
129                 // Use default time zone on device since in new schema we don't support specifying
130                 // time zone.
131                 .setString("timeZone", ZoneId.systemDefault().toString())
132                 .setAppFunctionData(
133                     "date",
134                     AppFunctionData.Builder(qualifiedName = "")
135                         .setInt("year", year)
136                         .setInt("month", monthValue)
137                         .setInt("day", dayOfMonth)
138                         .build()
139                 )
140                 .setAppFunctionData(
141                     "timeOfDay",
142                     AppFunctionData.Builder(qualifiedName = "")
143                         .setInt("hours", hour)
144                         .setInt("minutes", minute)
145                         .setInt("seconds", second)
146                         .setInt("nanos", nano)
147                         .build()
148                 )
149                 .build()
150     }
151 }
152 
153 @AppFunctionSerializable
154 internal data class FindNotesAppFunctionParams(
155     override val query: String? = null,
156     override val modifiedAfter: LocalDateTime? = null,
157     override val modifiedBefore: LocalDateTime? = null
158 ) : FindNotesAppFunction.Parameters
159 
160 @AppFunctionSerializable
161 internal data class FindNotesAppFunctionResponse(
162     override val notes: List<AppFunctionNoteImpl> = emptyList()
163 ) : FindNotesAppFunction.Response
164