1 /* 2 * Copyright 2016, 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.managedprovisioning.parser; 18 19 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE; 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE; 22 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE; 23 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE; 24 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 25 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; 26 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE; 27 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM; 28 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER; 29 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION; 30 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; 31 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM; 32 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMERS; 33 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMER_CONTENT; 34 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DISCLAIMER_HEADER; 35 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION; 36 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED; 37 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE; 38 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME; 39 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOGO_URI; 40 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ORGANIZATION_NAME; 41 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE; 42 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT; 43 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS; 44 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION; 45 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SUPPORTED_MODES; 46 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SUPPORT_URL; 47 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE; 48 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_USE_MOBILE_DATA; 49 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY; 50 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE; 51 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_DOMAIN; 52 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_EAP_METHOD; 53 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_HIDDEN; 54 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_IDENTITY; 55 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PAC_URL; 56 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD; 57 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PHASE2_AUTH; 58 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_BYPASS; 59 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_HOST; 60 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_PORT; 61 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE; 62 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID; 63 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE; 64 import static android.app.admin.DevicePolicyManager.FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED; 65 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_CLOUD_ENROLLMENT; 66 import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_QR_CODE; 67 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED; 68 69 import static com.android.internal.util.Preconditions.checkNotNull; 70 import static com.android.managedprovisioning.common.Globals.ACTION_PROVISION_MANAGED_DEVICE_SILENTLY; 71 import static com.android.managedprovisioning.common.Globals.ACTION_RESUME_PROVISIONING; 72 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS; 73 import static com.android.managedprovisioning.model.ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_USE_MOBILE_DATA; 74 75 import android.app.admin.DevicePolicyManager; 76 import android.content.ComponentName; 77 import android.content.Context; 78 import android.content.Intent; 79 import android.net.Uri; 80 import android.os.Bundle; 81 import android.os.Parcelable; 82 import android.os.UserHandle; 83 84 import androidx.annotation.Nullable; 85 import androidx.annotation.VisibleForTesting; 86 87 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 88 import com.android.managedprovisioning.common.LogoUtils; 89 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences; 90 import com.android.managedprovisioning.common.ProvisionLogger; 91 import com.android.managedprovisioning.common.SettingsFacade; 92 import com.android.managedprovisioning.common.StoreUtils; 93 import com.android.managedprovisioning.common.Utils; 94 import com.android.managedprovisioning.model.DisclaimersParam; 95 import com.android.managedprovisioning.model.PackageDownloadInfo; 96 import com.android.managedprovisioning.model.ProvisioningParams; 97 import com.android.managedprovisioning.model.WifiInfo; 98 99 import java.util.Arrays; 100 import java.util.HashMap; 101 import java.util.HashSet; 102 import java.util.IllformedLocaleException; 103 import java.util.Map; 104 import java.util.Set; 105 106 /** 107 * A parser which parses provisioning data from intent which stores in {@link Bundle} extras. 108 */ 109 110 @VisibleForTesting 111 public class ExtrasProvisioningDataParser implements ProvisioningDataParser { 112 private static final Set<String> PROVISIONING_ACTIONS_SUPPORT_ALL_PROVISIONING_DATA = 113 new HashSet<>(Arrays.asList( 114 ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE, 115 ACTION_PROVISION_FINANCED_DEVICE)); 116 117 private static final Set<String> PROVISIONING_ACTIONS_SUPPORT_MIN_PROVISIONING_DATA = 118 new HashSet<>(Arrays.asList( 119 ACTION_PROVISION_MANAGED_DEVICE, 120 ACTION_PROVISION_MANAGED_PROFILE, 121 ACTION_PROVISION_MANAGED_DEVICE_SILENTLY)); 122 123 @VisibleForTesting 124 static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE_SHORT = "a.a.e.PAEB"; 125 126 @VisibleForTesting 127 static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME_SHORT = "a.a.e.PDAPN"; 128 129 @VisibleForTesting 130 static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME_SHORT = "a.a.e.PDACN"; 131 132 @VisibleForTesting 133 static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE_SHORT = "a.a.e.PATM"; 134 135 @VisibleForTesting 136 static final String EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION_SHORT = "a.a.e.PKAOM"; 137 138 @VisibleForTesting 139 static final String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED_SHORT = "a.a.e.PLASAE"; 140 141 @VisibleForTesting 142 static final String EXTRA_PROVISIONING_TIME_ZONE_SHORT = "a.a.e.PTZ"; 143 144 @VisibleForTesting 145 static final String EXTRA_PROVISIONING_LOCAL_TIME_SHORT = "a.a.e.PLT"; 146 147 @VisibleForTesting 148 static final String EXTRA_PROVISIONING_LOCALE_SHORT = "a.a.e.PL"; 149 150 @VisibleForTesting 151 static final String EXTRA_PROVISIONING_WIFI_SSID_SHORT = "a.a.e.PWS"; 152 153 @VisibleForTesting 154 static final String EXTRA_PROVISIONING_WIFI_HIDDEN_SHORT = "a.a.e.PWH"; 155 156 @VisibleForTesting 157 static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE_SHORT = "a.a.e.PWST"; 158 159 @VisibleForTesting 160 static final String EXTRA_PROVISIONING_WIFI_PASSWORD_SHORT = "a.a.e.PWP"; 161 162 @VisibleForTesting 163 static final String EXTRA_PROVISIONING_WIFI_EAP_METHOD_SHORT = "a.a.e.PWEM"; 164 165 @VisibleForTesting 166 static final String EXTRA_PROVISIONING_WIFI_PHASE2_AUTH_SHORT = "a.a.e.PWPA"; 167 168 @VisibleForTesting 169 static final String EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE_SHORT = "a.a.e.PWCC"; 170 171 @VisibleForTesting 172 static final String EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE_SHORT = "a.a.e.PWUC"; 173 174 @VisibleForTesting 175 static final String EXTRA_PROVISIONING_WIFI_IDENTITY_SHORT = "a.a.e.PWI"; 176 177 @VisibleForTesting 178 static final String EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY_SHORT = "a.a.e.PWAI"; 179 180 @VisibleForTesting 181 static final String EXTRA_PROVISIONING_WIFI_DOMAIN_SHORT = "a.a.e.PWD"; 182 183 @VisibleForTesting 184 static final String EXTRA_PROVISIONING_WIFI_PROXY_HOST_SHORT = "a.a.e.PWPH"; 185 186 @VisibleForTesting 187 static final String EXTRA_PROVISIONING_WIFI_PROXY_PORT_SHORT = "a.a.e.PWPRP"; 188 189 @VisibleForTesting 190 static final String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS_SHORT = "a.a.e.PWPB"; 191 192 @VisibleForTesting 193 static final String EXTRA_PROVISIONING_WIFI_PAC_URL_SHORT = "a.a.e.PWPU"; 194 195 @VisibleForTesting 196 static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION_SHORT = 197 "a.a.e.PDAPDL"; 198 199 @VisibleForTesting 200 static final String EXTRA_PROVISIONING_ORGANIZATION_NAME_SHORT = "a.a.e.PON"; 201 202 @VisibleForTesting 203 static final String EXTRA_PROVISIONING_SUPPORT_URL_SHORT = "a.a.e.PSU"; 204 205 @VisibleForTesting 206 static final String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE_SHORT = "a.a.e.PDAMVC"; 207 208 @VisibleForTesting 209 static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER_SHORT = 210 "a.a.e.PDAPDCH"; 211 212 @VisibleForTesting 213 static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM_SHORT = "a.a.e.PDAPC"; 214 215 @VisibleForTesting 216 static final String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM_SHORT = "a.a.e.PDASC"; 217 218 @VisibleForTesting 219 static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION_SHORT = "a.a.e.PSE"; 220 221 @VisibleForTesting 222 static final String EXTRA_PROVISIONING_LOGO_URI_SHORT = "a.a.e.PLU"; 223 224 @VisibleForTesting 225 static final String EXTRA_PROVISIONING_DISCLAIMERS_SHORT = "a.a.e.PD"; 226 227 @VisibleForTesting 228 static final String EXTRA_PROVISIONING_DISCLAIMER_HEADER_SHORT = "a.a.e.PDH"; 229 230 @VisibleForTesting 231 static final String EXTRA_PROVISIONING_DISCLAIMER_CONTENT_SHORT = "a.a.e.PDC"; 232 233 @VisibleForTesting 234 static final String EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS_SHORT = "a.a.e.PSES"; 235 236 @VisibleForTesting 237 static final String EXTRA_PROVISIONING_USE_MOBILE_DATA_SHORT = "a.a.e.PUMD"; 238 239 @VisibleForTesting 240 static final String EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT_SHORT = "a.a.e.PPSGOO"; 241 242 private static final Map<String, String> SHORTER_EXTRAS = buildShorterExtrasMap(); 243 buildShorterExtrasMap()244 private static Map<String, String> buildShorterExtrasMap() { 245 Map<String, String> shorterExtras = new HashMap<>(); 246 shorterExtras.put( 247 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, 248 EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE_SHORT); 249 shorterExtras.put( 250 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, 251 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME_SHORT); 252 shorterExtras.put( 253 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, 254 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME_SHORT); 255 shorterExtras.put( 256 EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE, EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE_SHORT); 257 shorterExtras.put( 258 EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION, 259 EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION_SHORT); 260 shorterExtras.put( 261 EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, 262 EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED_SHORT); 263 shorterExtras.put( 264 EXTRA_PROVISIONING_TIME_ZONE, EXTRA_PROVISIONING_TIME_ZONE_SHORT); 265 shorterExtras.put( 266 EXTRA_PROVISIONING_LOCAL_TIME, EXTRA_PROVISIONING_LOCAL_TIME_SHORT); 267 shorterExtras.put( 268 EXTRA_PROVISIONING_LOCALE, EXTRA_PROVISIONING_LOCALE_SHORT); 269 shorterExtras.put( 270 EXTRA_PROVISIONING_WIFI_SSID, EXTRA_PROVISIONING_WIFI_SSID_SHORT); 271 shorterExtras.put( 272 EXTRA_PROVISIONING_WIFI_HIDDEN, EXTRA_PROVISIONING_WIFI_HIDDEN_SHORT); 273 shorterExtras.put( 274 EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, EXTRA_PROVISIONING_WIFI_SECURITY_TYPE_SHORT); 275 shorterExtras.put( 276 EXTRA_PROVISIONING_WIFI_PASSWORD, EXTRA_PROVISIONING_WIFI_PASSWORD_SHORT); 277 shorterExtras.put( 278 EXTRA_PROVISIONING_WIFI_EAP_METHOD, EXTRA_PROVISIONING_WIFI_EAP_METHOD_SHORT); 279 shorterExtras.put( 280 EXTRA_PROVISIONING_WIFI_PHASE2_AUTH, EXTRA_PROVISIONING_WIFI_PHASE2_AUTH_SHORT); 281 shorterExtras.put( 282 EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE, 283 EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE_SHORT); 284 shorterExtras.put( 285 EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE, 286 EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE_SHORT); 287 shorterExtras.put( 288 EXTRA_PROVISIONING_WIFI_IDENTITY, EXTRA_PROVISIONING_WIFI_IDENTITY_SHORT); 289 shorterExtras.put( 290 EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY, 291 EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY_SHORT); 292 shorterExtras.put( 293 EXTRA_PROVISIONING_WIFI_DOMAIN, EXTRA_PROVISIONING_WIFI_DOMAIN_SHORT); 294 shorterExtras.put( 295 EXTRA_PROVISIONING_WIFI_PROXY_HOST, EXTRA_PROVISIONING_WIFI_PROXY_HOST_SHORT); 296 shorterExtras.put( 297 EXTRA_PROVISIONING_WIFI_PROXY_PORT, EXTRA_PROVISIONING_WIFI_PROXY_PORT_SHORT); 298 shorterExtras.put( 299 EXTRA_PROVISIONING_WIFI_PROXY_BYPASS, EXTRA_PROVISIONING_WIFI_PROXY_BYPASS_SHORT); 300 shorterExtras.put( 301 EXTRA_PROVISIONING_WIFI_PAC_URL, EXTRA_PROVISIONING_WIFI_PAC_URL_SHORT); 302 shorterExtras.put( 303 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, 304 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION_SHORT); 305 shorterExtras.put( 306 EXTRA_PROVISIONING_ORGANIZATION_NAME, EXTRA_PROVISIONING_ORGANIZATION_NAME_SHORT); 307 shorterExtras.put( 308 EXTRA_PROVISIONING_SUPPORT_URL, EXTRA_PROVISIONING_SUPPORT_URL_SHORT); 309 shorterExtras.put( 310 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 311 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE_SHORT); 312 shorterExtras.put( 313 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER, 314 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER_SHORT); 315 shorterExtras.put( 316 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM, 317 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM_SHORT); 318 shorterExtras.put( 319 EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM, 320 EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM_SHORT); 321 shorterExtras.put( 322 EXTRA_PROVISIONING_SKIP_ENCRYPTION, EXTRA_PROVISIONING_SKIP_ENCRYPTION_SHORT); 323 shorterExtras.put( 324 EXTRA_PROVISIONING_DISCLAIMERS, EXTRA_PROVISIONING_DISCLAIMERS_SHORT); 325 shorterExtras.put( 326 EXTRA_PROVISIONING_LOGO_URI, EXTRA_PROVISIONING_LOGO_URI_SHORT); 327 shorterExtras.put( 328 EXTRA_PROVISIONING_DISCLAIMER_HEADER, EXTRA_PROVISIONING_DISCLAIMER_HEADER_SHORT); 329 shorterExtras.put( 330 EXTRA_PROVISIONING_DISCLAIMER_CONTENT, EXTRA_PROVISIONING_DISCLAIMER_CONTENT_SHORT); 331 shorterExtras.put( 332 EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS, 333 EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS_SHORT); 334 shorterExtras.put( 335 EXTRA_PROVISIONING_USE_MOBILE_DATA, EXTRA_PROVISIONING_USE_MOBILE_DATA_SHORT); 336 shorterExtras.put(EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT, 337 EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT_SHORT); 338 return shorterExtras; 339 } 340 341 private final Utils mUtils; 342 private final ParserUtils mParserUtils; 343 private final SettingsFacade mSettingsFacade; 344 private final Context mContext; 345 private final ManagedProvisioningSharedPreferences mSharedPreferences; 346 ExtrasProvisioningDataParser(Context context, Utils utils, ParserUtils parserUtils, SettingsFacade settingsFacade)347 ExtrasProvisioningDataParser(Context context, Utils utils, ParserUtils parserUtils, 348 SettingsFacade settingsFacade) { 349 this(context, utils, parserUtils, settingsFacade, 350 new ManagedProvisioningSharedPreferences(context)); 351 } 352 353 @VisibleForTesting ExtrasProvisioningDataParser(Context context, Utils utils, ParserUtils parserUtils, SettingsFacade settingsFacade, ManagedProvisioningSharedPreferences sharedPreferences)354 ExtrasProvisioningDataParser(Context context, Utils utils, ParserUtils parserUtils, 355 SettingsFacade settingsFacade, ManagedProvisioningSharedPreferences sharedPreferences) { 356 mContext = checkNotNull(context); 357 mUtils = checkNotNull(utils); 358 mParserUtils = checkNotNull(parserUtils); 359 mSettingsFacade = checkNotNull(settingsFacade); 360 mSharedPreferences = checkNotNull(sharedPreferences); 361 } 362 363 @Override parse(Intent provisioningIntent)364 public ProvisioningParams parse(Intent provisioningIntent) 365 throws IllegalProvisioningArgumentException{ 366 String provisioningAction = provisioningIntent.getAction(); 367 if (ACTION_RESUME_PROVISIONING.equals(provisioningAction)) { 368 return getParcelableExtraFromLongName(provisioningIntent, 369 ProvisioningParams.EXTRA_PROVISIONING_PARAMS); 370 } 371 if (PROVISIONING_ACTIONS_SUPPORT_MIN_PROVISIONING_DATA.contains(provisioningAction)) { 372 ProvisionLogger.logi("Processing mininalist extras intent."); 373 return parseMinimalistSupportedProvisioningDataInternal(provisioningIntent, mContext) 374 .build(); 375 } else if (PROVISIONING_ACTIONS_SUPPORT_ALL_PROVISIONING_DATA.contains( 376 provisioningAction)) { 377 return parseAllSupportedProvisioningData(provisioningIntent, mContext); 378 } else { 379 throw new IllegalProvisioningArgumentException("Unsupported provisioning action: " 380 + provisioningAction); 381 } 382 } 383 384 /** 385 * Returns a short version of the requested extra. 386 */ getShortExtraNames(String extraName)387 static String getShortExtraNames(String extraName) { 388 return SHORTER_EXTRAS.get(extraName); 389 } 390 hasExtraFromLongName(Intent intent, String longName)391 private boolean hasExtraFromLongName(Intent intent, String longName) { 392 return intent.hasExtra(longName) || intent.hasExtra(getShortExtraNames(longName)); 393 } 394 395 @Nullable getParcelableExtraFromLongName( Intent intent, String longName)396 private <T extends Parcelable> T getParcelableExtraFromLongName( 397 Intent intent, String longName) { 398 if (intent.hasExtra(longName)) { 399 return intent.getParcelableExtra(longName); 400 } 401 String shortName = getShortExtraNames(longName); 402 if (intent.hasExtra(shortName)) { 403 return intent.getParcelableExtra(shortName); 404 } 405 return null; 406 } 407 408 @Nullable getParcelableArrayExtraFromLongName(Intent intent, String longName)409 private Parcelable[] getParcelableArrayExtraFromLongName(Intent intent, String longName) { 410 if (intent.hasExtra(longName)) { 411 return intent.getParcelableArrayExtra(longName); 412 } 413 String shortName = getShortExtraNames(longName); 414 if (intent.hasExtra(shortName)) { 415 return intent.getParcelableArrayExtra(shortName); 416 } 417 return null; 418 } 419 getIntExtraFromLongName(Intent intent, String longName, int defaultValue)420 private int getIntExtraFromLongName(Intent intent, String longName, int defaultValue) { 421 if (intent.hasExtra(longName)) { 422 return intent.getIntExtra(longName, defaultValue); 423 } 424 String shortName = getShortExtraNames(longName); 425 if (intent.hasExtra(shortName)) { 426 return intent.getIntExtra(shortName, defaultValue); 427 } 428 return defaultValue; 429 } 430 getBooleanExtraFromLongName( Intent intent, String longName, boolean defaultValue)431 private boolean getBooleanExtraFromLongName( 432 Intent intent, String longName, boolean defaultValue) { 433 if (intent.hasExtra(longName)) { 434 return intent.getBooleanExtra(longName, defaultValue); 435 } 436 String shortName = getShortExtraNames(longName); 437 if (intent.hasExtra(shortName)) { 438 return intent.getBooleanExtra(shortName, defaultValue); 439 } 440 return defaultValue; 441 } 442 getParcelableExtraFromLongName(Intent intent, String longName, long defaultValue)443 private long getParcelableExtraFromLongName(Intent intent, String longName, long defaultValue) { 444 if (intent.hasExtra(longName)) { 445 return intent.getLongExtra(longName, defaultValue); 446 } 447 String shortName = getShortExtraNames(longName); 448 if (intent.hasExtra(shortName)) { 449 return intent.getLongExtra(shortName, defaultValue); 450 } 451 return defaultValue; 452 } 453 454 @Nullable getStringExtraFromLongName(Intent intent, String longName)455 private String getStringExtraFromLongName(Intent intent, String longName) { 456 if (intent.getStringExtra(longName) != null) { 457 return intent.getStringExtra(longName); 458 } 459 String shortName = getShortExtraNames(longName); 460 if (intent.getStringExtra(shortName) != null) { 461 return intent.getStringExtra(shortName); 462 } 463 return null; 464 } 465 466 /** 467 * Parses minimal supported set of parameters from bundle extras of a provisioning intent. 468 * 469 * <p>Here is the list of supported parameters. 470 * <ul> 471 * <li>{@link EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li> 472 * <li> 473 * {@link EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME} only in 474 * {@link ACTION_PROVISION_MANAGED_PROFILE}. 475 * </li> 476 * <li>{@link EXTRA_PROVISIONING_LOGO_URI}</li> 477 * <li>{@link EXTRA_PROVISIONING_SKIP_ENCRYPTION}</li> 478 * <li>{@link EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}</li> 479 * <li>{@link EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}</li> 480 * <li>{@link EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}</li> 481 * </ul> 482 */ parseMinimalistSupportedProvisioningDataInternal( Intent intent, Context context)483 private ProvisioningParams.Builder parseMinimalistSupportedProvisioningDataInternal( 484 Intent intent, Context context) 485 throws IllegalProvisioningArgumentException { 486 final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 487 boolean isProvisionManagedDeviceFromTrustedSourceIntent = 488 ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction()); 489 boolean isFinancedDeviceProvisioning = 490 ACTION_PROVISION_FINANCED_DEVICE.equals(intent.getAction()); 491 final boolean isManagedProfileAction = 492 ACTION_PROVISION_MANAGED_PROFILE.equals(intent.getAction()); 493 try { 494 final long provisioningId = mSharedPreferences.incrementAndGetProvisioningId(); 495 String provisioningAction = mParserUtils.extractProvisioningAction( 496 intent, mSettingsFacade, mContext); 497 498 // Parse device admin package name and component name. 499 ComponentName deviceAdminComponentName = getParcelableExtraFromLongName( 500 intent, EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME); 501 // Device admin package name is deprecated. It is only supported in Profile Owner 502 // provisioning and when resuming NFC provisioning. 503 String deviceAdminPackageName = null; 504 if (isManagedProfileAction) { 505 // In L, we only support package name. This means some DPC may still send us the 506 // device admin package name only. Attempts to obtain the package name from extras. 507 deviceAdminPackageName = getStringExtraFromLongName( 508 intent, EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME); 509 // For profile owner, the device admin package should be installed. Verify the 510 // device admin package. 511 deviceAdminComponentName = mUtils.findDeviceAdmin( 512 deviceAdminPackageName, 513 deviceAdminComponentName, 514 context, 515 UserHandle.myUserId()); 516 // Since the device admin package must be installed at this point and its component 517 // name has been obtained, it should be safe to set the deprecated package name 518 // value to null. 519 deviceAdminPackageName = null; 520 } 521 522 final boolean skipEducationScreens = shouldSkipEducationScreens(intent); 523 524 // Only when provisioning PO with ACTION_PROVISION_MANAGED_PROFILE 525 final boolean keepAccountMigrated = isManagedProfileAction 526 && getBooleanExtraFromLongName( 527 intent, EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION, 528 ProvisioningParams 529 .DEFAULT_EXTRA_PROVISIONING_KEEP_ACCOUNT_MIGRATED); 530 531 // Parse organization's logo. This is not supported in managed device 532 // from trusted source provisioning because, currently, there is no way to send 533 // organization logo to the device at this stage. 534 if (!isProvisionManagedDeviceFromTrustedSourceIntent) { 535 parseOrganizationLogoUrlFromExtras(context, intent); 536 } 537 538 DisclaimersParam disclaimersParam = new DisclaimersParser(context, provisioningId) 539 .parse(getParcelableArrayExtraFromLongName( 540 intent, EXTRA_PROVISIONING_DISCLAIMERS)); 541 542 String organizationName = 543 getStringExtraFromLongName(intent, EXTRA_PROVISIONING_ORGANIZATION_NAME); 544 String supportUrl = null; 545 if (isProvisionManagedDeviceFromTrustedSourceIntent || isFinancedDeviceProvisioning) { 546 supportUrl = getStringExtraFromLongName(intent, EXTRA_PROVISIONING_SUPPORT_URL); 547 } 548 549 final boolean leaveAllSystemAppsEnabled = isManagedProfileAction 550 ? false 551 : (isFinancedDeviceProvisioning || 552 getBooleanExtraFromLongName( 553 intent, EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, 554 ProvisioningParams.DEFAULT_LEAVE_ALL_SYSTEM_APPS_ENABLED)); 555 556 int provisioningTrigger = mParserUtils.extractProvisioningTrigger(intent); 557 int initiatorRequestedProvisioningModes = 558 getInitiatorRequestedProvisioningModes(intent); 559 560 final boolean adminOptedOutOfSensorsPermissionGrants = 561 getBooleanExtraFromLongName(intent, 562 EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT, 563 ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT); 564 return ProvisioningParams.Builder.builder() 565 .setProvisioningId(provisioningId) 566 .setProvisioningAction(provisioningAction) 567 .setDeviceAdminComponentName(deviceAdminComponentName) 568 .setDeviceAdminPackageName(deviceAdminPackageName) 569 .setSkipEncryption( 570 getBooleanExtraFromLongName( 571 intent, EXTRA_PROVISIONING_SKIP_ENCRYPTION, 572 ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_ENCRYPTION)) 573 .setLeaveAllSystemAppsEnabled(leaveAllSystemAppsEnabled) 574 .setAdminExtrasBundle(getParcelableExtraFromLongName( 575 intent, EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)) 576 .setDisclaimersParam(disclaimersParam) 577 .setKeepAccountMigrated(keepAccountMigrated) 578 .setSkipEducationScreens(skipEducationScreens) 579 .setAccountToMigrate(getParcelableExtraFromLongName( 580 intent, EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE)) 581 .setOrganizationName(organizationName) 582 .setSupportUrl(supportUrl) 583 .setIsQrProvisioning(provisioningTrigger == PROVISIONING_TRIGGER_QR_CODE) 584 .setProvisioningTrigger(provisioningTrigger) 585 .setAllowedProvisioningModes(mParserUtils.getAllowedProvisioningModes( 586 mContext, initiatorRequestedProvisioningModes, mUtils)) 587 .setInitiatorRequestedProvisioningModes( 588 initiatorRequestedProvisioningModes) 589 .setSkipOwnershipDisclaimer(getSkipOwnershipDisclaimer(intent)) 590 .setReturnBeforePolicyCompliance(getReturnBeforePolicyCompliance(intent)) 591 .setDeviceOwnerPermissionGrantOptOut( 592 adminOptedOutOfSensorsPermissionGrants); 593 } catch (ClassCastException e) { 594 throw new IllegalProvisioningArgumentException("Extra has invalid type", e); 595 } catch (IllegalArgumentException e) { 596 throw new IllegalProvisioningArgumentException("Invalid parameter found!", e); 597 } catch (NullPointerException e) { 598 throw new IllegalProvisioningArgumentException("Compulsory parameter not found!", e); 599 } 600 } 601 getSkipOwnershipDisclaimer(Intent intent)602 private boolean getSkipOwnershipDisclaimer(Intent intent) { 603 if (!intent.getAction().equals(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE)) { 604 return ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER; 605 } 606 return getBooleanExtraFromLongName( 607 intent, 608 DevicePolicyManager.EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER, 609 ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SKIP_OWNERSHIP_DISCLAIMER); 610 } 611 getReturnBeforePolicyCompliance(Intent intent)612 private boolean getReturnBeforePolicyCompliance(Intent intent) { 613 if (intent.getAction().equals(ACTION_PROVISION_MANAGED_PROFILE)) { 614 // TODO(b/182462297): Default to false after in-setup wizard is no longer supported 615 return mSettingsFacade.isDuringSetupWizard(mContext); 616 } 617 // TODO(b/177849035): Remove financed device-specific logic 618 if (intent.getAction().equals(ACTION_PROVISION_FINANCED_DEVICE)) { 619 return true; 620 } 621 return getBooleanExtraFromLongName( 622 intent, 623 EXTRA_PROVISIONING_RETURN_BEFORE_POLICY_COMPLIANCE, 624 /* defaultValue */ true); 625 } 626 getInitiatorRequestedProvisioningModes(Intent intent)627 private int getInitiatorRequestedProvisioningModes(Intent intent) { 628 if (!intent.getAction().equals(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE)) { 629 return ProvisioningParams.DEFAULT_EXTRA_PROVISIONING_SUPPORTED_MODES; 630 } 631 int supportedModes = getIntExtraFromLongName(intent, 632 EXTRA_PROVISIONING_SUPPORTED_MODES, 633 FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED); 634 mParserUtils.validateSupportedModes(supportedModes); 635 return supportedModes; 636 } 637 638 /** 639 * When {@link DevicePolicyManager#EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS} is passed as 640 * a provisioning extra, we only process it for managed Google account enrollment and 641 * persistent device owner. 642 */ shouldSkipEducationScreens(Intent intent)643 private boolean shouldSkipEducationScreens(Intent intent) { 644 if (!getBooleanExtraFromLongName(intent, 645 EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS, 646 DEFAULT_EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS)) { 647 return false; 648 } 649 // TODO(b/175021111): Remove managed account provisioning-specific logic in MP for the 650 // skip education screens extra. 651 int provisioningTrigger = mParserUtils.extractProvisioningTrigger(intent); 652 if (provisioningTrigger == PROVISIONING_TRIGGER_QR_CODE 653 || provisioningTrigger == PROVISIONING_TRIGGER_CLOUD_ENROLLMENT 654 || ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { 655 return false; 656 } 657 return isFullyManagedDeviceAction(intent); 658 } 659 isFullyManagedDeviceAction(Intent intent)660 private boolean isFullyManagedDeviceAction(Intent intent) { 661 return ACTION_PROVISION_MANAGED_DEVICE.equals(intent.getAction()) 662 || ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE.equals(intent.getAction()); 663 } 664 665 /** 666 * Parses an intent and return a corresponding {@link ProvisioningParams} object. 667 * 668 * @param intent intent to be parsed. 669 * @param context a context 670 */ parseAllSupportedProvisioningData(Intent intent, Context context)671 private ProvisioningParams parseAllSupportedProvisioningData(Intent intent, Context context) 672 throws IllegalProvisioningArgumentException { 673 try { 674 ProvisionLogger.logi("Processing all supported extras intent: " + intent.getAction()); 675 return parseMinimalistSupportedProvisioningDataInternal(intent, context) 676 // Parse time zone, local time and locale. 677 .setTimeZone(getStringExtraFromLongName(intent, EXTRA_PROVISIONING_TIME_ZONE)) 678 .setLocalTime( 679 getParcelableExtraFromLongName( 680 intent, EXTRA_PROVISIONING_LOCAL_TIME, 681 ProvisioningParams.DEFAULT_LOCAL_TIME)) 682 .setLocale(StoreUtils.stringToLocale( 683 getStringExtraFromLongName(intent,EXTRA_PROVISIONING_LOCALE))) 684 .setUseMobileData( 685 getBooleanExtraFromLongName( 686 intent, EXTRA_PROVISIONING_USE_MOBILE_DATA, 687 DEFAULT_EXTRA_PROVISIONING_USE_MOBILE_DATA)) 688 // Parse WiFi configuration. 689 .setWifiInfo(parseWifiInfoFromExtras(intent)) 690 // Parse device admin package download info. 691 .setDeviceAdminDownloadInfo(parsePackageDownloadInfoFromExtras(intent)) 692 // Cases where startedByTrustedSource can be true are 693 // 1. We are reloading a stored provisioning intent, either Nfc bump or 694 // PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE, after encryption reboot, 695 // which is a self-originated intent. 696 // 2. the intent is from a trusted source, for example QR provisioning. 697 .setStartedByTrustedSource(ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE 698 .equals(intent.getAction())) 699 .build(); 700 } catch (IllegalArgumentException e) { 701 throw new IllegalProvisioningArgumentException("Invalid parameter found!", e); 702 } catch (IllformedLocaleException e) { 703 throw new IllegalProvisioningArgumentException("Invalid locale format!", e); 704 } catch (NullPointerException e) { 705 throw new IllegalProvisioningArgumentException("Compulsory parameter not found!", e); 706 } 707 } 708 709 /** 710 * Parses Wifi configuration from an Intent and returns the result in {@link WifiInfo}. 711 */ 712 @Nullable parseWifiInfoFromExtras(Intent intent)713 private WifiInfo parseWifiInfoFromExtras(Intent intent) { 714 if (getStringExtraFromLongName(intent, EXTRA_PROVISIONING_WIFI_SSID) == null) { 715 return null; 716 } 717 return WifiInfo.Builder.builder() 718 .setSsid(getStringExtraFromLongName(intent, EXTRA_PROVISIONING_WIFI_SSID)) 719 .setSecurityType( 720 getStringExtraFromLongName(intent, EXTRA_PROVISIONING_WIFI_SECURITY_TYPE)) 721 .setPassword(getStringExtraFromLongName(intent, EXTRA_PROVISIONING_WIFI_PASSWORD)) 722 .setProxyHost(getStringExtraFromLongName( 723 intent, EXTRA_PROVISIONING_WIFI_PROXY_HOST)) 724 .setProxyBypassHosts( 725 getStringExtraFromLongName(intent, EXTRA_PROVISIONING_WIFI_PROXY_BYPASS)) 726 .setPacUrl(getStringExtraFromLongName(intent, EXTRA_PROVISIONING_WIFI_PAC_URL)) 727 .setProxyPort(getIntExtraFromLongName( 728 intent, EXTRA_PROVISIONING_WIFI_PROXY_PORT, 729 WifiInfo.DEFAULT_WIFI_PROXY_PORT)) 730 .setEapMethod(getStringExtraFromLongName( 731 intent, EXTRA_PROVISIONING_WIFI_EAP_METHOD)) 732 .setPhase2Auth(getStringExtraFromLongName( 733 intent, EXTRA_PROVISIONING_WIFI_PHASE2_AUTH)) 734 .setCaCertificate(getStringExtraFromLongName( 735 intent, EXTRA_PROVISIONING_WIFI_CA_CERTIFICATE)) 736 .setUserCertificate(getStringExtraFromLongName( 737 intent, EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE)) 738 .setIdentity(getStringExtraFromLongName(intent, EXTRA_PROVISIONING_WIFI_IDENTITY)) 739 .setAnonymousIdentity(getStringExtraFromLongName( 740 intent, EXTRA_PROVISIONING_WIFI_ANONYMOUS_IDENTITY)) 741 .setDomain(getStringExtraFromLongName(intent, EXTRA_PROVISIONING_WIFI_DOMAIN)) 742 .setHidden(getBooleanExtraFromLongName( 743 intent, EXTRA_PROVISIONING_WIFI_HIDDEN, WifiInfo.DEFAULT_WIFI_HIDDEN)) 744 .build(); 745 } 746 747 /** 748 * Parses device admin package download info configuration from an Intent and returns the result 749 * in {@link PackageDownloadInfo}. 750 */ 751 @Nullable parsePackageDownloadInfoFromExtras(Intent intent)752 private PackageDownloadInfo parsePackageDownloadInfoFromExtras(Intent intent) { 753 if (getStringExtraFromLongName( 754 intent, EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION) == null) { 755 return null; 756 } 757 PackageDownloadInfo.Builder downloadInfoBuilder = PackageDownloadInfo.Builder.builder() 758 .setMinVersion(getIntExtraFromLongName( 759 intent, EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 760 PackageDownloadInfo.DEFAULT_MINIMUM_VERSION)) 761 .setLocation(getStringExtraFromLongName( 762 intent, EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION)) 763 .setCookieHeader(getStringExtraFromLongName( 764 intent, EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER)); 765 String packageHash = 766 getStringExtraFromLongName( 767 intent, EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM); 768 if (packageHash != null) { 769 downloadInfoBuilder.setPackageChecksum(StoreUtils.stringToByteArray(packageHash)); 770 } 771 String sigHash = getStringExtraFromLongName( 772 intent, EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM); 773 if (sigHash != null) { 774 downloadInfoBuilder.setSignatureChecksum(StoreUtils.stringToByteArray(sigHash)); 775 } 776 return downloadInfoBuilder.build(); 777 } 778 779 /** 780 * Parses the organization logo url from intent. 781 */ parseOrganizationLogoUrlFromExtras(Context context, Intent intent)782 private void parseOrganizationLogoUrlFromExtras(Context context, Intent intent) { 783 Uri logoUri = getParcelableExtraFromLongName(intent, EXTRA_PROVISIONING_LOGO_URI); 784 if (logoUri != null) { 785 // If we go through encryption, and if the uri is a content uri: 786 // We'll lose the grant to this uri. So we need to save it to a local file. 787 LogoUtils.saveOrganisationLogo(context, logoUri); 788 } 789 } 790 } 791