Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6763d1f3 authored by Ricky Wai's avatar Ricky Wai Committed by Android (Google) Code Review
Browse files

Merge "Return app hidden details activity in launcher api"

parents a23e0965 cf134ebf
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 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 android.app;

import android.content.Intent;
import android.os.Bundle;

/**
 * Helper activity that forwards you to app details page.
 *
 * @hide
 */
public class AppDetailsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(android.net.Uri.fromParts("package", getPackageName(), null));
        startActivity(intent);
        finish();
    }
}
+24 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.content.pm;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager.ApplicationInfoFlags;
@@ -204,6 +205,29 @@ public abstract class PackageManagerInternal {
    public abstract PackageInfo getPackageInfo(String packageName,
            @PackageInfoFlags int flags, int filterCallingUid, int userId);

    /**
     * Return a List of all application packages that are installed on the
     * device, for a specific user. If flag GET_UNINSTALLED_PACKAGES has been
     * set, a list of all applications including those deleted with
     * {@code DONT_DELETE_DATA} (partially installed apps with data directory)
     * will be returned.
     *
     * @param flags Additional option flags to modify the data returned.
     * @param userId The user for whom the installed applications are to be
     *            listed
     * @param callingUid The uid of the original caller app
     * @return A List of ApplicationInfo objects, one for each installed
     *         application. In the unlikely case there are no installed
     *         packages, an empty list is returned. If flag
     *         {@code MATCH_UNINSTALLED_PACKAGES} is set, the application
     *         information is retrieved from the list of uninstalled
     *         applications (which includes installed applications as well as
     *         applications with data directory i.e. applications which had been
     *         deleted with {@code DONT_DELETE_DATA} flag set).
     */
    public abstract List<ApplicationInfo> getInstalledApplications(
            @ApplicationInfoFlags int flags, @UserIdInt int userId, int callingUid);

    /**
     * Retrieve launcher extras for a suspended package provided to the system in
     * {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
+69 −6
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityTaskManager;
import android.app.AppDetailsActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -3882,6 +3883,11 @@ public class PackageParser {
            }
        }

        // Add a hidden app detail activity which forwards user to App Details page.
        Activity a = generateAppDetailsHiddenActivity(owner, flags, outError,
                owner.baseHardwareAccelerated);
        owner.activities.add(a);

        if (hasActivityOrder) {
            Collections.sort(owner.activities, (a1, a2) -> Integer.compare(a2.order, a1.order));
        }
@@ -4121,9 +4127,14 @@ public class PackageParser {
                return false;
            }
        } else {
            outInfo.name
            String outInfoName
                = buildClassName(owner.applicationInfo.packageName, name, outError);
            if (outInfo.name == null) {
            if (AppDetailsActivity.class.getName().equals(outInfoName)) {
                outError[0] = tag + " invalid android:name";
                return false;
            }
            outInfo.name = outInfoName;
            if (outInfoName == null) {
                return false;
            }
        }
@@ -4162,6 +4173,45 @@ public class PackageParser {
        return true;
    }

    /**
     * Generate activity object that forwards user to App Details page automatically.
     * This activity should be invisible to user and user should not know or see it.
     */
    private @NonNull PackageParser.Activity generateAppDetailsHiddenActivity(
            PackageParser.Package owner, int flags, String[] outError,
            boolean hardwareAccelerated) {

        // Build custom App Details activity info instead of parsing it from xml
        Activity a = new Activity(owner, AppDetailsActivity.class.getName(), new ActivityInfo());
        a.owner = owner;
        a.setPackageName(owner.packageName);

        a.info.theme = 0;
        a.info.exported = true;
        a.info.name = AppDetailsActivity.class.getName();
        a.info.processName = owner.applicationInfo.processName;
        a.info.uiOptions = a.info.applicationInfo.uiOptions;
        a.info.taskAffinity = buildTaskAffinityName(owner.packageName, owner.packageName,
                ":app_details", outError);
        a.info.enabled = true;
        a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
        a.info.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE;
        a.info.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic();
        a.info.configChanges = getActivityConfigChanges(0, 0);
        a.info.softInputMode = 0;
        a.info.persistableMode = ActivityInfo.PERSIST_NEVER;
        a.info.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
        a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
        a.info.lockTaskLaunchMode = 0;
        a.info.encryptionAware = a.info.directBootAware = false;
        a.info.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
        a.info.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
        if (hardwareAccelerated) {
            a.info.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
        }
        return a;
    }

    private Activity parseActivity(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
            boolean receiver, boolean hardwareAccelerated)
@@ -7132,10 +7182,16 @@ public class PackageParser {
        ComponentName componentName;
        String componentShortName;

        public Component(Package _owner) {
            owner = _owner;
            intents = null;
            className = null;
        public Component(Package owner, ArrayList<II> intents, String className) {
            this.owner = owner;
            this.intents = intents;
            this.className = className;
        }

        public Component(Package owner) {
            this.owner = owner;
            this.intents = null;
            this.className = null;
        }

        public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
@@ -7600,6 +7656,13 @@ public class PackageParser {
            return mHasMaxAspectRatio;
        }

        // To construct custom activity which does not exist in manifest
        Activity(final Package owner, final String className, final ActivityInfo info) {
            super(owner, new ArrayList<>(0), className);
            this.info = info;
            this.info.applicationInfo = owner.applicationInfo;
        }

        public Activity(final ParseComponentArgs args, final ActivityInfo _info) {
            super(args, _info);
            info = _info;
+76 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppDetailsActivity;
import android.app.AppGlobals;
import android.app.IApplicationThread;
import android.app.PendingIntent;
@@ -65,7 +66,9 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityTaskManagerInternal;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

/**
@@ -74,6 +77,7 @@ import java.util.List;
 */
public class LauncherAppsService extends SystemService {

    private static final boolean SHOW_HIDDEN_APP_ENABLED = false;
    private final LauncherAppsImpl mLauncherAppsImpl;

    public LauncherAppsService(Context context) {
@@ -281,15 +285,84 @@ public class LauncherAppsService extends SystemService {
            }
        }

        private ResolveInfo getHiddenAppActivityInfo(String packageName, int callingUid,
                UserHandle user) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName(packageName, AppDetailsActivity.class.getName()));
            final PackageManagerInternal pmInt =
                    LocalServices.getService(PackageManagerInternal.class);
            List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
                    PackageManager.MATCH_DIRECT_BOOT_AWARE
                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
                    callingUid, user.getIdentifier());
            if (apps.size() > 0) {
                return apps.get(0);
            }
            return null;
        }

        @Override
        public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
                String packageName, UserHandle user)
                throws RemoteException {
            return queryActivitiesForUser(callingPackage,
                String packageName, UserHandle user) throws RemoteException {
            ParceledListSlice<ResolveInfo> launcherActivities = queryActivitiesForUser(
                    callingPackage,
                    new Intent(Intent.ACTION_MAIN)
                            .addCategory(Intent.CATEGORY_LAUNCHER)
                            .setPackage(packageName),
                    user);
            if (!SHOW_HIDDEN_APP_ENABLED) {
                return launcherActivities;
            }

            final int callingUid = injectBinderCallingUid();
            final ArrayList<ResolveInfo> result = new ArrayList<>(launcherActivities.getList());
            if (packageName != null) {
                // If target package has launcher activities, then return those launcher
                // activities. Otherwise, return hidden activity that forwards user to app
                // details page.
                if (result.size() > 0) {
                    return launcherActivities;
                }
                ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
                if (info != null) {
                    result.add(info);
                }
                return new ParceledListSlice<>(result);
            }

            long ident = injectClearCallingIdentity();
            try {
                final HashSet<String> visiblePackages = new HashSet<>();
                for (ResolveInfo info : result) {
                    visiblePackages.add(info.activityInfo.packageName);
                }
                final PackageManagerInternal pmInt =
                        LocalServices.getService(PackageManagerInternal.class);
                List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(0,
                        user.getIdentifier(), callingUid);
                for (ApplicationInfo applicationInfo : installedPackages) {
                    if (!visiblePackages.contains(applicationInfo.packageName)) {
                        if (!shouldShowHiddenApp(applicationInfo)) {
                            continue;
                        }
                        ResolveInfo info = getHiddenAppActivityInfo(applicationInfo.packageName,
                                callingUid, user);
                        if (info != null) {
                            result.add(info);
                        }
                    }
                }
                return new ParceledListSlice<>(result);
            } finally {
                injectRestoreCallingIdentity(ident);
            }
        }

        private static boolean shouldShowHiddenApp(ApplicationInfo appInfo) {
            if (appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
                return false;
            }
            return true;
        }

        @Override
+28 −3
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppDetailsActivity;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.ResourcesManager;
@@ -7869,10 +7870,16 @@ public class PackageManagerService extends IPackageManager.Stub
    @Override
    public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
        final int callingUid = Binder.getCallingUid();
        return new ParceledListSlice<>(
                getInstalledApplicationsListInternal(flags, userId, callingUid));
    }
    private List<ApplicationInfo> getInstalledApplicationsListInternal(int flags, int userId,
            int callingUid) {
        if (getInstantAppPackageName(callingUid) != null) {
            return ParceledListSlice.emptyList();
            return Collections.emptyList();
        }
        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        flags = updateFlagsForApplication(flags, userId, null);
        final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
@@ -7937,7 +7944,7 @@ public class PackageManagerService extends IPackageManager.Stub
                }
            }
            return new ParceledListSlice<>(list);
            return list;
        }
    }
@@ -19388,6 +19395,16 @@ public class PackageManagerService extends IPackageManager.Stub
                throw new SecurityException("Cannot disable a protected package: " + packageName);
            }
        }
        // Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden
        // app details activity
        if (AppDetailsActivity.class.getName().equals(className)) {
            if (mContext.checkCallingOrSelfPermission(
                    android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)
                    != PackageManager.PERMISSION_GRANTED) {
                Slog.e(TAG, "Cannot disable a protected component: " + packageName);
                return;
            }
        }
        synchronized (mPackages) {
            if (callingUid == Process.SHELL_UID
@@ -22282,6 +22299,14 @@ public class PackageManagerService extends IPackageManager.Stub
                    permName, packageName, flagMask, flagValues, userId);
        }
        @Override
        public List<ApplicationInfo> getInstalledApplications(int flags, int userId,
                int callingUid) {
            return PackageManagerService.this.getInstalledApplicationsListInternal(flags, userId,
                    callingUid);
        }
        @Override
        public boolean isPlatformSigned(String packageName) {
            PackageSetting packageSetting = mSettings.mPackages.get(packageName);