• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 com.android.car.tos
18 
19 import android.car.settings.CarSettings.Secure.KEY_UNACCEPTED_TOS_DISABLED_APPS
20 import android.car.settings.CarSettings.Secure.KEY_USER_TOS_ACCEPTED
21 import android.content.Context
22 import android.content.Intent
23 import android.os.UserHandle
24 import android.provider.Settings
25 import android.util.Log
26 import java.net.URISyntaxException
27 import java.util.Objects
28 
29 /** Helper methods for terms of services (tos) restrictions **/
30 object TosHelper {
31     private const val TAG = "TosHelper"
32 
33     // This value indicates if TOS is in uninitialized state
34     const val TOS_UNINITIALIZED = "0"
35 
36     // This value indicates if TOS has not been accepted by the user
37     const val TOS_NOT_ACCEPTED = "1"
38 
39     // This value indicates if TOS has been accepted by the user
40     const val TOS_ACCEPTED = "2"
41     private const val TOS_DISABLED_APPS_SEPARATOR = ","
42 
43     /**
44      * Returns a set of packages that are disabled when terms of services are not accepted.
45      *
46      * @param context The application context
47      * @param uid A user id for a particular user
48      *
49      * @return Set of packages disabled by tos
50      */
51     @JvmStatic
52     @JvmOverloads
getTosDisabledPackagesnull53     fun getTosDisabledPackages(context: Context, uid: Int = UserHandle.myUserId()): Set<String> {
54         val settingsValue = Settings.Secure.getStringForUser(
55             context.contentResolver,
56             KEY_UNACCEPTED_TOS_DISABLED_APPS,
57             uid
58         )
59         return settingsValue?.split(TOS_DISABLED_APPS_SEPARATOR)?.toSet() ?: emptySet()
60     }
61 
62     /**
63      * Gets the intent for launching the terms of service acceptance flow.
64      *
65      * @param context The app context
66      * @param id The desired resource identifier
67      *
68      * @return TOS intent, or null
69      */
70     @JvmStatic
getIntentForTosAcceptanceFlownull71     fun getIntentForTosAcceptanceFlow(context: Context, id: Int): Intent? {
72         val tosIntentName = context.resources.getString(id)
73         return try {
74             Intent.parseUri(tosIntentName, Intent.URI_ANDROID_APP_SCHEME)
75         } catch (e: URISyntaxException) {
76             Log.e(TAG, "Invalid intent URI in user_tos_activity_intent", e)
77             null
78         }
79     }
80 
81     /**
82      * Replaces the [mapIntent] with an intent defined in the resources with [id] if terms of
83      * services have not been accepted and the app defined by [mapIntent] is disabled.
84      */
85     @JvmStatic
86     @JvmOverloads
maybeReplaceWithTosMapIntentnull87     fun maybeReplaceWithTosMapIntent(
88          context: Context,
89          mapIntent: Intent,
90          id: Int,
91          uid: Int = UserHandle.myUserId()
92      ): Intent {
93          val packageName = mapIntent.component?.packageName
94          val tosDisabledPackages = getTosDisabledPackages(context, uid)
95 
96         Log.i(TAG, "TOS disabled packages:$tosDisabledPackages")
97         Log.i(TAG, "TOS accepted:" + tosAccepted(context))
98 
99         // Launch tos map intent when the user has not accepted tos and when the
100         // default maps package is not available to package manager, or it's disabled by tos
101         if (!tosAccepted(context) &&
102             (packageName == null || tosDisabledPackages.contains(packageName))
103         ) {
104             Log.i(TAG, "Replacing default maps intent with tos map intent")
105             return getIntentForTosAcceptanceFlow(context, id) ?: mapIntent
106         }
107         return mapIntent
108     }
109 
110     /**
111      * Returns true if tos is accepted or uninitialized, false otherwise.
112      */
113     @JvmStatic
114     @JvmOverloads
tosAcceptednull115     fun tosAccepted(context: Context, uid: Int = UserHandle.myUserId()): Boolean {
116         val settingsValue = Settings.Secure.getStringForUser(
117             context.contentResolver,
118             KEY_USER_TOS_ACCEPTED,
119             uid
120         )
121         // We consider an uninitialized state to be TOS accepted.
122         return Objects.equals(settingsValue, TOS_ACCEPTED) || tosStatusUninitialized(context, uid)
123     }
124 
125     /**
126      * Returns true if tos is uninitialized, false otherwise.
127      */
128     @JvmStatic
129     @JvmOverloads
tosStatusUninitializednull130     fun tosStatusUninitialized(context: Context, uid: Int = UserHandle.myUserId()): Boolean {
131         val settingsValue = Settings.Secure.getStringForUser(
132             context.contentResolver,
133             KEY_USER_TOS_ACCEPTED,
134             uid
135         )
136         return settingsValue == null || Objects.equals(settingsValue, TOS_UNINITIALIZED)
137     }
138 }
139