1 /* 2 * Copyright (C) 2019 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.developeroptions; 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.car.developeroptions.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.car.developeroptions.Settings.CreateShortcutActivity; 42 43 import java.util.ArrayList; 44 import java.util.List; 45 46 /** 47 * Listens to {@link Intent.ACTION_PRE_BOOT_COMPLETED} and {@link Intent.ACTION_USER_INITIALIZED} 48 * performs setup steps for a managed profile (disables the launcher icon of the Settings app, 49 * adds cross-profile intent filters for the appropriate Settings activities), disables the 50 * webview setting for non-admin users, and updates the intent flags for any existing shortcuts. 51 */ 52 public class SettingsInitialize extends BroadcastReceiver { 53 private static final String TAG = "Settings"; 54 private static final String PRIMARY_PROFILE_SETTING = 55 "com.android.car.developeroptions.PRIMARY_PROFILE_CONTROLLED"; 56 private static final String WEBVIEW_IMPLEMENTATION_ACTIVITY = ".WebViewImplementation"; 57 58 @Override onReceive(Context context, Intent broadcast)59 public void onReceive(Context context, Intent broadcast) { 60 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 61 UserInfo userInfo = um.getUserInfo(UserHandle.myUserId()); 62 final PackageManager pm = context.getPackageManager(); 63 managedProfileSetup(context, pm, broadcast, userInfo); 64 webviewSettingSetup(context, pm, userInfo); 65 refreshExistingShortcuts(context); 66 } 67 managedProfileSetup(Context context, final PackageManager pm, Intent broadcast, UserInfo userInfo)68 private void managedProfileSetup(Context context, final PackageManager pm, Intent broadcast, 69 UserInfo userInfo) { 70 if (userInfo == null || !userInfo.isManagedProfile()) { 71 return; 72 } 73 Log.i(TAG, "Received broadcast: " + broadcast.getAction() 74 + ". Setting up intent forwarding for managed profile."); 75 // Clear any previous intent forwarding we set up 76 pm.clearCrossProfileIntentFilters(userInfo.id); 77 78 // Set up intent forwarding for implicit intents 79 Intent intent = new Intent(); 80 intent.addCategory(Intent.CATEGORY_DEFAULT); 81 intent.setPackage(context.getPackageName()); 82 83 // Resolves activities for the managed profile (which we're running as) 84 List<ResolveInfo> resolvedIntents = pm.queryIntentActivities(intent, 85 GET_ACTIVITIES | GET_META_DATA | GET_RESOLVED_FILTER | MATCH_DISABLED_COMPONENTS); 86 final int count = resolvedIntents.size(); 87 for (int i = 0; i < count; i++) { 88 ResolveInfo info = resolvedIntents.get(i); 89 if (info.filter != null && info.activityInfo != null 90 && info.activityInfo.metaData != null) { 91 boolean shouldForward = info.activityInfo.metaData.getBoolean( 92 PRIMARY_PROFILE_SETTING); 93 if (shouldForward) { 94 pm.addCrossProfileIntentFilter(info.filter, userInfo.id, 95 userInfo.profileGroupId, PackageManager.SKIP_CURRENT_PROFILE); 96 } 97 } 98 } 99 100 // Disable launcher icon 101 ComponentName settingsComponentName = new ComponentName(context, Settings.class); 102 pm.setComponentEnabledSetting(settingsComponentName, 103 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); 104 // Disable shortcut picker. 105 ComponentName shortcutComponentName = new ComponentName( 106 context, CreateShortcutActivity.class); 107 pm.setComponentEnabledSetting(shortcutComponentName, 108 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); 109 } 110 111 // Disable WebView Setting if the current user is not an admin webviewSettingSetup(Context context, PackageManager pm, UserInfo userInfo)112 private void webviewSettingSetup(Context context, PackageManager pm, UserInfo userInfo) { 113 if (userInfo == null) { 114 return; 115 } 116 ComponentName settingsComponentName = 117 new ComponentName(SETTINGS_PACKAGE_NAME, 118 SETTINGS_PACKAGE_NAME + WEBVIEW_IMPLEMENTATION_ACTIVITY); 119 pm.setComponentEnabledSetting(settingsComponentName, 120 userInfo.isAdmin() ? 121 PackageManager.COMPONENT_ENABLED_STATE_ENABLED : 122 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 123 PackageManager.DONT_KILL_APP); 124 } 125 126 // Refresh settings shortcuts to have correct intent flags 127 @VisibleForTesting refreshExistingShortcuts(Context context)128 void refreshExistingShortcuts(Context context) { 129 final ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class); 130 final List<ShortcutInfo> pinnedShortcuts = shortcutManager.getPinnedShortcuts(); 131 final List<ShortcutInfo> updates = new ArrayList<>(); 132 for (ShortcutInfo info : pinnedShortcuts) { 133 if (info.isImmutable()) { 134 continue; 135 } 136 final Intent shortcutIntent = info.getIntent(); 137 shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 138 final ShortcutInfo updatedInfo = new ShortcutInfo.Builder(context, info.getId()) 139 .setIntent(shortcutIntent) 140 .build(); 141 updates.add(updatedInfo); 142 } 143 shortcutManager.updateShortcuts(updates); 144 } 145 146 } 147