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