summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tony Huang <tonyychuang@google.com> 2019-06-10 16:55:20 +0800
committer Tony Huang <tonyychuang@google.com> 2019-06-13 18:29:00 +0800
commitc39b0b23eb2003cc2eccbeaa166e21a88b198a13 (patch)
treeaf14bf965a296b523eb795009b9b707ebe65c31b
parent28d5f8ee15082927a9ff60c66bda831a7139f6e3 (diff)
Overlay manifest setting by package manager
Using overlay manager to get package name of overlay apk. And parse it's resources to get config value directly. Register PRE_BOOT_COMPLETED to set up the value. Bug: 134558563 Test: Preload RRO with "is_launcher_enabled:false", flash all device, boot to verify if DocumentsUI launcher icon hidden. Test: Preload RRO with "is_launcher_enabled:false", factory reset, and verify if DocumentsUI launcher icon hidden. Change-Id: Ifc5f90c853a9a2b8b367fa53a678a9ea959e441a
-rw-r--r--AndroidManifest.xml8
-rw-r--r--res/values/overlayable.xml1
-rw-r--r--src/com/android/documentsui/PreBootReceiver.java104
-rw-r--r--src/com/android/documentsui/theme/ThemeOverlayManager.java35
4 files changed, 144 insertions, 4 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ac16d214b..a2b01f33a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -116,7 +116,7 @@
</intent-filter>
</activity>
- <activity-alias android:name="ViewDownloadsActivity"
+ <activity-alias android:name=".ViewDownloadsActivity"
android:targetActivity=".files.FilesActivity"
android:enabled="@bool/handle_view_downloads_intent">
<intent-filter>
@@ -169,6 +169,12 @@
</intent-filter>
</receiver>
+ <receiver android:name=".PreBootReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.PRE_BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+
<!-- Run FileOperationService in a separate process so that we can use FileLock class to
wait until jumbo clip is done writing to disk before reading it. See ClipStorage for
details. -->
diff --git a/res/values/overlayable.xml b/res/values/overlayable.xml
index 23ca14e98..9a13207cf 100644
--- a/res/values/overlayable.xml
+++ b/res/values/overlayable.xml
@@ -45,6 +45,7 @@
<item type="bool" name="config_button_all_caps"/>
<item type="bool" name="config_default_show_device_root"/>
<item type="bool" name="feature_default_root_in_browse"/>
+ <item type="bool" name="handle_view_downloads_intent"/>
<item type="bool" name="is_launcher_enabled"/>
<item type="bool" name="show_search_bar"/>
<!-- END BOOLEAN CONFIG -->
diff --git a/src/com/android/documentsui/PreBootReceiver.java b/src/com/android/documentsui/PreBootReceiver.java
new file mode 100644
index 000000000..a983adcca
--- /dev/null
+++ b/src/com/android/documentsui/PreBootReceiver.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.base.SharedMinimal.DEBUG;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.documentsui.theme.ThemeOverlayManager;
+
+/**
+ * A receiver listening action.PRE_BOOT_COMPLETED event for setting component enable or disable.
+ * Since there's limitation of overlay AndroidManifest.xml attrs at boot stage.
+ * The workaround to retrieve config from DocumentsUI RRO package at boot time in Q.
+ */
+public class PreBootReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "PreBootReceiver";
+ private static final String CONFIG_IS_LAUNCHER_ENABLED = "is_launcher_enabled";
+ private static final String CONFIG_HANDLE_VIEW_DOWNLOADS = "handle_view_downloads_intent";
+ private static final String LAUNCHER_TARGET_CLASS = "com.android.documentsui.LauncherActivity";
+ private static final String DOWNLOADS_TARGET_CLASS =
+ "com.android.documentsui.ViewDownloadsActivity";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final PackageManager pm = context.getPackageManager();
+ if (pm == null) {
+ Log.w(TAG, "Can't obtain PackageManager from System Service!");
+ return;
+ }
+
+ final OverlayManager om = context.getSystemService(OverlayManager.class);
+ if (om == null) {
+ Log.w(TAG, "Can't obtain OverlayManager from System Service!");
+ return;
+ }
+
+ final OverlayInfo info = new ThemeOverlayManager(om,
+ context.getPackageName()).getValidOverlay(pm);
+
+ if (info == null) {
+ Log.w(TAG, "Can't get valid overlay info");
+ return;
+ }
+
+ final String overlayPkg = info.getPackageName();
+ final String packageName = context.getPackageName();
+
+ Resources overlayRes;
+ try {
+ overlayRes = pm.getResourcesForApplication(overlayPkg);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Failed while parse package res.");
+ overlayRes = null;
+ }
+ if (overlayRes == null) {
+ return;
+ }
+
+ setComponentEnabledByConfigResources(pm, packageName, LAUNCHER_TARGET_CLASS,
+ overlayPkg, overlayRes, CONFIG_IS_LAUNCHER_ENABLED);
+ setComponentEnabledByConfigResources(pm, packageName, DOWNLOADS_TARGET_CLASS,
+ overlayPkg, overlayRes, CONFIG_HANDLE_VIEW_DOWNLOADS);
+ }
+
+ private static void setComponentEnabledByConfigResources(PackageManager pm, String packageName,
+ String className, String overlayPkg, Resources overlayRes, String config) {
+ int resId = overlayRes.getIdentifier(config, "bool", overlayPkg);
+ if (resId != 0) {
+ final ComponentName component = new ComponentName(packageName, className);
+ final boolean value = overlayRes.getBoolean(resId);
+ if (DEBUG) {
+ Log.i(TAG, "Overlay package:" + overlayPkg + ", customize " + config + ":" + value);
+ }
+ pm.setComponentEnabledSetting(component, value
+ ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ }
+ }
+}
diff --git a/src/com/android/documentsui/theme/ThemeOverlayManager.java b/src/com/android/documentsui/theme/ThemeOverlayManager.java
index 623391810..ca8326870 100644
--- a/src/com/android/documentsui/theme/ThemeOverlayManager.java
+++ b/src/com/android/documentsui/theme/ThemeOverlayManager.java
@@ -19,13 +19,15 @@ package com.android.documentsui.theme;
import android.content.Context;
import android.content.om.OverlayInfo;
import android.content.om.OverlayManager;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
+import android.os.Environment;
import android.os.UserHandle;
-import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.util.Consumer;
@@ -73,6 +75,34 @@ public class ThemeOverlayManager {
return mOverlayManager.getOverlayInfosForTarget(mTargetPackageId, mUserHandle);
}
+ /**
+ * Return the OverlayInfo which is provided by the docsUI overlay package located product,
+ * system or vendor. We assume there should only one docsUI overlay package because priority
+ * not work for non-static overlay, so vendor should put only one docsUI overlay package.
+ *
+ * @param pm the PackageManager
+ */
+ @Nullable
+ public OverlayInfo getValidOverlay(@NonNull PackageManager pm) {
+ for (OverlayInfo info : getOverlayInfo()) {
+ try {
+ final ApplicationInfo ai = pm.getApplicationInfo(info.getPackageName(), 0);
+ // Since isProduct(), isVendor() and isSystemApp() functions in ApplicationInfo are
+ // hidden. The best way to avoid unknown sideload APKs is filter path by string
+ // comparison.
+ final String sourceDir = ai.sourceDir;
+ if (sourceDir.startsWith(Environment.getProductDirectory().getAbsolutePath())
+ || sourceDir.startsWith(Environment.getVendorDirectory().getAbsolutePath())
+ || sourceDir.startsWith(Environment.getRootDirectory().getAbsolutePath())) {
+ return info;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Can't get ApplicationInfo of overlay package " + info.getPackageName());
+ }
+ }
+ return null;
+ }
+
private void setEnabled(boolean enabled, Consumer<Boolean> callback) {
new AsyncTask<Void, Void, Boolean>() {
@Override
@@ -94,8 +124,7 @@ public class ThemeOverlayManager {
boolean bSuccess = true;
for (OverlayInfo info : infos) {
try {
- if (info != null && !TextUtils.isEmpty(info.getPackageName())
- && info.isEnabled() != enabled) {
+ if (info.isEnabled() != enabled) {
mOverlayManager.setEnabled(info.getPackageName(), enabled, mUserHandle);
} else {
Log.w(TAG, "Skip enabled overlay package:" + info.getPackageName()