• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package com.android.launcher3.model;
17 
18 import static android.app.PendingIntent.FLAG_IMMUTABLE;
19 import static android.app.PendingIntent.FLAG_ONE_SHOT;
20 import static android.os.Process.myUserHandle;
21 
22 import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle;
23 
24 import static java.util.stream.Collectors.groupingBy;
25 import static java.util.stream.Collectors.mapping;
26 
27 import android.app.PendingIntent;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.pm.PackageInstaller.SessionInfo;
31 import android.os.UserHandle;
32 import android.util.Log;
33 
34 import com.android.launcher3.LauncherSettings;
35 import com.android.launcher3.model.data.FolderInfo;
36 import com.android.launcher3.model.data.ItemInfo;
37 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
38 import com.android.launcher3.util.PackageUserKey;
39 
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Set;
45 import java.util.stream.Collectors;
46 
47 /**
48  * Helper class to send broadcasts to package installers that have:
49  * - Items on the first screen
50  * - Items with an active install session
51  *
52  * The packages are broken down by: folder items, workspace items, hotseat items, and widgets.
53  *
54  * Package installers only receive data for items that they are installing.
55  */
56 public class FirstScreenBroadcast {
57 
58     private static final String TAG = "FirstScreenBroadcast";
59     private static final boolean DEBUG = false;
60 
61     private static final String ACTION_FIRST_SCREEN_ACTIVE_INSTALLS
62             = "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS";
63 
64     private static final String FOLDER_ITEM_EXTRA = "folderItem";
65     private static final String WORKSPACE_ITEM_EXTRA = "workspaceItem";
66     private static final String HOTSEAT_ITEM_EXTRA = "hotseatItem";
67     private static final String WIDGET_ITEM_EXTRA = "widgetItem";
68 
69     private static final String VERIFICATION_TOKEN_EXTRA = "verificationToken";
70 
71     private final HashMap<PackageUserKey, SessionInfo> mSessionInfoForPackage;
72 
FirstScreenBroadcast(HashMap<PackageUserKey, SessionInfo> sessionInfoForPackage)73     public FirstScreenBroadcast(HashMap<PackageUserKey, SessionInfo> sessionInfoForPackage) {
74         mSessionInfoForPackage = sessionInfoForPackage;
75     }
76 
77     /**
78      * Sends a broadcast to all package installers that have items with active sessions on the users
79      * first screen.
80      */
sendBroadcasts(Context context, List<ItemInfo> firstScreenItems)81     public void sendBroadcasts(Context context, List<ItemInfo> firstScreenItems) {
82         UserHandle myUser = myUserHandle();
83         mSessionInfoForPackage
84                 .values()
85                 .stream()
86                 .filter(info -> myUser.equals(getUserHandle(info)))
87                 .collect(groupingBy(SessionInfo::getInstallerPackageName,
88                         mapping(SessionInfo::getAppPackageName, Collectors.toSet())))
89                 .forEach((installer, packages) ->
90                     sendBroadcastToInstaller(context, installer, packages, firstScreenItems));
91     }
92 
93     /**
94      * @param installerPackageName Package name of the package installer.
95      * @param packages List of packages with active sessions for this package installer.
96      * @param firstScreenItems List of items on the first screen.
97      */
sendBroadcastToInstaller(Context context, String installerPackageName, Set<String> packages, List<ItemInfo> firstScreenItems)98     private void sendBroadcastToInstaller(Context context, String installerPackageName,
99             Set<String> packages, List<ItemInfo> firstScreenItems) {
100         Set<String> folderItems = new HashSet<>();
101         Set<String> workspaceItems = new HashSet<>();
102         Set<String> hotseatItems = new HashSet<>();
103         Set<String> widgetItems = new HashSet<>();
104 
105         for (ItemInfo info : firstScreenItems) {
106             if (info instanceof FolderInfo) {
107                 FolderInfo folderInfo = (FolderInfo) info;
108                 String folderItemInfoPackage;
109                 for (ItemInfo folderItemInfo : folderInfo.contents) {
110                     folderItemInfoPackage = getPackageName(folderItemInfo);
111                     if (folderItemInfoPackage != null
112                             && packages.contains(folderItemInfoPackage)) {
113                         folderItems.add(folderItemInfoPackage);
114                     }
115                 }
116             }
117 
118             String packageName = getPackageName(info);
119             if (packageName == null || !packages.contains(packageName)) {
120                 continue;
121             }
122             if (info instanceof LauncherAppWidgetInfo) {
123                 widgetItems.add(packageName);
124             } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
125                 hotseatItems.add(packageName);
126             } else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
127                 workspaceItems.add(packageName);
128             }
129         }
130 
131         if (DEBUG) {
132             printList(installerPackageName, "Folder item", folderItems);
133             printList(installerPackageName, "Workspace item", workspaceItems);
134             printList(installerPackageName, "Hotseat item", hotseatItems);
135             printList(installerPackageName, "Widget item", widgetItems);
136         }
137 
138         context.sendBroadcast(new Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS)
139                 .setPackage(installerPackageName)
140                 .putStringArrayListExtra(FOLDER_ITEM_EXTRA, new ArrayList<>(folderItems))
141                 .putStringArrayListExtra(WORKSPACE_ITEM_EXTRA, new ArrayList<>(workspaceItems))
142                 .putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems))
143                 .putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems))
144                 .putExtra(VERIFICATION_TOKEN_EXTRA, PendingIntent.getActivity(context, 0,
145                         new Intent(), FLAG_ONE_SHOT | FLAG_IMMUTABLE)));
146     }
147 
getPackageName(ItemInfo info)148     private static String getPackageName(ItemInfo info) {
149         String packageName = null;
150         if (info instanceof LauncherAppWidgetInfo) {
151             LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
152             if (widgetInfo.providerName != null) {
153                 packageName = widgetInfo.providerName.getPackageName();
154             }
155         } else if (info.getTargetComponent() != null){
156             packageName = info.getTargetComponent().getPackageName();
157         }
158         return packageName;
159     }
160 
printList(String packageInstaller, String label, Set<String> packages)161     private static void printList(String packageInstaller, String label, Set<String> packages) {
162         for (String pkg : packages) {
163             Log.d(TAG, packageInstaller + ":" + label + ":" + pkg);
164         }
165     }
166 }
167