OS: RK3568 Android11.0
现在的产品基本都是按照手机样式去做,所以需要把系统默认的Launcher样式,去掉抽屉改为单层显示,也就是把所有的app添加到workspace中。
以下修改是在设备横屏模式下进行 。
文章目录
1.添加一个宏开关控制Launcher单双层显示
- 源码: /packages/apps/Launcher3/src/com/android/launcher3/config/FeatureFlags.java
/**
* true: All applications are displayed in the workspace. Turn off the display of the allapp list
*/
public static final boolean REMOVE_DRAWER = true;
2.去掉Qsb
- 源码: /packages/apps/Launcher3/src/com/android/launcher3/config/FeatureFlags.java
public static final boolean QSB_ON_FIRST_SCREEN = false/*!Utilities.isEinkProduct()*/;
将这个宏改为false,第一页顶部的搜索框就不会显示了
3.加载所有app到workspace中并排序
- 源码:packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java
// add start
import com.android.launcher3.allapps.AppInfoComparator;
import android.util.Pair;
// end
public void run() {
synchronized (this) {
// Skip fast if we are already stopped.
if (mStopped) {
return;
}
}
...
// second step
List<LauncherActivityInfo> allActivityList = loadAllApps();
logger.addSplit("loadAllApps");
// add start
if (FeatureFlags.REMOVE_DRAWER) {
bindAllAppsToWorkspace();
}
// add end
verifyNotStopped();
mResults.bindAllApps();
logger.addSplit("bindAllApps");
...
}
// add start
private void bindAllAppsToWorkspace(){
if (mBgAllAppsList.data.size() > 0) {
AppInfoComparator mAppNameComparator = new AppInfoComparator(mApp.getContext());
ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>(mBgAllAppsList.data);
// 按照名称进行排序
Collections.sort(appInfos, mAppNameComparator);
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
for (AppInfo info : appInfos) {
installQueue.add(Pair.create((ItemInfo) info, null));
}
mApp.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
// end
loadAllApps()中会获取所有应用数据,在添加的bindAllAppsToWorkspace方法中将获取的应用数据按名称排序,然后调用addAndBindAddedWorkspaceItems方法开始app数据与workspace的绑定,处理逻辑在AddWorkspaceItemsTask中进行。
4.系统应用不在workspace中显示
- 源码: /packages/apps/Launcher3/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
if (mItemList.isEmpty()) {
return;
}
...
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;
}
// add start
if (!FeatureFlags.REMOVE_DRAWER) {
// b/139663018 Short-circuit this logic if the icon is a system app
if (PackageManagerHelper.isSystemApp(app.getContext(), item.getIntent())) {
continue;
}
}
// add end
}
在开始处理的时候会判断,如果是系统应用会被忽略,所以我们要把这步跳过去。
5.Hotseat中的应用不在workspace中显示
- 源码:packages/apps/Launcher3/src/com/android/launcher3/model/LoaderCursor.java
protected boolean checkItemPlacement(ItemInfo item) {
int containerIndex = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
// add start
if (FeatureFlags.REMOVE_DRAWER) {
return false;
}
// add end
final GridOccupancy hotseatOccupancy =
occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT);
...
默认在hotseat中的应用不会被添加到workspace中,属于hotseat的应用的container值是-101,所以在此处根据宏做处理或者注释掉default_workspace_xx.xml中launcher:container=“-101”的项
6.所有应用不在第一页显示
- 源码: /packages/apps/Launcher3/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
protected int[] findSpaceForItem( LauncherAppState app, BgDataModel dataModel,
IntArray workspaceScreens, IntArray addedWorkspaceScreensFinal, int spanX, int spanY) {
...
// Find appropriate space for the item.
int screenId = 0;
int[] cordinates = new int[2];
boolean found = false;
int screenCount = workspaceScreens.size();
// First check the preferred screen.
int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;
// add start
if (FeatureFlags.REMOVE_DRAWER) {
preferredScreenIndex = 0;
}
// add end
if (preferredScreenIndex < screenCount) {
screenId = workspaceScreens.get(preferredScreenIndex);
found = findNextAvailableIconSpaceInScreen(
app, screenItems.get(screenId), cordinates, spanX, spanY);
}
这个方法是添加item到workspace中时判断当前页是否有空余位置的,按照上面修改使绑定数据从workspace第一页开始。
7.app数据变化时,更新workspace
- 源码:/packages/apps/Launcher3/src/com/android/launcher3/model/PackageUpdatedTask.java
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
final Context context = app.getContext();
final IconCache iconCache = app.getIconCache();
...
if (Utilities.ATLEAST_OREO && mOp == OP_ADD) {
// Load widgets for the new package. Changes due to app updates are handled through
// AppWidgetHost events, this is just to initialize the long-press options.
for (int i = 0; i < N; i++) {
dataModel.widgetsModel.update(app, new PackageUserKey(packages[i], mUser));
}
bindUpdatedWidgets(dataModel);
}
// add start
if (FeatureFlags.REMOVE_DRAWER) {
bindAllAppsToWorkspace(app, appsList);
}
// add end
}
// add start
private void bindAllAppsToWorkspace(LauncherAppState app, AllAppsList mBgAllAppsList){
if (mBgAllAppsList.data.size() > 0) {
// AppInfoComparator mAppNameComparator = new AppInfoComparator(mApp.getContext());
ArrayList<AppInfo> appInfos = new ArrayList<AppInfo>(mBgAllAppsList.data);
// Collections.sort(appInfos, mAppNameComparator);
ArrayList<Pair<ItemInfo, Object>> installQueue = new ArrayList<>();
for (AppInfo info : appInfos) {
installQueue.add(Pair.create((ItemInfo) info, null));
}
app.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
// add end
8.禁止上滑显示Allapp
- 源码:/packages/apps/Launcher3/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@Override
public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mNoIntercept = !canInterceptTouch(ev);
if (mNoIntercept) {
return false;
}
...
}
// add start
if (FeatureFlags.REMOVE_DRAWER) {
return false;
}
// add end
if (mNoIntercept) {
return false;
}
onControllerTouchEvent(ev);
return mDetector.isDraggingOrSettling();
}
9.调整UI,去掉hotseat和AllApp button
去掉hotseat和Allapp按钮调整布局,设置workspace的行列
9.1 隐藏AllApp button
- 源码:packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsTransitionController.java
public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) {
mAppsView = appsView;
mScrimView = scrimView;
// add start
if (FeatureFlags.REMOVE_DRAWER) {
mScrimView.setVisibility(View.GONE);
}
// add end
PluginManagerWrapper.INSTANCE.get(mLauncher)
.addPluginListener(this, AllAppsSearchPlugin.class, false);
}
9.2 去掉hotseat
- 源码:/packages/apps/Launcher3/src/com/android/launcher3/Hotseat.java
@Override
public void setInsets(Rect insets) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
DeviceProfile grid = mActivity.getDeviceProfile();
...
// add start
if (FeatureFlags.REMOVE_DRAWER) {
lp.height = 0;
}
// add end
setLayoutParams(lp);
InsettableFrameLayout.dispatchInsets(this, insets);
}
直接设置hotseat的高为0
9.3 横屏下workspace界面item的标题不显示
- 源码:/packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java
// 横屏下进入这里,会隐藏workspace中item的title
if (isVerticalBarLayout()) {
// Always hide the Workspace text with vertical bar layout.
adjustToHideWorkspaceLabels();
}
...
public boolean isVerticalBarLayout() {
return isLandscape && transposeLayoutWithOrientation;
}
...
public Builder(Context context, InvariantDeviceProfile inv, DefaultDisplay.Info info) {
mContext = context;
mInv = inv;
mInfo = info;
// add start
if (FeatureFlags.REMOVE_DRAWER) {
mTransposeLayoutWithOrientation = false;
} else {
mTransposeLayoutWithOrientation = context.getResources()
.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
}
// add end
}
hotseat_transpose_layout_with_orientation为true,hotseat的位置会根据屏幕方向旋转改变,这里直接修改为false,相应的isVerticalBarLayout()方法也返回false。
9.4 调整workspace的item的图标和标题的距离
private void updateIconSize(float scale, Resources res) {
// Workspace
...
if (iconDrawablePaddingPx > cellYPadding && !isVerticalLayout
&& !isMultiWindowMode) {
// Ensures that the label is closer to its corresponding icon. This is not an issue
// with vertical bar layout or multi-window mode since the issue is handled separately
// with their calls to {@link #adjustToHideWorkspaceLabels}.
cellHeightPx -= (iconDrawablePaddingPx - cellYPadding);
iconDrawablePaddingPx = cellYPadding;
}
// add start
if (FeatureFlags.REMOVE_DRAWER) {
iconDrawablePaddingPx = 0;
}
// add end
cellWidthPx = iconSizePx + iconDrawablePaddingPx;
9.5 调整workspace到屏幕底部的间隔距离
private void updateWorkspacePadding() {
Rect padding = workspacePadding;
if (isVerticalBarLayout()) {
padding.top = 0;
padding.bottom = edgeMarginPx;
if (isSeascape()) {
padding.left = hotseatBarSizePx;
padding.right = hotseatBarSidePaddingStartPx;
} else {
padding.left = hotseatBarSidePaddingStartPx;
padding.right = hotseatBarSizePx;
}
} else {
// add start
if (FeatureFlags.REMOVE_DRAWER) {
hotseatBarSizePx = 0;
}
// add end
int paddingBottom = hotseatBarSizePx + workspacePageIndicatorHeight
- mWorkspacePageIndicatorOverlapWorkspace;
...
}
9.6. 修改workspace行列
- 源码: packages/apps/Launcher3/src/com/android/launcher3/InvariantDeviceProfile.java
private void initGrid(
Context context, DefaultDisplay.Info displayInfo, DisplayOption displayOption) {
GridOption closestProfile = displayOption.grid;
numRows = closestProfile.numRows;
numColumns = closestProfile.numColumns;
// add start
if (FeatureFlags.REMOVE_DRAWER) {
numRows = 5;
numColumns = 7;
}
// add end
10.修改workspace中的应用和文件拖拽移除为取消
- 源码:/packages/apps/Launcher3/src/com/android/launcher3/DeleteDropTarget.java
private boolean canRemove(ItemInfo item) {
// ad start
boolean remove = FeatureFlags.REMOVE_DRAWER ? !canCancel(item)
: item.id != ItemInfo.NO_ID;
// add end
return remove;
}
/**
* Set mControlType depending on the drag item.
*/
private void setControlTypeBasedOnDragSource(ItemInfo item) {
mControlType = (FeatureFlags.REMOVE_DRAWER ? !canCancel(item) :
item.id != ItemInfo.NO_ID) ? ControlType.REMOVE_TARGET
: ControlType.CANCEL_TARGET;
}
// add start
private boolean canCancel(ItemInfo item){
return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
// add end
- 源码:/packages/apps/Launcher3/src/com/android/launcher3/dragndrop/DragController.java
private void drop(DropTarget dropTarget, Runnable flingAnimation) {
...
// 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);
}
// add start
if (FeatureFlags.REMOVE_DRAWER) {
if (dropTarget instanceof DeleteDropTarget && canCancel(mDragObject.dragInfo)) {
cancelDrag();
}
}
// add end
accepted = true;
}
}
...
}
// add start
private boolean canCancel(ItemInfo item){
return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
//add end