1.概述

在系统Launcher3中 第一屏默认会放一个时钟AppWidget,对于时钟布局是可以任意拖动的,也是可以任意拖动到其他屏,拖动到其他屏显得很不好看,所以根据需求改成不能拖动时钟去其他屏,这就需要分析拖拽整个流程,根据包名获取如果是时钟就静止拖拽就可以了

2.Launcher3 禁止首屏时钟AppWidget拖动到其他屏的相关核心代码

packages/apps/Launcher3/src/com/android/launcher3/Workspace.java
packages/apps/Launcher3/src/com/android/launcher3/DropTarget.java

3.Launcher3 禁止首屏时钟AppWidget拖动到其他屏的代码分析和功能实现

3.1DropTarget.java关于拖拽类的接口分析

   public interface DropTarget {class DragObject {boolean isDropEnabled();/*** Handle an object being dropped on the DropTarget.** This will be called only if this target previously returned true for {@link #acceptDrop}. It* is the responsibility of this target to exit out of the spring loaded mode (either* immediately or after any pending animations).** If the drop was cancelled for some reason, onDrop will never get called, the UI will* automatically exit out of this mode.*/void onDrop(DragObject dragObject, DragOptions options);void onDragEnter(DragObject dragObject);void onDragOver(DragObject dragObject);void onDragExit(DragObject dragObject);/*** Check if a drop action can occur at, or near, the requested location.* This will be called just before onDrop.* @return True if the drop will be accepted, false otherwise.*/boolean acceptDrop(DragObject dragObject);void prepareAccessibilityDrop();// These methods are implemented in Viewsvoid getHitRectRelativeToDragLayer(Rect outRect);}

从代码中可以看到onDrop()拖拽停止后执行的动作 onDragEnter(拖拽中onDragOver(拖拽结束
onDragExit(退出拖拽的,整个拖拽完成执行相关功能代码

3.2 Workspace.java关于拖拽的功能分析

workSpace是实现了DropTarget的接口类,所以会对整个拖拽过程有详细的执行过程,来分析
拖拽过程执行相关的代码就可以实现这个功能
首选分析Workspace.java 看拖拽流程

packages/apps/Launcher3/src/com/android/launcher3/Workspace.java@Override
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {if (TestProtocol.sDebugTracing) {android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"onDragStart 1");
}
if (ENFORCE_DRAG_EVENT_ORDER) {enforceDragParity("onDragStart", 0, 0);
}if (mDragInfo != null && mDragInfo.cell != null && mDragInfo.cell.getParent() != null) {CellLayout layout = (CellLayout) mDragInfo.cell.getParent().getParent();if (layout != null) layout.markCellsAsUnoccupiedForView(mDragInfo.cell);}if (mOutlineProvider != null) {if (dragObject.dragView != null) {Bitmap preview = dragObject.dragView.getPreviewBitmap();// The outline is used to visualize where the item will land if droppedmOutlineProvider.generateDragOutline(preview);}}updateChildrenLayersEnabled();// Do not add a new page if it is a accessible drag which was not started by the workspace.// We do not support accessibility drag from other sources and instead provide a direct// action for move/add to homescreen.// When a accessible drag is started by the folder, we only allow rearranging withing the// folder.boolean addNewPage = !(options.isAccessibleDrag && dragObject.dragSource != this);if (addNewPage) {mDeferRemoveExtraEmptyScreen = false;addExtraEmptyScreenOnDrag();if (dragObject.dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET&& dragObject.dragSource != this) {// When dragging a widget from different source, move to a page which has// enough space to place this widget (after rearranging/resizing). We special case// widgets as they cannot be placed inside a folder.// Start at the current page and search right (on LTR) until finding a page with// enough space. Since an empty screen is the furthest right, a page must be found.int currentPage = getPageNearestToCenterOfScreen();for (int pageIndex = currentPage; pageIndex < getPageCount(); pageIndex++) {CellLayout page = (CellLayout) getPageAt(pageIndex);if (page.hasReorderSolution(dragObject.dragInfo)) {setCurrentPage(pageIndex);break;}}}}// Always enter the spring loaded modeif (TestProtocol.sDebugTracing) {android.util.Log.d(TestProtocol.NO_DRAG_TAG,"onDragStart 2");}mLauncher.getStateManager().goToState(SPRING_LOADED);
}

从上述代码发现onDragStart() 处理的是开始拖拽的事件,当长按图标的时候开始执行初始化拖拽的相关代码,做好准备工作而
onDrop() 处理的是拖拽后的事件处理,获取当前拖拽的对象,以及要拖拽到哪里去,然后做出相关的处理

public void onDrop(final DragObject d, DragOptions options) {mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
CellLayout dropTargetLayout = mDropToLayout;// We want the point to be mapped to the dragTarget.if (dropTargetLayout != null) {mapPointFromDropLayout(dropTargetLayout, mDragViewVisualCenter);}boolean droppedOnOriginalCell = false;int snapScreen = -1;boolean resizeOnDrop = false;if (d.dragSource != this || mDragInfo == null) {final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],(int) mDragViewVisualCenter[1] };onDropExternal(touchXY, dropTargetLayout, d);} else {AbstractFloatingView.closeOpenViews(mLauncher, false, AbstractFloatingView.TYPE_WIDGET_RESIZE_FRAME);final View cell = mDragInfo.cell;boolean droppedOnOriginalCellDuringTransition = false;Runnable onCompleteRunnable = null;//DragObject对象是对拖拽对象的封装 dragInfo是他的一些详细信息,而包名类名也是可以通过 providerName来获取的//只要获取到包名的相关信息 可以对包名进行判断就可以了 ,如果是这个包名就不会移动到其他屏,当拖动放开后会回到以前的位置// add code startItemInfo iteminfo = d.dragInfo;String packagename = "";if(iteminfo!=null && iteminfo instanceof LauncherAppWidgetInfo){ComponentName componentName = ((LauncherAppWidgetInfo)iteminfo).providerName;if(componentName!=null){packagename = componentName.getPackageName();}}// add code end- if (dropTargetLayout != null && !d.cancelled ) {+  if (dropTargetLayout != null && !d.cancelled && !packagename.equals("com.android.deskclock")) {// Move internallyboolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);int container = hasMovedIntoHotseat ?LauncherSettings.Favorites.CONTAINER_HOTSEAT :LauncherSettings.Favorites.CONTAINER_DESKTOP;int screenId = (mTargetCell[0] < 0) ?mDragInfo.screenId : getIdForScreen(dropTargetLayout);int spanX = mDragInfo != null ? mDragInfo.spanX : 1;int spanY = mDragInfo != null ? mDragInfo.spanY : 1;// First we find the cell nearest to point at which the item is// dropped, without any consideration to whether there is an item there.mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],mDragViewVisualCenter[1], mTargetCell);// If the item being dropped is a shortcut and the nearest drop// cell also contains a shortcut, then create a folder with the two shortcuts.if (createUserFolderIfNecessary(cell, container,dropTargetLayout, mTargetCell, distance, false, d.dragView) ||addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,distance, d, false)) {mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);return;}// Aside from the special case where we're dropping a shortcut onto a shortcut,// we need to find the nearest cell location that is vacantItemInfo item = d.dragInfo;int minSpanX = item.spanX;int minSpanY = item.spanY;if (item.minSpanX > 0 && item.minSpanY > 0) {minSpanX = item.minSpanX;minSpanY = item.minSpanY;}droppedOnOriginalCell = item.screenId == screenId && item.container == container&& item.cellX == mTargetCell[0] && item.cellY == mTargetCell[1];droppedOnOriginalCellDuringTransition = droppedOnOriginalCell && mIsSwitchingState;// When quickly moving an item, a user may accidentally rearrange their// workspace. So instead we move the icon back safely to its original position.boolean returnToOriginalCellToPreventShuffling = !isFinishedSwitchingState()&& !droppedOnOriginalCellDuringTransition && !dropTargetLayout.isRegionVacant(mTargetCell[0], mTargetCell[1], spanX, spanY);int[] resultSpan = new int[2];if (returnToOriginalCellToPreventShuffling) {mTargetCell[0] = mTargetCell[1] = -1;} else {mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],(int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);}boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;// if the widget resizes on dropif (foundCell && (cell instanceof AppWidgetHostView) &&(resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {resizeOnDrop = true;item.spanX = resultSpan[0];item.spanY = resultSpan[1];AppWidgetHostView awhv = (AppWidgetHostView) cell;AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],resultSpan[1]);}if (foundCell) {if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) {snapScreen = getPageIndexForScreenId(screenId);snapToPage(snapScreen);}final ItemInfo info = (ItemInfo) cell.getTag();if (hasMovedLayouts) {// Reparent the viewCellLayout parentCell = getParentCellLayoutForView(cell);if (parentCell != null) {parentCell.removeView(cell);} else if (FeatureFlags.IS_DOGFOOD_BUILD) {throw new NullPointerException("mDragInfo.cell has null parent");}addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],info.spanX, info.spanY);}// update the item's position after dropCellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();lp.cellX = lp.tmpCellX = mTargetCell[0];lp.cellY = lp.tmpCellY = mTargetCell[1];lp.cellHSpan = item.spanX;lp.cellVSpan = item.spanY;lp.isLockedToGrid = true;if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&cell instanceof LauncherAppWidgetHostView) {final CellLayout cellLayout = dropTargetLayout;// We post this call so that the widget has a chance to be placed// in its final locationfinal LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo();if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE&& !d.accessibleDrag) {onCompleteRunnable = new Runnable() {public void run() {if (!isPageInTransition()) {AppWidgetResizeFrame.showForWidget(hostView, cellLayout);}}};}}mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId,lp.cellX, lp.cellY, item.spanX, item.spanY);} else {if (!returnToOriginalCellToPreventShuffling) {onNoCellFound(dropTargetLayout);}// If we can't find a drop location, we return the item to its original positionCellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();mTargetCell[0] = lp.cellX;mTargetCell[1] = lp.cellY;if (cell.getParent() != null) {CellLayout layout = (CellLayout) cell.getParent().getParent();layout.markCellsAsOccupiedForView(cell);}}}final CellLayout parent =cell.getParent() == null ? null : (CellLayout) cell.getParent().getParent();if (d.dragView.hasDrawn()) {if (droppedOnOriginalCellDuringTransition) {// Animate the item to its original position, while simultaneously exiting// spring-loaded mode so the page meets the icon where it was picked up.if (cell.getParent() != null) {mLauncher.getDragController().animateDragViewToOriginalPosition(onCompleteRunnable, cell, SPRING_LOADED_TRANSITION_MS);} else {resetDragCellIfNeed(mDragInfo);}mLauncher.getStateManager().goToState(NORMAL);mLauncher.getDropTargetBar().onDragEnd();if (parent != null) {parent.onDropChild(cell);}return;}final ItemInfo info = (ItemInfo) cell.getTag();boolean isWidget = info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET|| info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;if (isWidget) {int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :ANIMATE_INTO_POSITION_AND_DISAPPEAR;if (parent != null) {animateWidgetDrop(info, parent, d.dragView, null, animationType, cell, false);}} else {int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;if (cell.getParent() != null) {mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,this);} else {d.deferDragViewCleanupPostAnimation = false;resetDragCellIfNeed(mDragInfo);}}} else {d.deferDragViewCleanupPostAnimation = false;if (cell.getParent() != null) {cell.setVisibility(VISIBLE);} else {resetDragCellIfNeed(mDragInfo);}}if (parent != null) {parent.onDropChild(cell);}mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY, onCompleteRunnable);}if (d.stateAnnouncer != null && !droppedOnOriginalCell) {d.stateAnnouncer.completeAction(R.string.item_moved);}
}

可以发现在onDrop()中可以通过DragObject对象获取拖拽的包名,然后对包名进行判断,如果是时钟就排除在外就可以实现功能了

Android 10.0 Launcher3 禁止首屏时钟AppWidget拖动到其他屏相关推荐

  1. 【Android】 禁止首屏时钟AppWidget拖动到其他屏

    ​ ​ 活动地址:CSDN21天学习挑战赛 Android 10.0 Launcher3 禁止首屏时钟AppWidget拖动到其他屏:在日常开发中,屏幕第一屏默认会放一个时钟AppWidget,但是这 ...

  2. Android 9.0 Launcher3 禁止首屏时钟AppWidget拖动到其他屏

    1.前言 在9.0的系统rom定制化开发工作中,在系统Launcher3中 第一屏默认会放一个时钟AppWidget,对于时钟布局是可以任意拖动的,也是可以任意拖动到其他屏,但是如果 拖动时钟控件到其 ...

  3. android 8.1 9.0 10.0 Launcher3禁止拖拽app图标到第一屏

    1.概述 在10.0的产品进行定制化开发Launcher3中,会对Launcher3 做些要求,比如现在的需求就是Launcher3第一屏的图标固定,不让其他屏的图标拖动到第一屏所以说这个需求和 禁止 ...

  4. Android 10.0 Launcher3桌面禁止左右滑动

    1.1概述 在10.0的rom定制化开发中,由于Launcher3有一些功能需要定制,这样的需求也好多的,现在功能需求要求桌面固定在Launcher3的app列表页,不让左右移动,就是禁止左右移动的功 ...

  5. Android 10.0 Launcher3双层(抽屉)高斯模糊(毛玻璃)背景功能的实现

    1.概述 在进行定制开发的功能需求方面,Launcher3的需求也挺多的,单双层抽屉高斯模糊毛玻璃背景功能也是一个需求功能,最近按照功能需求来开发 双层抽屉高斯模糊毛玻璃效果背景的功能 效果图如图: ...

  6. Android 10.0 Launcher3 单层app列表页排序功能实现

    1.概述 在定制化开发中,对于Launcher3的功能定制也是好多的,而对于单层app列表页来说排序功能的开发,也是常有的功能这就需要了解加载app数据的流程,然后根据需要进行排序就可以了, 如图: ...

  7. android 10.0 launcher3 app列表隐藏某个app

    1.概述 在10.0的系统产品中,对于在Launcher3中对于一些app不想显示出来的app中,需要在app列表中去掉不显示这些app的需要更改两处地方,一处是 加在列表时 一处是安装卸载app 更 ...

  8. Android 10.0 Launcher3 抽屉式(双层)app列表排序

    目录 1.概述 2.Launcher3 抽屉式(双层)app列表排序的相关代码 3.Launcher3 抽屉式(双层)app列表排序的相关代码和功能实

  9. Android 10.0 Launcher3 电话和短信app图标显示未读短信和未接来电的条数

    最近客户有需求要求在电话app图标显示未接来电的条数 在短信app图标上显示未读信息的条数 根据需求首选要在Launcher3的Launcher.java中,启动launcher时,查询未读短信和未接 ...

最新文章

  1. 编程大神竟“玩”出了不像 C 的 C 程序
  2. 【C#】允许泛型方法T返回空值Null
  3. hdu 2222:Keywords Search
  4. Silverlight 5 beta新特性探索系列:9.视频快进快退和TextSearch对象对文字项查询
  5. 【BootStrap】初步教程
  6. 轻量在线人工客服系统 支持多商家+自动适配移动端
  7. 不可重复读和幻读的区别_图解脏写、脏读、不可重复读、幻读
  8. 第一:Pytest简介和环境准备
  9. JavaScript自定义事件
  10. 机器视觉:药液质量检测
  11. 二维码QR码的“疯狂”广告
  12. java替换字符串_java string中的替换字符串
  13. android手机wifi快的办法,手机wifi如何设置网速变快(这样设置网速瞬间堪比5G)...
  14. NXP KV10 FTM fault功能的配置
  15. 计算机画图星星怎么画,教你尺规作图画五角星!
  16. Linux内核4.14版本——mmc core(2)——bus模块
  17. 机器学习三 归一化_正则化_多项式升维
  18. autoware.auto版本说明
  19. 01 二叉树的BFS(广度、层次或水平遍历实现)【Binary Tree 二叉树】
  20. MAC OS X下的截图方法

热门文章

  1. pipioj 1028
  2. 简单的YouTube菜单效果
  3. Arduino ESP8266 使用LittleFS存储配置文件实践
  4. 混合云——企业的最佳解决方案?
  5. CVPR2022: Oriented RepPoints论文模型实践(用dota数据集)
  6. 路由器DNS代理的工作原理介绍
  7. 少说话多写代码之Python学习008——字符串的方法02
  8. 简要视音频发展编年史
  9. 微信被封可私聊收费解封 是真的吗?腾讯官方回应来了
  10. GD32F427使用HAL库读写U盘文件的BUG