CellLayout, ICONS, folders, and widgets are the binding process of the desktop CellLayout. This is mainly the binding process of the desktop CellLayout. When users install a new application, or update an application, the binding process of CellLayout is the first time. Or what happens on the desktop when you uninstall an application. Today we’re going to look at the process.

We know that the installation and update of applications are started through the app market, while the uninstallation of applications is started through the desktop or system app management, so we will talk about the installation and update of applications together, and the uninstallation of applications separately. First let’s take a look at desktop data loading during application installation and update.

Application installation and updates


When we install or update an application through the application market, the installation interface of the system will be called and the installation program will be executed. After the application is installed or updated, the system will send out the corresponding broadcast, and the corresponding loader will be executed through the corresponding broadcast Launcher. LauncherAppsCompat is a compatible library for App management, which includes an interface and abstract methods. The main interface we use is the LauncherAppsCompat interface and two abstract methods:

Interface class:

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);
    }
Copy the code

As you can see from the methods in this interface, this is how apps are removed, added, changed, available, and unavailable.

Abstract method:

 public abstract void addOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
 public abstract void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
Copy the code

These two methods are mainly to add and remove app-managed listeners.

We see that LauncherAppsCompat is an abstract class, so let’s see where the method is implemented:

From the figure above we can see that there are two classes that inherit from this abstract class: LauncherAppsCompatV16 and LauncherAppsCompatVL are compatable for compatvl and API versions. LauncherAppsCompatV16 is a compatcompatability for any system that has an SDK version higher than 16 and less than 21. LauncherAppsCompatVL is for systems with SDK versions higher than 21 to compatvl, so there is an abstract method in their parent class:

 public abstract List<LauncherActivityInfoCompat> getActivityList(String packageName, UserHandleCompat user);
Copy the code

This method is a way to get all the applications in the system, let’s see how this works in different versions, starting with LauncherAppsCompatV16:

 public List<LauncherActivityInfoCompat> getActivityList(String packageName, UserHandleCompat user) {
        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        mainIntent.setPackage(packageName);
        List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0);
        List<LauncherActivityInfoCompat> list =
                new ArrayList<LauncherActivityInfoCompat>(infos.size());
        for (ResolveInfo info : infos) {
            list.add(new LauncherActivityInfoCompatV16(mContext, info));
        }
        return list;
    }
Copy the code

The approach is to query all applications through package management, and then collect all application information based on a loop.

And LauncherAppsCompatVL:

public List<LauncherActivityInfoCompat> getActivityList(String packageName, UserHandleCompat user) {
        List<LauncherActivityInfo> list = mLauncherApps.getActivityList(packageName,
                user.getUser());
        if (list.size() == 0) {
            return Collections.emptyList();
        }
        ArrayList<LauncherActivityInfoCompat> compatList =
                new ArrayList<LauncherActivityInfoCompat>(list.size());
        for (LauncherActivityInfo info : list) {
            compatList.add(new LauncherActivityInfoCompatVL(info));
        }
        return compatList;
    }
Copy the code

In this method, the list information is passed directly through mLauncherApps, so let’s look at the API documentation. When did the launcherApps start?

As you can see, it was only added when Api was 21, so let’s take a look at the main methods in this class;

public class LauncherApps {...public static abstract class Callback {
       
        abstract public void onPackageRemoved(String packageName, UserHandle user);
        
        abstract public void onPackageAdded(String packageName, UserHandle user);
        
        abstract public void onPackageChanged(String packageName, UserHandle user);

        abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
                boolean replacing);

        abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
                boolean replacing);
    }
    
    public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {... }private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {

        @Override
        public void onPackageRemoved(UserHandle user, String packageName)
                throws RemoteException {... }@Override
        public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {... }@Override
        public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {... }@Override
        public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
                throws RemoteException {... }@Override
        public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
                throws RemoteException {... }}};private static class CallbackMessageHandler extends Handler {...@Override
        public void handleMessage(Message msg) {
            if (mCallback == null| |! (msg.objinstanceof CallbackInfo)) {
                return;
            }
            CallbackInfo info = (CallbackInfo) msg.obj;
            switch (msg.what) {
                case MSG_ADDED:
                    mCallback.onPackageAdded(info.packageName, info.user);
                    break;
                case MSG_REMOVED:
                    mCallback.onPackageRemoved(info.packageName, info.user);
                    break;
                case MSG_CHANGED:
                    mCallback.onPackageChanged(info.packageName, info.user);
                    break;
                case MSG_AVAILABLE:
                    mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
                    break;
                case MSG_UNAVAILABLE:
                    mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
                    break; }}public void postOnPackageAdded(String packageName, UserHandle user) {... }public void postOnPackageRemoved(String packageName, UserHandle user) {... }public void postOnPackageChanged(String packageName, UserHandle user) {... }public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
                boolean replacing) {... }public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
                boolean replacing) {... }}}Copy the code

