AllAppsList.java revision 054019dbeafd33de4e39601e0f305926c15bad15
19c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato/* 29c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Copyright (C) 2008 The Android Open Source Project 39c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * 49c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Licensed under the Apache License, Version 2.0 (the "License"); 59c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * you may not use this file except in compliance with the License. 69c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * You may obtain a copy of the License at 79c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * 89c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * http://www.apache.org/licenses/LICENSE-2.0 99c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * 109c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Unless required by applicable law or agreed to in writing, software 119c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * distributed under the License is distributed on an "AS IS" BASIS, 129c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * See the License for the specific language governing permissions and 149c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * limitations under the License. 159c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 169c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 179c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratopackage com.android.launcher2; 189c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 199c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoimport android.content.ComponentName; 209c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoimport android.content.Intent; 219c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoimport android.content.Context; 229c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoimport android.content.pm.ActivityInfo; 239c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoimport android.content.pm.PackageManager; 249c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoimport android.content.pm.ResolveInfo; 259c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 269c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoimport java.util.ArrayList; 27dca661236c73ecd819cfea964c6f8170e5cc40aeDaniel Sandlerimport java.util.Collections; 289c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoimport java.util.List; 299c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 309c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 319c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato/** 329c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Stores the list of all applications for the all apps view. 339c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 349c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onoratoclass AllAppsList { 359c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato public static final int DEFAULT_APPLICATIONS_NUMBER = 42; 369c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 379c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** The list off all apps. */ 385c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy public ArrayList<ApplicationInfo> data = 395c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER); 409c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** The list of apps that have been added since the last notify() call. */ 415c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy public ArrayList<ApplicationInfo> added = 425c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER); 439c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** The list of apps that have been removed since the last notify() call. */ 445c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy public ArrayList<ApplicationInfo> removed = new ArrayList<ApplicationInfo>(); 459c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** The list of apps that have been modified since the last notify() call. */ 465c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy public ArrayList<ApplicationInfo> modified = new ArrayList<ApplicationInfo>(); 479c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 480589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato private IconCache mIconCache; 490589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato 509c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** 519c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Boring constructor. 529c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 530589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato public AllAppsList(IconCache iconCache) { 540589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato mIconCache = iconCache; 559c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 569c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 579c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** 589c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Add the supplied ApplicationInfo objects to the list, and enqueue it into the 599c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * list to broadcast when notify() is called. 609c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 619c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato public void add(ApplicationInfo info) { 62054019dbeafd33de4e39601e0f305926c15bad15Daniel Sandler data.add(info); 63054019dbeafd33de4e39601e0f305926c15bad15Daniel Sandler added.add(info); 649c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 659c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 669c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato public void clear() { 679c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato data.clear(); 689c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato // TODO: do we clear these too? 699c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato added.clear(); 709c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato removed.clear(); 719c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato modified.clear(); 729c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 739c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 749c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato public int size() { 759c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato return data.size(); 769c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 779c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 789c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato public ApplicationInfo get(int index) { 799c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato return data.get(index); 809c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 819c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 829c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** 839c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Add the icons for the supplied apk called packageName. 849c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 859c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato public void addPackage(Context context, String packageName) { 869c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName); 879c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 889c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (matches.size() > 0) { 899c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato for (ResolveInfo info : matches) { 90dca661236c73ecd819cfea964c6f8170e5cc40aeDaniel Sandler add(new ApplicationInfo(info, mIconCache)); 919c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 929c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 939c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 949c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 959c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** 969c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Remove the apps for the given apk identified by packageName. 979c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 989c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato public void removePackage(String packageName) { 999c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final List<ApplicationInfo> data = this.data; 1005c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy for (int i = data.size() - 1; i >= 0; i--) { 1019c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato ApplicationInfo info = data.get(i); 1029c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final ComponentName component = info.intent.getComponent(); 1039c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (packageName.equals(component.getPackageName())) { 1049c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato removed.add(info); 1059c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato data.remove(i); 1069c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1079c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1089c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato // This is more aggressive than it needs to be. 1090589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato mIconCache.flush(); 1109c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1110589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato 1129c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** 1139c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Add and remove icons for this package which has been updated. 1149c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 1159c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato public void updatePackage(Context context, String packageName) { 1169c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName); 1179c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (matches.size() > 0) { 1189c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato // Find disabled/removed activities and remove them from data and add them 1199c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato // to the removed list. 1205c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy for (int i = data.size() - 1; i >= 0; i--) { 1219c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final ApplicationInfo applicationInfo = data.get(i); 1229c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final ComponentName component = applicationInfo.intent.getComponent(); 1239c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (packageName.equals(component.getPackageName())) { 1249c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (!findActivity(matches, component)) { 1259c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato removed.add(applicationInfo); 1260589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato mIconCache.remove(component); 1279c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato data.remove(i); 1289c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1299c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1309c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1319c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 1329c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato // Find enabled activities and add them to the adapter 1339c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato // Also updates existing activities with new labels/icons 1349c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato int count = matches.size(); 1355c16f3ecd6b47bff3abbe40deb3d39c66a3b0012Romain Guy for (int i = 0; i < count; i++) { 1369c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final ResolveInfo info = matches.get(i); 1379c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato ApplicationInfo applicationInfo = findApplicationInfoLocked( 1389c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato info.activityInfo.applicationInfo.packageName, 1399c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato info.activityInfo.name); 1409c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (applicationInfo == null) { 141dca661236c73ecd819cfea964c6f8170e5cc40aeDaniel Sandler add(new ApplicationInfo(info, mIconCache)); 1429c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } else { 1430589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato mIconCache.remove(applicationInfo.componentName); 1440589f0f66ce498512c6ee47482c649d88294c9d0Joe Onorato mIconCache.getTitleAndIcon(applicationInfo, info); 1459c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato modified.add(applicationInfo); 1469c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1479c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1489c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1499c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1509c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 1519c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** 1529c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Query the package manager for MAIN/LAUNCHER activities in the supplied package. 1539c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 1549c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato private static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) { 1559c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final PackageManager packageManager = context.getPackageManager(); 1569c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 1579c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 1589c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 1599c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 1609c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0); 1619c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final List<ResolveInfo> matches = new ArrayList<ResolveInfo>(); 1629c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 1639c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (apps != null) { 1649c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato // Find all activities that match the packageName 1659c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato int count = apps.size(); 1669c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato for (int i = 0; i < count; i++) { 1679c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final ResolveInfo info = apps.get(i); 1689c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final ActivityInfo activityInfo = info.activityInfo; 1699c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (packageName.equals(activityInfo.packageName)) { 1709c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato matches.add(info); 1719c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1729c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1739c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1749c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 1759c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato return matches; 1769c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1779c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 1789c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** 1799c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Returns whether <em>apps</em> contains <em>component</em>. 1809c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 1819c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato private static boolean findActivity(List<ResolveInfo> apps, ComponentName component) { 1829c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final String className = component.getClassName(); 1839c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato for (ResolveInfo info : apps) { 1849c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final ActivityInfo activityInfo = info.activityInfo; 1859c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (activityInfo.name.equals(className)) { 1869c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato return true; 1879c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1889c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1899c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato return false; 1909c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 1919c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato 1929c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato /** 1939c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato * Find an ApplicationInfo object for the given packageName and className. 1949c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato */ 1959c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato private ApplicationInfo findApplicationInfoLocked(String packageName, String className) { 1969c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato for (ApplicationInfo info: data) { 1979c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato final ComponentName component = info.intent.getComponent(); 1989c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato if (packageName.equals(component.getPackageName()) 1999c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato && className.equals(component.getClassName())) { 2009c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato return info; 2019c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 2029c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 2039c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato return null; 2049c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato } 2059c1289cb3bfb74f86e53ec7ac6dd76bb39666b2dJoe Onorato} 206