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 17 package com.android.devicelockcontroller.storage; 18 19 import static com.android.devicelockcontroller.storage.ISetupParametersService.Stub.asInterface; 20 21 import android.annotation.SuppressLint; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.os.Bundle; 25 26 import androidx.annotation.GuardedBy; 27 import androidx.annotation.NonNull; 28 import androidx.annotation.Nullable; 29 import androidx.annotation.VisibleForTesting; 30 31 import com.android.devicelockcontroller.DeviceLockControllerApplication; 32 import com.android.devicelockcontroller.common.DeviceLockConstants.ProvisioningType; 33 34 import com.google.common.util.concurrent.ListenableFuture; 35 import com.google.common.util.concurrent.ListeningExecutorService; 36 import com.google.common.util.concurrent.MoreExecutors; 37 38 import java.util.List; 39 import java.util.concurrent.Executors; 40 41 /** 42 * Class used to access Setup Parameters from any users. 43 * Storage is hosted by user 0 and is accessed indirectly using a service. 44 */ 45 public final class SetupParametersClient extends DlcClient 46 implements SetupParametersClientInterface { 47 private static final Object sInstanceLock = new Object(); 48 49 @SuppressLint("StaticFieldLeak") // Only holds application context. 50 @GuardedBy("sInstanceLock") 51 private static SetupParametersClient sClient; 52 SetupParametersClient(@onNull Context context, ListeningExecutorService executorService)53 private SetupParametersClient(@NonNull Context context, 54 ListeningExecutorService executorService) { 55 super(context, new ComponentName(context, SetupParametersService.class), executorService); 56 } 57 58 /** 59 * Get the SetupParametersClient singleton instance. 60 */ getInstance()61 public static SetupParametersClient getInstance() { 62 return getInstance(DeviceLockControllerApplication.getAppContext(), 63 /* executorService= */ null); 64 } 65 66 /** 67 * Get the SetupParametersClient singleton instance. 68 */ 69 @VisibleForTesting getInstance(Context appContext, @Nullable ListeningExecutorService executorService)70 public static SetupParametersClient getInstance(Context appContext, 71 @Nullable ListeningExecutorService executorService) { 72 synchronized (sInstanceLock) { 73 if (sClient == null) { 74 sClient = new SetupParametersClient( 75 appContext, 76 executorService == null 77 ? MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()) 78 : executorService); 79 } 80 return sClient; 81 } 82 } 83 84 /** 85 * Reset the Client singleton instance 86 */ 87 @VisibleForTesting reset()88 public static void reset() { 89 synchronized (sInstanceLock) { 90 if (sClient != null) { 91 sClient.tearDown(); 92 sClient = null; 93 } 94 } 95 } 96 97 /** 98 * Override setup parameters if there exists any; otherwise create new parameters. 99 * Note that this API can only be called in debuggable build for debugging purpose. 100 */ 101 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). overridePrefs(Bundle bundle)102 public ListenableFuture<Void> overridePrefs(Bundle bundle) { 103 return call(() -> { 104 asInterface(getService()).overridePrefs(bundle); 105 return null; 106 }); 107 } 108 109 /** 110 * Dump current values of SetupParameters to logcat. 111 * Note that this API can only be called in debuggable build for debugging purpose. 112 */ 113 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). dump()114 public ListenableFuture<Void> dump() { 115 return call(() -> { 116 asInterface(getService()).dump(); 117 return null; 118 }); 119 } 120 121 /** 122 * Clear any existing setup parameters. 123 * Note that this API can only be called in debuggable build for debugging purpose. 124 */ 125 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 126 public ListenableFuture<Void> clear() { 127 return call(() -> { 128 asInterface(getService()).clear(); 129 return null; 130 }); 131 } 132 133 /** 134 * Parse setup parameters from the extras bundle. 135 * 136 * @param bundle Bundle with provisioning parameters. 137 */ 138 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 139 public ListenableFuture<Void> createPrefs(Bundle bundle) { 140 return call(() -> { 141 asInterface(getService()).createPrefs(bundle); 142 return null; 143 }); 144 } 145 146 /** 147 * Get the name of the package implementing the kiosk app. 148 * 149 * @return kiosk app package name. 150 */ 151 @Override 152 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 153 public ListenableFuture<String> getKioskPackage() { 154 return call(() -> asInterface(getService()).getKioskPackage()); 155 } 156 157 /** 158 * Check if the configuration disables outgoing calls. 159 * 160 * @return True if outgoign calls are disabled. 161 */ 162 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 163 public ListenableFuture<Boolean> getOutgoingCallsDisabled() { 164 return call(() -> asInterface(getService()).getOutgoingCallsDisabled()); 165 } 166 167 /** 168 * Get package allowlist provisioned by the server. 169 * 170 * @return List of allowed packages. 171 */ 172 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 173 public ListenableFuture<List<String>> getKioskAllowlist() { 174 return call(() -> asInterface(getService()).getKioskAllowlist()); 175 } 176 177 /** 178 * Check if notifications are enabled in lock task mode. 179 * 180 * @return True if notification are enabled. 181 */ 182 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 183 public ListenableFuture<Boolean> isNotificationsInLockTaskModeEnabled() { 184 return call(() -> asInterface(getService()).isNotificationsInLockTaskModeEnabled()); 185 } 186 187 /** 188 * Check if adb debugging is allowed even on prod devices. 189 * 190 * @return True if adb debugging is allowed 191 */ 192 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 193 public ListenableFuture<Boolean> isDebuggingAllowed() { 194 return call(() -> asInterface(getService()).isDebuggingAllowed()); 195 } 196 197 /** 198 * Get the provisioning type of this configuration. 199 * 200 * @return The type of provisioning which could be one of {@link ProvisioningType}. 201 */ 202 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 203 public ListenableFuture<@ProvisioningType Integer> getProvisioningType() { 204 return call(() -> asInterface(getService()).getProvisioningType()); 205 } 206 207 /** 208 * Check if provision is mandatory. 209 * 210 * @return True if the provision should be mandatory. 211 */ 212 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 213 public ListenableFuture<Boolean> isProvisionMandatory() { 214 return call(() -> asInterface(getService()).isProvisionMandatory()); 215 } 216 217 /** 218 * Get the name of the provider of the kiosk app. 219 * 220 * @return the name of the provider. 221 */ 222 @Nullable 223 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 224 public ListenableFuture<String> getKioskAppProviderName() { 225 return call(() -> asInterface(getService()).getKioskAppProviderName()); 226 } 227 228 /** 229 * Check if installing from unknown sources should be disallowed on this device after 230 * provision 231 * 232 * @return True if installing from unknown sources is disallowed. 233 */ 234 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 235 public ListenableFuture<Boolean> isInstallingFromUnknownSourcesDisallowed() { 236 return call(() -> asInterface(getService()).isInstallingFromUnknownSourcesDisallowed()); 237 } 238 239 /** 240 * Get the Terms and Conditions URL of the partner for enrolling in a Device Lock program. 241 * 242 * @return The URL to the terms and conditions. 243 */ 244 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 245 public ListenableFuture<String> getTermsAndConditionsUrl() { 246 return call(() -> asInterface(getService()).getTermsAndConditionsUrl()); 247 } 248 249 /** 250 * The URL to the support page the user can use to get help. 251 * 252 * @return The URL to the support page. 253 */ 254 @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone). 255 public ListenableFuture<String> getSupportUrl() { 256 return call(() -> asInterface(getService()).getSupportUrl()); 257 } 258 } 259