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.documentsui;
18 
19 import static com.android.documentsui.base.Shared.LAUNCHER_TARGET_CLASS;
20 import static com.android.documentsui.base.SharedMinimal.DEBUG;
21 
22 import android.annotation.SuppressLint;
23 import android.content.BroadcastReceiver;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.om.OverlayInfo;
28 import android.content.om.OverlayManager;
29 import android.content.pm.PackageManager;
30 import android.content.res.Resources;
31 import android.util.Log;
32 
33 import com.android.documentsui.theme.ThemeOverlayManager;
34 import com.android.documentsui.util.VersionUtils;
35 
36 /**
37  * A receiver listening action.PRE_BOOT_COMPLETED event for setting component enable or disable.
38  * Since there's limitation of overlay AndroidManifest.xml attrs at boot stage.
39  * The workaround to retrieve config from DocumentsUI RRO package at boot time in Q.
40  */
41 public class PreBootReceiver extends BroadcastReceiver {
42 
43     private static final String TAG = "PreBootReceiver";
44     private static final String CONFIG_IS_LAUNCHER_ENABLED = "is_launcher_enabled";
45     private static final String CONFIG_HANDLE_VIEW_DOWNLOADS = "handle_view_downloads_intent";
46     private static final String DOWNLOADS_TARGET_CLASS =
47             "com.android.documentsui.ViewDownloadsActivity";
48 
49     @SuppressLint("NewApi") // OverlayManager is @hdie
50     @Override
onReceive(Context context, Intent intent)51     public void onReceive(Context context, Intent intent) {
52         final PackageManager pm = context.getPackageManager();
53         if (pm == null) {
54             Log.w(TAG, "Can't obtain PackageManager from System Service!");
55             return;
56         }
57 
58         final OverlayManager om = context.getSystemService(OverlayManager.class);
59         if (om == null) {
60             Log.w(TAG, "Can't obtain OverlayManager from System Service!");
61             return;
62         }
63 
64         final OverlayInfo info = new ThemeOverlayManager(om,
65                 context.getPackageName()).getValidOverlay(pm);
66 
67         if (info == null) {
68             Log.w(TAG, "Can't get valid overlay info");
69             return;
70         }
71 
72         final String overlayPkg = info.getPackageName();
73         final String packageName = context.getPackageName();
74 
75         Resources overlayRes;
76         try {
77             overlayRes = pm.getResourcesForApplication(overlayPkg);
78         } catch (PackageManager.NameNotFoundException e) {
79             Log.w(TAG, "Failed while parse package res.");
80             overlayRes = null;
81         }
82         if (overlayRes == null) {
83             return;
84         }
85 
86         setComponentEnabledByConfigResources(pm, packageName, LAUNCHER_TARGET_CLASS,
87                 overlayPkg, overlayRes, CONFIG_IS_LAUNCHER_ENABLED);
88         setComponentEnabledByConfigResources(pm, packageName, DOWNLOADS_TARGET_CLASS,
89                 overlayPkg, overlayRes, CONFIG_HANDLE_VIEW_DOWNLOADS);
90     }
91 
setComponentEnabledByConfigResources(PackageManager pm, String packageName, String className, String overlayPkg, Resources overlayRes, String config)92     private static void setComponentEnabledByConfigResources(PackageManager pm, String packageName,
93             String className, String overlayPkg, Resources overlayRes, String config) {
94         int resId = overlayRes.getIdentifier(config, "bool", overlayPkg);
95         if (resId != 0) {
96             final ComponentName component = new ComponentName(packageName, className);
97             boolean enabled = overlayRes.getBoolean(resId);
98             if (VersionUtils.isAtLeastS() && CONFIG_IS_LAUNCHER_ENABLED.equals(config)) {
99                 enabled = false; // Do not allow LauncherActivity to be enabled for S+.
100             }
101             if (DEBUG) {
102                 Log.i(TAG,
103                         "Overlay package:" + overlayPkg + ", customize " + config + ":" + enabled);
104             }
105             pm.setComponentEnabledSetting(component, enabled
106                             ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
107                             : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
108                     PackageManager.DONT_KILL_APP);
109         }
110     }
111 }
112