193568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk/*
293568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * Copyright (C) 2015 The Android Open Source Project
393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk *
493568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * Licensed under the Apache License, Version 2.0 (the "License");
593568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * you may not use this file except in compliance with the License.
693568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * You may obtain a copy of the License at
793568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk *
893568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk *
1093568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * Unless required by applicable law or agreed to in writing, software
1193568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * distributed under the License is distributed on an "AS IS" BASIS,
1293568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * See the License for the specific language governing permissions and
1493568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk * limitations under the License.
1593568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk */
1693568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkpackage com.android.packageinstaller.permission.model;
1793568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk
1893568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkimport android.content.BroadcastReceiver;
1993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkimport android.content.Context;
2093568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkimport android.content.Intent;
2193568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkimport android.content.pm.PackageInfo;
2293568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkimport android.content.pm.PackageManager;
2393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkimport android.content.pm.PackageManager.NameNotFoundException;
247445ca7255d491bbc41f7532af758f96f55e0602Svet Ganovimport android.util.ArrayMap;
259f0442cdfc055cc3aed19770f48f516b052f6e60Jason Monkimport android.util.ArraySet;
2693568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk
2793568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkimport com.android.packageinstaller.permission.model.PermissionApps.PermissionApp;
2893568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monkimport com.android.packageinstaller.permission.utils.Utils;
2993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk
30bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onukiimport java.text.Collator;
31bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onukiimport java.util.ArrayList;
32bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onukiimport java.util.Collections;
3393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk
34bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onukipublic class PermissionStatusReceiver extends BroadcastReceiver {
3593568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk    @Override
3693568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk    public void onReceive(Context context, Intent intent) {
37bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki        int[] counts = new int[3];
38bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki        ArrayList<CharSequence> grantedGroups = new ArrayList<>();
3993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        boolean succeeded = false;
40bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
41bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki        boolean isForPackage = intent.hasExtra(Intent.EXTRA_PACKAGE_NAME);
42bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
4393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        Intent responseIntent = new Intent(intent.getStringExtra(
4493568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                Intent.EXTRA_GET_PERMISSIONS_RESPONSE_INTENT));
4593568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        responseIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
46bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
47bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
48bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki        if (isForPackage) {
4993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            String pkg = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
50bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            succeeded = getPermissionsCount(context, pkg, counts, grantedGroups);
5193568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        } else {
52bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            succeeded = getAppsWithPermissionsCount(context, counts);
5393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        }
54bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki        if (succeeded) {
55bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_COUNT_RESULT, counts);
56bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
57bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            if (isForPackage) {
58bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki                responseIntent.putExtra(Intent.EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT,
59bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki                        grantedGroups.toArray(new CharSequence[grantedGroups.size()]));
60bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            }
61bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki        }
62bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
6393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        context.sendBroadcast(responseIntent);
6493568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk    }
6593568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk
66bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki    public boolean getPermissionsCount(Context context, String pkg, int[] counts,
67bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            ArrayList<CharSequence> grantedGroups) {
6893568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        try {
6993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            PackageInfo packageInfo =
7093568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                    context.getPackageManager().getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
7193568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            AppPermissions appPermissions =
7248f67a93bfec31dc8bf0f89290056e5f36434fa2Svetoslav                    new AppPermissions(context, packageInfo, null, false, null);
7393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            int grantedCount = 0;
7493568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            int totalCount = 0;
75bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            int additionalCount = 0;
76bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
7793568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            for (AppPermissionGroup group : appPermissions.getPermissionGroups()) {
78c83c08a579316c432c6d0c009aba0fdc3b6cdb12Svetoslav                if (Utils.shouldShowPermission(group, pkg)) {
7993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                    totalCount++;
8095560c737ad280d1582c4e0bd66dc76a89b6cdc0Ian Pedowitz                    if (group.areRuntimePermissionsGranted()) {
8193568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                        grantedCount++;
82bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
83bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki                        if (Utils.OS_PKG.equals(group.getDeclaringPackage())) {
84bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki                            grantedGroups.add(group.getLabel());
85bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki                        } else {
86bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki                            additionalCount++;
87bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki                        }
8893568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                    }
8993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                }
9093568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            }
91bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
92bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            // Sort
93bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            Collator coll = Collator.getInstance();
94bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            coll.setStrength(Collator.PRIMARY);
95bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            Collections.sort(grantedGroups, coll);
96bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
97bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            // Set results
9893568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            counts[0] = grantedCount;
9993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            counts[1] = totalCount;
100bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki            counts[2] = additionalCount;
101bf3e576881748a1420fabc9c7ecc55cbadcc8136Makoto Onuki
10293568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            return true;
10393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        } catch (NameNotFoundException e) {
10493568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            return false;
10593568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        }
10693568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk    }
10793568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk
10893568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk    public boolean getAppsWithPermissionsCount(Context context, int[] counts) {
1099f0442cdfc055cc3aed19770f48f516b052f6e60Jason Monk        ArraySet<String> launcherPkgs = Utils.getLauncherPackages(context);
11093568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        // Indexed by uid.
1117445ca7255d491bbc41f7532af758f96f55e0602Svet Ganov        ArrayMap<String, Boolean> grantedApps = new ArrayMap<>();
1127445ca7255d491bbc41f7532af758f96f55e0602Svet Ganov        ArrayMap<String, Boolean> allApps = new ArrayMap<>();
11393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        for (String group : Utils.MODERN_PERMISSION_GROUPS) {
11493568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            PermissionApps permissionApps = new PermissionApps(context,
11593568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                    group, null);
11693568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            permissionApps.loadNowWithoutUi();
11793568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            for (PermissionApp app : permissionApps.getApps()) {
1187445ca7255d491bbc41f7532af758f96f55e0602Svet Ganov                String key = app.getKey();
1199f0442cdfc055cc3aed19770f48f516b052f6e60Jason Monk                if (Utils.isSystem(app, launcherPkgs)) {
120ae2ceca3c7ac2c3420541f552a2dc47f261ec199Jason Monk                    // We default to not showing system apps, so hide them from count.
121ae2ceca3c7ac2c3420541f552a2dc47f261ec199Jason Monk                    continue;
122ae2ceca3c7ac2c3420541f552a2dc47f261ec199Jason Monk                }
12393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                if (app.areRuntimePermissionsGranted()) {
1247445ca7255d491bbc41f7532af758f96f55e0602Svet Ganov                    grantedApps.put(key, true);
12593568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk                }
1267445ca7255d491bbc41f7532af758f96f55e0602Svet Ganov                allApps.put(key, true);
12793568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk            }
12893568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        }
12993568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        counts[0] = grantedApps.size();
13093568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        counts[1] = allApps.size();
13193568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk        return true;
13293568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk    }
13393568c580d730911a6e2734e79fbe6dc27c1bca1Jason Monk}
134