• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
20 
21 import android.content.ActivityNotFoundException;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.LauncherActivityInfo;
26 import android.content.pm.LauncherApps;
27 import android.content.pm.PackageManager;
28 import android.content.pm.PackageManager.NameNotFoundException;
29 import android.graphics.Rect;
30 import android.os.Bundle;
31 import android.os.Process;
32 import android.os.UserHandle;
33 import android.text.TextUtils;
34 import android.util.Log;
35 import android.widget.Toast;
36 
37 import androidx.annotation.NonNull;
38 import androidx.annotation.Nullable;
39 
40 import com.android.launcher3.PendingAddItemInfo;
41 import com.android.launcher3.R;
42 import com.android.launcher3.dagger.ApplicationContext;
43 import com.android.launcher3.dagger.LauncherAppSingleton;
44 import com.android.launcher3.dagger.LauncherBaseAppComponent;
45 import com.android.launcher3.model.data.AppInfo;
46 import com.android.launcher3.model.data.ItemInfo;
47 import com.android.launcher3.model.data.ItemInfoWithIcon;
48 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
49 import com.android.launcher3.model.data.WorkspaceItemInfo;
50 
51 import java.util.List;
52 import java.util.Objects;
53 
54 import javax.inject.Inject;
55 
56 /**
57  * Utility methods using package manager
58  */
59 @LauncherAppSingleton
60 public class PackageManagerHelper {
61 
62     private static final String TAG = "PackageManagerHelper";
63 
64     @NonNull
65     public static DaggerSingletonObject<PackageManagerHelper> INSTANCE =
66             new DaggerSingletonObject<>(LauncherBaseAppComponent::getPackageManagerHelper);
67 
68     @NonNull
69     private final Context mContext;
70 
71     @NonNull
72     private final PackageManager mPm;
73 
74     @NonNull
75     private final LauncherApps mLauncherApps;
76 
77     @Inject
PackageManagerHelper(@pplicationContext final Context context)78     public PackageManagerHelper(@ApplicationContext final Context context) {
79         mContext = context;
80         mPm = context.getPackageManager();
81         mLauncherApps = Objects.requireNonNull(context.getSystemService(LauncherApps.class));
82     }
83 
84     /**
85      * Returns the installing app package for the given package
86      */
getAppInstallerPackage(@onNull final String packageName)87     public String getAppInstallerPackage(@NonNull final String packageName) {
88         try {
89             return mPm.getInstallSourceInfo(packageName).getInstallingPackageName();
90         } catch (NameNotFoundException e) {
91             Log.e(TAG, "Failed to get installer package for app package:" + packageName, e);
92             return null;
93         }
94     }
95 
96     /**
97      * Returns the preferred launch activity intent for a given package.
98      */
99     @Nullable
getAppLaunchIntent(@ullable final String pkg, @NonNull final UserHandle user)100     public Intent getAppLaunchIntent(@Nullable final String pkg, @NonNull final UserHandle user) {
101         LauncherActivityInfo info = getAppLaunchInfo(pkg, user);
102         return info != null ? AppInfo.makeLaunchIntent(info) : null;
103     }
104 
105     /**
106      * Returns the preferred launch activity for a given package.
107      */
108     @Nullable
getAppLaunchInfo(@ullable final String pkg, @NonNull final UserHandle user)109     public LauncherActivityInfo getAppLaunchInfo(@Nullable final String pkg,
110             @NonNull final UserHandle user) {
111         List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(pkg, user);
112         return activities.isEmpty() ? null : activities.get(0);
113     }
114 
115     /**
116      * Starts the details activity for {@code info}
117      */
startDetailsActivityForInfo(Context context, ItemInfo info, Rect sourceBounds, Bundle opts)118     public static void startDetailsActivityForInfo(Context context, ItemInfo info,
119             Rect sourceBounds, Bundle opts) {
120         if (info instanceof ItemInfoWithIcon appInfo
121                 && (appInfo.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {
122             context.startActivity(ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent(
123                     appInfo.getTargetComponent().getPackageName(), Process.myUserHandle()), opts);
124             return;
125         }
126         ComponentName componentName = null;
127         if (info instanceof AppInfo) {
128             componentName = ((AppInfo) info).componentName;
129         } else if (info instanceof WorkspaceItemInfo) {
130             componentName = info.getTargetComponent();
131         } else if (info instanceof PendingAddItemInfo) {
132             componentName = ((PendingAddItemInfo) info).componentName;
133         } else if (info instanceof LauncherAppWidgetInfo) {
134             componentName = ((LauncherAppWidgetInfo) info).providerName;
135         }
136         if (componentName != null) {
137             try {
138                 context.getSystemService(LauncherApps.class).startAppDetailsActivity(componentName,
139                         info.user, sourceBounds, opts);
140             } catch (SecurityException | ActivityNotFoundException e) {
141                 Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
142                 Log.e(TAG, "Unable to launch settings", e);
143             }
144         }
145     }
146 
147     /**
148      * Returns true if the intent is a valid launch intent for a launcher activity of an app.
149      * This is used to identify shortcuts which are different from the ones exposed by the
150      * applications' manifest file.
151      *
152      * @param launchIntent The intent that will be launched when the shortcut is clicked.
153      */
isLauncherAppTarget(Intent launchIntent)154     public static boolean isLauncherAppTarget(Intent launchIntent) {
155         if (launchIntent != null
156                 && Intent.ACTION_MAIN.equals(launchIntent.getAction())
157                 && launchIntent.getComponent() != null
158                 && launchIntent.getCategories() != null
159                 && launchIntent.getCategories().size() == 1
160                 && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
161                 && TextUtils.isEmpty(launchIntent.getDataString())) {
162             // An app target can either have no extra or have ItemInfo.EXTRA_PROFILE.
163             Bundle extras = launchIntent.getExtras();
164             return extras == null || extras.keySet().isEmpty();
165         }
166         return false;
167     }
168 
169     /**
170      * Returns true if Launcher has the permission to access shortcuts.
171      *
172      * @see LauncherApps#hasShortcutHostPermission()
173      */
hasShortcutsPermission(Context context)174     public static boolean hasShortcutsPermission(Context context) {
175         try {
176             return context.getSystemService(LauncherApps.class).hasShortcutHostPermission();
177         } catch (SecurityException | IllegalStateException e) {
178             Log.e(TAG, "Failed to make shortcut manager call", e);
179         }
180         return false;
181     }
182 
183     /** Returns the incremental download progress for the given shortcut's app. */
getLoadingProgress(LauncherActivityInfo info)184     public static int getLoadingProgress(LauncherActivityInfo info) {
185         return (int) (100 * info.getLoadingProgress());
186     }
187 
188     /**
189      * Returns whether two apps should be considered the same for multi-instance purposes, which
190      * requires additional checks to ensure they can be started as multiple instances.
191      */
isSameAppForMultiInstance(@onNull ItemInfo app1, @NonNull ItemInfo app2)192     public static boolean isSameAppForMultiInstance(@NonNull ItemInfo app1,
193             @NonNull ItemInfo app2) {
194         return app1.getTargetPackage().equals(app2.getTargetPackage())
195                 && app1.user.equals(app2.user);
196     }
197 }
198