1、首先需要增加一个标志flag,通过true或者false进行是否去除抽屉模式的表达。
FeatureFlags.java
public static final boolean REMOVE_DRAWER = true;
2、将allApp显示到桌面Workspace上
LoaderTask.java
先导包:
import android.util.Pair;
import java.util.function.Supplier;
import com.android.launcher3.model.ItemInstallQueue;
再在run方法中加入条件判断语句,进行控制。
if(FeatureFlags.REMOVE_DRAWER){
verifyApplications();
}
注意代码放在的位置,如下图所示:
最后增加一个verifyApplications方法进行将allapp的一个显示的操作。
public void verifyApplications(){
final Context context = mApp.getContext();
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
List<UserHandle> profiles = mUserManager.getUserProfiles();
for (UserHandle user : profiles) {
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
ArrayList<ItemInstallQueue.PendingInstallShortcutInfo> added = new ArrayList<ItemInstallQueue.PendingInstallShortcutInfo>();
synchronized (this) {
for (LauncherActivityInfo app : apps) {
ItemInstallQueue.PendingInstallShortcutInfo pendingInstallShortcutInfo = new ItemInstallQueue.PendingInstallShortcutInfo(app.getComponentName().getPackageName(), user);
Log.d("mlb","11111:"+app.getComponentName().getPackageName()+"user:"+user);
added.add(pendingInstallShortcutInfo);
installQueue.add(pendingInstallShortcutInfo.getItemInfo(context));
}
}
if (!added.isEmpty()) {
mApp.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
}
咳咳,下面我用AI解释一下上面的代码哈:
这段代码定义了一个名为 verifyApplications
的方法,它的作用是验证或刷新启动器(Launcher)中的应用程序列表,并将新的快捷方式添加到启动器的工作区。以下是对这个方法的逐行解释:
-
public void verifyApplications(){}
- 定义了一个公共方法
verifyApplications
,该方法没有接收任何参数,也不返回任何值。
- 定义了一个公共方法
-
final Context context = mApp.getContext();
- 获取与启动器应用相关的
Context
对象。mApp
可能是一个全局变量,代表启动器应用的实例。
- 获取与启动器应用相关的
-
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
- 创建一个
ArrayList
,用于存储待安装的快捷方式信息。Pair
类型的installQueue
存储了ItemInfo
和一个关联的Object
。
- 创建一个
-
List<UserHandle> profiles = mUserManager.getUserProfiles();
- 获取当前设备上所有用户配置文件的列表。
mUserManager
是一个全局变量,代表设备的用户管理服务。
- 获取当前设备上所有用户配置文件的列表。
-
for (UserHandle user : profiles) {
- 遍历所有用户配置文件。
-
final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
- 对于每个用户,获取该用户可以启动的所有活动(应用)的列表。
mLauncherApps
是一个全局变量,代表启动器应用的LauncherApps
服务。
- 对于每个用户,获取该用户可以启动的所有活动(应用)的列表。
-
ArrayList<ItemInstallQueue.PendingInstallShortcutInfo> added = new ArrayList<>();
- 创建一个
ArrayList
,用于存储本次添加的快捷方式信息。
- 创建一个
-
synchronized (this) {
- 使用
synchronized
关键字来确保以下代码块在同一时间只能被一个线程执行,这是为了防止多线程环境下的数据不一致问题。
- 使用
-
for (LauncherActivityInfo app : apps) {
- 遍历所有应用。
-
ItemInstallQueue.PendingInstallShortcutInfo pendingInstallShortcutInfo = new ItemInstallQueue.PendingInstallShortcutInfo(app.getComponentName().getPackageName(), user);
- 为每个应用创建一个
PendingInstallShortcutInfo
对象,它包含了应用的包名和用户信息。
- 为每个应用创建一个
-
Log.d("mlb","11111:"+app.getComponentName().getPackageName()+"user:"+user);
- 输出一条调试日志,显示应用的包名和用户信息。
-
added.add(pendingInstallShortcutInfo);
- 将新创建的
PendingInstallShortcutInfo
对象添加到added
列表中。
- 将新创建的
-
installQueue.add(pendingInstallShortcutInfo.getItemInfo(context));
- 将
PendingInstallShortcutInfo
对象转换为ItemInfo
对象,并添加到installQueue
列表中。
- 将
-
}
- 结束
for
循环。
- 结束
-
if (!added.isEmpty()) {
- 检查
added
列表是否不为空。
- 检查
-
mApp.getModel().addAndBindAddedWorkspaceItems(installQueue);
- 如果
added
列表不为空,调用mApp
的getModel
方法来获取启动器的模型,并使用addAndBindAddedWorkspaceItems
方法将installQueue
中的快捷方式添加到启动器的工作空间,并绑定它们。
- 如果
-
}
- 结束
if
代码块。
- 结束
-
}
- 结束
synchronized
代码块。
- 结束
-
}
- 结束
for
循环。
- 结束
-
}
- 结束
verifyApplications
方法。
- 结束
这个方法的主要目的是确保启动器的工作空间包含所有用户配置文件中安装的应用的快捷方式。这通常在启动器应用启动时执行,或者在应用安装或更新后执行,以确保工作空间中的快捷方式是最新的。通过遍历所有用户配置文件,这个方法确保了所有用户的主屏幕都包含了最新的应用快捷方式。
ok,AI解释到此结束
3、还差一点,马上就能将app显示到桌面上了
@Override
public final void run() {
boolean isModelLoaded = Objects.requireNonNull(mModel).isModelLoaded();
testLogD(WORK_TAB_MISSING, "modelLoaded: " + isModelLoaded + " forTask: " + this);
if (!isModelLoaded) {
if (DEBUG_TASKS) {
Log.d(TAG, "Ignoring model task since loader is pending=" + this);
}
// Loader has not yet run.
//return;
}
if(!FeatureFlags.REMOVE_DRAWER){
return;
}
execute(mApp, mDataModel, mAllAppsList);
}
上面这个代码,当我们需要显示所有app到桌面的时候,那么就不会执行return;这个语句,就去执行execute这个方法。
4、注意哈,上面的代码在桌面上有可能只显示下载的app,而不显示系统自带的app
上面的代码会进行往下走,会走到LauncherModel.java这个文件中:
LauncherModel.java
public void addAndBindAddedWorkspaceItems(
@NonNull final List<Pair<ItemInfo, Object>> itemList) {
for (Callbacks cb : getCallbacks()) {
cb.preAddApps();
}
enqueueModelUpdateTask(new AddWorkspaceItemsTask(itemList));
}
可以看到在上面的代码中,会new一个AddWorkspaceItemsTask对象,开启添加的任务,我们深入进去看一下:
AddWorkspaceItemsTask.java
先导包:
import android.util.Log;
然后在构造方法中打Log,发现确实是走到这个地方的
public AddWorkspaceItemsTask(@NonNull final List<Pair<ItemInfo, Object>> itemList,
@NonNull final WorkspaceItemSpaceFinder itemSpaceFinder) {
mItemList = itemList;
for(Pair i : mItemList){
Log.d("mmlb",""+i);
}
mItemSpaceFinder = itemSpaceFinder;
}
还是在这个文件中,我们继续看:
@Override
public void execute(@NonNull final LauncherAppState app, @NonNull final BgDataModel dataModel,
@NonNull final AllAppsList apps) {
if (mItemList.isEmpty()) {
return;
}
final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
final IntArray addedWorkspaceScreensFinal = new IntArray();
synchronized (dataModel) {
IntArray workspaceScreens = dataModel.collectWorkspaceScreens();
List<ItemInfo> filteredItems = new ArrayList<>();
for (Pair<ItemInfo, Object> entry : mItemList) {
ItemInfo item = entry.first;
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
// Short-circuit this logic if the icon exists somewhere on the workspace
if (shortcutExists(dataModel, item.getIntent(), item.user)) {
continue;
}
// b/139663018 Short-circuit this logic if the icon is a system app
if (PackageManagerHelper.isSystemApp(app.getContext(),
Objects.requireNonNull(item.getIntent()))) {
// continue;
}
}
if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
if (item instanceof WorkspaceItemFactory) {
item = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
}
}
if (item != null) {
filteredItems.add(item);
}
}
将上面的continue注释掉,这样的话,系统app也会加载到桌面上。
5、好,显示到桌面上了,下面就要禁止上滑的操作了
PortraitStatesTouchController.java
先导包:
import com.android.launcher3.config.FeatureFlags;
加判断逻辑:
if(FeatureFlags.REMOVE_DRAWER){
return false;
}
返回值是false就表示的是不能上滑显示出所有的app,上面的代码加载的位置如下哦:
这样写到这里,上滑就被禁止了。注意一个文件吧,AllAppsSwipeController.java这个文件你可能会用到。
6、还一个问题,显示到桌面上的app就没有移除按钮了,应该改成取消按钮,点击取消按钮的时候,图标回到原处,其余没有任何操作即可。
移除按钮变取消按钮:
DeleteDropTarget.java
先导包:
import com.android.launcher3.config.FeatureFlags;
再加条件判断语句进行取消拖拽操作:
protected void drop(DropTarget dropTarget, Runnable flingAnimation) {
final int[] coordinates = mCoordinatesTemp;
mDragObject.x = coordinates[0];
mDragObject.y = coordinates[1];
// Move dragging to the final target.
if (dropTarget != mLastDropTarget) {
if (mLastDropTarget != null) {
mLastDropTarget.onDragExit(mDragObject);
}
mLastDropTarget = dropTarget;
if (dropTarget != null) {
dropTarget.onDragEnter(mDragObject);
}
}
mDragObject.dragComplete = true;
if (mIsInPreDrag) {
if (dropTarget != null) {
dropTarget.onDragExit(mDragObject);
}
return;
}
// Drop onto the target.
boolean accepted = false;
if (dropTarget != null) {
dropTarget.onDragExit(mDragObject);
if (dropTarget.acceptDrop(mDragObject)) {
if (flingAnimation != null) {
flingAnimation.run();
} else {
dropTarget.onDrop(mDragObject, mOptions);
}
accepted = true;
if (FeatureFlags.REMOVE_DRAWER) {
cancelDrag();
}
}
}
final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null;
dispatchDropComplete(dropTargetAsView, accepted);
}
修改处如图所示:
取消按钮相应的不能移除图标的实现:
DeleteDropTarget.java
先导包:
import com.android.launcher3.config.FeatureFlags;
再加条件控制语句:
private boolean canRemove(ItemInfo item) {
if(FeatureFlags.REMOVE_DRAWER) {
return false ;
}
return item.id != ItemInfo.NO_ID;
}
over:给你们个链接,这朋友写的比我还详细,不同的人,有不一样的实现方法,地方点也不同。