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.wallpaper.module; 17 18 import android.content.Context; 19 import android.content.Intent; 20 import android.content.pm.LauncherApps; 21 import android.content.pm.PackageManager; 22 import android.os.UserHandle; 23 24 import java.util.HashMap; 25 import java.util.Map; 26 27 /** 28 * Default version of {@link PackageStatusNotifier} that uses {@link LauncherApps} 29 */ 30 public class DefaultPackageStatusNotifier implements PackageStatusNotifier { 31 32 private final Map<Listener, ListenerWrapper> mListeners = new HashMap<>(); 33 private final Context mAppContext; 34 private final LauncherApps mLauncherApps; 35 36 DefaultPackageStatusNotifier(Context context)37 public DefaultPackageStatusNotifier(Context context) { 38 mAppContext = context.getApplicationContext(); 39 mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); 40 } 41 42 @Override addListener(Listener listener, String action)43 public void addListener(Listener listener, String action) { 44 ListenerWrapper wrapper = new ListenerWrapper(mAppContext, action, listener); 45 removeListenerAndMaybeUnregisterCallback(listener); 46 mListeners.put(listener, wrapper); 47 mLauncherApps.registerCallback(wrapper); 48 } 49 50 @Override removeListener(Listener listener)51 public void removeListener(Listener listener) { 52 removeListenerAndMaybeUnregisterCallback(listener); 53 } 54 removeListenerAndMaybeUnregisterCallback(Listener listener)55 private void removeListenerAndMaybeUnregisterCallback(Listener listener) { 56 ListenerWrapper oldWrapper = mListeners.remove(listener); 57 if (oldWrapper != null) { 58 mLauncherApps.unregisterCallback(oldWrapper); 59 } 60 } 61 62 private static class ListenerWrapper extends LauncherApps.Callback { 63 64 private final Context mAppContext; 65 private final Intent mIntentFilter; 66 private final Listener mListener; 67 ListenerWrapper(Context context, String action, Listener listener)68 ListenerWrapper(Context context, String action, Listener listener) { 69 mAppContext = context.getApplicationContext(); 70 mIntentFilter = new Intent(action); 71 mListener = listener; 72 } 73 isValidPackage(String packageName)74 private boolean isValidPackage(String packageName) { 75 mIntentFilter.setPackage(packageName); 76 PackageManager pm = mAppContext.getPackageManager(); 77 return !pm.queryIntentServices(mIntentFilter, 0).isEmpty() 78 || !pm.queryIntentActivities(mIntentFilter, 0).isEmpty(); 79 } 80 81 82 @Override onPackageRemoved(String packageName, UserHandle userHandle)83 public void onPackageRemoved(String packageName, UserHandle userHandle) { 84 // We can't check if the removed package is "valid" for the given action, as it's not 85 // there any more, so trigger REMOVED for all cases. 86 mListener.onPackageChanged(packageName, PackageStatus.REMOVED); 87 } 88 89 @Override onPackageAdded(String packageName, UserHandle userHandle)90 public void onPackageAdded(String packageName, UserHandle userHandle) { 91 if (isValidPackage(packageName)) { 92 mListener.onPackageChanged(packageName, PackageStatus.ADDED); 93 } 94 } 95 96 @Override onPackageChanged(String packageName, UserHandle userHandle)97 public void onPackageChanged(String packageName, UserHandle userHandle) { 98 if (isValidPackage(packageName)) { 99 mListener.onPackageChanged(packageName, PackageStatus.CHANGED); 100 } 101 } 102 103 @Override onPackagesAvailable(String[] packageNames, UserHandle userHandle, boolean replacing)104 public void onPackagesAvailable(String[] packageNames, UserHandle userHandle, 105 boolean replacing) { 106 for (String packageName : packageNames) { 107 if (isValidPackage(packageName)) { 108 mListener.onPackageChanged(packageName, 109 replacing ? PackageStatus.CHANGED : PackageStatus.ADDED); 110 } 111 } 112 } 113 114 @Override onPackagesUnavailable(String[] packageNames, UserHandle userHandle, boolean replacing)115 public void onPackagesUnavailable(String[] packageNames, UserHandle userHandle, 116 boolean replacing) { 117 for (String packageName : packageNames) { 118 if (!replacing && isValidPackage(packageName)) { 119 mListener.onPackageChanged(packageName, PackageStatus.REMOVED); 120 } 121 } 122 } 123 124 @Override onPackagesSuspended(String[] packageNames, UserHandle user)125 public void onPackagesSuspended(String[] packageNames, UserHandle user) { 126 for (String packageName : packageNames) { 127 if (isValidPackage(packageName)) { 128 mListener.onPackageChanged(packageName, PackageStatus.REMOVED); 129 } 130 } 131 } 132 133 @Override onPackagesUnsuspended(String[] packageNames, UserHandle user)134 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) { 135 for (String packageName : packageNames) { 136 if (isValidPackage(packageName)) { 137 mListener.onPackageChanged(packageName, PackageStatus.ADDED); 138 } 139 } 140 } 141 } 142 } 143