1 /* 2 * Copyright (C) 2014 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; 18 19 import static android.content.pm.PackageManager.GET_ACTIVITIES; 20 import static android.content.pm.PackageManager.GET_META_DATA; 21 import static android.content.pm.PackageManager.GET_RESOLVED_FILTER; 22 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; 23 24 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; 25 26 import android.content.BroadcastReceiver; 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.pm.PackageManager; 31 import android.content.pm.ResolveInfo; 32 import android.content.pm.ShortcutInfo; 33 import android.content.pm.ShortcutManager; 34 import android.content.pm.UserInfo; 35 import android.os.UserHandle; 36 import android.os.UserManager; 37 import android.util.Log; 38 39 import androidx.annotation.VisibleForTesting; 40 41 import com.android.settings.activityembedding.ActivityEmbeddingUtils; 42 import com.android.settings.homepage.DeepLinkHomepageActivity; 43 import com.android.settings.search.SearchStateReceiver; 44 import com.android.settingslib.utils.ThreadUtils; 45 46 import java.util.ArrayList; 47 import java.util.List; 48 49 /** 50 * Listens to {@link Intent.ACTION_PRE_BOOT_COMPLETED} and {@link Intent.ACTION_USER_INITIALIZE} 51 * performs setup steps for a managed profile (disables the launcher icon of the Settings app, 52 * adds cross-profile intent filters for the appropriate Settings activities), disables the 53 * webview setting for non-admin users, updates the intent flags for any existing shortcuts and 54 * enables DeepLinkHomepageActivity for large screen devices. 55 */ 56 public class SettingsInitialize extends BroadcastReceiver { 57 private static final String TAG = "Settings"; 58 private static final String PRIMARY_PROFILE_SETTING = 59 "com.android.settings.PRIMARY_PROFILE_CONTROLLED"; 60 private static final String WEBVIEW_IMPLEMENTATION_ACTIVITY = ".WebViewImplementation"; 61 62 @Override onReceive(Context context, Intent broadcast)63 public void onReceive(Context context, Intent broadcast) { 64 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 65 UserInfo userInfo = um.getUserInfo(UserHandle.myUserId()); 66 final PackageManager pm = context.getPackageManager(); 67 managedProfileSetup(context, pm, broadcast, userInfo); 68 cloneProfileSetup(context, pm, userInfo); 69 webviewSettingSetup(context, pm, userInfo); 70 ThreadUtils.postOnBackgroundThread(() -> refreshExistingShortcuts(context)); 71 enableTwoPaneDeepLinkActivityIfNecessary(pm, context); 72 } 73 managedProfileSetup(Context context, final PackageManager pm, Intent broadcast, UserInfo userInfo)74 private void managedProfileSetup(Context context, final PackageManager pm, Intent broadcast, 75 UserInfo userInfo) { 76 if (userInfo == null || !userInfo.isManagedProfile()) { 77 return; 78 } 79 Log.i(TAG, "Received broadcast: " + broadcast.getAction() 80 + ". Setting up intent forwarding for managed profile."); 81 // Clear any previous intent forwarding we set up 82 pm.clearCrossProfileIntentFilters(userInfo.id); 83 84 // Set up intent forwarding for implicit intents 85 Intent intent = new Intent(); 86 intent.addCategory(Intent.CATEGORY_DEFAULT); 87 intent.setPackage(context.getPackageName()); 88 89 // Resolves activities for the managed profile (which we're running as) 90 List<ResolveInfo> resolvedIntents = pm.queryIntentActivities(intent, 91 GET_ACTIVITIES | GET_META_DATA | GET_RESOLVED_FILTER | MATCH_DISABLED_COMPONENTS); 92 final int count = resolvedIntents.size(); 93 for (int i = 0; i < count; i++) { 94 ResolveInfo info = resolvedIntents.get(i); 95 if (info.filter != null && info.activityInfo != null 96 && info.activityInfo.metaData != null) { 97 boolean shouldForward = info.activityInfo.metaData.getBoolean( 98 PRIMARY_PROFILE_SETTING); 99 if (shouldForward) { 100 pm.addCrossProfileIntentFilter(info.filter, userInfo.id, 101 userInfo.profileGroupId, PackageManager.SKIP_CURRENT_PROFILE); 102 } 103 } 104 } 105 106 Utils.disableComponentsToHideSettings(context, pm); 107 } 108 cloneProfileSetup(Context context, PackageManager pm, UserInfo userInfo)109 private void cloneProfileSetup(Context context, PackageManager pm, UserInfo userInfo) { 110 if (userInfo == null || !userInfo.isCloneProfile()) { 111 return; 112 } 113 114 Utils.disableComponentsToHideSettings(context, pm); 115 } 116 117 // Disable WebView Setting if the current user is not an admin webviewSettingSetup(Context context, PackageManager pm, UserInfo userInfo)118 private void webviewSettingSetup(Context context, PackageManager pm, UserInfo userInfo) { 119 if (userInfo == null) { 120 return; 121 } 122 ComponentName settingsComponentName = 123 new ComponentName(SETTINGS_PACKAGE_NAME, 124 SETTINGS_PACKAGE_NAME + WEBVIEW_IMPLEMENTATION_ACTIVITY); 125 pm.setComponentEnabledSetting(settingsComponentName, 126 userInfo.isAdmin() ? 127 PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 128 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 129 PackageManager.DONT_KILL_APP); 130 } 131 132 // Refresh settings shortcuts to have correct intent flags 133 @VisibleForTesting refreshExistingShortcuts(Context context)134 void refreshExistingShortcuts(Context context) { 135 final ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class); 136 final List<ShortcutInfo> pinnedShortcuts = shortcutManager.getPinnedShortcuts(); 137 final List<ShortcutInfo> updates = new ArrayList<>(); 138 for (ShortcutInfo info : pinnedShortcuts) { 139 if (info.isImmutable()) { 140 continue; 141 } 142 final Intent shortcutIntent = info.getIntent(); 143 shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 144 final ShortcutInfo updatedInfo = new ShortcutInfo.Builder(context, info.getId()) 145 .setIntent(shortcutIntent) 146 .build(); 147 updates.add(updatedInfo); 148 } 149 shortcutManager.updateShortcuts(updates); 150 } 151 enableTwoPaneDeepLinkActivityIfNecessary(PackageManager pm, Context context)152 private void enableTwoPaneDeepLinkActivityIfNecessary(PackageManager pm, Context context) { 153 final ComponentName deepLinkHome = new ComponentName(context, 154 DeepLinkHomepageActivity.class); 155 final ComponentName searchStateReceiver = new ComponentName(context, 156 SearchStateReceiver.class); 157 final int enableState = ActivityEmbeddingUtils.isSettingsSplitEnabled(context) 158 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED 159 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 160 pm.setComponentEnabledSetting(deepLinkHome, enableState, PackageManager.DONT_KILL_APP); 161 pm.setComponentEnabledSetting(searchStateReceiver, enableState, 162 PackageManager.DONT_KILL_APP); 163 } 164 } 165