同时制作了下载的资源,资源是按照我我这篇文章的内容针对原生的launcher3代码做了大部分修改,横竖屏都有适配,我自己使用时直接删除了hotseat相关的部分,不过下载资源中做了保留以满足有需要的朋友,下载资源地址:https://download.csdn.net/download/weixue9/12691528
前篇文章已经能够让我们能够成功打包apk了,本人在做自定义修改的时候也借鉴了一些前辈的佳作,在文章结尾处有链接感兴趣的可以自行查看,这篇文章大部分内容与链接中的内容有重复,由于launcher3的开发时公司项目所以不便详细说明,只能总结一些大家熟知的,不过这篇文章的内容也足够满足我们初始的定制化目标,更为个性化的内容需自行摸索了,这篇主要是介绍如何修改以满足我们的需求,具体如下:
1、去掉第一屏google搜索框
修改位置
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\Workspace.java
注释 bindAndInitFirstWorkspaceScreen() 中 if (qsb == null) 开始到结尾
public void bindAndInitFirstWorkspaceScreen(View qsb) {
if (!FeatureFlags.QSB_ON_FIRST_SCREEN) {
return;
}
// Add the first page
CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0);
if (FeatureFlags.PULLDOWN_SEARCH) {
.....
}
//add don't show google quick search box[qsb]
// Always add a QSB on the first screen.
/*if (qsb == null) {
// In transposed layout, we add the QSB in the Grid. As workspace does not touch the
// edges, we do not need a full width QSB.
qsb = LayoutInflater.from(getContext())
.inflate(R.layout.search_container_workspace,firstPage, false);
}
CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, firstPage.getCountX(), 1);
lp.canReorder = false;
if (!firstPage.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true)) {
Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout");
}*/
//add don't show google quick search box[qsb]
}
2、去掉上滑后显示所有 app 界面搜索应用栏
修改位置
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsContainerView.java
在 onFinishInflate() 中添加一行 mSearchContainer.setVisibility(View.GONE);
@Override
protected void onFinishInflate() {
super.onFinishInflate();
....
mSearchContainer = findViewById(R.id.search_container_all_apps);
mSearchUiManager = (SearchUiManager) mSearchContainer;
mSearchUiManager.initialize(mApps, mAppsRecyclerView);
/// add this code don't show all app quick search box
mSearchContainer.setVisibility(View.GONE);
......
}
3、隐藏hotseat中添加老版本的所有应用图标,并去除上滑箭头和屏蔽 Drag 动画
修改位置
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\Hotseat.java
在 resetLayout() 中将 FeatureFlags.NO_ALL_APPS_ICON 写成 true 则默认加载六个点按钮
void resetLayout() {
mContent.removeAllViewsInLayout();
//change true default add all app button
if (/*!FeatureFlags.NO_ALL_APPS_ICON*/true) {
// Add the Apps button
Context context = getContext();
DeviceProfile grid = mLauncher.getDeviceProfile();
int allAppsButtonRank = grid.inv.getAllAppsButtonRank();
LayoutInflater inflater = LayoutInflater.from(context);
TextView allAppsButton = (TextView)
inflater.inflate(R.layout.all_apps_button, mContent, false);
Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
d.setBounds(0, 0, grid.iconSizePx, grid.iconSizePx);
...
}
}
vendor\mediatek\proprietary\packages\apps\Launcher3\res\layout-land\launcher.xml
给 PageIndicatorCaretLandscape 控件添加 gone 属性,注意我此处修改的是横屏的版本,若你是竖屏则修改
layout 文件夹下 launcher.xml
此处添加完成后小箭头确实不显示了,但是当你在 workspace 长按时,小箭头又出现了,坑爹的找了半天,最终终
于搞定了。
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\pageindicators\PageIndicatorCaretLandscape.java
@Override
protected void onDraw(Canvas canvas) {
//annotaion for longclick don't show up arrow
/*Rect drawableBounds = getCaretDrawable().getBounds();
int count = canvas.save();
canvas.translate((getWidth() - drawableBounds.width()) / 2,
getHeight() - drawableBounds.height());
getCaretDrawable().draw(canvas);
canvas.restoreToCount(count);*/
}
注释 onDraw() 的方法体就好了,因为当你长按 workSpace 时,触发长按事件,最终调用了 Launcher
中的 showOverviewMode(),通过 mWorkspace.setVisibility(View.VISIBLE);
PageIndicatorCaretLandscape 和 Workspace 是绑定的,导致 onDraw 执行,重新绘制。
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\allapps\AllAppsTransitionController.java
@Override
public boolean onDrag(float displacement, float velocity) {
Log.e("Launcher3", "onDrag()");
if (true) return true;
//add for forbidden workspace drag change GradientView alph
if (mAppsView == null) {
return false; // early termination.
}
mContainerVelocity = velocity;
float shift = Math.min(Math.max(0, mShiftStart + displacement), mShiftRange);
setProgress(shift / mShiftRange);
return true;
}
@Override
public void onDragEnd(float velocity, boolean fling) {
Log.e("Launcher3", "onDragEnd()");
//add for forbidden workspace drag change GradientView alph
if (true){
if (velocity < 0) {
mLauncher.showWorkspace(true);
}
return;
}
//add for forbidden workspace drag change GradientView alph
if (mAppsView == null) {
return; // early termination.
}
final int containerType = mTouchEventStartedOnHotseat
? ContainerType.HOTSEAT : ContainerType.WORKSPACE;
if (fling) {
if (velocity < 0) {
calculateDuration(velocity, mAppsView.getTranslationY());
if (!mLauncher.isAllAppsVisible()) {
mLauncher.getUserEventDispatcher().logActionOnContainer(
Action.Touch.FLING,
Action.Direction.UP,
containerType);
}
mLauncher.showAppsView(true /* animated */, false /* updatePredictedApps */);
if (hasSpringAnimationHandler()) {
mSpringAnimationHandler.add(mSearchSpring, true /* setDefaultValues */);
// The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
mSpringAnimationHandler.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
}
} else {
calculateDuration(velocity, Math.abs(mShiftRange - mAppsView.getTranslationY()));
mLauncher.showWorkspace(true);
}
// snap to top or bottom using the release velocity
}
.....
}
分别在 onDrag() 和 onDragEnd() 回调方法中直接 return,需要注意的是在 onDragEnd 中需要将
workSpace 的状态复原,不然下一次点击所有APP 按钮时,会出现白屏现象。
4、workSpace 中应用名称文字显示不全或不显示的问题
(1)、显示不全修改如下:
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\BubbleTextView.java
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLauncher = Launcher.getLauncher(context);
DeviceProfile grid = mLauncher.getDeviceProfile();
mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
mDeferShadowGenerationOnTouch =
a.getBoolean(R.styleable.BubbleTextView_deferShadowGeneration, false);
int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
int defaultIconSize = grid.iconSizePx;
if (display == DISPLAY_WORKSPACE) {
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
//cczheng add -11 for text show half
setCompoundDrawablePadding(grid.iconDrawablePaddingPx - 11);
} else if (display == DISPLAY_ALL_APPS) {
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
defaultIconSize = grid.allAppsIconSizePx;
} else if (display == DISPLAY_FOLDER) {
setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx);
setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx);
defaultIconSize = grid.folderChildIconSizePx;
}
.......
setCompoundDrawablePadding()方法 设置图片和 text 之间的间距 ,我们的问题是间距太大导致的,所以在 DISPLAY_WORKSPACE 语句块中,将间距减少 11,同样的当两个图标放置到一块成为文件夹时,对应修改的地方如下,而不是上面的 DISPLAY_FOLDER 语句块。
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\folder\FolderIcon.java
public static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
FolderInfo folderInfo) {
@SuppressWarnings("all") // suppress dead code warning
final boolean error = INITIAL_ITEM_ANIMATION_DURATION >= DROP_IN_ANIMATION_DURATION;
if (error) {
throw new IllegalStateException("DROP_IN_ANIMATION_DURATION must be greater than " +
"INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " +
"is dependent on this");
}
DeviceProfile grid = launcher.getDeviceProfile();
FolderIcon icon = (FolderIcon) LayoutInflater.from(group.getContext())
.inflate(resId, group, false);
icon.setClipToPadding(false);
icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
icon.mFolderName.setText(folderInfo.title);
icon.mFolderName.setCompoundDrawablePadding(0);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams();
//cczheng add -11 for folder text show half
lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx - 11;
icon.setTag(folderInfo);
icon.setOnClickListener(launcher);
icon.mInfo = folderInfo;
icon.mLauncher = launcher;
....
mFolderName 的 setCompoundDrawablePadding 已经是 0, 下面又增加了单独的 marginTop ,同理减去 11.
(2)、不显示的问题
应用名称的的显示主要是通过下面文件中的如下方法的返回值进行控制的,所以这个可以自行灵活控制
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\DeviceProfile.java
/**
* When {@code true}, the device is in landscape mode and the hotseat is on the right column.
* When {@code false}, either device is in portrait mode or the device is in landscape mode and
* the hotseat is on the bottom row.
*/
public boolean isVerticalBarLayout() {
return isLandscape && transposeLayoutWithOrientation;
}
5、去掉抽屉式的打开方式
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\LoaderTask.java
首先在run方法中添加一个loadAllApplications()方法的调用,主要是循环遍历LauncherActivityInfo并通过 LauncherModel的addAndBindAddedWorkspaceItems()方法添加到桌面上,其中主要涉及的知识就是循环遍历,代码如下:
private void loadAllApplications() {
final Context context = mApp.getContext();
final List profiles = mUserManager.getUserProfiles();
for (UserHandle user : profiles) {
final List apps = mLauncherApps.getActivityList(null, user);
ArrayList added = new ArrayList();
synchronized (this) {
for (LauncherActivityInfo app : apps) {
PendingInstallShortcutInfo pendingInstallShortcutInfo = new PendingInstallShortcutInfo(app,context);
added.add(pendingInstallShortcutInfo);
}
}
if (!added.isEmpty()) {
mLauncherModel.addAndBindAddedWorkspaceItems(new LazyShortcutsProvider(context.getApplicationContext(), added));
}
}
}
当时在加上这段代码之后,桌面的iocn还是一直加载不出来,检查了很多遍代码之后,苦思不得其解,只好加log将加载流程一个个打印看看哪里出了问题。接下来修改
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\BaseModelUpdateTask.java
的run方法中代码,修改如下:
@Override
public final void run() {
if (!mModel.isModelLoaded()) {
if (DEBUG_TASKS) {
Log.d(TAG, "Ignoring model task since loader is pending=" + this);
}
// Loader has not yet run.
// return;
}
execute(mApp, mDataModel, mAllAppsList);
}
6、禁止 Workspace 图标长按删除选项
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\DeleteDropTarget.java
在 setTextBasedOnDragSource() 、setControlTypeBasedOnDragSource()、onAccessibilityDrop() 中分别增加判断是否需要删除图标
方法一、直接将 supportsDrop() 返回 false
@Override
protected boolean supportsDrop(DragSource source, ItemInfo info) {
//return true;
return false;// change false
}
7、安装新应用时,要把图标加载到workspace中
vendor\mediatek\proprietary\packages\apps\Launcher3\src\com\android\launcher3\model\PackageUpdatedTask.java
不过要注意加在added这个ArrayList之前被clear之前
addedOrModified.addAll(appsList.added);
//add by gaoshifeng start
final List profiles = UserManagerCompat.getInstance(context).getUserProfiles();
ArrayList added = new ArrayList();
for (UserHandle user : profiles) {
final List apps = LauncherAppsCompat.getInstance(context).getActivityList(null, user);
synchronized (this) {
for (LauncherActivityInfo info : apps) {
for (AppInfo appInfo : appsList.added) {
if(info.getComponentName().equalsappInfo.componentName)){
PendingInstallShortcutInfomPendingInstallShortcutInfo= new PendingInstallShortcutInfo(info,context);
added.add(mPendingInstallShortcutInfo);
}
}
}
}
}
if (!added.isEmpty()) {
app.getModel().addAndBindAddedWorkspaceItems(new LazyShortcutsProvider(context.getApplicationContext(), added));
}
//add by gaoshifeng end
appsList.added.clear();
以上基本上就能完成launcher3的初步自定义了,其他的一些细节的处理请自行debug,我在此基础上做了其他的自定义修改就不一一写出,有什么不妥之处请见谅,以上内容主要借鉴如下几位博主的文章:
https://blog.csdn.net/u012932409/article/details/102941114
https://blog.csdn.net/u012932409/article/details/93221912
https://blog.csdn.net/illailla/article/details/80972830