In this class, Google engineers directly encapsulated the method of finding all application information and the method of App package management, that is, the abstract method in the class Callback, which is the same as the interface in the compatibility library we mentioned above, except that before 21, we wrote it by ourselves, and after 21, the system did the processing for us. Let’s just implement it.

LauncherAppsCompatVL

private static class WrappedCallback extends LauncherApps.Callback {... }Copy the code

This callback class is the method that implements app management, so let’s look at how LauncherAppsCompat16 can do this:

@Thunk
class PackageMonitor extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {...if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)
                    || Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                ...
                if(Intent.ACTION_PACKAGE_CHANGED.equals(action)) { ... callback.onPackageChanged(packageName, user); . }else if(Intent.ACTION_PACKAGE_REMOVED.equals(action)) { ... callback.onPackageRemoved(packageName, user); . }else if(Intent.ACTION_PACKAGE_ADDED.equals(action)) { ... callback.onPackageChanged(packageName, user); . }}else if(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { ... callback.onPackagesAvailable(packages, user, replacing); . }else if(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { ... callback.onPackagesUnavailable(packages, user, replacing); . }}}Copy the code

At this point we can see that this is done by receiving the broadcast and then calling back to a different method. Callback (); callback (); callback (); callback ();

public synchronized void addOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {... }Copy the code

This method is called from LauncherAppState:

LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);
Copy the code

LauncherAppsCompatVL is also called on the compatvl, so we don’t have to look at it to find out for yourself. The code in the LauncherModel is as follows:

@Override
    public void onPackageChanged(String packageName, UserHandleCompat user) {
        int op = PackageUpdatedTask.OP_UPDATE;
        enqueuePackageUpdated(new PackageUpdatedTask(op, new String[]{packageName},
                user));
    }

    @Override
    public void onPackageRemoved(String packageName, UserHandleCompat user) {
        int op = PackageUpdatedTask.OP_REMOVE;
        enqueuePackageUpdated(new PackageUpdatedTask(op, new String[]{packageName},
                user));
    }

    @Override
    public void onPackageAdded(String packageName, UserHandleCompat user) {
        int op = PackageUpdatedTask.OP_ADD;
        enqueuePackageUpdated(new PackageUpdatedTask(op, newString[]{packageName}, user)); }...Copy the code

Through the code above we know the end is called PackageUpdatedTask this task execution, just different the incoming parameters, the task code in many don’t stick, I simply introduce the task execution process, first is to distinguish the received radio installation, update, remove or unavailable, then perform different processing to the operation of the different, To add the call addAppsToAllApps this method for processing, finally calling callbacks. BindAppsAdded method binding, update the call callbacks. BindAppsUpdated this method to update operation, the code is very simple, Take a look yourself, for uninstall, update the icon cache, remove it, in these operations at the same time, to return the data update operation, if there are widgets, also want to do the corresponding operation on widgets.

Application uninstallation


In the native desktop uninstall application, the icon is dropped to the uninstall box to uninstall. We will explain the operation process in detail later. In this case, we will directly look at the handling of the drop to the corresponding position.

There are three implementations here, and actually the last one, as you can tell from the name, is the implementation of the uninstall application,

void completeDrop(final DragObject d) {...if (startUninstallActivity(mLauncher, d.dragInfo)) {

            final Runnable checkIfUninstallWasSuccess = new Runnable() {
                @Override
                public void run(a) {
                    String packageName = componentInfo.first.getPackageName();
                    boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
                            getContext(), packageName, user);
                    sendUninstallResult(d.dragSource, uninstallSuccessful);
                }
            };
            mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess);
        } else {
            sendUninstallResult(d.dragSource, false); }}Copy the code

First determines startUninstallActivity, call startApplicationUninstallActivity method this method, if it is a system application returns false, if not start unloading interface and returns true, The uninstallation interface is started with the intent. ACTION_DELETE action. If the uninstallation is successful, check whether the uninstallation is successful when you return to the desktop or cancel the uninstallation and call sendUninstallResult. OnUninstallActivityReturned callback function called in this method, the callback function is implemented in a Folder or workspace, actually code these two places are the same, the last is executed onDropCompleted method, if removed successfully, The removeWorkspaceItem method is called, which removes the corresponding icon from CellLayout and, if unsuccessful, refreshes the UI, putting the corresponding icon back in place.

For the system how to uninstall the application here will not speak, interested can go to see the source code processing.

The last


Github address: github.com/yuchuangu85…