In the development of the Launcher, I sometimes need to hide the application icon display or hide the widget display of some applications. What should I do?

Launcher3 contains an abstract class called AppFilter, which is an app filter.

package com.codemx.launcher3;



import android.content.ComponentName;

import android.text.TextUtils;

import android.util.Log;



public abstract class AppFilter {



private static final boolean DBG = false;

private static final String TAG = "AppFilter";



public abstract boolean shouldShowApp(ComponentName app);



public static AppFilter loadByName(String className) {

if (TextUtils.isEmpty(className)) return null;

if (DBG) Log.d(TAG, "Loading AppFilter: " + className);

try {

Class<? > cls = Class.forName(className);

return (AppFilter) cls.newInstance();

} catch (ClassNotFoundException e) {

Log.e(TAG, "Bad AppFilter class", e);

return null;

} catch (InstantiationException e) {

Log.e(TAG, "Bad AppFilter class", e);

return null;

} catch (IllegalAccessException e) {

Log.e(TAG, "Bad AppFilter class", e);

return null;

} catch (ClassCastException e) {

Log.e(TAG, "Bad AppFilter class", e);

return null;

}

}



}

Copy the code

ShouldShowApp (shouldShowApp) provides a shouldShowApp (shouldShowApp) abstract method to determine which apps need to be displayed and filter through this method. A static loadByName method is also provided. The implementation instantiates an AppFilter by reflection based on className.

Now, which class inherits the abstract AppFilter class? A search found that the source code was not found. Since it is through loadByName instantiated then see where this method USES, finally found in LauncherAppState. Java calls in the constructor:

private LauncherAppState() {

.



mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class));

mBuildInfo = BuildInfo.loadByName(sContext.getString(R.string.build_info_class));

mModel = new LauncherModel(this, mIconCache, mAppFilter);



.

}

Copy the code

Scontext.getstring (r.string.app_filter_class) is a string resource. Let’s look at the string value in config.xml:

<! -- Name of a subclass of AppFilter used to

filter the activities shown in the launcher. Can be empty. -->

<string name="app_filter_class" translatable="false"></string>

Copy the code

Found that the configured value is empty, that is, there is no implementation class by default. Can we just write a class that inherits AppFilter and add it to this configuration? Write a simple implementation class AppFilterImpl:

public class AppFilterImpl extends AppFilter {



@Override

public boolean shouldShowApp(ComponentName app) {

return !" com.android.email".equals(app.getPackageName());

}

}

Copy the code

Very simple, judge if the registration is not a mailbox display, that is, hide the mailbox APP icon display. Then configure this custom class to app_filter_class:

<! -- Name of a subclass of AppFilter used to

filter the activities shown in the launcher. Can be empty. -->

<string name="app_filter_class" translatable="false">com.android.launcher3.AppFilterImpl</string>

Copy the code

Run it, and see that the app list of the desktop and Launcher is gone, and the mailbox widget is not found in the widget. It does work. So let’s see how that works.

Check that the shouldShowApp method is called in two places: in the Add method of AllAppsList and in the WidgetsModel first look at the code in AllAppsList:

/ * *

* Add the supplied ApplicationInfo objects to the list, and enqueue it into the

* list to broadcast when notify() is called.

*

* If the app is already in the list, doesn't add it.

* /

public void add(AppInfo info) {

if (mAppFilter ! = null && ! mAppFilter.shouldShowApp(info.componentName)) {

return;

}

if (findActivity(data, info.componentName, info.user)) {

return;

}

data.add(info);

added.add(info);

}

Copy the code

ShouldShowApp = mappFilter.shouldShowApp = mappFilter.shouldShowApp = mappFilter.shouldShowApp = mappFilter.shouldShowApp = mappFilter.shouldShowApp = mappFilter.shouldShowApp = mappFilter.shouldShowApp

Let’s look at the widget filtering implementation in WidgetsModel.java:

public void setWidgetsAndShortcuts(ArrayList<Object> rawWidgetsShortcuts) {

Utilities.assertWorkerThread();

mRawList = rawWidgetsShortcuts;

if (DEBUG) {

Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());

}



// Temporary list for {@link PackageItemInfos} to avoid having to go through

// {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}

HashMap<String, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();



// clear the lists.

mWidgetsList.clear();

mPackageItemInfos.clear();

mWidgetAndShortcutNameComparator.reset();



InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();



// add and update.

for (Object o: rawWidgetsShortcuts) {

String packageName = "";

UserHandleCompat userHandle = null;

ComponentName componentName = null;

if (o instanceof LauncherAppWidgetProviderInfo) {

LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o;



// Ensure that all widgets we show can be added on a workspace of this size

int minSpanX = Math.min(widgetInfo.spanX, widgetInfo.minSpanX);

int minSpanY = Math.min(widgetInfo.spanY, widgetInfo.minSpanY);

if (minSpanX <= (int) idp.numColumns &&

minSpanY <= (int) idp.numRows) {

componentName = widgetInfo.provider;

packageName = widgetInfo.provider.getPackageName();

userHandle = mAppWidgetMgr.getUser(widgetInfo);

} else {

if (DEBUG) {

Log.d(TAG, String.format(

"Widget %s : (%d X %d) can't fit on this device",

widgetInfo.provider, minSpanX, minSpanY));

}

continue;

}

} else if (o instanceof ResolveInfo) {

ResolveInfo resolveInfo = (ResolveInfo) o;

componentName = new ComponentName(resolveInfo.activityInfo.packageName,

resolveInfo.activityInfo.name);

packageName = resolveInfo.activityInfo.packageName;

userHandle = UserHandleCompat.myUserHandle();

}



if (componentName == null || userHandle == null) {

Log.e(TAG, String.format("Widget cannot be set for %s.", o.getClass().toString()));

continue;

}



if (mAppFilter ! = null && ! mAppFilter.shouldShowApp(componentName)) {

if (DEBUG) {

Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",

packageName));

}

continue;

}



PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);

ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(pInfo);

if (widgetsShortcutsList ! = null) {

widgetsShortcutsList.add(o);

} else {

widgetsShortcutsList = new ArrayList<>();

widgetsShortcutsList.add(o);

pInfo = new PackageItemInfo(packageName);

mIconCache.getTitleAndIconForApp(packageName, userHandle,

true /* userLowResIcon */, pInfo);

pInfo.titleSectionName = mIndexer.computeSectionName(pInfo.title);

mWidgetsList.put(pInfo, widgetsShortcutsList);

tmpPackageItemInfos.put(packageName, pInfo);

mPackageItemInfos.add(pInfo);

}

}



// sort.

Collections.sort(mPackageItemInfos, mAppNameComparator);

for (PackageItemInfo p: mPackageItemInfos) {

Collections.sort(mWidgetsList.get(p), mWidgetAndShortcutNameComparator);

}

}

Copy the code

Added a judgment to the for loop, if mappFilter.shouldShowApp returns false continue to skip processing and not add to widgetsShortcutsList. This makes it impossible to display in the widget list

So what if we just want to hide an app or a widget from an app? It’s really easy. Write a WidgetFilter like AppFilter, Then add a judgment below the AppFilter call in setWidgetsAndShortcuts:

if (mAppFilter ! = null && ! mAppFilter.shouldShowApp(componentName)) {

if (DEBUG) {

Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",

packageName));

}

continue;

}



if (mWidgetFilter ! = null && ! mWidgetFilter.shouldShowAppWidget(componentName)) {

continue;

}

Copy the code

This enables the individual widgets to be hidden.