Android Launcher 应用的安装、更新、移除介绍--LauncherAppsCompat
说明
当进行Laucher开发时,不可避免的需要对应用的安装、移除、更新等进行处理,此时我们用到了LauncherAppsCompat。由于Android 21前后对于应用更新操作的处理有所不同,所以LauncherAppsCompat只声明了抽像方法面由其子类来实现,子类为LauncherAppsCompatVL、LauncherAppsCompatV16。
LauncherAppsCompatVL针对Android 21 及以上版本的实现方法
LauncherAppsCompatV16 对于Android 16到21版本的实现方法
实现方法
LauncherAppsCompat
LauncherAppsCompat声明为单例模式,在取得单例的时候需要判断Android的版本号,当Android版本号>=21时直接声明返回 LauncherAppsCompatVL,否则返回LauncherAppsCompatV16代码如下:
public static LauncherAppsCompat getInstance(Context context) {
synchronized (sInstanceLock) {
if (sInstance == null) {
if (Utilities.ATLEAST_LOLLIPOP) {
sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
} else {
sInstance = new LauncherAppsCompatV16(context.getApplicationContext());
}
}
return sInstance;
}
}
在LauncherAppsCompat 中声明对于应用的处理
public interface OnAppsChangedCallbackCompat {
//应用移除
void onPackageRemoved(String packageName, UserHandleCompat user);
//应用添加
void onPackageAdded(String packageName, UserHandleCompat user);
//应用更新
void onPackageChanged(String packageName, UserHandleCompat user);
//应用移动
void onPackagesAvailable(String[] packageNames, UserHandleCompat user, boolean replacing);
//应用移动过程当中
void onPackagesUnavailable(String[] packageNames, UserHandleCompat user, boolean replacing);
}
说明:UserHandleCompat 是UserHandle的实现类,UserHandler是针对多用户的类。
LauncherAppsCompatV16
LauncherAppsCompatV16通过广播机制接收系统关于应用更新发送了来的广播,
LauncherAppsCompatV16 继承LauncherAppsCompat,在构造方法中注册广播并设置过滤条件接收应用更新广播,并调用父类的OnAppsChangedCallbackCompat接口。
广播注册代码如下:
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme(“package”);
mContext.registerReceiver(mPackageMonitor, filter);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mPackageMonitor, filter);
过滤条件说明:
Intent.ACTION_PACKAGE_REMOVED;
//成功的删除某个APK之后发出的广播
//一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)
Intent.ACTION_PACKAGE_CHANGED;
//一个已存在的应用程序包已经改变,包括包名
Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE;
移动APP完成之后,发出的广播(移动是指:APP2SD)
Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
//正在移动APP时,发出的广播(移动是指:APP2SD)
广播接收对于不现条件下的action分别处理,实现代码如下:
@Thunk
class PackageMonitor extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(TAG, "onReceive: " + action + " - " + intent.getData().toString());
final UserHandleCompat user = UserHandleCompat.myUserHandle();
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
|| Intent.ACTION_PACKAGE_REMOVED.equals(action)
|| Intent.ACTION_PACKAGE_ADDED.equals(action)) {
final String packageName = intent.getData().getSchemeSpecificPart();
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (packageName == null || packageName.length() == 0) {
// they sent us a bad intent
return;
}
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
callback.onPackageChanged(packageName, user);
}
} else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
if (!replacing) {
for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
callback.onPackageRemoved(packageName, user);
}
}
// else, we are replacing the package, so a PACKAGE_ADDED will be sent
// later, we will update the package at this time
} else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
if (!replacing) {
for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
callback.onPackageAdded(packageName, user);
}
} else {
for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
callback.onPackageChanged(packageName, user);
}
}
}
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
// EXTRA_REPLACING is available Kitkat onwards. For lower devices, it is broadcasted
// when moving a package or mounting/un-mounting external storage. Assume that
// it is a replacing operation.
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING,
!Utilities.ATLEAST_KITKAT);
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
callback.onPackagesAvailable(packages, user, replacing);
}
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
// This intent is broadcasted when moving a package or mounting/un-mounting
// external storage.
// However on Kitkat this is also sent when a package is being updated, and
// contains an extra Intent.EXTRA_REPLACING=true for that case.
// Using false as default for Intent.EXTRA_REPLACING gives correct value on
// lower devices as the intent is not sent when the app is updating/replacing.
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
callback.onPackagesUnavailable(packages, user, replacing);
}
}
}
}
LauncherAppsCompatVL
LauncherAppsCompatVL继承LauncherAppsCompat并利用回调方法处理应用更新的消息
LauncherAppsCompatVL 在构造函数中获取系统服务"launcherapps",实现回调函数代码如下:
private static class WrappedCallback extends LauncherApps.Callback {
private LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback;
public WrappedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
mCallback = callback;
}
public void onPackageRemoved(String packageName, UserHandle user) {
mCallback.onPackageRemoved(packageName, UserHandleCompat.fromUser(user));
}
public void onPackageAdded(String packageName, UserHandle user) {
mCallback.onPackageAdded(packageName, UserHandleCompat.fromUser(user));
}
public void onPackageChanged(String packageName, UserHandle user) {
mCallback.onPackageChanged(packageName, UserHandleCompat.fromUser(user));
}
public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
mCallback.onPackagesAvailable(packageNames, UserHandleCompat.fromUser(user), replacing);
}
public void onPackagesUnavailable(String[] packageNames, UserHandle user,
boolean replacing) {
mCallback.onPackagesUnavailable(packageNames, UserHandleCompat.fromUser(user),
replacing);
}
}
总结
以上LauncherAppsCompat需要在LaucherMode中注册使用。