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