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.content.Context; 20 import android.content.SharedPreferences; 21 import android.content.pm.LauncherActivityInfo; 22 import android.os.UserHandle; 23 24 import com.android.launcher3.Utilities; 25 import com.android.launcher3.compat.LauncherAppsCompat; 26 import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat; 27 import com.android.launcher3.compat.UserManagerCompat; 28 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 import java.util.Collections; 32 import java.util.HashSet; 33 import java.util.List; 34 import java.util.Set; 35 36 /** 37 * Utility class to track list of installed packages. It persists the list so that apps 38 * installed/uninstalled while Launcher was dead can also be handled properly. 39 */ 40 public abstract class CachedPackageTracker implements OnAppsChangedCallbackCompat { 41 42 protected static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_"; 43 44 protected final SharedPreferences mPrefs; 45 protected final UserManagerCompat mUserManager; 46 protected final LauncherAppsCompat mLauncherApps; 47 CachedPackageTracker(Context context, String preferenceFileName)48 public CachedPackageTracker(Context context, String preferenceFileName) { 49 mPrefs = context.getSharedPreferences(preferenceFileName, Context.MODE_PRIVATE); 50 mUserManager = UserManagerCompat.getInstance(context); 51 mLauncherApps = LauncherAppsCompat.getInstance(context); 52 } 53 54 /** 55 * Checks the list of user apps, and generates package event accordingly. 56 * {@see #onLauncherAppsAdded}, {@see #onLauncherPackageRemoved} 57 */ processUserApps(List<LauncherActivityInfo> apps, UserHandle user)58 public void processUserApps(List<LauncherActivityInfo> apps, UserHandle user) { 59 String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); 60 HashSet<String> oldPackageSet = new HashSet<>(); 61 final boolean userAppsExisted = getUserApps(oldPackageSet, prefKey); 62 63 HashSet<String> packagesRemoved = new HashSet<>(oldPackageSet); 64 HashSet<String> newPackageSet = new HashSet<>(); 65 ArrayList<LauncherActivityInstallInfo> packagesAdded = new ArrayList<>(); 66 67 for (LauncherActivityInfo info : apps) { 68 String packageName = info.getComponentName().getPackageName(); 69 newPackageSet.add(packageName); 70 packagesRemoved.remove(packageName); 71 72 if (!oldPackageSet.contains(packageName)) { 73 oldPackageSet.add(packageName); 74 packagesAdded.add(new LauncherActivityInstallInfo( 75 info, info.getFirstInstallTime())); 76 } 77 } 78 79 if (!packagesAdded.isEmpty() || !packagesRemoved.isEmpty()) { 80 mPrefs.edit().putStringSet(prefKey, newPackageSet).apply(); 81 82 if (!packagesAdded.isEmpty()) { 83 Collections.sort(packagesAdded); 84 onLauncherAppsAdded(packagesAdded, user, userAppsExisted); 85 } 86 87 if (!packagesRemoved.isEmpty()) { 88 for (String pkg : packagesRemoved) { 89 onLauncherPackageRemoved(pkg, user); 90 } 91 } 92 } 93 } 94 95 /** 96 * Reads the list of user apps which have already been processed. 97 * @return false if the list didn't exist, true otherwise 98 */ getUserApps(HashSet<String> outExistingApps, String prefKey)99 private boolean getUserApps(HashSet<String> outExistingApps, String prefKey) { 100 Set<String> userApps = mPrefs.getStringSet(prefKey, null); 101 if (userApps == null) { 102 return false; 103 } else { 104 outExistingApps.addAll(userApps); 105 return true; 106 } 107 } 108 109 @Override onPackageRemoved(String packageName, UserHandle user)110 public void onPackageRemoved(String packageName, UserHandle user) { 111 String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); 112 HashSet<String> packageSet = new HashSet<>(); 113 if (getUserApps(packageSet, prefKey) && packageSet.remove(packageName)) { 114 mPrefs.edit().putStringSet(prefKey, packageSet).apply(); 115 } 116 117 onLauncherPackageRemoved(packageName, user); 118 } 119 120 @Override onPackageAdded(String packageName, UserHandle user)121 public void onPackageAdded(String packageName, UserHandle user) { 122 String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); 123 HashSet<String> packageSet = new HashSet<>(); 124 final boolean userAppsExisted = getUserApps(packageSet, prefKey); 125 if (!packageSet.contains(packageName)) { 126 List<LauncherActivityInfo> activities = 127 mLauncherApps.getActivityList(packageName, user); 128 if (!activities.isEmpty()) { 129 LauncherActivityInfo activityInfo = activities.get(0); 130 131 packageSet.add(packageName); 132 mPrefs.edit().putStringSet(prefKey, packageSet).apply(); 133 onLauncherAppsAdded(Arrays.asList( 134 new LauncherActivityInstallInfo(activityInfo, System.currentTimeMillis())), 135 user, userAppsExisted); 136 } 137 } 138 } 139 140 @Override onPackageChanged(String packageName, UserHandle user)141 public void onPackageChanged(String packageName, UserHandle user) { } 142 143 @Override onPackagesAvailable( String[] packageNames, UserHandle user, boolean replacing)144 public void onPackagesAvailable( 145 String[] packageNames, UserHandle user, boolean replacing) { } 146 147 @Override onPackagesUnavailable( String[] packageNames, UserHandle user, boolean replacing)148 public void onPackagesUnavailable( 149 String[] packageNames, UserHandle user, boolean replacing) { } 150 151 @Override onPackagesSuspended(String[] packageNames, UserHandle user)152 public void onPackagesSuspended(String[] packageNames, UserHandle user) { } 153 154 @Override onPackagesUnsuspended(String[] packageNames, UserHandle user)155 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) { } 156 157 /** 158 * Called when new launcher apps are added. 159 * @param apps list of newly added activities. Only one entry per package is sent. 160 * @param user the user for this event. All activities in {@param apps} will belong to 161 * the same user. 162 * @param userAppsExisted false if the list was processed for the first time, like in case 163 * when Launcher was newly installed or a new user was added. 164 */ onLauncherAppsAdded(List<LauncherActivityInstallInfo> apps, UserHandle user, boolean userAppsExisted)165 protected abstract void onLauncherAppsAdded(List<LauncherActivityInstallInfo> apps, 166 UserHandle user, boolean userAppsExisted); 167 168 /** 169 * Called when apps are removed from the system. 170 */ onLauncherPackageRemoved(String packageName, UserHandle user)171 protected abstract void onLauncherPackageRemoved(String packageName, UserHandle user); 172 173 public static class LauncherActivityInstallInfo 174 implements Comparable<LauncherActivityInstallInfo> { 175 public final LauncherActivityInfo info; 176 public final long installTime; 177 LauncherActivityInstallInfo(LauncherActivityInfo info, long installTime)178 public LauncherActivityInstallInfo(LauncherActivityInfo info, long installTime) { 179 this.info = info; 180 this.installTime = installTime; 181 } 182 183 @Override compareTo(LauncherActivityInstallInfo another)184 public int compareTo(LauncherActivityInstallInfo another) { 185 return Utilities.longCompare(installTime, another.installTime); 186 } 187 } 188 } 189