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.settings.activityembedding 18 19 import android.app.Activity 20 import android.content.ActivityNotFoundException 21 import android.content.Context 22 import android.content.Intent 23 import android.content.pm.UserInfo 24 import android.provider.Settings 25 import android.util.Log 26 import com.android.settings.SettingsActivity 27 import com.android.settings.Utils 28 import com.android.settings.homepage.DeepLinkHomepageActivityInternal 29 import com.android.settings.homepage.SettingsHomepageActivity 30 import com.android.settings.password.PasswordUtils 31 import com.android.settingslib.spaprivileged.framework.common.userManager 32 33 object EmbeddedDeepLinkUtils { 34 private const val TAG = "EmbeddedDeepLinkUtils" 35 36 @JvmStatic tryStartMultiPaneDeepLinknull37 fun Activity.tryStartMultiPaneDeepLink( 38 intent: Intent, 39 highlightMenuKey: String? = null, 40 ): Boolean { 41 intent.putExtra( 42 SettingsActivity.EXTRA_INITIAL_CALLING_PACKAGE, 43 PasswordUtils.getCallingAppPackageName(activityToken), 44 ) 45 val trampolineIntent: Intent 46 if (intent.getBooleanExtra(SettingsActivity.EXTRA_IS_FROM_SLICE, false)) { 47 // Get menu key for slice deep link case. 48 var sliceHighlightMenuKey: String? = intent.getStringExtra( 49 Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY 50 ) 51 if (sliceHighlightMenuKey.isNullOrEmpty()) { 52 sliceHighlightMenuKey = highlightMenuKey 53 } 54 trampolineIntent = getTrampolineIntent(intent, sliceHighlightMenuKey) 55 trampolineIntent.setClass(this, DeepLinkHomepageActivityInternal::class.java) 56 } else { 57 trampolineIntent = getTrampolineIntent(intent, highlightMenuKey) 58 } 59 return startTrampolineIntent(trampolineIntent) 60 } 61 62 /** 63 * Returns the deep link trampoline intent for large screen devices. 64 */ 65 @JvmStatic getTrampolineIntentnull66 fun getTrampolineIntent(intent: Intent, highlightMenuKey: String?): Intent { 67 val detailIntent = Intent(intent) 68 // Guard against the arbitrary Intent injection. 69 if (detailIntent.selector != null) { 70 detailIntent.setSelector(null) 71 } 72 // It's a deep link intent, SettingsHomepageActivity will set SplitPairRule and start it. 73 return Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY).apply { 74 setPackage(Utils.SETTINGS_PACKAGE_NAME) 75 replaceExtras(detailIntent) 76 77 // Relay detail intent data to prevent failure of Intent#ParseUri. 78 // If Intent#getData() is not null, Intent#toUri will return an Uri which has the scheme 79 // of Intent#getData() and it may not be the scheme of an Intent. 80 putExtra( 81 SettingsHomepageActivity.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA, 82 detailIntent.data 83 ) 84 detailIntent.setData(null) 85 putExtra( 86 Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI, 87 detailIntent.toUri(Intent.URI_INTENT_SCHEME) 88 ) 89 putExtra( 90 Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, 91 highlightMenuKey 92 ) 93 addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) 94 } 95 } 96 97 98 /** 99 * Returns whether the user is a sub profile. 100 */ 101 @JvmStatic isSubProfilenull102 fun isSubProfile(userInfo: UserInfo): Boolean = 103 userInfo.isManagedProfile || userInfo.isPrivateProfile 104 105 private fun Context.startTrampolineIntent(trampolineIntent: Intent): Boolean = try { 106 val userInfo = userManager.getUserInfo(user.identifier) 107 if (isSubProfile(userInfo)) { 108 trampolineIntent.setClass(this, DeepLinkHomepageActivityInternal::class.java) 109 .putExtra(SettingsActivity.EXTRA_USER_HANDLE, user) 110 startActivityAsUser( 111 trampolineIntent, 112 userManager.getProfileParent(userInfo.id).userHandle 113 ) 114 } else { 115 startActivity(trampolineIntent) 116 } 117 true 118 } catch (e: ActivityNotFoundException) { 119 Log.e(TAG, "Deep link homepage is not available to show 2-pane UI") 120 false 121 } 122 } 123