1 /*
2  * Copyright (C) 2022 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.safetycenter.internaldata;
18 
19 import static android.os.Build.VERSION_CODES.TIRAMISU;
20 
21 import android.util.Base64;
22 
23 import androidx.annotation.RequiresApi;
24 
25 import com.google.protobuf.InvalidProtocolBufferException;
26 import com.google.protobuf.MessageLite;
27 import com.google.protobuf.Parser;
28 
29 /** A class to facilitate working with Safety Center IDs. */
30 @RequiresApi(TIRAMISU)
31 public final class SafetyCenterIds {
32 
33     private static final int ENCODING_FLAGS = Base64.NO_WRAP | Base64.URL_SAFE;
34 
SafetyCenterIds()35     private SafetyCenterIds() {}
36 
37     /**
38      * Converts a String to a {@link SafetyCenterEntryId}.
39      *
40      * <p>Throws an {@link IllegalArgumentException} if the String couldn't be converted to a {@link
41      * SafetyCenterEntryId}.
42      */
entryIdFromString(String encoded)43     public static SafetyCenterEntryId entryIdFromString(String encoded) {
44         return decodeToProto(SafetyCenterEntryId.parser(), encoded);
45     }
46 
47     /**
48      * Converts a String to a {@link SafetyCenterIssueId}.
49      *
50      * <p>Throws an {@link IllegalArgumentException} if the String couldn't be converted to a {@link
51      * SafetyCenterIssueId}.
52      */
issueIdFromString(String encoded)53     public static SafetyCenterIssueId issueIdFromString(String encoded) {
54         return decodeToProto(SafetyCenterIssueId.parser(), encoded);
55     }
56 
57     /**
58      * Converts a String to a {@link SafetyCenterIssueKey}.
59      *
60      * <p>Throws an {@link IllegalArgumentException} if the String couldn't be converted to a {@link
61      * SafetyCenterIssueKey}.
62      */
issueKeyFromString(String encoded)63     public static SafetyCenterIssueKey issueKeyFromString(String encoded) {
64         return decodeToProto(SafetyCenterIssueKey.parser(), encoded);
65     }
66 
67     /**
68      * Converts a String to a {@link SafetyCenterIssueActionId}.
69      *
70      * <p>Throws an {@link IllegalArgumentException} if the String couldn't be converted to a {@link
71      * SafetyCenterIssueActionId}.
72      */
issueActionIdFromString(String encoded)73     public static SafetyCenterIssueActionId issueActionIdFromString(String encoded) {
74         return decodeToProto(SafetyCenterIssueActionId.parser(), encoded);
75     }
76 
77     /** Encodes a Safety Center id to a String. */
encodeToString(MessageLite message)78     public static String encodeToString(MessageLite message) {
79         return Base64.encodeToString(message.toByteArray(), ENCODING_FLAGS);
80     }
81 
82     /**
83      * Converts a {@link SafetyCenterIssueKey} to a readable string.
84      *
85      * <p>This is necessary as the implementation of {@link #toString()} for Java lite protos is
86      * optimized in production builds and does not return a user-readable output.
87      */
toUserFriendlyString(SafetyCenterIssueKey safetyCenterIssueKey)88     public static String toUserFriendlyString(SafetyCenterIssueKey safetyCenterIssueKey) {
89         return "SafetyCenterIssueKey{safetySourceId='"
90                 + safetyCenterIssueKey.getSafetySourceId()
91                 + "', safetySourceIssueId='"
92                 + safetyCenterIssueKey.getSafetySourceIssueId()
93                 + "', userId="
94                 + safetyCenterIssueKey.getUserId()
95                 + "}";
96     }
97 
98     /**
99      * Converts a {@link SafetyCenterIssueId} to a readable string.
100      *
101      * <p>This is necessary as the implementation of {@link #toString()} for Java lite protos is
102      * optimized in production builds and does not return a user-readable output.
103      */
toUserFriendlyString(SafetyCenterIssueId safetyCenterIssueId)104     public static String toUserFriendlyString(SafetyCenterIssueId safetyCenterIssueId) {
105         return "SafetyCenterIssueId{safetyCenterIssueKey="
106                 + toUserFriendlyString(safetyCenterIssueId.getSafetyCenterIssueKey())
107                 + ", issueTypeId='"
108                 + safetyCenterIssueId.getIssueTypeId()
109                 + "', taskId="
110                 + safetyCenterIssueId.getTaskId()
111                 + "}";
112     }
113 
114     /**
115      * Converts a {@link SafetyCenterIssueActionId} to a readable string.
116      *
117      * <p>This is necessary as the implementation of {@link #toString()} for Java lite protos is
118      * optimized in production builds and does not return a user-readable output.
119      */
toUserFriendlyString(SafetyCenterIssueActionId safetyCenterIssueActionId)120     public static String toUserFriendlyString(SafetyCenterIssueActionId safetyCenterIssueActionId) {
121         return "SafetyCenterIssueActionId{safetyCenterIssueKey="
122                 + toUserFriendlyString(safetyCenterIssueActionId.getSafetyCenterIssueKey())
123                 + ", safetySourceIssueActionId='"
124                 + safetyCenterIssueActionId.getSafetySourceIssueActionId()
125                 + "'}";
126     }
127 
decodeToProto(Parser<T> parser, String encoded)128     private static <T extends MessageLite> T decodeToProto(Parser<T> parser, String encoded) {
129         try {
130             return parser.parseFrom(Base64.decode(encoded, ENCODING_FLAGS));
131         } catch (InvalidProtocolBufferException e) {
132             throw new IllegalArgumentException(
133                     "Invalid ID: "
134                             + encoded
135                             + " couldn't be parsed with "
136                             + parser.getClass().getSimpleName());
137         }
138     }
139 }
140