diff --git a/app/src/main/java/fr/neamar/kiss/broadcast/PackageAddedRemovedHandler.java b/app/src/main/java/fr/neamar/kiss/broadcast/PackageAddedRemovedHandler.java index 528260157..9afe45da6 100644 --- a/app/src/main/java/fr/neamar/kiss/broadcast/PackageAddedRemovedHandler.java +++ b/app/src/main/java/fr/neamar/kiss/broadcast/PackageAddedRemovedHandler.java @@ -1,11 +1,19 @@ package fr.neamar.kiss.broadcast; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.preference.PreferenceManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.Set; + import fr.neamar.kiss.KissApplication; +import fr.neamar.kiss.pojo.AppPojo; +import fr.neamar.kiss.utils.PackageManagerUtils; import fr.neamar.kiss.utils.UserHandle; /** @@ -18,55 +26,89 @@ */ public class PackageAddedRemovedHandler extends BroadcastReceiver { - public static void handleEvent(Context ctx, String action, String packageName, UserHandle user, boolean replacing) { + public static void handleEvent(@NonNull Context ctx, @Nullable String action, @NonNull String[] packageNames, @NonNull UserHandle user, boolean replacing) { + if (packageNames.length == 1 && packageNames[0].equalsIgnoreCase(ctx.getPackageName())) { + // When running KISS locally, sending a new version of the APK immediately triggers a "package removed" for fr.neamar.kiss, + // There is no need to handle this event. + // Discarding it makes startup time much faster locally as apps don't have to be loaded twice. + return; + } + if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { if (!replacing) { - Intent launchIntent = ctx.getPackageManager().getLaunchIntentForPackage(packageName); - // launchIntent can be null for some plugin app - if (launchIntent != null) { - // Add new package to history - if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("enable-app-history", true)) { - String className = launchIntent.getComponent().getClassName(); - String pojoID = user.addUserSuffixToString("app://" + packageName + "/" + className, '/'); - KissApplication.getApplication(ctx).getDataHandler().addToHistory(pojoID); + for (String packageName : packageNames) { + Intent launchIntent = ctx.getPackageManager().getLaunchIntentForPackage(packageName); + // launchIntent can be null for some plugin app + if (launchIntent != null) { + // Add new package to history + if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("enable-app-history", true)) { + String className = launchIntent.getComponent().getClassName(); + String pojoID = user.addUserSuffixToString("app://" + packageName + "/" + className, '/'); + KissApplication.getApplication(ctx).getDataHandler().addToHistory(pojoID); + } } } } } - KissApplication.getApplication(ctx).resetIconsHandler(); - if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { if (!replacing) { + KissApplication.getApplication(ctx).resetIconsHandler(); // Reload application list KissApplication.getApplication(ctx).getDataHandler().reloadApps(); // Remove all installed shortcuts - KissApplication.getApplication(ctx).getDataHandler().removeShortcuts(packageName); - KissApplication.getApplication(ctx).getDataHandler().removeFromExcluded(packageName); + for (String packageName : packageNames) { + KissApplication.getApplication(ctx).getDataHandler().removeShortcuts(packageName); + KissApplication.getApplication(ctx).getDataHandler().removeFromExcluded(packageName); + } } } else { - // Reload application list - KissApplication.getApplication(ctx).getDataHandler().reloadApps(); - // Reload shortcuts - KissApplication.getApplication(ctx).getDataHandler().reloadShortcuts(); + KissApplication.getApplication(ctx).resetIconsHandler(); + + boolean isAnyPackageVisible = isAnyPackageVisible(ctx, packageNames, user); + if (isAnyPackageVisible) { + // Reload application list + KissApplication.getApplication(ctx).getDataHandler().reloadApps(); + // Reload shortcuts + KissApplication.getApplication(ctx).getDataHandler().reloadShortcuts(); + } + } + } + + /** + * @param ctx + * @param packageNames + * @param userHandle + * @return true, if any of packages has activity for launching and is not excluded from KISS + */ + private static boolean isAnyPackageVisible(Context ctx, String[] packageNames, UserHandle userHandle) { + Set excludedApps = KissApplication.getApplication(ctx).getDataHandler().getExcluded(); + for (String packageName : packageNames) { + ComponentName launchingComponent = PackageManagerUtils.getLaunchingComponent(ctx, packageName); + if (launchingComponent != null) { + boolean isExcluded = excludedApps.contains(AppPojo.getComponentName(launchingComponent.getPackageName(), launchingComponent.getClassName(), userHandle)); + if (!isExcluded) { + return true; + } + } } + return false; } @Override public void onReceive(Context ctx, Intent intent) { - - String packageName = intent.getData().getSchemeSpecificPart(); - - if (packageName.equalsIgnoreCase(ctx.getPackageName())) { - // When running KISS locally, sending a new version of the APK immediately triggers a "package removed" for fr.neamar.kiss, - // There is no need to handle this event. - // Discarding it makes startup time much faster locally as apps don't have to be loaded twice. + String[] packageNames = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + if (packageNames == null && intent.getData() != null) { + String packageName = intent.getData().getSchemeSpecificPart(); + packageNames = new String[]{packageName}; + } + if (packageNames == null) { return; } handleEvent(ctx, intent.getAction(), - packageName, new UserHandle(), + packageNames, new UserHandle(), intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) ); diff --git a/app/src/main/java/fr/neamar/kiss/dataprovider/AppProvider.java b/app/src/main/java/fr/neamar/kiss/dataprovider/AppProvider.java index 67822cf6b..366f543fa 100644 --- a/app/src/main/java/fr/neamar/kiss/dataprovider/AppProvider.java +++ b/app/src/main/java/fr/neamar/kiss/dataprovider/AppProvider.java @@ -6,7 +6,6 @@ import android.content.SharedPreferences; import android.content.pm.LauncherApps; import android.os.Build; -import android.os.Process; import android.os.UserManager; import android.preference.PreferenceManager; @@ -28,8 +27,6 @@ public class AppProvider extends Provider { @Override public void onCreate() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - // Package installation/uninstallation events for the main - // profile are still handled using PackageAddedRemovedHandler itself final UserManager manager = (UserManager) this.getSystemService(Context.USER_SERVICE); assert manager != null; @@ -39,71 +36,73 @@ public void onCreate() { launcher.registerCallback(new LauncherAppsCallback() { @Override public void onPackageAdded(String packageName, android.os.UserHandle user) { - handleEvent(Intent.ACTION_PACKAGE_ADDED, packageName, user, false); + handleEvent(Intent.ACTION_PACKAGE_ADDED, new String[]{packageName}, user, false); } @Override public void onPackageChanged(String packageName, android.os.UserHandle user) { - handleEvent(Intent.ACTION_PACKAGE_CHANGED, packageName, user, true); + handleEvent(Intent.ACTION_PACKAGE_CHANGED, new String[]{packageName}, user, true); } @Override public void onPackageRemoved(String packageName, android.os.UserHandle user) { - handleEvent(Intent.ACTION_PACKAGE_REMOVED, packageName, user, false); + handleEvent(Intent.ACTION_PACKAGE_REMOVED, new String[]{packageName}, user, false); } @Override public void onPackagesAvailable(String[] packageNames, android.os.UserHandle user, boolean replacing) { - handleEvent(Intent.ACTION_MEDIA_MOUNTED, null, user, replacing); + handleEvent(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE, packageNames, user, replacing); } @Override public void onPackagesSuspended(String[] packageNames, android.os.UserHandle user) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - handleEvent(Intent.ACTION_PACKAGES_SUSPENDED, null, user, false); + handleEvent(Intent.ACTION_PACKAGES_SUSPENDED, packageNames, user, false); } } @Override public void onPackagesUnsuspended(String[] packageNames, android.os.UserHandle user) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - handleEvent(Intent.ACTION_PACKAGES_UNSUSPENDED, null, user, false); + handleEvent(Intent.ACTION_PACKAGES_UNSUSPENDED, packageNames, user, false); } } @Override public void onPackagesUnavailable(String[] packageNames, android.os.UserHandle user, boolean replacing) { - handleEvent(Intent.ACTION_MEDIA_UNMOUNTED, null, user, replacing); + handleEvent(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE, packageNames, user, replacing); } - private void handleEvent(String action, String packageName, android.os.UserHandle user, boolean replacing) { - if (!Process.myUserHandle().equals(user)) { - PackageAddedRemovedHandler.handleEvent(AppProvider.this, - action, - packageName, new UserHandle(manager.getSerialNumberForUser(user), user), replacing - ); - } + private void handleEvent(String action, String[] packageNames, android.os.UserHandle user, boolean replacing) { + PackageAddedRemovedHandler.handleEvent(AppProvider.this, + action, + packageNames, new UserHandle(manager.getSerialNumberForUser(user), user), replacing + ); } }); + } else { + // Get notified when app changes on standard user profile + PackageAddedRemovedHandler packageAddedRemovedHandler = new PackageAddedRemovedHandler(); + + IntentFilter appChangedFilter = new IntentFilter(); + appChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + appChangedFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); + appChangedFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + appChangedFilter.addDataScheme("package"); + this.registerReceiver(packageAddedRemovedHandler, appChangedFilter); + + IntentFilter mediaChangedFilter = new IntentFilter(); + mediaChangedFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); + mediaChangedFilter.addAction(Intent.ACTION_MEDIA_REMOVED); + mediaChangedFilter.addDataScheme("file"); + this.registerReceiver(packageAddedRemovedHandler, mediaChangedFilter); + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + intentFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + this.registerReceiver(packageAddedRemovedHandler, intentFilter); } - // Get notified when app changes on standard user profile - IntentFilter appChangedFilter = new IntentFilter(); - appChangedFilter.addAction(Intent.ACTION_PACKAGE_ADDED); - appChangedFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); - appChangedFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); - appChangedFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); - appChangedFilter.addAction(Intent.ACTION_MEDIA_REMOVED); - appChangedFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); - appChangedFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - appChangedFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED); - appChangedFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED); - } - appChangedFilter.addDataScheme("package"); - appChangedFilter.addDataScheme("file"); - this.registerReceiver(new PackageAddedRemovedHandler(), appChangedFilter); - super.onCreate(); } diff --git a/fastlane/metadata/android/en-US/changelogs/209.txt b/fastlane/metadata/android/en-US/changelogs/209.txt index 7fda820ef..e15785e74 100644 --- a/fastlane/metadata/android/en-US/changelogs/209.txt +++ b/fastlane/metadata/android/en-US/changelogs/209.txt @@ -5,3 +5,4 @@ * Add operators '×x÷' back to the calculator * Fix popup menu position for widgets using whole screen * Fix reset of custom app name +* Fix listening on package changes