Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2016 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.launcher3.util;
     18 
     19 import android.app.AppOpsManager;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.pm.ApplicationInfo;
     23 import android.content.pm.LauncherActivityInfo;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.PackageManager.NameNotFoundException;
     26 import android.content.pm.ResolveInfo;
     27 import android.net.Uri;
     28 import android.os.Build;
     29 import android.os.UserHandle;
     30 import android.text.TextUtils;
     31 
     32 import com.android.launcher3.AppInfo;
     33 import com.android.launcher3.R;
     34 import com.android.launcher3.Utilities;
     35 import com.android.launcher3.compat.LauncherAppsCompat;
     36 
     37 import java.net.URISyntaxException;
     38 import java.util.List;
     39 
     40 /**
     41  * Utility methods using package manager
     42  */
     43 public class PackageManagerHelper {
     44 
     45     private final Context mContext;
     46     private final PackageManager mPm;
     47     private final LauncherAppsCompat mLauncherApps;
     48 
     49     public PackageManagerHelper(Context context) {
     50         mContext = context;
     51         mPm = context.getPackageManager();
     52         mLauncherApps = LauncherAppsCompat.getInstance(context);
     53     }
     54 
     55     /**
     56      * Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
     57      * guarantee that the app is on SD card.
     58      */
     59     public boolean isAppOnSdcard(String packageName, UserHandle user) {
     60         ApplicationInfo info = mLauncherApps.getApplicationInfo(
     61                 packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, user);
     62         return info != null && (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
     63     }
     64 
     65     /**
     66      * Returns whether the target app is suspended for a given user as per
     67      * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
     68      */
     69     public boolean isAppSuspended(String packageName, UserHandle user) {
     70         ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, 0, user);
     71         return info != null && isAppSuspended(info);
     72     }
     73 
     74     public boolean isSafeMode() {
     75         return mContext.getPackageManager().isSafeMode();
     76     }
     77 
     78     public Intent getAppLaunchIntent(String pkg, UserHandle user) {
     79         List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(pkg, user);
     80         return activities.isEmpty() ? null :
     81                 AppInfo.makeLaunchIntent(activities.get(0));
     82     }
     83 
     84     /**
     85      * Returns whether an application is suspended as per
     86      * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
     87      */
     88     public static boolean isAppSuspended(ApplicationInfo info) {
     89         // The value of FLAG_SUSPENDED was reused by a hidden constant
     90         // ApplicationInfo.FLAG_PRIVILEGED prior to N, so only check for suspended flag on N
     91         // or later.
     92         if (Utilities.ATLEAST_NOUGAT) {
     93             return (info.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
     94         } else {
     95             return false;
     96         }
     97     }
     98 
     99     /**
    100      * Returns true if {@param srcPackage} has the permission required to start the activity from
    101      * {@param intent}. If {@param srcPackage} is null, then the activity should not need
    102      * any permissions
    103      */
    104     public boolean hasPermissionForActivity(Intent intent, String srcPackage) {
    105         ResolveInfo target = mPm.resolveActivity(intent, 0);
    106         if (target == null) {
    107             // Not a valid target
    108             return false;
    109         }
    110         if (TextUtils.isEmpty(target.activityInfo.permission)) {
    111             // No permission is needed
    112             return true;
    113         }
    114         if (TextUtils.isEmpty(srcPackage)) {
    115             // The activity requires some permission but there is no source.
    116             return false;
    117         }
    118 
    119         // Source does not have sufficient permissions.
    120         if(mPm.checkPermission(target.activityInfo.permission, srcPackage) !=
    121                 PackageManager.PERMISSION_GRANTED) {
    122             return false;
    123         }
    124 
    125         if (!Utilities.ATLEAST_MARSHMALLOW) {
    126             // These checks are sufficient for below M devices.
    127             return true;
    128         }
    129 
    130         // On M and above also check AppOpsManager for compatibility mode permissions.
    131         if (TextUtils.isEmpty(AppOpsManager.permissionToOp(target.activityInfo.permission))) {
    132             // There is no app-op for this permission, which could have been disabled.
    133             return true;
    134         }
    135 
    136         // There is no direct way to check if the app-op is allowed for a particular app. Since
    137         // app-op is only enabled for apps running in compatibility mode, simply block such apps.
    138 
    139         try {
    140             return mPm.getApplicationInfo(srcPackage, 0).targetSdkVersion >= Build.VERSION_CODES.M;
    141         } catch (NameNotFoundException e) { }
    142 
    143         return false;
    144     }
    145 
    146     public static Intent getMarketIntent(String packageName) {
    147         return new Intent(Intent.ACTION_VIEW)
    148                 .setData(new Uri.Builder()
    149                         .scheme("market")
    150                         .authority("details")
    151                         .appendQueryParameter("id", packageName)
    152                         .build());
    153     }
    154 
    155     /**
    156      * Creates a new market search intent.
    157      */
    158     public static Intent getMarketSearchIntent(Context context, String query) {
    159         try {
    160             Intent intent = Intent.parseUri(context.getString(R.string.market_search_intent), 0);
    161             if (!TextUtils.isEmpty(query)) {
    162                 intent.setData(
    163                         intent.getData().buildUpon().appendQueryParameter("q", query).build());
    164             }
    165             return intent;
    166         } catch (URISyntaxException e) {
    167             throw new RuntimeException(e);
    168         }
    169     }
    170 }
    171