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