前言
参考自以下博文,感谢博主
https://blog.csdn.net/qq_30552095/article/details/80494770
https://blog.csdn.net/illailla/article/details/80972830
先下载Launcher3,git clone 或者到googlesource 下载,或者其他地方下载
git clone https://android.googlesource.com/platform/packages/apps/Launcher3
git clone 需要 遇到443问题的话设置下代理
git config --global http.proxy “localhost:1080”
下载后checkout branch到android 9.0 pie, 我check 的分支是pie-release-2
接下来就开始将Launcher3改成我们需要的样式了
Launcher3 改成抽屉式需要更改的内容
1.显示所有app在桌面上
2.去掉上划展开应用列表
3.长按拖动图标去掉删除改成取消 卸载
显示所有app在桌面上
要显示所有app在桌面上,也就是workspace上,首先是要先把所有应用加到桌面,然后要考虑安装后的应用显示到桌面
先在src/com.android.launcher3.config.BaseFlags添加个boolean值
abstract class BaseFlags {
BaseFlags() {}
public static final boolean REMOVE_DRAWER = true;
...
1.显示所有应用
应用加载在src/com.android.launcher3.model.LoaderTask 里
在run里面添加方法加载所有应用
// second step
TraceHelper.partitionSection(TAG, "step 2.1: loading all apps");
loadAllApps();
//add by yy
if (FeatureFlags.REMOVE_DRAWER) {
verifyApplications();
}
//end add by yy
TraceHelper.partitionSection(TAG, "step 2.2: Binding all apps");
verifyNotStopped();
mResults.bindAllApps();
//add by yy
private void verifyApplications() {
final Context context = mApp.getContext();
ArrayList> installQueue = new ArrayList<>();
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) {
InstallShortcutReceiver.PendingInstallShortcutInfo pendingInstallShortcutInfo = new InstallShortcutReceiver.PendingInstallShortcutInfo(app, context);
added.add(pendingInstallShortcutInfo);
installQueue.add(pendingInstallShortcutInfo.getItemInfo());
}
}
if (!added.isEmpty()) {
mApp.getModel().addAndBindAddedWorkspaceItems(installQueue);
}
}
}
//end add by yy
然后再修改src/com.android.launcher3.model.BaseModelUpdateTask,把return 给注释掉
@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.
if(!FeatureFlags.REMOVE_DRAWER){
return;
}
}
execute(mApp, mDataModel, mAllAppsList);
}
这样 应用就可以显示到桌面上了
2.应用安装后加载到桌面
涉及到文件src/com.android.launcher3.model.PackageUpdatedTask
final ArrayList addedOrModified = new ArrayList<>();
addedOrModified.addAll(appsList.added);
//add by yy
if(FeatureFlags.REMOVE_DRAWER){
updateToWorkSpace(context, app, appsList);
}
//end add by yy
appsList.added.clear();
addedOrModified.addAll(appsList.modified);
appsList.modified.clear();
这样第一步就完成了
去掉上划展开应用列表
这一个问题跟了好多个文件,先是从博文里提到的src/com.android.launcher3.allapps.AllAppsTransitionController
再到src/com.android.launcher3.LauncherStateManager/StateHandler
再到src/com.android.launcher3.LauncherStateManager
在AllAppsTransitionController里修改setState方法和setStateWithAnimation方法
public void setState(LauncherState state) {
//2018.12.12 更新 setState方法可以不用管,不然会导致有动画效果没有
// if(FeatureFlags.REMOVE_DRAWER)
// return;
setProgress(state.getVerticalProgress(mLauncher));
setAlphas(state, NO_ANIM_PROPERTY_SETTER);
onProgressAnimationEnd();
}
@Override
public void setStateWithAnimation(LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
if(FeatureFlags.REMOVE_DRAWER)
return;
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config.getPropertySetter(builder));
// Fail fast
onProgressAnimationEnd();
return;
}
这样可以实现上划去掉展开所有app,但是可以上划,上划后会隐藏掉所有的app
然后找到滑动的地方src/com.android.launcher3.touch.AbstractStateChangeTouchController
最后发现修改src_ui_overrides/com.android.launcher3.uioverrides.AllAppsSwipeController
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mTouchDownEvent = ev;
}
if (mCurrentAnimation != null) {
// If we are already animating from a previous state, we can intercept.
return true;
}
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
return false;
}
if (!mLauncher.isInState(NORMAL) && !mLauncher.isInState(ALL_APPS)) {
// Don't listen for the swipe gesture if we are already in some other state.
return false;
}
if (mLauncher.isInState(ALL_APPS) && !mLauncher.getAppsView().shouldContainerScroll(ev)) {
return false;
}
//add by yy
if(FeatureFlags.REMOVE_DRAWER){
return false;
}
//end add by yy
return true;
}
这样就上划不了了,但是这样会有什么其他影响暂时还没研究出来
长按拖动图标去掉删除改成取消 卸载
长按图标出现删除,卸载栏
src/com.android.launcher3.DropTargetBar
应用图标拖动的控制类
src/com.android.launcher3.dragndrop.DragController
删除,卸载类
src/com.android.launcher3.DeleteDropTarget
src/com.android.launcher3.SecondaryDropTarget
拖动应用图标或者文件夹的时候我们需要把删除改成取消,并且拖到取消后桌面不能移除图标
1.应用图标或者文件夹拖动删除改成取消
src/com.android.launcher3.DeleteDropTarget
private void setTextBasedOnDragSource(ItemInfo item) {
if (!TextUtils.isEmpty(mText)) {
mText = getResources().getString(item.id != ItemInfo.NO_ID
? R.string.remove_drop_target_label
: android.R.string.cancel);
if(FeatureFlags.REMOVE_DRAWER){
mText = getResources().getString(isCanDrop(item)
? R.string.remove_drop_target_label
: android.R.string.cancel);
}
requestLayout();
}
}
mControlType 具体作用还不清楚,也一起改了
/**
* Set mControlType depending on the drag item.
*/
private void setControlTypeBasedOnDragSource(ItemInfo item) {
mControlType = item.id != ItemInfo.NO_ID ? ControlType.REMOVE_TARGET
: ControlType.CANCEL_TARGET;
if(FeatureFlags.REMOVE_DRAWER) {
mControlType = isCanDrop(item) ? ControlType.REMOVE_TARGET
: ControlType.CANCEL_TARGET;
}
}
2.删除操作改为取消操作
DragController是应用图标拖动的控制类
onDriverDragEnd是拖动结束后调用的地方,drop 是执行拖动后操作
@Override
public void onDriverDragEnd(float x, float y) {
DropTarget dropTarget;
Runnable flingAnimation = mFlingToDeleteHelper.getFlingAnimation(mDragObject);
if (flingAnimation != null) {
dropTarget = mFlingToDeleteHelper.getDropTarget();
} else {
dropTarget = findDropTarget((int) x, (int) y, mCoordinatesTemp);
}
drop(dropTarget, flingAnimation);
endDrag();
}
在drop方法里对droptarget 判断 如果是拖动到删除 也就是DeleteDropTarget 就取消拖动
private 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;
//add by yy //2018-11-30 16:05 修改
if (FeatureFlags.REMOVE_DRAWER && dropTarget instanceof DeleteDropTarget &&
isNeedCancelDrag(mDragObject.dragInfo)) {
cancelDrag();
}
//end add by yy
}
}
final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null;
mLauncher.getUserEventDispatcher().logDragNDrop(mDragObject, dropTargetAsView);
dispatchDropComplete(dropTargetAsView, accepted);
}
private boolean isNeedCancelDrag(ItemInfo item){
return (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
这样只完成了一步,看 dropTarget.onDrop(mDragObject, mOptions); 这里执行了drop操作.
看DeleteDropTarget 的父类src/com.android.launcher3.ButtonDropTarget
@Override
public void onDrop(final DragObject d, final DragOptions options) {
final DragLayer dragLayer = mLauncher.getDragLayer();
final Rect from = new Rect();
dragLayer.getViewRectRelativeToSelf(d.dragView, from);
final Rect to = getIconRect(d);
final float scale = (float) to.width() / from.width();
mDropTargetBar.deferOnDragEnd();
Runnable onAnimationEndRunnable = () -> {
completeDrop(d);
mDropTargetBar.onDragEnd();
mLauncher.getStateManager().goToState(NORMAL);
};
dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
DRAG_VIEW_DROP_DURATION,
Interpolators.DEACCEL_2, Interpolators.LINEAR, onAnimationEndRunnable,
DragLayer.ANIMATION_END_DISAPPEAR, null);
}
这里做了一个动画效果,动画完后就调用了onAnimationEndRunnable
completeDrop 就是做对应的操作了,然后看DeleteDropTarget 的completeDrop 方法
@Override
public void completeDrop(DragObject d) {
ItemInfo item = d.dragInfo;
if ((d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder)) {
onAccessibilityDrop(null, item);
}
}
/**
* Removes the item from the workspace. If the view is not null, it also removes the view.
*/
@Override
public void onAccessibilityDrop(View view, ItemInfo item) {
// Remove the item from launcher and the db, we can ignore the containerInfo in this call
// because we already remove the drag view from the folder (if the drag originated from
// a folder) in Folder.beginDrag()
// add by yy ,cancel to remove app icon and folder
if(!FeatureFlags.REMOVE_DRAWER || isCanDrop(item)) {
mLauncher.removeItem(view, item, true /* deleteFromDb */);
mLauncher.getWorkspace().stripEmptyScreens();
mLauncher.getDragLayer()
.announceForAccessibility(getContext().getString(R.string.item_removed));
}
// end add by yy
}
private boolean isCanDrop(ItemInfo item){
return !(item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
}
把删除应用图标操作去掉就好了,不让删除应用图标和文件夹
2018-12-03 12:00 更新
应用列表会有个提示上拉的跳动小动画,在src/com.android.launcher3.Launcher 的onResume里,把它去掉就好了
@Override
protected void onResume() {
TraceHelper.beginSection("ON_RESUME");
super.onResume();
TraceHelper.partitionSection("ON_RESUME", "superCall");
mHandler.removeCallbacks(mLogOnDelayedResume);
Utilities.postAsyncCallback(mHandler, mLogOnDelayedResume);
setOnResumeCallback(null);
// Process any items that were added while Launcher was away.
InstallShortcutReceiver.disableAndFlushInstallQueue(
InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
// Refresh shortcuts if the permission changed.
mModel.refreshShortcutsIfRequired();
//Add by yy
if(!FeatureFlags.REMOVE_DRAWER)
DiscoveryBounce.showForHomeIfNeeded(this);
//end add by yy
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
}
UiFactory.onLauncherStateOrResumeChanged(this);
TraceHelper.endSection("ON_RESUME");
}
Launcher3 的Quickstep会调用DiscoveryBounce.showForOverviewIfNeeded 也会有all app跳动的动画
所以我把DiscoveryBounce里的showForHomeIfNeeded 和 showForOverviewIfNeeded 都给注释掉了